From f93accd4a19a0b53dfe056fe39c574cd8ae9f91a Mon Sep 17 00:00:00 2001 From: Anthony Samms Date: Sun, 2 Nov 2025 18:29:46 -0500 Subject: [PATCH] minor fixes --- PyTaiko.py | 4 ++-- libs/audio.py | 8 ++++++-- libs/bg_collabs/a3.py | 6 +----- libs/bg_collabs/animal.py | 2 -- libs/bg_collabs/buttoburst.py | 2 -- libs/bg_collabs/dan.py | 4 ++-- libs/file_navigator.py | 17 ++++++++++------- libs/global_data.py | 4 ++-- libs/transition.py | 17 ++++++++++------- libs/video.py | 7 ++++--- scenes/{ => dan}/dan_select.py | 7 ++----- scenes/{ => dan}/game_dan.py | 7 ++++--- scenes/result.py | 12 ++++++------ scenes/settings.py | 2 +- scenes/song_select.py | 12 ++++++++---- scenes/two_player/song_select.py | 4 ++-- 16 files changed, 60 insertions(+), 55 deletions(-) rename scenes/{ => dan}/dan_select.py (99%) rename scenes/{ => dan}/game_dan.py (99%) diff --git a/PyTaiko.py b/PyTaiko.py index b852841..b36420b 100644 --- a/PyTaiko.py +++ b/PyTaiko.py @@ -21,7 +21,7 @@ from libs.utils import ( from scenes.devtest import DevScreen from scenes.entry import EntryScreen from scenes.game import GameScreen -from scenes.game_dan import DanGameScreen +from scenes.dan.game_dan import DanGameScreen from scenes.two_player.game import TwoPlayerGameScreen from scenes.two_player.result import TwoPlayerResultScreen from scenes.loading import LoadScreen @@ -30,7 +30,7 @@ from scenes.settings import SettingsScreen from scenes.song_select import SongSelectScreen from scenes.title import TitleScreen from scenes.two_player.song_select import TwoPlayerSongSelectScreen -from scenes.dan_select import DanSelectScreen +from scenes.dan.dan_select import DanSelectScreen logger = logging.getLogger(__name__) diff --git a/libs/audio.py b/libs/audio.py index 06ac2cf..32b02d4 100644 --- a/libs/audio.py +++ b/libs/audio.py @@ -3,6 +3,7 @@ import platform import logging from pathlib import Path +from libs.global_data import VolumeConfig from libs.utils import get_config ffi = cffi.FFI() @@ -118,7 +119,7 @@ except OSError as e: class AudioEngine: """Initialize an audio engine for playing sounds and music.""" - def __init__(self, device_type: int, sample_rate: float, buffer_size: int, volume_presets: dict[str, float]): + def __init__(self, device_type: int, sample_rate: float, buffer_size: int, volume_presets: VolumeConfig): self.device_type = device_type if sample_rate < 0: self.target_sample_rate = 44100 @@ -142,7 +143,10 @@ class AudioEngine: def get_host_api_name(self, api_id: int) -> str: """Returns the name of the host API with the given ID""" result = lib.get_host_api_name(api_id) # type: ignore - return ffi.string(result).decode('utf-8') + result = ffi.string(result) + if isinstance(result, bytes): + result = result.decode('utf-8') + return result def init_audio_device(self) -> bool: """Initialize the audio device""" diff --git a/libs/bg_collabs/a3.py b/libs/bg_collabs/a3.py index 3591484..f803517 100644 --- a/libs/bg_collabs/a3.py +++ b/libs/bg_collabs/a3.py @@ -75,10 +75,6 @@ class DonBG(DonBGBase): self.move = Animation.create_move(10000, total_distance=-1280) self.move.start() self.move.loop = True - def draw(self, tex: TextureWrapper): - self._draw_textures(tex, 1.0) - if self.is_clear: - self._draw_textures(tex, self.clear_fade.attribute) - def _draw_textures(self, tex: TextureWrapper, fade: float): + def _draw_textures(self, tex: TextureWrapper, fade: float, y: float): for i in range(2): tex.draw_texture(self.name, 'background', frame=self.is_clear, fade=fade, x=(i*1280)+self.move.attribute) diff --git a/libs/bg_collabs/animal.py b/libs/bg_collabs/animal.py index c6a8ad7..c71e4f6 100644 --- a/libs/bg_collabs/animal.py +++ b/libs/bg_collabs/animal.py @@ -37,7 +37,5 @@ class DancerGroup(BaseDancerGroup): class BGFever(BGFeverBase): def start(self): self.transitioned = True - def update(self, current_time_ms: float): - pass def draw(self, tex: TextureWrapper): tex.draw_texture(self.name, 'background') diff --git a/libs/bg_collabs/buttoburst.py b/libs/bg_collabs/buttoburst.py index 08d5aeb..d1a11db 100644 --- a/libs/bg_collabs/buttoburst.py +++ b/libs/bg_collabs/buttoburst.py @@ -36,8 +36,6 @@ class DancerGroup(BaseDancerGroup): class BGFever(BGFeverBase): def start(self): self.transitioned = True - def update(self, current_time_ms: float): - pass def draw(self, tex: TextureWrapper): tex.draw_texture(self.name, 'background') tex.draw_texture(self.name, 'overlay') diff --git a/libs/bg_collabs/dan.py b/libs/bg_collabs/dan.py index 7d5e8f1..3445408 100644 --- a/libs/bg_collabs/dan.py +++ b/libs/bg_collabs/dan.py @@ -19,8 +19,8 @@ class Background: self.chibi = ChibiController(self.tex_wrapper, 2, bpm, path) class DonBG(DonBG6): - def __init__(self, tex: TextureWrapper, player_num: int, bpm: float, path: str): - super().__init__(tex, player_num, bpm, path) + def __init__(self, tex: TextureWrapper, index: int, player_num: int, path: str): + super().__init__(tex, index, player_num, path) self.overlay_move_2 = Animation.create_move(8000, total_distance=-760) self.overlay_move_2.loop = True self.overlay_move_2.start() diff --git a/libs/file_navigator.py b/libs/file_navigator.py index 5a13041..d3fa6b0 100644 --- a/libs/file_navigator.py +++ b/libs/file_navigator.py @@ -404,7 +404,7 @@ class YellowBox: if self.tja.metadata.course_data[diff].is_branching and (get_current_ms() // 1000) % 2 == 0: tex.draw_texture('yellow_box', 'branch_indicator', x=(diff*60), color=color) - def _draw_tja_data_diff(self, is_ura: bool, song_box): + def _draw_tja_data_diff(self, is_ura: bool, song_box: Optional[SongBox] = None): if self.tja is None: return tex.draw_texture('diff_select', 'back', fade=self.fade_in.attribute) @@ -412,6 +412,8 @@ class YellowBox: tex.draw_texture('diff_select', 'neiro', fade=self.fade_in.attribute) for diff in self.tja.metadata.course_data: + if song_box is None: + continue if diff >= 4: continue elif diff in song_box.scores and song_box.scores[diff] is not None and ((song_box.scores[diff][4] == 2 and song_box.scores[diff][2] == 0) or (song_box.scores[diff][2] == 0 and song_box.scores[diff][3] == 0)): @@ -472,7 +474,7 @@ class YellowBox: tex.draw_texture('yellow_box', 'yellow_box_top', x=self.left_x + self.edge_height, y=self.top_y, x2=self.center_width) tex.draw_texture('yellow_box', 'yellow_box_center', x=self.left_x + self.edge_height, y=self.top_y + self.edge_height, x2=self.center_width, y2=self.center_height) - def draw(self, song_box: SongBox, fade_override: Optional[float], is_ura: bool): + def draw(self, song_box: Optional[SongBox], fade_override: Optional[float], is_ura: bool): self._draw_yellow_box() if self.is_dan: return @@ -604,7 +606,7 @@ class DanBox: def _draw_open(self, x: int, y: int, is_ura: bool): if self.yellow_box is not None: - self.yellow_box.draw(x, y, False) + self.yellow_box.draw(None, None, False) for i, song in enumerate(self.song_text): title, subtitle = song x = i * 140 @@ -895,8 +897,8 @@ class DanCourse(FileSystemItem): self.charts = [] for chart in data["charts"]: hash = chart["hash"] - chart_title = chart["title"] - chart_subtitle = chart["subtitle"] + #chart_title = chart["title"] + #chart_subtitle = chart["subtitle"] difficulty = chart["difficulty"] if hash in global_data.song_hashes: path = Path(global_data.song_hashes[hash][0]["file_path"]) @@ -997,10 +999,11 @@ class FileNavigator: song_list = self._read_song_list(self.favorite_folder.path) for song_obj in song_list: if str(song_obj) in self.all_song_files: - if isinstance(self.all_song_files[str(song_obj)].box, DanBox): + box = self.all_song_files[str(song_obj)].box + if isinstance(box, DanBox): logger.warning(f"Cannot favorite DanCourse: {song_obj}") else: - self.all_song_files[str(song_obj)].box.is_favorite = True + box.is_favorite = True logging.info(f"Object generation complete. " f"Directories: {len(self.all_directories)}, " diff --git a/libs/global_data.py b/libs/global_data.py index 29bf5db..2bde4fd 100644 --- a/libs/global_data.py +++ b/libs/global_data.py @@ -120,7 +120,7 @@ class SessionData: result_bad: int = 0 result_max_combo: int = 0 result_total_drumroll: int = 0 - result_gauge_length: int = 0 + result_gauge_length: float = 0 prev_score: int = 0 @dataclass @@ -142,7 +142,7 @@ class GlobalData: session_data (list[SessionData]): Session data for both players. """ songs_played: int = 0 - config: Config = field(default_factory=lambda: dict()) + config: dict = field(default_factory=dict) song_hashes: dict[str, list[dict]] = field(default_factory=lambda: dict()) #Hash to path song_paths: dict[Path, str] = field(default_factory=lambda: dict()) #path to hash song_progress: float = 0.0 diff --git a/libs/transition.py b/libs/transition.py index fae240c..a5b3165 100644 --- a/libs/transition.py +++ b/libs/transition.py @@ -51,14 +51,17 @@ class Transition: offset = 816 - self.rainbow_up.attribute global_tex.draw_texture('rainbow_transition', 'text_bg', y=-self.rainbow_up.attribute - offset, color=color_2) - texture = self.title.texture - x = 1280//2 - texture.width//2 - y = 1176 - texture.height//2 - int(self.rainbow_up.attribute) - offset - 20 - self.title.draw(outline_color=ray.BLACK, x=x, y=y, color=color_1) + if isinstance(self.title, OutlinedText): + texture = self.title.texture + x = 1280//2 - texture.width//2 + y = 1176 - texture.height//2 - int(self.rainbow_up.attribute) - offset - 20 + self.title.draw(outline_color=ray.BLACK, x=x, y=y, color=color_1) - texture = self.subtitle.texture - x = 1280//2 - texture.width//2 - self.subtitle.draw(outline_color=ray.BLACK, x=x, y=y + 50, color=color_1) + if isinstance(self.subtitle, OutlinedText): + texture = self.subtitle.texture + x = 1280//2 - texture.width//2 + y = 1176 - texture.height//2 - int(self.rainbow_up.attribute) - offset - 20 + self.subtitle.draw(outline_color=ray.BLACK, x=x, y=y + 50, color=color_1) def draw(self): """Draw the transition effect.""" diff --git a/libs/video.py b/libs/video.py index d666000..7184b47 100644 --- a/libs/video.py +++ b/libs/video.py @@ -54,9 +54,10 @@ class VideoPlayer: image = ray.Image(frame_data, self.video.w, self.video.h, 1, ray.PixelFormat.PIXELFORMAT_UNCOMPRESSED_R8G8B8) self.texture = ray.load_texture_from_image(image) else: - frame_bytes = frame_data.tobytes() - pixels_ptr = ray.ffi.cast('void *', ray.ffi.from_buffer('unsigned char[]', frame_bytes)) - ray.update_texture(self.texture, pixels_ptr) + if frame_data is not None: + frame_bytes = frame_data.tobytes() + pixels_ptr = ray.ffi.cast('void *', ray.ffi.from_buffer('unsigned char[]', frame_bytes)) + ray.update_texture(self.texture, pixels_ptr) self.current_frame_data = frame_data return True diff --git a/scenes/dan_select.py b/scenes/dan/dan_select.py similarity index 99% rename from scenes/dan_select.py rename to scenes/dan/dan_select.py index 667bf10..d5da339 100644 --- a/scenes/dan_select.py +++ b/scenes/dan/dan_select.py @@ -183,16 +183,13 @@ class DanSelectPlayer: def handle_input(self, state, screen): """Main input dispatcher. Delegates to state-specific handlers.""" - if self.is_voice_playing(): - return if state == State.BROWSING: screen.handle_input_browsing() elif state == State.SONG_SELECTED: res = screen.handle_input_selected() - - if res: - return res + if res: + return res def handle_input_selected(self): """Handle input for selecting difficulty. Returns 'cancel', 'confirm', or None""" diff --git a/scenes/game_dan.py b/scenes/dan/game_dan.py similarity index 99% rename from scenes/game_dan.py rename to scenes/dan/game_dan.py index 958b99e..00bf2a1 100644 --- a/scenes/game_dan.py +++ b/scenes/dan/game_dan.py @@ -12,7 +12,7 @@ from libs.tja import TJAParser from libs.transition import Transition from libs.utils import OutlinedText, get_current_ms from libs.texture import tex -from scenes.game import ClearAnimation, FCAnimation, FailAnimation, GameScreen, ResultTransition, SongInfo +from scenes.game import ClearAnimation, FCAnimation, FailAnimation, GameScreen, Gauge, ResultTransition, SongInfo logger = logging.getLogger(__name__) @@ -91,7 +91,8 @@ class DanGameScreen(GameScreen): session_data.selected_difficulty = difficulty self.player_1.difficulty = difficulty self.tja = TJAParser(song.file_path, start_delay=self.start_delay, distance=SCREEN_WIDTH - GameScreen.JUDGE_X) - audio.unload_music_stream(self.song_music) + if self.song_music is not None: + audio.unload_music_stream(self.song_music) self.song_music = None self.song_started = False @@ -326,7 +327,7 @@ class DanTransition: tex.draw_texture('dan', 'transition', index=1, x=-self.move.attribute) -class DanGauge: +class DanGauge(Gauge): """The player's gauge""" def __init__(self, player_num: str, total_notes: int): self.player_num = player_num diff --git a/scenes/result.py b/scenes/result.py index 660a1c9..0b34d67 100644 --- a/scenes/result.py +++ b/scenes/result.py @@ -122,12 +122,12 @@ class ResultPlayer: plate_info = global_data.config[f'nameplate_{self.player_num}p'] self.nameplate = Nameplate(plate_info['name'], plate_info['title'], int(self.player_num), plate_info['dan'], plate_info['gold'], plate_info['title_bg']) self.score, self.good, self.ok, self.bad, self.max_combo, self.total_drumroll = '', '', '', '', '', '' - self.update_list: list[tuple[str, int]] = [['score', session_data.result_score], - ['good', session_data.result_good], - ['ok', session_data.result_ok], - ['bad', session_data.result_bad], - ['max_combo', session_data.result_max_combo], - ['total_drumroll', session_data.result_total_drumroll]] + self.update_list: list[tuple[str, int]] = [('score', session_data.result_score), + ('good', session_data.result_good), + ('ok', session_data.result_ok), + ('bad', session_data.result_bad), + ('max_combo', session_data.result_max_combo), + ('total_drumroll', session_data.result_total_drumroll)] self.update_index = 0 if session_data.result_ok == 0 and session_data.result_bad == 0: self.crown_type = 'crown_dfc' diff --git a/scenes/settings.py b/scenes/settings.py index f9cdccc..f7f3fab 100644 --- a/scenes/settings.py +++ b/scenes/settings.py @@ -252,7 +252,7 @@ class SettingsScreen(Screen): display_value = ', '.join(map(str, value)) else: display_value = str(value) - if key == 'device_type': + if key == 'device_type' and not isinstance(value, list): display_value = f'{display_value} ({audio.get_host_api_name(value)})' ray.draw_text(f'{key}: {display_value}', 250, i*25 + 70, 20, color) diff --git a/scenes/song_select.py b/scenes/song_select.py index 60c0363..3583991 100644 --- a/scenes/song_select.py +++ b/scenes/song_select.py @@ -5,7 +5,7 @@ from pathlib import Path import pyray as ray import logging -from libs.file_navigator import navigator +from libs.file_navigator import DanCourse, navigator from libs.audio import audio from libs.chara_2d import Chara2D from libs.file_navigator import Directory, SongBox, SongFile @@ -74,7 +74,9 @@ class SongSelectScreen(Screen): return self.on_screen_end("ENTRY") if str(session_data.selected_song) in self.navigator.all_song_files: - self.navigator.mark_crowns_dirty_for_song(self.navigator.all_song_files[str(session_data.selected_song)]) + selected_song = self.navigator.all_song_files[str(session_data.selected_song)] + if not isinstance(selected_song, DanCourse): + self.navigator.mark_crowns_dirty_for_song(selected_song) curr_item = self.navigator.get_current_item() curr_item.box.get_scores() @@ -214,7 +216,7 @@ class SongSelectScreen(Screen): def handle_input(self): self.player_1.handle_input(self.state, self) - def update_players(self, current_time): + def update_players(self, current_time) -> str: self.player_1.update(current_time) if self.text_fade_out.is_finished: self.player_1.selected_song = True @@ -376,6 +378,7 @@ class SongSelectPlayer: self.selected_difficulty = -3 self.prev_diff = -3 self.selected_song = False + self.is_ready = False self.is_ura = False self.ura_toggle = 0 self.diff_select_move_right = False @@ -492,7 +495,7 @@ class SongSelectPlayer: def handle_input(self, state, screen): """Main input dispatcher. Delegates to state-specific handlers.""" - if self.is_voice_playing(): + if self.is_voice_playing() or self.is_ready: return if state == State.BROWSING: @@ -538,6 +541,7 @@ class SongSelectPlayer: self.neiro_selector = NeiroSelector(self.player_num) return None else: + self.is_ready = True return "confirm" if is_l_kat_pressed(self.player_num) or is_r_kat_pressed(self.player_num): diff --git a/scenes/two_player/song_select.py b/scenes/two_player/song_select.py index 7a6de4e..d994b93 100644 --- a/scenes/two_player/song_select.py +++ b/scenes/two_player/song_select.py @@ -128,7 +128,7 @@ class TwoPlayerSongSelectScreen(SongSelectScreen): super()._cancel_selection() self.player_2.selected_song = False - def _confirm_selection(self, player_selected: int): + def _confirm_selection(self, player_selected: int = 1): """Confirm song selection and create game transition""" audio.play_sound('don', 'sound') audio.play_sound(f'voice_start_song_{global_data.player_num}p', 'voice') @@ -160,7 +160,7 @@ class TwoPlayerSongSelectScreen(SongSelectScreen): self.game_transition.start() logger.info(f"Game transition started for song: {title} - {subtitle}") - def update_players(self, current_time): + def update_players(self, current_time) -> str: self.player_1.update(current_time) self.player_2.update(current_time) if self.text_fade_out.is_finished: