mirror of
https://github.com/Yonokid/PyTaiko.git
synced 2026-02-04 11:40:13 +01:00
fix double free bug, add logging, update to python 3.14
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,6 +3,5 @@ __pycache__
|
|||||||
scores.db
|
scores.db
|
||||||
cache
|
cache
|
||||||
dev-config.toml
|
dev-config.toml
|
||||||
.env
|
|
||||||
libaudio.so
|
libaudio.so
|
||||||
win-libs
|
latest.log
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3.12
|
3.14
|
||||||
|
|||||||
103
PyTaiko.py
103
PyTaiko.py
@@ -1,7 +1,9 @@
|
|||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
from raylib import CAMERA_ORTHOGRAPHIC
|
|
||||||
from raylib.defines import (
|
from raylib.defines import (
|
||||||
RL_FUNC_ADD,
|
RL_FUNC_ADD,
|
||||||
RL_ONE,
|
RL_ONE,
|
||||||
@@ -29,6 +31,8 @@ from scenes.title import TitleScreen
|
|||||||
from scenes.two_player.song_select import TwoPlayerSongSelectScreen
|
from scenes.two_player.song_select import TwoPlayerSongSelectScreen
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Screens:
|
class Screens:
|
||||||
TITLE = "TITLE"
|
TITLE = "TITLE"
|
||||||
ENTRY = "ENTRY"
|
ENTRY = "ENTRY"
|
||||||
@@ -42,6 +46,22 @@ class Screens:
|
|||||||
DEV_MENU = "DEV_MENU"
|
DEV_MENU = "DEV_MENU"
|
||||||
LOADING = "LOADING"
|
LOADING = "LOADING"
|
||||||
|
|
||||||
|
class ColoredFormatter(logging.Formatter):
|
||||||
|
COLORS = {
|
||||||
|
'DEBUG': '\033[36m', # Cyan
|
||||||
|
'INFO': '\033[32m', # Green
|
||||||
|
'WARNING': '\033[33m', # Yellow
|
||||||
|
'ERROR': '\033[31m', # Red
|
||||||
|
'CRITICAL': '\033[35m', # Magenta
|
||||||
|
}
|
||||||
|
RESET = '\033[0m'
|
||||||
|
|
||||||
|
def format(self, record):
|
||||||
|
log_color = self.COLORS.get(record.levelname, self.RESET)
|
||||||
|
record = logging.makeLogRecord(record.__dict__)
|
||||||
|
record.levelname = f"{log_color}{record.levelname}{self.RESET}"
|
||||||
|
return super().format(record)
|
||||||
|
|
||||||
def create_song_db():
|
def create_song_db():
|
||||||
"""Create the scores database if it doesn't exist
|
"""Create the scores database if it doesn't exist
|
||||||
The migration will eventually be removed"""
|
The migration will eventually be removed"""
|
||||||
@@ -64,62 +84,78 @@ def create_song_db():
|
|||||||
'''
|
'''
|
||||||
cursor.execute(create_table_query)
|
cursor.execute(create_table_query)
|
||||||
con.commit()
|
con.commit()
|
||||||
# Migrate existing records: set clear=2 for full combos (bad=0)
|
logger.info("Scores database created successfully")
|
||||||
cursor.execute("""
|
|
||||||
UPDATE Scores
|
|
||||||
SET clear = 2
|
|
||||||
WHERE bad = 0 AND (clear IS NULL OR clear <> 2)
|
|
||||||
""")
|
|
||||||
con.commit()
|
|
||||||
print("Scores database created successfully")
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
force_dedicated_gpu()
|
force_dedicated_gpu()
|
||||||
global_data.config = get_config()
|
global_data.config = get_config()
|
||||||
|
log_level = global_data.config["general"]["log_level"]
|
||||||
|
colored_formatter = ColoredFormatter('[%(levelname)s] %(name)s: %(message)s')
|
||||||
|
plain_formatter = logging.Formatter('[%(levelname)s] %(name)s: %(message)s')
|
||||||
|
console_handler = logging.StreamHandler()
|
||||||
|
console_handler.setFormatter(colored_formatter)
|
||||||
|
|
||||||
|
file_handler = logging.FileHandler("latest.log")
|
||||||
|
file_handler.setFormatter(plain_formatter)
|
||||||
|
logging.basicConfig(
|
||||||
|
level=log_level,
|
||||||
|
handlers=[console_handler, file_handler]
|
||||||
|
)
|
||||||
|
logger.info("Starting PyTaiko")
|
||||||
|
|
||||||
|
logger.debug(f"Loaded config: {global_data.config}")
|
||||||
screen_width: int = global_data.config["video"]["screen_width"]
|
screen_width: int = global_data.config["video"]["screen_width"]
|
||||||
screen_height: int = global_data.config["video"]["screen_height"]
|
screen_height: int = global_data.config["video"]["screen_height"]
|
||||||
|
|
||||||
if global_data.config["video"]["vsync"]:
|
if global_data.config["video"]["vsync"]:
|
||||||
ray.set_config_flags(ray.ConfigFlags.FLAG_VSYNC_HINT)
|
ray.set_config_flags(ray.ConfigFlags.FLAG_VSYNC_HINT)
|
||||||
|
logger.info("VSync enabled")
|
||||||
if global_data.config["video"]["target_fps"] != -1:
|
if global_data.config["video"]["target_fps"] != -1:
|
||||||
ray.set_target_fps(global_data.config["video"]["target_fps"])
|
ray.set_target_fps(global_data.config["video"]["target_fps"])
|
||||||
|
logger.info(f"Target FPS set to {global_data.config['video']['target_fps']}")
|
||||||
ray.set_config_flags(ray.ConfigFlags.FLAG_MSAA_4X_HINT)
|
ray.set_config_flags(ray.ConfigFlags.FLAG_MSAA_4X_HINT)
|
||||||
ray.set_trace_log_level(ray.TraceLogLevel.LOG_WARNING)
|
ray.set_trace_log_level(ray.TraceLogLevel.LOG_WARNING)
|
||||||
|
|
||||||
camera = ray.Camera3D()
|
|
||||||
camera.position = ray.Vector3(0.0, 0.0, 10.0) # Camera position
|
|
||||||
camera.target = ray.Vector3(0.0, 0.0, 0.0) # Camera looking at point
|
|
||||||
camera.up = ray.Vector3(0.0, 1.0, 0.0) # Camera up vector
|
|
||||||
camera.fovy = screen_height # For orthographic, this acts as the view height
|
|
||||||
camera.projection = CAMERA_ORTHOGRAPHIC
|
|
||||||
|
|
||||||
ray.init_window(screen_width, screen_height, "PyTaiko")
|
ray.init_window(screen_width, screen_height, "PyTaiko")
|
||||||
|
logger.info(f"Window initialized: {screen_width}x{screen_height}")
|
||||||
global_tex.load_screen_textures('global')
|
global_tex.load_screen_textures('global')
|
||||||
|
logger.info("Global screen textures loaded")
|
||||||
global_tex.load_zip('chara', 'chara_0')
|
global_tex.load_zip('chara', 'chara_0')
|
||||||
global_tex.load_zip('chara', 'chara_1')
|
global_tex.load_zip('chara', 'chara_1')
|
||||||
|
logger.info("Chara textures loaded")
|
||||||
if global_data.config["video"]["borderless"]:
|
if global_data.config["video"]["borderless"]:
|
||||||
ray.toggle_borderless_windowed()
|
ray.toggle_borderless_windowed()
|
||||||
|
logger.info("Borderless window enabled")
|
||||||
if global_data.config["video"]["fullscreen"]:
|
if global_data.config["video"]["fullscreen"]:
|
||||||
ray.toggle_fullscreen()
|
ray.toggle_fullscreen()
|
||||||
|
logger.info("Fullscreen enabled")
|
||||||
|
|
||||||
current_screen = Screens.LOADING
|
current_screen = Screens.LOADING
|
||||||
|
logger.info(f"Initial screen: {current_screen}")
|
||||||
|
|
||||||
audio.set_log_level(1)
|
audio.set_log_level(1)
|
||||||
|
old_stderr = os.dup(2)
|
||||||
|
devnull = os.open(os.devnull, os.O_WRONLY)
|
||||||
|
os.dup2(devnull, 2)
|
||||||
|
os.close(devnull)
|
||||||
audio.init_audio_device()
|
audio.init_audio_device()
|
||||||
|
os.dup2(old_stderr, 2)
|
||||||
|
os.close(old_stderr)
|
||||||
|
logger.info("Audio device initialized")
|
||||||
|
|
||||||
create_song_db()
|
create_song_db()
|
||||||
|
|
||||||
title_screen = TitleScreen()
|
title_screen = TitleScreen('title')
|
||||||
entry_screen = EntryScreen()
|
entry_screen = EntryScreen('entry')
|
||||||
song_select_screen = SongSelectScreen()
|
song_select_screen = SongSelectScreen('song_select')
|
||||||
song_select_screen_2p = TwoPlayerSongSelectScreen()
|
song_select_screen_2p = TwoPlayerSongSelectScreen('song_select')
|
||||||
load_screen = LoadScreen()
|
load_screen = LoadScreen('loading')
|
||||||
game_screen = GameScreen()
|
game_screen = GameScreen('game')
|
||||||
game_screen_2p = TwoPlayerGameScreen()
|
game_screen_2p = TwoPlayerGameScreen('game')
|
||||||
result_screen = ResultScreen()
|
result_screen = ResultScreen('result')
|
||||||
result_screen_2p = TwoPlayerResultScreen()
|
result_screen_2p = TwoPlayerResultScreen('result')
|
||||||
settings_screen = SettingsScreen()
|
settings_screen = SettingsScreen('settings')
|
||||||
dev_screen = DevScreen()
|
dev_screen = DevScreen('dev')
|
||||||
|
|
||||||
screen_mapping = {
|
screen_mapping = {
|
||||||
Screens.ENTRY: entry_screen,
|
Screens.ENTRY: entry_screen,
|
||||||
@@ -141,12 +177,15 @@ def main():
|
|||||||
ray.set_exit_key(ord(global_data.config["keys_1p"]["exit_key"]))
|
ray.set_exit_key(ord(global_data.config["keys_1p"]["exit_key"]))
|
||||||
|
|
||||||
ray.hide_cursor()
|
ray.hide_cursor()
|
||||||
|
logger.info("Cursor hidden")
|
||||||
|
|
||||||
while not ray.window_should_close():
|
while not ray.window_should_close():
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_F11):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_F11):
|
||||||
ray.toggle_fullscreen()
|
ray.toggle_fullscreen()
|
||||||
|
logger.info("Toggled fullscreen")
|
||||||
elif ray.is_key_pressed(ray.KeyboardKey.KEY_F10):
|
elif ray.is_key_pressed(ray.KeyboardKey.KEY_F10):
|
||||||
ray.toggle_borderless_windowed()
|
ray.toggle_borderless_windowed()
|
||||||
|
logger.info("Toggled borderless windowed mode")
|
||||||
|
|
||||||
ray.begin_texture_mode(target)
|
ray.begin_texture_mode(target)
|
||||||
ray.begin_blend_mode(ray.BlendMode.BLEND_CUSTOM_SEPARATE)
|
ray.begin_blend_mode(ray.BlendMode.BLEND_CUSTOM_SEPARATE)
|
||||||
@@ -154,13 +193,12 @@ def main():
|
|||||||
screen = screen_mapping[current_screen]
|
screen = screen_mapping[current_screen]
|
||||||
|
|
||||||
next_screen = screen.update()
|
next_screen = screen.update()
|
||||||
ray.clear_background(ray.BLACK)
|
if screen.screen_init:
|
||||||
screen.draw()
|
ray.clear_background(ray.BLACK)
|
||||||
#ray.begin_mode_3d(camera)
|
screen.draw()
|
||||||
#screen.draw_3d()
|
|
||||||
# ray.end_mode_3d()
|
|
||||||
|
|
||||||
if next_screen is not None:
|
if next_screen is not None:
|
||||||
|
logger.info(f"Screen changed from {current_screen} to {next_screen}")
|
||||||
current_screen = next_screen
|
current_screen = next_screen
|
||||||
global_data.input_locked = 0
|
global_data.input_locked = 0
|
||||||
|
|
||||||
@@ -181,6 +219,7 @@ def main():
|
|||||||
ray.end_drawing()
|
ray.end_drawing()
|
||||||
ray.close_window()
|
ray.close_window()
|
||||||
audio.close_audio_device()
|
audio.close_audio_device()
|
||||||
|
logger.info("Window closed and audio device shut down")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ touch_enabled = false
|
|||||||
timer_frozen = true
|
timer_frozen = true
|
||||||
judge_counter = false
|
judge_counter = false
|
||||||
nijiiro_notes = false
|
nijiiro_notes = false
|
||||||
|
log_level = 30
|
||||||
|
|
||||||
[nameplate_1p]
|
[nameplate_1p]
|
||||||
name = 'どんちゃん'
|
name = 'どんちゃん'
|
||||||
@@ -47,7 +48,7 @@ right_kat = [12]
|
|||||||
[audio]
|
[audio]
|
||||||
# device_type: 0 = default, check console output from list_host_apis() for other options
|
# device_type: 0 = default, check console output from list_host_apis() for other options
|
||||||
# Windows users should generally pick 3 (WASAPI) and Linux users should pick 0 (ALSA)
|
# Windows users should generally pick 3 (WASAPI) and Linux users should pick 0 (ALSA)
|
||||||
device_type = 3
|
device_type = 0
|
||||||
# sample_rate: -1 = use device default (usually 44100 or 48000)
|
# sample_rate: -1 = use device default (usually 44100 or 48000)
|
||||||
sample_rate = -1
|
sample_rate = -1
|
||||||
# buffer_size: Size in samples per audio buffer
|
# buffer_size: Size in samples per audio buffer
|
||||||
@@ -67,4 +68,4 @@ screen_height = 720
|
|||||||
fullscreen = false
|
fullscreen = false
|
||||||
borderless = false
|
borderless = false
|
||||||
target_fps = -1
|
target_fps = -1
|
||||||
vsync = true
|
vsync = false
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import cffi
|
import cffi
|
||||||
import ctypes
|
|
||||||
import platform
|
import platform
|
||||||
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from libs.utils import get_config
|
from libs.utils import get_config
|
||||||
@@ -43,6 +43,7 @@ ffi.cdef("""
|
|||||||
|
|
||||||
// Device management
|
// Device management
|
||||||
void list_host_apis(void);
|
void list_host_apis(void);
|
||||||
|
const char* get_host_api_name(PaHostApiIndex hostApi);
|
||||||
void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned long buffer_size);
|
void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned long buffer_size);
|
||||||
void close_audio_device(void);
|
void close_audio_device(void);
|
||||||
bool is_audio_device_ready(void);
|
bool is_audio_device_ready(void);
|
||||||
@@ -102,6 +103,8 @@ ffi.cdef("""
|
|||||||
void free(void *ptr);
|
void free(void *ptr);
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
lib = ffi.dlopen("libaudio.dll")
|
lib = ffi.dlopen("libaudio.dll")
|
||||||
@@ -110,23 +113,9 @@ try:
|
|||||||
else: # Assume Linux/Unix
|
else: # Assume Linux/Unix
|
||||||
lib = ffi.dlopen("./libaudio.so")
|
lib = ffi.dlopen("./libaudio.so")
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
print(f"Failed to load shared library: {e}")
|
logger.error(f"Failed to load shared library: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def get_short_path_name(long_path: str) -> str:
|
|
||||||
"""Convert long path to Windows short path (8.3 format)"""
|
|
||||||
if platform.system() != 'Windows':
|
|
||||||
return long_path
|
|
||||||
|
|
||||||
# Get short path name
|
|
||||||
buffer = ctypes.create_unicode_buffer(512)
|
|
||||||
get_short_path = ctypes.windll.kernel32.GetShortPathNameW
|
|
||||||
ret = get_short_path(long_path, buffer, 512)
|
|
||||||
|
|
||||||
if ret:
|
|
||||||
return buffer.value
|
|
||||||
return long_path
|
|
||||||
|
|
||||||
class AudioEngine:
|
class AudioEngine:
|
||||||
"""Initialize an audio engine for playing sounds and music."""
|
"""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: dict[str, float]):
|
||||||
@@ -150,6 +139,11 @@ class AudioEngine:
|
|||||||
"""Prints a list of available host APIs to the console"""
|
"""Prints a list of available host APIs to the console"""
|
||||||
lib.list_host_apis() # type: ignore
|
lib.list_host_apis() # type: ignore
|
||||||
|
|
||||||
|
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')
|
||||||
|
|
||||||
def init_audio_device(self) -> bool:
|
def init_audio_device(self) -> bool:
|
||||||
"""Initialize the audio device"""
|
"""Initialize the audio device"""
|
||||||
try:
|
try:
|
||||||
@@ -160,10 +154,10 @@ class AudioEngine:
|
|||||||
file_path_str = str(self.sounds_path / 'ka.wav').encode('utf-8')
|
file_path_str = str(self.sounds_path / 'ka.wav').encode('utf-8')
|
||||||
self.kat = lib.load_sound(file_path_str) # type: ignore
|
self.kat = lib.load_sound(file_path_str) # type: ignore
|
||||||
if self.audio_device_ready:
|
if self.audio_device_ready:
|
||||||
print("Audio device initialized successfully")
|
logger.info("Audio device initialized successfully")
|
||||||
return self.audio_device_ready
|
return self.audio_device_ready
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to initialize audio device: {e}")
|
logger.error(f"Failed to initialize audio device: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def close_audio_device(self) -> None:
|
def close_audio_device(self) -> None:
|
||||||
@@ -179,9 +173,9 @@ class AudioEngine:
|
|||||||
lib.unload_sound(self.kat) # type: ignore
|
lib.unload_sound(self.kat) # type: ignore
|
||||||
lib.close_audio_device() # type: ignore
|
lib.close_audio_device() # type: ignore
|
||||||
self.audio_device_ready = False
|
self.audio_device_ready = False
|
||||||
print("Audio device closed")
|
logger.info("Audio device closed")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error closing audio device: {e}")
|
logger.error(f"Error closing audio device: {e}")
|
||||||
|
|
||||||
def is_audio_device_ready(self) -> bool:
|
def is_audio_device_ready(self) -> bool:
|
||||||
"""Check if audio device is ready"""
|
"""Check if audio device is ready"""
|
||||||
@@ -210,10 +204,10 @@ class AudioEngine:
|
|||||||
self.sounds[name] = sound
|
self.sounds[name] = sound
|
||||||
return name
|
return name
|
||||||
else:
|
else:
|
||||||
print(f"Failed to load sound: {file_path}")
|
logger.error(f"Failed to load sound: {file_path}")
|
||||||
return ""
|
return ""
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error loading sound {file_path}: {e}")
|
logger.error(f"Error loading sound {file_path}: {e}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def unload_sound(self, name: str) -> None:
|
def unload_sound(self, name: str) -> None:
|
||||||
@@ -222,11 +216,14 @@ class AudioEngine:
|
|||||||
lib.unload_sound(self.sounds[name]) # type: ignore
|
lib.unload_sound(self.sounds[name]) # type: ignore
|
||||||
del self.sounds[name]
|
del self.sounds[name]
|
||||||
else:
|
else:
|
||||||
print(f"Sound {name} not found")
|
logger.warning(f"Sound {name} not found")
|
||||||
|
|
||||||
def load_screen_sounds(self, screen_name: str) -> None:
|
def load_screen_sounds(self, screen_name: str) -> None:
|
||||||
"""Load sounds for a given screen"""
|
"""Load sounds for a given screen"""
|
||||||
path = self.sounds_path / screen_name
|
path = self.sounds_path / screen_name
|
||||||
|
if not path.exists():
|
||||||
|
logger.warning(f"Sounds for {screen_name} not found")
|
||||||
|
return
|
||||||
for sound in path.iterdir():
|
for sound in path.iterdir():
|
||||||
if sound.is_dir():
|
if sound.is_dir():
|
||||||
for file in sound.iterdir():
|
for file in sound.iterdir():
|
||||||
@@ -263,7 +260,7 @@ class AudioEngine:
|
|||||||
lib.set_sound_volume(sound, self.volume_presets[volume_preset]) # type: ignore
|
lib.set_sound_volume(sound, self.volume_presets[volume_preset]) # type: ignore
|
||||||
lib.play_sound(sound) # type: ignore
|
lib.play_sound(sound) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Sound {name} not found")
|
logger.warning(f"Sound {name} not found")
|
||||||
|
|
||||||
def stop_sound(self, name: str) -> None:
|
def stop_sound(self, name: str) -> None:
|
||||||
"""Stop a sound"""
|
"""Stop a sound"""
|
||||||
@@ -275,7 +272,7 @@ class AudioEngine:
|
|||||||
sound = self.sounds[name]
|
sound = self.sounds[name]
|
||||||
lib.stop_sound(sound) # type: ignore
|
lib.stop_sound(sound) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Sound {name} not found")
|
logger.warning(f"Sound {name} not found")
|
||||||
|
|
||||||
def is_sound_playing(self, name: str) -> bool:
|
def is_sound_playing(self, name: str) -> bool:
|
||||||
"""Check if a sound is playing"""
|
"""Check if a sound is playing"""
|
||||||
@@ -287,7 +284,7 @@ class AudioEngine:
|
|||||||
sound = self.sounds[name]
|
sound = self.sounds[name]
|
||||||
return lib.is_sound_playing(sound) # type: ignore
|
return lib.is_sound_playing(sound) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Sound {name} not found")
|
logger.warning(f"Sound {name} not found")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def set_sound_volume(self, name: str, volume: float) -> None:
|
def set_sound_volume(self, name: str, volume: float) -> None:
|
||||||
@@ -300,7 +297,7 @@ class AudioEngine:
|
|||||||
sound = self.sounds[name]
|
sound = self.sounds[name]
|
||||||
lib.set_sound_volume(sound, volume) # type: ignore
|
lib.set_sound_volume(sound, volume) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Sound {name} not found")
|
logger.warning(f"Sound {name} not found")
|
||||||
|
|
||||||
def set_sound_pan(self, name: str, pan: float) -> None:
|
def set_sound_pan(self, name: str, pan: float) -> None:
|
||||||
"""Set the pan of a specific sound"""
|
"""Set the pan of a specific sound"""
|
||||||
@@ -312,7 +309,7 @@ class AudioEngine:
|
|||||||
sound = self.sounds[name]
|
sound = self.sounds[name]
|
||||||
lib.set_sound_pan(sound, pan) # type: ignore
|
lib.set_sound_pan(sound, pan) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Sound {name} not found")
|
logger.warning(f"Sound {name} not found")
|
||||||
|
|
||||||
# Music management
|
# Music management
|
||||||
def load_music_stream(self, file_path: Path, name: str) -> str:
|
def load_music_stream(self, file_path: Path, name: str) -> str:
|
||||||
@@ -326,10 +323,10 @@ class AudioEngine:
|
|||||||
|
|
||||||
if lib.is_music_valid(music): # type: ignore
|
if lib.is_music_valid(music): # type: ignore
|
||||||
self.music_streams[name] = music
|
self.music_streams[name] = music
|
||||||
print(f"Loaded music stream from {file_path} as {name}")
|
logger.info(f"Loaded music stream from {file_path} as {name}")
|
||||||
return name
|
return name
|
||||||
else:
|
else:
|
||||||
print(f"Failed to load music: {file_path}")
|
logger.error(f"Failed to load music: {file_path}")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def play_music_stream(self, name: str, volume_preset: str) -> None:
|
def play_music_stream(self, name: str, volume_preset: str) -> None:
|
||||||
@@ -341,7 +338,7 @@ class AudioEngine:
|
|||||||
lib.set_music_volume(music, self.volume_presets[volume_preset]) # type: ignore
|
lib.set_music_volume(music, self.volume_presets[volume_preset]) # type: ignore
|
||||||
lib.play_music_stream(music) # type: ignore
|
lib.play_music_stream(music) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
|
|
||||||
def update_music_stream(self, name: str) -> None:
|
def update_music_stream(self, name: str) -> None:
|
||||||
"""Update a music stream"""
|
"""Update a music stream"""
|
||||||
@@ -349,7 +346,7 @@ class AudioEngine:
|
|||||||
music = self.music_streams[name]
|
music = self.music_streams[name]
|
||||||
lib.update_music_stream(music) # type: ignore
|
lib.update_music_stream(music) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
|
|
||||||
def get_music_time_length(self, name: str) -> float:
|
def get_music_time_length(self, name: str) -> float:
|
||||||
"""Get the time length of a music stream"""
|
"""Get the time length of a music stream"""
|
||||||
@@ -357,7 +354,7 @@ class AudioEngine:
|
|||||||
music = self.music_streams[name]
|
music = self.music_streams[name]
|
||||||
return lib.get_music_time_length(music) # type: ignore
|
return lib.get_music_time_length(music) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
def get_music_time_played(self, name: str) -> float:
|
def get_music_time_played(self, name: str) -> float:
|
||||||
@@ -366,7 +363,7 @@ class AudioEngine:
|
|||||||
music = self.music_streams[name]
|
music = self.music_streams[name]
|
||||||
return lib.get_music_time_played(music) # type: ignore
|
return lib.get_music_time_played(music) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
return 0.0
|
return 0.0
|
||||||
|
|
||||||
def set_music_volume(self, name: str, volume: float) -> None:
|
def set_music_volume(self, name: str, volume: float) -> None:
|
||||||
@@ -375,7 +372,7 @@ class AudioEngine:
|
|||||||
music = self.music_streams[name]
|
music = self.music_streams[name]
|
||||||
lib.set_music_volume(music, volume) # type: ignore
|
lib.set_music_volume(music, volume) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
|
|
||||||
def is_music_stream_playing(self, name: str) -> bool:
|
def is_music_stream_playing(self, name: str) -> bool:
|
||||||
"""Check if a music stream is playing"""
|
"""Check if a music stream is playing"""
|
||||||
@@ -383,7 +380,7 @@ class AudioEngine:
|
|||||||
music = self.music_streams[name]
|
music = self.music_streams[name]
|
||||||
return lib.is_music_stream_playing(music) # type: ignore
|
return lib.is_music_stream_playing(music) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def stop_music_stream(self, name: str) -> None:
|
def stop_music_stream(self, name: str) -> None:
|
||||||
@@ -392,7 +389,7 @@ class AudioEngine:
|
|||||||
music = self.music_streams[name]
|
music = self.music_streams[name]
|
||||||
lib.stop_music_stream(music) # type: ignore
|
lib.stop_music_stream(music) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
|
|
||||||
def unload_music_stream(self, name: str) -> None:
|
def unload_music_stream(self, name: str) -> None:
|
||||||
"""Unload a music stream"""
|
"""Unload a music stream"""
|
||||||
@@ -401,7 +398,7 @@ class AudioEngine:
|
|||||||
lib.unload_music_stream(music) # type: ignore
|
lib.unload_music_stream(music) # type: ignore
|
||||||
del self.music_streams[name]
|
del self.music_streams[name]
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
|
|
||||||
def unload_all_music(self) -> None:
|
def unload_all_music(self) -> None:
|
||||||
"""Unload all music streams"""
|
"""Unload all music streams"""
|
||||||
@@ -414,7 +411,7 @@ class AudioEngine:
|
|||||||
music = self.music_streams[name]
|
music = self.music_streams[name]
|
||||||
lib.seek_music_stream(music, position) # type: ignore
|
lib.seek_music_stream(music, position) # type: ignore
|
||||||
else:
|
else:
|
||||||
print(f"Music stream {name} not found")
|
logger.warning(f"Music stream {name} not found")
|
||||||
|
|
||||||
# Create the global audio instance
|
# Create the global audio instance
|
||||||
audio = AudioEngine(get_config()["audio"]["device_type"], get_config()["audio"]["sample_rate"], get_config()["audio"]["buffer_size"], get_config()["volume"])
|
audio = AudioEngine(get_config()["audio"]["device_type"], get_config()["audio"]["sample_rate"], get_config()["audio"]["buffer_size"], get_config()["volume"])
|
||||||
|
|||||||
@@ -116,6 +116,7 @@ typedef struct AudioData {
|
|||||||
} AudioData;
|
} AudioData;
|
||||||
|
|
||||||
void list_host_apis(void);
|
void list_host_apis(void);
|
||||||
|
const char* get_host_api_name(PaHostApiIndex hostApi);
|
||||||
void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned long buffer_size);
|
void init_audio_device(PaHostApiIndex host_api, double sample_rate, unsigned long buffer_size);
|
||||||
void close_audio_device(void);
|
void close_audio_device(void);
|
||||||
bool is_audio_device_ready(void);
|
bool is_audio_device_ready(void);
|
||||||
@@ -289,6 +290,16 @@ void list_host_apis(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* get_host_api_name(PaHostApiIndex hostApi)
|
||||||
|
{
|
||||||
|
const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo(hostApi);
|
||||||
|
if (!hostApiInfo) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostApiInfo->name;
|
||||||
|
}
|
||||||
|
|
||||||
PaDeviceIndex get_best_output_device_for_host_api(PaHostApiIndex hostApi)
|
PaDeviceIndex get_best_output_device_for_host_api(PaHostApiIndex hostApi)
|
||||||
{
|
{
|
||||||
const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo(hostApi);
|
const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo(hostApi);
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ void set_log_level(int level);
|
|||||||
* Print available host APIs to the console
|
* Print available host APIs to the console
|
||||||
*/
|
*/
|
||||||
void list_host_apis(void);
|
void list_host_apis(void);
|
||||||
|
/**
|
||||||
|
* Get the name of a host API by index
|
||||||
|
*/
|
||||||
|
const char* get_host_api_name(PaHostApiIndex hostApi);
|
||||||
/**
|
/**
|
||||||
* Initialize the audio device and system
|
* Initialize the audio device and system
|
||||||
* Must be called before using any other audio functions
|
* Must be called before using any other audio functions
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import random
|
import random
|
||||||
|
|
||||||
import libs.bg_collabs
|
import libs.bg_collabs
|
||||||
@@ -11,6 +12,8 @@ from libs.bg_objects.footer import Footer
|
|||||||
from libs.bg_objects.renda import RendaController
|
from libs.bg_objects.renda import RendaController
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Background:
|
class Background:
|
||||||
"""The background class for the game."""
|
"""The background class for the game."""
|
||||||
COLLABS = {
|
COLLABS = {
|
||||||
@@ -24,6 +27,7 @@ class Background:
|
|||||||
"IMAS_SIDEM": (libs.bg_collabs.imas_sidem.Background, 'background/collab/imas_sidem', 3),
|
"IMAS_SIDEM": (libs.bg_collabs.imas_sidem.Background, 'background/collab/imas_sidem', 3),
|
||||||
"DAN": (libs.bg_collabs.dan.Background, 'background/collab/dan', 1)
|
"DAN": (libs.bg_collabs.dan.Background, 'background/collab/dan', 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, player_num: int, bpm: float, scene_preset: str = ''):
|
def __init__(self, player_num: int, bpm: float, scene_preset: str = ''):
|
||||||
"""
|
"""
|
||||||
Initialize the background class.
|
Initialize the background class.
|
||||||
@@ -87,7 +91,8 @@ class Background:
|
|||||||
self.chibi = collab_bg.chibi
|
self.chibi = collab_bg.chibi
|
||||||
self.is_clear = False
|
self.is_clear = False
|
||||||
self.is_rainbow = False
|
self.is_rainbow = False
|
||||||
self.last_milestone = 0
|
self.last_milestone = 1
|
||||||
|
logger.info(f"Background initialized for player {player_num}, bpm={bpm}, scene_preset={scene_preset}")
|
||||||
|
|
||||||
def add_chibi(self, bad: bool, player_num: int):
|
def add_chibi(self, bad: bool, player_num: int):
|
||||||
"""
|
"""
|
||||||
@@ -122,14 +127,17 @@ class Background:
|
|||||||
current_milestone = min(self.max_dancers - 1, int(gauge_1p.gauge_length / (clear_threshold / self.max_dancers)))
|
current_milestone = min(self.max_dancers - 1, int(gauge_1p.gauge_length / (clear_threshold / self.max_dancers)))
|
||||||
else:
|
else:
|
||||||
current_milestone = self.max_dancers
|
current_milestone = self.max_dancers
|
||||||
if current_milestone > self.last_milestone and current_milestone < self.max_dancers:
|
if current_milestone > self.last_milestone and current_milestone <= self.max_dancers:
|
||||||
self.dancer.add_dancer()
|
self.dancer.add_dancer()
|
||||||
self.last_milestone = current_milestone
|
self.last_milestone = current_milestone
|
||||||
|
logger.info(f"Dancer milestone reached: {current_milestone}/{self.max_dancers}")
|
||||||
if self.bg_fever is not None:
|
if self.bg_fever is not None:
|
||||||
if not self.is_clear and gauge_1p.is_clear:
|
if not self.is_clear and gauge_1p.is_clear:
|
||||||
self.bg_fever.start()
|
self.bg_fever.start()
|
||||||
|
logger.info("Fever started")
|
||||||
if not self.is_rainbow and gauge_1p.is_rainbow and self.fever is not None:
|
if not self.is_rainbow and gauge_1p.is_rainbow and self.fever is not None:
|
||||||
self.fever.start()
|
self.fever.start()
|
||||||
|
logger.info("Rainbow fever started")
|
||||||
self.is_clear = gauge_1p.is_clear
|
self.is_clear = gauge_1p.is_clear
|
||||||
self.is_rainbow = gauge_1p.is_rainbow
|
self.is_rainbow = gauge_1p.is_rainbow
|
||||||
self.don_bg.update(current_time_ms, self.is_clear)
|
self.don_bg.update(current_time_ms, self.is_clear)
|
||||||
@@ -182,3 +190,4 @@ class Background:
|
|||||||
Unload the background.
|
Unload the background.
|
||||||
"""
|
"""
|
||||||
self.tex_wrapper.unload_textures()
|
self.tex_wrapper.unload_textures()
|
||||||
|
logger.info("Background textures unloaded")
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import logging
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.utils import global_tex
|
from libs.utils import global_tex
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Chara2D:
|
class Chara2D:
|
||||||
def __init__(self, index: int, bpm: float, path: str = 'chara'):
|
def __init__(self, index: int, bpm: float, path: str = 'chara'):
|
||||||
"""
|
"""
|
||||||
@@ -33,6 +36,7 @@ class Chara2D:
|
|||||||
textures = [[duration*i, duration*(i+1), index] for i, index in enumerate(keyframes)]
|
textures = [[duration*i, duration*(i+1), index] for i, index in enumerate(keyframes)]
|
||||||
self.anims[name] = Animation.create_texture_change(total_duration, textures=textures)
|
self.anims[name] = Animation.create_texture_change(total_duration, textures=textures)
|
||||||
self.anims[name].start()
|
self.anims[name].start()
|
||||||
|
logger.info(f"Chara2D initialized: index={index}, bpm={bpm}, path={path}")
|
||||||
|
|
||||||
def set_animation(self, name: str):
|
def set_animation(self, name: str):
|
||||||
"""
|
"""
|
||||||
@@ -62,6 +66,7 @@ class Chara2D:
|
|||||||
self.past_anim = 'gogo'
|
self.past_anim = 'gogo'
|
||||||
self.current_anim = name
|
self.current_anim = name
|
||||||
self.anims[name].start()
|
self.anims[name].start()
|
||||||
|
logger.debug(f"Animation set: {name}")
|
||||||
def update(self, current_time_ms: float, bpm: float, is_clear: bool, is_rainbow: bool):
|
def update(self, current_time_ms: float, bpm: float, is_clear: bool, is_rainbow: bool):
|
||||||
"""
|
"""
|
||||||
Update the character's animation state and appearance.
|
Update the character's animation state and appearance.
|
||||||
@@ -75,10 +80,12 @@ class Chara2D:
|
|||||||
if is_rainbow and not self.is_rainbow:
|
if is_rainbow and not self.is_rainbow:
|
||||||
self.is_rainbow = True
|
self.is_rainbow = True
|
||||||
self.set_animation('soul_in')
|
self.set_animation('soul_in')
|
||||||
|
logger.info("Rainbow state entered, soul_in animation triggered")
|
||||||
if is_clear and not self.is_clear:
|
if is_clear and not self.is_clear:
|
||||||
self.is_clear = True
|
self.is_clear = True
|
||||||
self.set_animation('clear_in')
|
self.set_animation('clear_in')
|
||||||
self.past_anim = 'clear'
|
self.past_anim = 'clear'
|
||||||
|
logger.info("Clear state entered, clear_in animation triggered")
|
||||||
if bpm != self.bpm:
|
if bpm != self.bpm:
|
||||||
self.bpm = bpm
|
self.bpm = bpm
|
||||||
for name in self.tex.textures[self.name]:
|
for name in self.tex.textures[self.name]:
|
||||||
@@ -90,6 +97,7 @@ class Chara2D:
|
|||||||
textures = [[duration*i, duration*(i+1), index] for i, index in enumerate(keyframes)]
|
textures = [[duration*i, duration*(i+1), index] for i, index in enumerate(keyframes)]
|
||||||
self.anims[name] = Animation.create_texture_change(total_duration, textures=textures)
|
self.anims[name] = Animation.create_texture_change(total_duration, textures=textures)
|
||||||
self.anims[name].start()
|
self.anims[name].start()
|
||||||
|
logger.info(f"BPM changed, animations updated: bpm={bpm}")
|
||||||
self.anims[self.current_anim] = self.anims[self.current_anim]
|
self.anims[self.current_anim] = self.anims[self.current_anim]
|
||||||
self.anims[self.current_anim].update(current_time_ms)
|
self.anims[self.current_anim].update(current_time_ms)
|
||||||
if self.anims[self.current_anim].is_finished:
|
if self.anims[self.current_anim].is_finished:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import random
|
import random
|
||||||
from typing import Optional, Union
|
from typing import Optional, Union
|
||||||
@@ -12,6 +13,8 @@ import pyray as ray
|
|||||||
|
|
||||||
BOX_CENTER = 444
|
BOX_CENTER = 444
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SongBox:
|
class SongBox:
|
||||||
"""A box for the song select screen."""
|
"""A box for the song select screen."""
|
||||||
OUTLINE_MAP = {
|
OUTLINE_MAP = {
|
||||||
@@ -132,6 +135,8 @@ class SongBox:
|
|||||||
if self.move.is_finished:
|
if self.move.is_finished:
|
||||||
self.position = self.target_position
|
self.position = self.target_position
|
||||||
self.move = None
|
self.move = None
|
||||||
|
if not (-56 <= self.position <= 1280):
|
||||||
|
self.reset()
|
||||||
|
|
||||||
def update(self, is_diff_select):
|
def update(self, is_diff_select):
|
||||||
self.is_diff_select = is_diff_select
|
self.is_diff_select = is_diff_select
|
||||||
@@ -723,12 +728,14 @@ class FileNavigator:
|
|||||||
self.box_open = False
|
self.box_open = False
|
||||||
self.genre_bg = None
|
self.genre_bg = None
|
||||||
self.song_count = 0
|
self.song_count = 0
|
||||||
|
logger.info("FileNavigator initialized")
|
||||||
|
|
||||||
def initialize(self, root_dirs: list[Path]):
|
def initialize(self, root_dirs: list[Path]):
|
||||||
self.root_dirs = [Path(p) if not isinstance(p, Path) else p for p in root_dirs]
|
self.root_dirs = [Path(p) if not isinstance(p, Path) else p for p in root_dirs]
|
||||||
self._generate_all_objects()
|
self._generate_all_objects()
|
||||||
self._create_virtual_root()
|
self._create_virtual_root()
|
||||||
self.load_current_directory()
|
self.load_current_directory()
|
||||||
|
logger.info(f"FileNavigator initialized with root_dirs: {self.root_dirs}")
|
||||||
|
|
||||||
def _create_virtual_root(self):
|
def _create_virtual_root(self):
|
||||||
"""Create a virtual root directory containing all root directories"""
|
"""Create a virtual root directory containing all root directories"""
|
||||||
@@ -762,12 +769,12 @@ class FileNavigator:
|
|||||||
|
|
||||||
def _generate_all_objects(self):
|
def _generate_all_objects(self):
|
||||||
"""Generate all Directory and SongFile objects in advance"""
|
"""Generate all Directory and SongFile objects in advance"""
|
||||||
print("Generating all Directory and SongFile objects...")
|
logging.info("Generating all Directory and SongFile objects...")
|
||||||
|
|
||||||
# Generate objects for each root directory
|
# Generate objects for each root directory
|
||||||
for root_path in self.root_dirs:
|
for root_path in self.root_dirs:
|
||||||
if not root_path.exists():
|
if not root_path.exists():
|
||||||
print(f"Root directory does not exist: {root_path}")
|
logging.warning(f"Root directory does not exist: {root_path}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._generate_objects_recursive(root_path)
|
self._generate_objects_recursive(root_path)
|
||||||
@@ -778,7 +785,7 @@ class FileNavigator:
|
|||||||
if str(song_obj) in self.all_song_files:
|
if str(song_obj) in self.all_song_files:
|
||||||
self.all_song_files[str(song_obj)].box.is_favorite = True
|
self.all_song_files[str(song_obj)].box.is_favorite = True
|
||||||
|
|
||||||
print(f"Object generation complete. "
|
logging.info(f"Object generation complete. "
|
||||||
f"Directories: {len(self.all_directories)}, "
|
f"Directories: {len(self.all_directories)}, "
|
||||||
f"Songs: {len(self.all_song_files)}")
|
f"Songs: {len(self.all_song_files)}")
|
||||||
|
|
||||||
@@ -905,7 +912,7 @@ class FileNavigator:
|
|||||||
global_data.song_progress = self.song_count / global_data.total_songs
|
global_data.song_progress = self.song_count / global_data.total_songs
|
||||||
self.all_song_files[song_key] = song_obj
|
self.all_song_files[song_key] = song_obj
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error creating SongFile for {tja_path}: {e}")
|
logger.error(f"Error creating SongFile for {tja_path}: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def is_at_root(self) -> bool:
|
def is_at_root(self) -> bool:
|
||||||
@@ -1191,7 +1198,7 @@ class FileNavigator:
|
|||||||
elif line.startswith("#COLLECTION"):
|
elif line.startswith("#COLLECTION"):
|
||||||
collection = line.split(":", 1)[1].strip()
|
collection = line.split(":", 1)[1].strip()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error parsing box.def in {path}: {e}")
|
logger.error(f"Error parsing box.def in {path}: {e}")
|
||||||
|
|
||||||
return name, texture_index, collection
|
return name, texture_index, collection
|
||||||
|
|
||||||
@@ -1237,7 +1244,7 @@ class FileNavigator:
|
|||||||
if file_updated:
|
if file_updated:
|
||||||
with open(path / 'song_list.txt', 'w', encoding='utf-8-sig') as song_list:
|
with open(path / 'song_list.txt', 'w', encoding='utf-8-sig') as song_list:
|
||||||
for line in updated_lines:
|
for line in updated_lines:
|
||||||
print("updated", line)
|
logger.info(f"updated: {line}")
|
||||||
song_list.write(line + '\n')
|
song_list.write(line + '\n')
|
||||||
|
|
||||||
return tja_files
|
return tja_files
|
||||||
@@ -1323,7 +1330,7 @@ class FileNavigator:
|
|||||||
with open(recents_path, 'w', encoding='utf-8-sig') as song_list:
|
with open(recents_path, 'w', encoding='utf-8-sig') as song_list:
|
||||||
song_list.writelines(recent_entries)
|
song_list.writelines(recent_entries)
|
||||||
|
|
||||||
print("Added recent: ", song.hash, song.tja.metadata.title['en'], song.tja.metadata.subtitle['en'])
|
logger.info(f"Added Recent: {song.hash} {song.tja.metadata.title['en']} {song.tja.metadata.subtitle['en']}")
|
||||||
|
|
||||||
def add_favorite(self) -> bool:
|
def add_favorite(self) -> bool:
|
||||||
"""Add the current song to the favorites list"""
|
"""Add the current song to the favorites list"""
|
||||||
@@ -1351,11 +1358,11 @@ class FileNavigator:
|
|||||||
with open(favorites_path, 'w', encoding='utf-8-sig') as song_list:
|
with open(favorites_path, 'w', encoding='utf-8-sig') as song_list:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
song_list.write(line + '\n')
|
song_list.write(line + '\n')
|
||||||
print("Removed favorite:", song.hash, song.tja.metadata.title['en'], song.tja.metadata.subtitle['en'])
|
logger.info(f"Removed Favorite: {song.hash} {song.tja.metadata.title['en']} {song.tja.metadata.subtitle['en']}")
|
||||||
else:
|
else:
|
||||||
with open(favorites_path, 'a', encoding='utf-8-sig') as song_list:
|
with open(favorites_path, 'a', encoding='utf-8-sig') as song_list:
|
||||||
song_list.write(f'{song.hash}|{song.tja.metadata.title["en"]}|{song.tja.metadata.subtitle["en"]}\n')
|
song_list.write(f'{song.hash}|{song.tja.metadata.title["en"]}|{song.tja.metadata.subtitle["en"]}\n')
|
||||||
print("Added favorite: ", song.hash, song.tja.metadata.title['en'], song.tja.metadata.subtitle['en'])
|
logger.info(f"Added Favorite: {song.hash} {song.tja.metadata.title['en']} {song.tja.metadata.subtitle['en']}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
navigator = FileNavigator()
|
navigator = FileNavigator()
|
||||||
|
|||||||
41
libs/screen.py
Normal file
41
libs/screen.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
from libs.audio import audio
|
||||||
|
from libs.texture import tex
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class Screen:
|
||||||
|
def __init__(self, name: str):
|
||||||
|
self.screen_init = False
|
||||||
|
self.screen_name = name
|
||||||
|
|
||||||
|
def _do_screen_start(self):
|
||||||
|
if not self.screen_init:
|
||||||
|
self.screen_init = True
|
||||||
|
self.on_screen_start()
|
||||||
|
logger.info(f"{self.__class__.__name__} initialized")
|
||||||
|
|
||||||
|
def on_screen_start(self) -> Any:
|
||||||
|
tex.load_screen_textures(self.screen_name)
|
||||||
|
logger.info(f"Loaded textures for screen: {self.screen_name}")
|
||||||
|
audio.load_screen_sounds(self.screen_name)
|
||||||
|
logger.info(f"Loaded sounds for screen: {self.screen_name}")
|
||||||
|
|
||||||
|
def on_screen_end(self, next_screen: str):
|
||||||
|
self.screen_init = False
|
||||||
|
logger.info(f"{self.__class__.__name__} ended, transitioning to {next_screen} screen")
|
||||||
|
audio.unload_all_sounds()
|
||||||
|
audio.unload_all_music()
|
||||||
|
logger.info(f"Unloaded sounds for screen: {next_screen}")
|
||||||
|
tex.unload_textures()
|
||||||
|
logger.info(f"Unloaded textures for screen: {next_screen}")
|
||||||
|
return next_screen
|
||||||
|
|
||||||
|
def update(self) -> Any:
|
||||||
|
ret_val = self._do_screen_start()
|
||||||
|
if ret_val:
|
||||||
|
return ret_val
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
pass
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import configparser
|
import configparser
|
||||||
import csv
|
import csv
|
||||||
|
import logging
|
||||||
import json
|
import json
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import sys
|
import sys
|
||||||
@@ -9,6 +10,7 @@ from pathlib import Path
|
|||||||
from libs.tja import NoteList, TJAParser, test_encodings
|
from libs.tja import NoteList, TJAParser, test_encodings
|
||||||
from libs.utils import get_config, global_data
|
from libs.utils import get_config, global_data
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def diff_hashes_object_hook(obj):
|
def diff_hashes_object_hook(obj):
|
||||||
if "diff_hashes" in obj:
|
if "diff_hashes" in obj:
|
||||||
@@ -137,7 +139,7 @@ def build_song_hashes(output_dir=Path("cache")):
|
|||||||
all_notes.bars.extend(branch.bars)
|
all_notes.bars.extend(branch.bars)
|
||||||
all_notes.bars.extend(diff_notes.bars)
|
all_notes.bars.extend(diff_notes.bars)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to parse TJA {tja_path}: {e}")
|
logger.error(f"Failed to parse TJA {tja_path}: {e}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if all_notes == NoteList():
|
if all_notes == NoteList():
|
||||||
@@ -190,7 +192,7 @@ def build_song_hashes(output_dir=Path("cache")):
|
|||||||
""", (diff_hashes[i], en_name, jp_name, i, imported_scores[i], clear, bads))
|
""", (diff_hashes[i], en_name, jp_name, i, imported_scores[i], clear, bads))
|
||||||
if cursor.rowcount > 0:
|
if cursor.rowcount > 0:
|
||||||
action = "Added" if not existing_record else "Updated"
|
action = "Added" if not existing_record else "Updated"
|
||||||
print(f"{action} entry for {en_name} ({i}) - Score: {imported_scores[i]}")
|
logger.info(f"{action} entry for {en_name} ({i}) - Score: {imported_scores[i]}")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
@@ -213,18 +215,18 @@ def build_song_hashes(output_dir=Path("cache")):
|
|||||||
WHERE (en_name = ? AND jp_name = ?) AND diff = ?
|
WHERE (en_name = ? AND jp_name = ?) AND diff = ?
|
||||||
""", (diff_hash, en_name, jp_name, diff))
|
""", (diff_hash, en_name, jp_name, diff))
|
||||||
if cursor.rowcount > 0:
|
if cursor.rowcount > 0:
|
||||||
print(f"Updated {cursor.rowcount} entries for {en_name} ({diff})")
|
logger.info(f"Updated {cursor.rowcount} entries for {en_name} ({diff})")
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
print(f"Database update completed. Processed {len(db_updates)} difficulty hash updates.")
|
logger.info(f"Database update completed. Processed {len(db_updates)} difficulty hash updates.")
|
||||||
|
|
||||||
except sqlite3.Error as e:
|
except sqlite3.Error as e:
|
||||||
print(f"Database error: {e}")
|
logger.error(f"Database error: {e}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error updating database: {e}")
|
logger.error(f"Error updating database: {e}")
|
||||||
elif db_updates:
|
elif db_updates:
|
||||||
print(f"Warning: scores.db not found, skipping {len(db_updates)} database updates")
|
logger.warning(f"Warning: scores.db not found, skipping {len(db_updates)} database updates")
|
||||||
|
|
||||||
# Save both files
|
# Save both files
|
||||||
with open(output_path, "w", encoding="utf-8") as f:
|
with open(output_path, "w", encoding="utf-8") as f:
|
||||||
@@ -345,11 +347,11 @@ def get_japanese_songs_for_version(csv_file_path, version_column):
|
|||||||
if len(matches) == 1:
|
if len(matches) == 1:
|
||||||
path = matches[0][1]
|
path = matches[0][1]
|
||||||
elif len(matches) > 1:
|
elif len(matches) > 1:
|
||||||
print(
|
logger.info(
|
||||||
f"Multiple matches found for '{title.split('/')[0]} ({title.split('/')[1] if len(title.split('/')) > 1 else ''})':"
|
f"Multiple matches found for '{title.split('/')[0]} ({title.split('/')[1] if len(title.split('/')) > 1 else ''})':"
|
||||||
)
|
)
|
||||||
for i, (key, path_val) in enumerate(matches, 1):
|
for i, (key, path_val) in enumerate(matches, 1):
|
||||||
print(f"{i}. {key}: {path_val}")
|
logger.info(f"{i}. {key}: {path_val}")
|
||||||
choice = int(input("Choose number: ")) - 1
|
choice = int(input("Choose number: ")) - 1
|
||||||
path = matches[choice][1]
|
path = matches[choice][1]
|
||||||
else:
|
else:
|
||||||
@@ -362,7 +364,7 @@ def get_japanese_songs_for_version(csv_file_path, version_column):
|
|||||||
text_files[genre].append(
|
text_files[genre].append(
|
||||||
f"{hash}|{tja_parse.metadata.title['en'].strip()}|{tja_parse.metadata.subtitle['en'].strip()}"
|
f"{hash}|{tja_parse.metadata.title['en'].strip()}|{tja_parse.metadata.subtitle['en'].strip()}"
|
||||||
)
|
)
|
||||||
print(f"Added {title}: {path}")
|
logger.info(f"Added {title}: {path}")
|
||||||
for genre in text_files:
|
for genre in text_files:
|
||||||
if not Path(version_column).exists():
|
if not Path(version_column).exists():
|
||||||
Path(version_column).mkdir()
|
Path(version_column).mkdir()
|
||||||
|
|||||||
108
libs/texture.py
108
libs/texture.py
@@ -1,6 +1,7 @@
|
|||||||
import copy
|
import copy
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
import tempfile
|
import tempfile
|
||||||
import zipfile
|
import zipfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -13,6 +14,8 @@ from libs.animation import BaseAnimation, parse_animations
|
|||||||
SCREEN_WIDTH = 1280
|
SCREEN_WIDTH = 1280
|
||||||
SCREEN_HEIGHT = 720
|
SCREEN_HEIGHT = 720
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class Texture:
|
class Texture:
|
||||||
"""Texture class for managing textures and animations."""
|
"""Texture class for managing textures and animations."""
|
||||||
def __init__(self, name: str, texture: Union[ray.Texture, list[ray.Texture]], init_vals: dict[str, int]):
|
def __init__(self, name: str, texture: Union[ray.Texture, list[ray.Texture]], init_vals: dict[str, int]):
|
||||||
@@ -42,14 +45,28 @@ class TextureWrapper:
|
|||||||
|
|
||||||
def unload_textures(self):
|
def unload_textures(self):
|
||||||
"""Unload all textures and animations."""
|
"""Unload all textures and animations."""
|
||||||
|
ids = {} # Map ID to texture name
|
||||||
for zip in self.textures:
|
for zip in self.textures:
|
||||||
for file in self.textures[zip]:
|
for file in self.textures[zip]:
|
||||||
tex_object = self.textures[zip][file]
|
tex_object = self.textures[zip][file]
|
||||||
if isinstance(tex_object.texture, list):
|
if isinstance(tex_object.texture, list):
|
||||||
for texture in tex_object.texture:
|
for i, texture in enumerate(tex_object.texture):
|
||||||
ray.unload_texture(texture)
|
if texture.id in ids:
|
||||||
|
logger.warning(f"Duplicate texture ID {texture.id}: {ids[texture.id]} and {zip}/{file}[{i}]")
|
||||||
|
else:
|
||||||
|
ids[texture.id] = f"{zip}/{file}[{i}]"
|
||||||
|
ray.unload_texture(texture)
|
||||||
else:
|
else:
|
||||||
ray.unload_texture(tex_object.texture)
|
if tex_object.texture.id in ids:
|
||||||
|
logger.warning(f"Duplicate texture ID {tex_object.texture.id}: {ids[tex_object.texture.id]} and {zip}/{file}")
|
||||||
|
else:
|
||||||
|
ids[tex_object.texture.id] = f"{zip}/{file}"
|
||||||
|
ray.unload_texture(tex_object.texture)
|
||||||
|
|
||||||
|
self.textures.clear()
|
||||||
|
self.animations.clear()
|
||||||
|
|
||||||
|
logger.info("All textures unloaded")
|
||||||
|
|
||||||
def get_animation(self, index: int, is_copy: bool = False):
|
def get_animation(self, index: int, is_copy: bool = False):
|
||||||
"""Get an animation by ID and returns a reference.
|
"""Get an animation by ID and returns a reference.
|
||||||
@@ -93,52 +110,57 @@ class TextureWrapper:
|
|||||||
if (screen_path / 'animation.json').exists():
|
if (screen_path / 'animation.json').exists():
|
||||||
with open(screen_path / 'animation.json') as json_file:
|
with open(screen_path / 'animation.json') as json_file:
|
||||||
self.animations = parse_animations(json.loads(json_file.read()))
|
self.animations = parse_animations(json.loads(json_file.read()))
|
||||||
|
logger.info(f"Animations loaded for screen: {screen_name}")
|
||||||
|
|
||||||
def load_zip(self, screen_name: str, subset: str):
|
def load_zip(self, screen_name: str, subset: str):
|
||||||
"""Load textures from a zip file."""
|
"""Load textures from a zip file."""
|
||||||
zip = (self.graphics_path / screen_name / subset).with_suffix('.zip')
|
zip = (self.graphics_path / screen_name / subset).with_suffix('.zip')
|
||||||
if screen_name in self.textures and subset in self.textures[screen_name]:
|
if screen_name in self.textures and subset in self.textures[screen_name]:
|
||||||
return
|
return
|
||||||
with zipfile.ZipFile(zip, 'r') as zip_ref:
|
try:
|
||||||
if 'texture.json' not in zip_ref.namelist():
|
with zipfile.ZipFile(zip, 'r') as zip_ref:
|
||||||
raise Exception(f"texture.json file missing from {zip}")
|
if 'texture.json' not in zip_ref.namelist():
|
||||||
|
raise Exception(f"texture.json file missing from {zip}")
|
||||||
|
|
||||||
with zip_ref.open('texture.json') as json_file:
|
with zip_ref.open('texture.json') as json_file:
|
||||||
tex_mapping_data = json.loads(json_file.read().decode('utf-8'))
|
tex_mapping_data = json.loads(json_file.read().decode('utf-8'))
|
||||||
self.textures[zip.stem] = dict()
|
self.textures[zip.stem] = dict()
|
||||||
|
|
||||||
for tex_name in tex_mapping_data:
|
for tex_name in tex_mapping_data:
|
||||||
if f"{tex_name}/" in zip_ref.namelist():
|
if f"{tex_name}/" in zip_ref.namelist():
|
||||||
tex_mapping = tex_mapping_data[tex_name]
|
tex_mapping = tex_mapping_data[tex_name]
|
||||||
|
|
||||||
with tempfile.TemporaryDirectory() as temp_dir:
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
zip_ref.extractall(temp_dir, members=[name for name in zip_ref.namelist()
|
zip_ref.extractall(temp_dir, members=[name for name in zip_ref.namelist()
|
||||||
if name.startswith(tex_name)])
|
if name.startswith(tex_name)])
|
||||||
|
|
||||||
extracted_path = Path(temp_dir) / tex_name
|
extracted_path = Path(temp_dir) / tex_name
|
||||||
if extracted_path.is_dir():
|
if extracted_path.is_dir():
|
||||||
frames = [ray.load_texture(str(frame)) for frame in sorted(extracted_path.iterdir(),
|
frames = [ray.load_texture(str(frame)) for frame in sorted(extracted_path.iterdir(),
|
||||||
key=lambda x: int(x.stem)) if frame.is_file()]
|
key=lambda x: int(x.stem)) if frame.is_file()]
|
||||||
else:
|
else:
|
||||||
frames = [ray.load_texture(str(extracted_path))]
|
frames = [ray.load_texture(str(extracted_path))]
|
||||||
self.textures[zip.stem][tex_name] = Texture(tex_name, frames, tex_mapping)
|
self.textures[zip.stem][tex_name] = Texture(tex_name, frames, tex_mapping)
|
||||||
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
|
|
||||||
elif f"{tex_name}.png" in zip_ref.namelist():
|
|
||||||
tex_mapping = tex_mapping_data[tex_name]
|
|
||||||
|
|
||||||
png_filename = f"{tex_name}.png"
|
|
||||||
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
|
|
||||||
temp_file.write(zip_ref.read(png_filename))
|
|
||||||
temp_path = temp_file.name
|
|
||||||
|
|
||||||
try:
|
|
||||||
tex = ray.load_texture(temp_path)
|
|
||||||
self.textures[zip.stem][tex_name] = Texture(tex_name, tex, tex_mapping)
|
|
||||||
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
|
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
|
||||||
finally:
|
elif f"{tex_name}.png" in zip_ref.namelist():
|
||||||
os.unlink(temp_path)
|
tex_mapping = tex_mapping_data[tex_name]
|
||||||
else:
|
|
||||||
raise Exception(f"Texture {tex_name} was not found in {zip}")
|
png_filename = f"{tex_name}.png"
|
||||||
|
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
|
||||||
|
temp_file.write(zip_ref.read(png_filename))
|
||||||
|
temp_path = temp_file.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
tex = ray.load_texture(temp_path)
|
||||||
|
self.textures[zip.stem][tex_name] = Texture(tex_name, tex, tex_mapping)
|
||||||
|
self._read_tex_obj_data(tex_mapping, self.textures[zip.stem][tex_name])
|
||||||
|
finally:
|
||||||
|
os.unlink(temp_path)
|
||||||
|
else:
|
||||||
|
raise Exception(f"Texture {tex_name} was not found in {zip}")
|
||||||
|
logger.info(f"Textures loaded from zip: {zip}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to load textures from zip {zip}: {e}")
|
||||||
|
|
||||||
def load_screen_textures(self, screen_name: str) -> None:
|
def load_screen_textures(self, screen_name: str) -> None:
|
||||||
"""Load textures for a screen."""
|
"""Load textures for a screen."""
|
||||||
@@ -146,10 +168,12 @@ class TextureWrapper:
|
|||||||
if (screen_path / 'animation.json').exists():
|
if (screen_path / 'animation.json').exists():
|
||||||
with open(screen_path / 'animation.json') as json_file:
|
with open(screen_path / 'animation.json') as json_file:
|
||||||
self.animations = parse_animations(json.loads(json_file.read()))
|
self.animations = parse_animations(json.loads(json_file.read()))
|
||||||
|
logger.info(f"Animations loaded for screen: {screen_name}")
|
||||||
for zip in screen_path.iterdir():
|
for zip in screen_path.iterdir():
|
||||||
if zip.is_dir() or zip.suffix != ".zip":
|
if zip.is_dir() or zip.suffix != ".zip":
|
||||||
continue
|
continue
|
||||||
self.load_zip(screen_name, zip.name)
|
self.load_zip(screen_name, zip.name)
|
||||||
|
logger.info(f"Screen textures loaded for: {screen_name}")
|
||||||
|
|
||||||
def control(self, tex_object: Texture, index: int = 0):
|
def control(self, tex_object: Texture, index: int = 0):
|
||||||
'''debug function'''
|
'''debug function'''
|
||||||
@@ -158,16 +182,16 @@ class TextureWrapper:
|
|||||||
distance = 10
|
distance = 10
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_LEFT):
|
||||||
tex_object.x[index] -= distance
|
tex_object.x[index] -= distance
|
||||||
print(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
logger.info(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_RIGHT):
|
||||||
tex_object.x[index] += distance
|
tex_object.x[index] += distance
|
||||||
print(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
logger.info(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_UP):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_UP):
|
||||||
tex_object.y[index] -= distance
|
tex_object.y[index] -= distance
|
||||||
print(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
logger.info(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_DOWN):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_DOWN):
|
||||||
tex_object.y[index] += distance
|
tex_object.y[index] += distance
|
||||||
print(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
logger.info(f"{tex_object.name}: {tex_object.x[index]}, {tex_object.y[index]}")
|
||||||
|
|
||||||
def draw_texture(self, subset: str, texture: str, color: ray.Color=ray.WHITE, frame: int = 0, scale: float = 1.0, center: bool = False,
|
def draw_texture(self, subset: str, texture: str, color: ray.Color=ray.WHITE, frame: int = 0, scale: float = 1.0, center: bool = False,
|
||||||
mirror: str = '', x: float = 0, y: float = 0, x2: float = 0, y2: float = 0,
|
mirror: str = '', x: float = 0, y: float = 0, x2: float = 0, y2: float = 0,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import bisect
|
import bisect
|
||||||
import hashlib
|
import hashlib
|
||||||
import math
|
import math
|
||||||
|
import logging
|
||||||
import random
|
import random
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from dataclasses import dataclass, field, fields
|
from dataclasses import dataclass, field, fields
|
||||||
@@ -285,6 +286,7 @@ def test_encodings(file_path):
|
|||||||
continue
|
continue
|
||||||
return final_encoding
|
return final_encoding
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class TJAParser:
|
class TJAParser:
|
||||||
"""Parse a TJA file and extract metadata and data.
|
"""Parse a TJA file and extract metadata and data.
|
||||||
@@ -318,6 +320,7 @@ class TJAParser:
|
|||||||
|
|
||||||
self.metadata = TJAMetadata()
|
self.metadata = TJAMetadata()
|
||||||
self.ex_data = TJAEXData()
|
self.ex_data = TJAEXData()
|
||||||
|
logger.debug(f"Parsing TJA file: {self.file_path}")
|
||||||
self.get_metadata()
|
self.get_metadata()
|
||||||
|
|
||||||
self.distance = distance
|
self.distance = distance
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import ctypes
|
|||||||
import hashlib
|
import hashlib
|
||||||
import math
|
import math
|
||||||
import sys
|
import sys
|
||||||
|
import logging
|
||||||
import time
|
import time
|
||||||
import json
|
import json
|
||||||
from libs.global_data import global_data
|
from libs.global_data import global_data
|
||||||
@@ -19,6 +20,7 @@ from raylib import (
|
|||||||
|
|
||||||
from libs.texture import TextureWrapper
|
from libs.texture import TextureWrapper
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
def force_dedicated_gpu():
|
def force_dedicated_gpu():
|
||||||
"""Force Windows to use dedicated GPU for this application"""
|
"""Force Windows to use dedicated GPU for this application"""
|
||||||
@@ -29,13 +31,13 @@ def force_dedicated_gpu():
|
|||||||
if nvapi:
|
if nvapi:
|
||||||
ctypes.windll.kernel32.SetEnvironmentVariableW("SHIM_MCCOMPAT", "0x800000001")
|
ctypes.windll.kernel32.SetEnvironmentVariableW("SHIM_MCCOMPAT", "0x800000001")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logger.error(e)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# AMD PowerXpress
|
# AMD PowerXpress
|
||||||
ctypes.windll.kernel32.SetEnvironmentVariableW("AMD_VULKAN_ICD", "DISABLE")
|
ctypes.windll.kernel32.SetEnvironmentVariableW("AMD_VULKAN_ICD", "DISABLE")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
logger.error(e)
|
||||||
|
|
||||||
def rounded(num: float) -> int:
|
def rounded(num: float) -> int:
|
||||||
"""Round a number to the nearest integer"""
|
"""Round a number to the nearest integer"""
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
from moviepy import VideoFileClip
|
from moviepy import VideoFileClip
|
||||||
@@ -6,6 +7,7 @@ from moviepy import VideoFileClip
|
|||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.utils import get_current_ms
|
from libs.utils import get_current_ms
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class VideoPlayer:
|
class VideoPlayer:
|
||||||
def __init__(self, path: Path):
|
def __init__(self, path: Path):
|
||||||
@@ -61,7 +63,7 @@ class VideoPlayer:
|
|||||||
|
|
||||||
return texture
|
return texture
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error loading frame at index {index}: {e}")
|
logger.error(f"Error loading frame at index {index}: {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _manage_buffer(self):
|
def _manage_buffer(self):
|
||||||
|
|||||||
@@ -1,16 +1,26 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "pytaiko"
|
name = "pytaiko"
|
||||||
version = "0.1.0"
|
version = "0.9.0"
|
||||||
description = "Taiko no Tatsujin simulator written in python and raylib"
|
description = "Taiko no Tatsujin simulator written in python and raylib"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"moviepy>=2.1.2",
|
"moviepy>=2.1.2",
|
||||||
"pyinstrument>=5.1.1",
|
"raylib-sdl>=5.5.0.3",
|
||||||
"raylib-sdl>=5.5.0.2",
|
|
||||||
"tomlkit>=0.13.3",
|
"tomlkit>=0.13.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.vulture]
|
[tool.vulture]
|
||||||
exclude = ["*.git", "*./.github", "*./.venv", "*./cache"]
|
exclude = ["*.git", ".github/", ".venv/", "cache/"]
|
||||||
paths = ["."]
|
paths = ["."]
|
||||||
|
|
||||||
|
[tool.uv.sources]
|
||||||
|
raylib-sdl = { path = "raylib_sdl-5.5.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" }
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"nuitka>=2.8.4",
|
||||||
|
"pyinstrument>=5.1.1",
|
||||||
|
"ruff>=0.14.2",
|
||||||
|
"vulture>=2.14",
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,38 +1,17 @@
|
|||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.utils import get_current_ms
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
|
||||||
from scenes.game import JudgeCounter
|
|
||||||
|
|
||||||
|
|
||||||
class DevScreen:
|
class DevScreen(Screen):
|
||||||
def __init__(self):
|
def on_screen_start(self, screen_name: str):
|
||||||
self.width = 1280
|
super().on_screen_start(screen_name)
|
||||||
self.height = 720
|
|
||||||
self.screen_init = False
|
|
||||||
self.length = 100
|
|
||||||
|
|
||||||
def on_screen_start(self):
|
|
||||||
if not self.screen_init:
|
|
||||||
self.screen_init = True
|
|
||||||
tex.load_screen_textures('game')
|
|
||||||
self.obj = JudgeCounter()
|
|
||||||
|
|
||||||
def on_screen_end(self, next_screen: str):
|
def on_screen_end(self, next_screen: str):
|
||||||
self.screen_init = False
|
return super().on_screen_end(next_screen)
|
||||||
return next_screen
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super().update()
|
||||||
self.obj.update(0, 0, 0, 0)
|
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_ENTER):
|
|
||||||
return self.on_screen_end('GAME')
|
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_SPACE):
|
|
||||||
self.obj = JudgeCounter()
|
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
ray.draw_rectangle(0, 0, 1280, 720, ray.GREEN)
|
ray.draw_rectangle(0, 0, 1280, 720, ray.GREEN)
|
||||||
self.obj.draw()
|
|
||||||
|
|
||||||
def draw_3d(self):
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate, Indicator, EntryOverlay, Timer
|
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate, Indicator, EntryOverlay, Timer
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
|
from libs.screen import Screen
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
OutlinedText,
|
OutlinedText,
|
||||||
get_current_ms,
|
get_current_ms,
|
||||||
@@ -14,53 +17,45 @@ from libs.utils import (
|
|||||||
is_r_kat_pressed,
|
is_r_kat_pressed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class State:
|
class State:
|
||||||
"""State enum for the entry screen"""
|
"""State enum for the entry screen"""
|
||||||
SELECT_SIDE = 0
|
SELECT_SIDE = 0
|
||||||
SELECT_MODE = 1
|
SELECT_MODE = 1
|
||||||
|
|
||||||
class EntryScreen:
|
class EntryScreen(Screen):
|
||||||
def __init__(self):
|
|
||||||
self.screen_init = False
|
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
super().on_screen_start()
|
||||||
tex.load_screen_textures('entry')
|
self.side = 1
|
||||||
audio.load_screen_sounds('entry')
|
self.is_2p = False
|
||||||
self.side = 1
|
self.box_manager = BoxManager()
|
||||||
self.is_2p = False
|
self.state = State.SELECT_SIDE
|
||||||
self.box_manager = BoxManager()
|
|
||||||
self.state = State.SELECT_SIDE
|
|
||||||
|
|
||||||
# Initial nameplate for side selection
|
# Initial nameplate for side selection
|
||||||
plate_info = global_data.config['nameplate_1p']
|
plate_info = global_data.config['nameplate_1p']
|
||||||
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], -1, -1, False)
|
self.nameplate = Nameplate(plate_info['name'], plate_info['title'], -1, -1, False)
|
||||||
|
|
||||||
self.coin_overlay = CoinOverlay()
|
self.coin_overlay = CoinOverlay()
|
||||||
self.allnet_indicator = AllNetIcon()
|
self.allnet_indicator = AllNetIcon()
|
||||||
self.entry_overlay = EntryOverlay()
|
self.entry_overlay = EntryOverlay()
|
||||||
self.timer = Timer(60, get_current_ms(), self.box_manager.select_box)
|
self.timer = Timer(60, get_current_ms(), self.box_manager.select_box)
|
||||||
self.screen_init = True
|
self.screen_init = True
|
||||||
self.side_select_fade = tex.get_animation(0)
|
self.side_select_fade = tex.get_animation(0)
|
||||||
self.bg_flicker = tex.get_animation(1)
|
self.bg_flicker = tex.get_animation(1)
|
||||||
self.side_select_fade.start()
|
self.side_select_fade.start()
|
||||||
self.chara = Chara2D(0, 100)
|
self.chara = Chara2D(0, 100)
|
||||||
self.announce_played = False
|
self.announce_played = False
|
||||||
self.players = [None, None]
|
self.players: list[Optional[EntryPlayer]] = [None, None]
|
||||||
audio.play_sound('bgm', 'music')
|
audio.play_sound('bgm', 'music')
|
||||||
|
|
||||||
def on_screen_end(self, next_screen: str):
|
def on_screen_end(self, next_screen: str):
|
||||||
self.screen_init = False
|
|
||||||
audio.stop_sound('bgm')
|
audio.stop_sound('bgm')
|
||||||
self.nameplate.unload()
|
self.nameplate.unload()
|
||||||
for player in self.players:
|
for player in self.players:
|
||||||
if player:
|
if player:
|
||||||
player.unload()
|
player.unload()
|
||||||
tex.unload_textures()
|
return super().on_screen_end(next_screen)
|
||||||
audio.unload_all_sounds()
|
|
||||||
audio.unload_all_music()
|
|
||||||
return next_screen
|
|
||||||
|
|
||||||
def handle_input(self):
|
def handle_input(self):
|
||||||
if self.state == State.SELECT_SIDE:
|
if self.state == State.SELECT_SIDE:
|
||||||
@@ -118,7 +113,7 @@ class EntryScreen:
|
|||||||
self.side = 1
|
self.side = 1
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super().update()
|
||||||
current_time = get_current_ms()
|
current_time = get_current_ms()
|
||||||
self.side_select_fade.update(current_time)
|
self.side_select_fade.update(current_time)
|
||||||
self.bg_flicker.update(current_time)
|
self.bg_flicker.update(current_time)
|
||||||
@@ -130,6 +125,7 @@ class EntryScreen:
|
|||||||
if player:
|
if player:
|
||||||
player.update(current_time)
|
player.update(current_time)
|
||||||
if self.box_manager.is_finished():
|
if self.box_manager.is_finished():
|
||||||
|
logger.info(f"Box selection finished, transitioning to {self.box_manager.selected_box()}")
|
||||||
return self.on_screen_end(self.box_manager.selected_box())
|
return self.on_screen_end(self.box_manager.selected_box())
|
||||||
for player in self.players:
|
for player in self.players:
|
||||||
if player and player.cloud_fade.is_finished and not audio.is_sound_playing(f'entry_start_{global_data.player_num}p') and not self.announce_played:
|
if player and player.cloud_fade.is_finished and not audio.is_sound_playing(f'entry_start_{global_data.player_num}p') and not self.announce_played:
|
||||||
|
|||||||
143
scenes/game.py
143
scenes/game.py
@@ -1,5 +1,6 @@
|
|||||||
import bisect
|
import bisect
|
||||||
import math
|
import math
|
||||||
|
import logging
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -13,6 +14,7 @@ from libs.background import Background
|
|||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
from libs.global_data import Modifiers
|
from libs.global_data import Modifiers
|
||||||
from libs.global_objects import AllNetIcon, Nameplate
|
from libs.global_objects import AllNetIcon, Nameplate
|
||||||
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.tja import (
|
from libs.tja import (
|
||||||
Balloon,
|
Balloon,
|
||||||
@@ -33,22 +35,70 @@ from libs.utils import (
|
|||||||
is_l_kat_pressed,
|
is_l_kat_pressed,
|
||||||
is_r_don_pressed,
|
is_r_don_pressed,
|
||||||
is_r_kat_pressed,
|
is_r_kat_pressed,
|
||||||
rounded
|
|
||||||
)
|
)
|
||||||
from libs.video import VideoPlayer
|
from libs.video import VideoPlayer
|
||||||
|
|
||||||
SCREEN_WIDTH = 1280
|
SCREEN_WIDTH = 1280
|
||||||
SCREEN_HEIGHT = 720
|
SCREEN_HEIGHT = 720
|
||||||
|
|
||||||
class GameScreen:
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class GameScreen(Screen):
|
||||||
JUDGE_X = 414
|
JUDGE_X = 414
|
||||||
def __init__(self):
|
def on_screen_start(self):
|
||||||
|
super().on_screen_start()
|
||||||
|
self.mask_shader = ray.load_shader("shader/outline.vs", "shader/mask.fs")
|
||||||
self.current_ms = 0
|
self.current_ms = 0
|
||||||
self.screen_init = False
|
|
||||||
self.end_ms = 0
|
self.end_ms = 0
|
||||||
self.start_delay = 1000
|
self.start_delay = 1000
|
||||||
self.song_started = False
|
self.song_started = False
|
||||||
self.mask_shader = ray.load_shader("shader/outline.vs", "shader/mask.fs")
|
self.screen_init = True
|
||||||
|
self.movie = None
|
||||||
|
self.song_music = None
|
||||||
|
tex.load_screen_textures('game')
|
||||||
|
logger.info("Game screen textures loaded")
|
||||||
|
if global_data.config["general"]["nijiiro_notes"]:
|
||||||
|
# drop original
|
||||||
|
if "notes" in tex.textures:
|
||||||
|
del tex.textures["notes"]
|
||||||
|
# load nijiiro, rename "notes"
|
||||||
|
# to leave hardcoded 'notes' in calls below
|
||||||
|
tex.load_zip("game", "notes_nijiiro")
|
||||||
|
tex.textures["notes"] = tex.textures.pop("notes_nijiiro")
|
||||||
|
logger.info("Loaded nijiiro notes textures")
|
||||||
|
audio.load_screen_sounds('game')
|
||||||
|
logger.info("Game screen sounds loaded")
|
||||||
|
ray.set_shader_value_texture(self.mask_shader, ray.get_shader_location(self.mask_shader, "texture0"), tex.textures['balloon']['rainbow_mask'].texture)
|
||||||
|
ray.set_shader_value_texture(self.mask_shader, ray.get_shader_location(self.mask_shader, "texture1"), tex.textures['balloon']['rainbow'].texture)
|
||||||
|
session_data = global_data.session_data[global_data.player_num-1]
|
||||||
|
self.init_tja(global_data.selected_song)
|
||||||
|
logger.info(f"TJA initialized for song: {global_data.selected_song}")
|
||||||
|
self.load_hitsounds()
|
||||||
|
self.song_info = SongInfo(session_data.song_title, session_data.genre_index)
|
||||||
|
self.result_transition = ResultTransition(global_data.player_num)
|
||||||
|
subtitle = self.tja.metadata.subtitle.get(global_data.config['general']['language'].lower(), '')
|
||||||
|
self.bpm = self.tja.metadata.bpm
|
||||||
|
scene_preset = self.tja.metadata.scene_preset
|
||||||
|
if self.movie is None:
|
||||||
|
self.background = Background(global_data.player_num, self.bpm, scene_preset=scene_preset)
|
||||||
|
logger.info("Background initialized")
|
||||||
|
else:
|
||||||
|
self.background = None
|
||||||
|
logger.info("Movie initialized")
|
||||||
|
self.transition = Transition(session_data.song_title, subtitle, is_second=True)
|
||||||
|
self.allnet_indicator = AllNetIcon()
|
||||||
|
self.transition.start()
|
||||||
|
|
||||||
|
def on_screen_end(self, next_screen):
|
||||||
|
self.song_started = False
|
||||||
|
self.end_ms = 0
|
||||||
|
if self.movie is not None:
|
||||||
|
self.movie.stop()
|
||||||
|
logger.info("Movie stopped")
|
||||||
|
if self.background is not None:
|
||||||
|
self.background.unload()
|
||||||
|
logger.info("Background unloaded")
|
||||||
|
return super().on_screen_end(next_screen)
|
||||||
|
|
||||||
def load_hitsounds(self):
|
def load_hitsounds(self):
|
||||||
"""Load the hit sounds"""
|
"""Load the hit sounds"""
|
||||||
@@ -56,16 +106,19 @@ class GameScreen:
|
|||||||
if global_data.hit_sound == -1:
|
if global_data.hit_sound == -1:
|
||||||
audio.load_sound(Path('none.wav'), 'hitsound_don_1p')
|
audio.load_sound(Path('none.wav'), 'hitsound_don_1p')
|
||||||
audio.load_sound(Path('none.wav'), 'hitsound_kat_1p')
|
audio.load_sound(Path('none.wav'), 'hitsound_kat_1p')
|
||||||
|
logger.info("Loaded default (none) hit sounds for 1P")
|
||||||
if global_data.hit_sound == 0:
|
if global_data.hit_sound == 0:
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.wav", 'hitsound_don_1p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.wav", 'hitsound_don_1p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.wav", 'hitsound_kat_1p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.wav", 'hitsound_kat_1p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don.wav", 'hitsound_don_2p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don.wav", 'hitsound_don_2p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka.wav", 'hitsound_kat_2p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka.wav", 'hitsound_kat_2p')
|
||||||
|
logger.info("Loaded wav hit sounds for 1P and 2P")
|
||||||
else:
|
else:
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.ogg", 'hitsound_don_1p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.ogg", 'hitsound_don_1p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.ogg", 'hitsound_kat_1p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.ogg", 'hitsound_kat_1p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don.ogg", 'hitsound_don_2p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don.ogg", 'hitsound_don_2p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka.ogg", 'hitsound_kat_2p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka.ogg", 'hitsound_kat_2p')
|
||||||
|
logger.info("Loaded ogg hit sounds for 1P and 2P")
|
||||||
|
|
||||||
def init_tja(self, song: Path):
|
def init_tja(self, song: Path):
|
||||||
"""Initialize the TJA file"""
|
"""Initialize the TJA file"""
|
||||||
@@ -82,52 +135,6 @@ class GameScreen:
|
|||||||
self.player_1 = Player(self.tja, global_data.player_num, global_data.session_data[global_data.player_num-1].selected_difficulty, False, global_data.modifiers[0])
|
self.player_1 = Player(self.tja, global_data.player_num, global_data.session_data[global_data.player_num-1].selected_difficulty, False, global_data.modifiers[0])
|
||||||
self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000)
|
self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000)
|
||||||
|
|
||||||
def on_screen_start(self):
|
|
||||||
if not self.screen_init:
|
|
||||||
self.screen_init = True
|
|
||||||
self.movie = None
|
|
||||||
self.song_music = None
|
|
||||||
tex.load_screen_textures('game')
|
|
||||||
if global_data.config["general"]["nijiiro_notes"]:
|
|
||||||
# drop original
|
|
||||||
if "notes" in tex.textures:
|
|
||||||
del tex.textures["notes"]
|
|
||||||
# load nijiiro, rename "notes"
|
|
||||||
# to leave hardcoded 'notes' in calls below
|
|
||||||
tex.load_zip("game", "notes_nijiiro")
|
|
||||||
tex.textures["notes"] = tex.textures.pop("notes_nijiiro")
|
|
||||||
audio.load_screen_sounds('game')
|
|
||||||
ray.set_shader_value_texture(self.mask_shader, ray.get_shader_location(self.mask_shader, "texture0"), tex.textures['balloon']['rainbow_mask'].texture)
|
|
||||||
ray.set_shader_value_texture(self.mask_shader, ray.get_shader_location(self.mask_shader, "texture1"), tex.textures['balloon']['rainbow'].texture)
|
|
||||||
session_data = global_data.session_data[global_data.player_num-1]
|
|
||||||
self.init_tja(global_data.selected_song)
|
|
||||||
self.load_hitsounds()
|
|
||||||
self.song_info = SongInfo(session_data.song_title, session_data.genre_index)
|
|
||||||
self.result_transition = ResultTransition(global_data.player_num)
|
|
||||||
subtitle = self.tja.metadata.subtitle.get(global_data.config['general']['language'].lower(), '')
|
|
||||||
self.bpm = self.tja.metadata.bpm
|
|
||||||
scene_preset = self.tja.metadata.scene_preset
|
|
||||||
if self.movie is None:
|
|
||||||
self.background = Background(global_data.player_num, self.bpm, scene_preset=scene_preset)
|
|
||||||
else:
|
|
||||||
self.background = None
|
|
||||||
self.transition = Transition(session_data.song_title, subtitle, is_second=True)
|
|
||||||
self.allnet_indicator = AllNetIcon()
|
|
||||||
self.transition.start()
|
|
||||||
|
|
||||||
def on_screen_end(self, next_screen):
|
|
||||||
self.screen_init = False
|
|
||||||
tex.unload_textures()
|
|
||||||
audio.unload_all_sounds()
|
|
||||||
audio.unload_all_music()
|
|
||||||
self.song_started = False
|
|
||||||
self.end_ms = 0
|
|
||||||
if self.movie is not None:
|
|
||||||
self.movie.stop()
|
|
||||||
if self.background is not None:
|
|
||||||
self.background.unload()
|
|
||||||
return next_screen
|
|
||||||
|
|
||||||
def write_score(self):
|
def write_score(self):
|
||||||
"""Write the score to the database"""
|
"""Write the score to the database"""
|
||||||
if self.tja is None:
|
if self.tja is None:
|
||||||
@@ -193,7 +200,7 @@ class GameScreen:
|
|||||||
if (self.current_ms >= self.tja.metadata.offset*1000 + self.start_delay - global_data.config["general"]["audio_offset"]) and not self.song_started:
|
if (self.current_ms >= self.tja.metadata.offset*1000 + self.start_delay - global_data.config["general"]["audio_offset"]) and not self.song_started:
|
||||||
if self.song_music is not None:
|
if self.song_music is not None:
|
||||||
audio.play_music_stream(self.song_music, 'music')
|
audio.play_music_stream(self.song_music, 'music')
|
||||||
print(f"Song started at {self.current_ms}")
|
logger.info(f"Song started at {self.current_ms}")
|
||||||
if self.movie is not None:
|
if self.movie is not None:
|
||||||
self.movie.start(current_time)
|
self.movie.start(current_time)
|
||||||
self.song_started = True
|
self.song_started = True
|
||||||
@@ -229,7 +236,7 @@ class GameScreen:
|
|||||||
self.background.update(current_time, self.bpm, self.player_1.gauge, None)
|
self.background.update(current_time, self.bpm, self.player_1.gauge, None)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super().update()
|
||||||
current_time = get_current_ms()
|
current_time = get_current_ms()
|
||||||
self.transition.update(current_time)
|
self.transition.update(current_time)
|
||||||
self.current_ms = current_time - self.start_ms
|
self.current_ms = current_time - self.start_ms
|
||||||
@@ -243,6 +250,7 @@ class GameScreen:
|
|||||||
self.song_info.update(current_time)
|
self.song_info.update(current_time)
|
||||||
self.result_transition.update(current_time)
|
self.result_transition.update(current_time)
|
||||||
if self.result_transition.is_finished and not audio.is_sound_playing('result_transition'):
|
if self.result_transition.is_finished and not audio.is_sound_playing('result_transition'):
|
||||||
|
logger.info("Result transition finished, moving to RESULT screen")
|
||||||
return self.on_screen_end('RESULT')
|
return self.on_screen_end('RESULT')
|
||||||
elif self.current_ms >= self.player_1.end_time:
|
elif self.current_ms >= self.player_1.end_time:
|
||||||
session_data = global_data.session_data[global_data.player_num-1]
|
session_data = global_data.session_data[global_data.player_num-1]
|
||||||
@@ -252,11 +260,13 @@ class GameScreen:
|
|||||||
if current_time >= self.end_ms + 1000:
|
if current_time >= self.end_ms + 1000:
|
||||||
if self.player_1.ending_anim is None:
|
if self.player_1.ending_anim is None:
|
||||||
self.write_score()
|
self.write_score()
|
||||||
|
logger.info("Score written and ending animations spawned")
|
||||||
self.spawn_ending_anims()
|
self.spawn_ending_anims()
|
||||||
if current_time >= self.end_ms + 8533.34:
|
if current_time >= self.end_ms + 8533.34:
|
||||||
if not self.result_transition.is_started:
|
if not self.result_transition.is_started:
|
||||||
self.result_transition.start()
|
self.result_transition.start()
|
||||||
audio.play_sound('result_transition', 'voice')
|
audio.play_sound('result_transition', 'voice')
|
||||||
|
logger.info("Result transition started and voice played")
|
||||||
else:
|
else:
|
||||||
self.end_ms = current_time
|
self.end_ms = current_time
|
||||||
|
|
||||||
@@ -692,7 +702,7 @@ class Player:
|
|||||||
|
|
||||||
big = curr_note.type == 3 or curr_note.type == 4
|
big = curr_note.type == 3 or curr_note.type == 4
|
||||||
if (curr_note.hit_ms - good_window_ms) <= ms_from_start <= (curr_note.hit_ms + good_window_ms):
|
if (curr_note.hit_ms - good_window_ms) <= ms_from_start <= (curr_note.hit_ms + good_window_ms):
|
||||||
self.draw_judge_list.append(Judgement('GOOD', big, self.is_2p, ms_display=ms_from_start - curr_note.hit_ms))
|
self.draw_judge_list.append(Judgement('GOOD', big, self.is_2p))
|
||||||
self.lane_hit_effect = LaneHitEffect('GOOD', self.is_2p)
|
self.lane_hit_effect = LaneHitEffect('GOOD', self.is_2p)
|
||||||
self.good_count += 1
|
self.good_count += 1
|
||||||
self.score += self.base_score
|
self.score += self.base_score
|
||||||
@@ -708,7 +718,7 @@ class Player:
|
|||||||
background.add_chibi(False, 1)
|
background.add_chibi(False, 1)
|
||||||
|
|
||||||
elif (curr_note.hit_ms - ok_window_ms) <= ms_from_start <= (curr_note.hit_ms + ok_window_ms):
|
elif (curr_note.hit_ms - ok_window_ms) <= ms_from_start <= (curr_note.hit_ms + ok_window_ms):
|
||||||
self.draw_judge_list.append(Judgement('OK', big, self.is_2p, ms_display=ms_from_start - curr_note.hit_ms))
|
self.draw_judge_list.append(Judgement('OK', big, self.is_2p))
|
||||||
self.ok_count += 1
|
self.ok_count += 1
|
||||||
self.score += 10 * math.floor(self.base_score / 2 / 10)
|
self.score += 10 * math.floor(self.base_score / 2 / 10)
|
||||||
self.base_score_list.append(ScoreCounterAnimation(self.player_number, 10 * math.floor(self.base_score / 2 / 10), self.is_2p))
|
self.base_score_list.append(ScoreCounterAnimation(self.player_number, 10 * math.floor(self.base_score / 2 / 10), self.is_2p))
|
||||||
@@ -723,7 +733,7 @@ class Player:
|
|||||||
background.add_chibi(False, 1)
|
background.add_chibi(False, 1)
|
||||||
|
|
||||||
elif (curr_note.hit_ms - bad_window_ms) <= ms_from_start <= (curr_note.hit_ms + bad_window_ms):
|
elif (curr_note.hit_ms - bad_window_ms) <= ms_from_start <= (curr_note.hit_ms + bad_window_ms):
|
||||||
self.draw_judge_list.append(Judgement('BAD', big, self.is_2p, ms_display=ms_from_start - curr_note.hit_ms))
|
self.draw_judge_list.append(Judgement('BAD', big, self.is_2p))
|
||||||
self.bad_count += 1
|
self.bad_count += 1
|
||||||
self.combo = 0
|
self.combo = 0
|
||||||
# Remove from both the specific note list and the main play_notes list
|
# Remove from both the specific note list and the main play_notes list
|
||||||
@@ -1109,14 +1119,11 @@ class Player:
|
|||||||
|
|
||||||
class Judgement:
|
class Judgement:
|
||||||
"""Shows the judgement of the player's hit"""
|
"""Shows the judgement of the player's hit"""
|
||||||
def __init__(self, type: str, big: bool, is_2p: bool, ms_display: Optional[float]=None):
|
def __init__(self, type: str, big: bool, is_2p: bool):
|
||||||
self.is_2p = is_2p
|
self.is_2p = is_2p
|
||||||
self.type = type
|
self.type = type
|
||||||
self.big = big
|
self.big = big
|
||||||
self.is_finished = False
|
self.is_finished = False
|
||||||
self.curr_hit_ms = None
|
|
||||||
if ms_display is not None:
|
|
||||||
self.curr_hit_ms = str(round(ms_display, 2))
|
|
||||||
|
|
||||||
self.fade_animation_1 = Animation.create_fade(132, initial_opacity=0.5, delay=100)
|
self.fade_animation_1 = Animation.create_fade(132, initial_opacity=0.5, delay=100)
|
||||||
self.fade_animation_1.start()
|
self.fade_animation_1.start()
|
||||||
@@ -2120,14 +2127,14 @@ class JudgeCounter:
|
|||||||
total_notes = self.good + self.ok + self.bad
|
total_notes = self.good + self.ok + self.bad
|
||||||
if total_notes == 0:
|
if total_notes == 0:
|
||||||
total_notes = 1
|
total_notes = 1
|
||||||
self.draw_counter(self.good / total_notes * 100, 260, 440, 23, ray.Color(253, 161, 0, 255))
|
self.draw_counter(self.good / total_notes * 100, 260, 440, 23, self.orange)
|
||||||
self.draw_counter(self.ok / total_notes * 100, 260, 477, 23, ray.Color(253, 161, 0, 255))
|
self.draw_counter(self.ok / total_notes * 100, 260, 477, 23, self.orange)
|
||||||
self.draw_counter(self.bad / total_notes * 100, 260, 515, 23, ray.Color(253, 161, 0, 255))
|
self.draw_counter(self.bad / total_notes * 100, 260, 515, 23, self.orange)
|
||||||
self.draw_counter((self.good + self.ok) / total_notes * 100, 270, 388, 23, ray.Color(253, 161, 0, 255))
|
self.draw_counter((self.good + self.ok) / total_notes * 100, 270, 388, 23, self.orange)
|
||||||
self.draw_counter(self.good, 180, 440, 23, ray.WHITE)
|
self.draw_counter(self.good, 180, 440, 23, self.white)
|
||||||
self.draw_counter(self.ok, 180, 477, 23, ray.WHITE)
|
self.draw_counter(self.ok, 180, 477, 23, self.white)
|
||||||
self.draw_counter(self.bad, 180, 515, 23, ray.WHITE)
|
self.draw_counter(self.bad, 180, 515, 23, self.white)
|
||||||
self.draw_counter(self.drumrolls, 180, 577, 23, ray.WHITE)
|
self.draw_counter(self.drumrolls, 180, 577, 23, self.white)
|
||||||
|
|
||||||
class Gauge:
|
class Gauge:
|
||||||
"""The player's gauge"""
|
"""The player's gauge"""
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.animation import Animation
|
from libs.animation import Animation
|
||||||
from libs.global_objects import AllNetIcon
|
from libs.global_objects import AllNetIcon
|
||||||
|
from libs.screen import Screen
|
||||||
from libs.song_hash import build_song_hashes
|
from libs.song_hash import build_song_hashes
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.utils import get_current_ms, global_data
|
from libs.utils import get_current_ms, global_data
|
||||||
from libs.file_navigator import navigator
|
from libs.file_navigator import navigator
|
||||||
|
|
||||||
|
|
||||||
class LoadScreen:
|
logger = logging.getLogger(__name__)
|
||||||
def __init__(self):
|
|
||||||
|
class LoadScreen(Screen):
|
||||||
|
def __init__(self, name: str):
|
||||||
|
super().__init__(name)
|
||||||
self.width = 1280
|
self.width = 1280
|
||||||
self.height = 720
|
self.height = 720
|
||||||
self.screen_init = False
|
|
||||||
self.songs_loaded = False
|
self.songs_loaded = False
|
||||||
self.navigator_started = False
|
self.navigator_started = False
|
||||||
self.loading_complete = False
|
self.loading_complete = False
|
||||||
@@ -37,42 +41,44 @@ class LoadScreen:
|
|||||||
"""Background thread function to load song hashes"""
|
"""Background thread function to load song hashes"""
|
||||||
global_data.song_hashes = build_song_hashes()
|
global_data.song_hashes = build_song_hashes()
|
||||||
self.songs_loaded = True
|
self.songs_loaded = True
|
||||||
|
logger.info("Song hashes loaded")
|
||||||
|
|
||||||
def _load_navigator(self):
|
def _load_navigator(self):
|
||||||
"""Background thread function to load navigator"""
|
"""Background thread function to load navigator"""
|
||||||
self.navigator.initialize(global_data.config["paths"]["tja_path"])
|
self.navigator.initialize(global_data.config["paths"]["tja_path"])
|
||||||
self.loading_complete = True
|
self.loading_complete = True
|
||||||
|
logger.info("Navigator initialized")
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
super().on_screen_start()
|
||||||
tex.load_screen_textures('loading')
|
self.loading_thread = threading.Thread(target=self._load_song_hashes)
|
||||||
self.loading_thread = threading.Thread(target=self._load_song_hashes)
|
self.loading_thread.daemon = True
|
||||||
self.loading_thread.daemon = True
|
self.loading_thread.start()
|
||||||
self.loading_thread.start()
|
logger.info("Started song hashes loading thread")
|
||||||
self.screen_init = True
|
|
||||||
|
|
||||||
def on_screen_end(self, next_screen: str):
|
def on_screen_end(self, next_screen: str):
|
||||||
self.screen_init = False
|
|
||||||
tex.unload_textures()
|
|
||||||
if self.loading_thread and self.loading_thread.is_alive():
|
if self.loading_thread and self.loading_thread.is_alive():
|
||||||
self.loading_thread.join(timeout=1.0)
|
self.loading_thread.join(timeout=1.0)
|
||||||
|
logger.info("Joined song hashes loading thread")
|
||||||
if self.navigator_thread and self.navigator_thread.is_alive():
|
if self.navigator_thread and self.navigator_thread.is_alive():
|
||||||
self.navigator_thread.join(timeout=1.0)
|
self.navigator_thread.join(timeout=1.0)
|
||||||
|
logger.info("Joined navigator loading thread")
|
||||||
return next_screen
|
return super().on_screen_end(next_screen)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super().update()
|
||||||
|
|
||||||
if self.songs_loaded and not self.navigator_started:
|
if self.songs_loaded and not self.navigator_started:
|
||||||
self.navigator_thread = threading.Thread(target=self._load_navigator)
|
self.navigator_thread = threading.Thread(target=self._load_navigator)
|
||||||
self.navigator_thread.daemon = True
|
self.navigator_thread.daemon = True
|
||||||
self.navigator_thread.start()
|
self.navigator_thread.start()
|
||||||
self.navigator_started = True
|
self.navigator_started = True
|
||||||
|
logger.info("Started navigator loading thread")
|
||||||
|
|
||||||
if self.loading_complete and self.fade_in is None:
|
if self.loading_complete and self.fade_in is None:
|
||||||
self.fade_in = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0, ease_in='cubic')
|
self.fade_in = Animation.create_fade(1000, initial_opacity=0.0, final_opacity=1.0, ease_in='cubic')
|
||||||
self.fade_in.start()
|
self.fade_in.start()
|
||||||
|
logger.info("Fade-in animation started")
|
||||||
|
|
||||||
if self.fade_in is not None:
|
if self.fade_in is not None:
|
||||||
self.fade_in.update(get_current_ms())
|
self.fade_in.update(get_current_ms())
|
||||||
@@ -107,5 +113,3 @@ class LoadScreen:
|
|||||||
if self.fade_in is not None:
|
if self.fade_in is not None:
|
||||||
ray.draw_rectangle(0, 0, self.width, self.height, ray.fade(ray.WHITE, self.fade_in.attribute))
|
ray.draw_rectangle(0, 0, self.width, self.height, ray.fade(ray.WHITE, self.fade_in.attribute))
|
||||||
self.allnet_indicator.draw()
|
self.allnet_indicator.draw()
|
||||||
def draw_3d(self):
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
import logging
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.global_data import reset_session
|
from libs.global_data import reset_session
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
from libs.chara_2d import Chara2D
|
from libs.chara_2d import Chara2D
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate
|
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate
|
||||||
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
OutlinedText,
|
OutlinedText,
|
||||||
@@ -13,46 +15,32 @@ from libs.utils import (
|
|||||||
is_r_don_pressed
|
is_r_don_pressed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class State:
|
class State:
|
||||||
"""
|
"""Enum representing the state of the result screen."""
|
||||||
Enum representing the state of the result screen.
|
|
||||||
"""
|
|
||||||
FAIL = 0
|
FAIL = 0
|
||||||
CLEAR = 1
|
CLEAR = 1
|
||||||
RAINBOW = 2
|
RAINBOW = 2
|
||||||
|
|
||||||
class ResultScreen:
|
class ResultScreen(Screen):
|
||||||
def __init__(self):
|
|
||||||
self.width = 1280
|
|
||||||
self.height = 720
|
|
||||||
self.screen_init = False
|
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
super().on_screen_start()
|
||||||
tex.load_screen_textures('result')
|
self.song_info = OutlinedText(global_data.session_data[0].song_title, 40, ray.WHITE, ray.BLACK, outline_thickness=5)
|
||||||
audio.load_screen_sounds('result')
|
audio.play_sound('bgm', 'music')
|
||||||
self.screen_init = True
|
self.fade_in = FadeIn(str(global_data.player_num))
|
||||||
self.song_info = OutlinedText(global_data.session_data[0].song_title, 40, ray.WHITE, ray.BLACK, outline_thickness=5)
|
self.fade_out = tex.get_animation(0)
|
||||||
audio.play_sound('bgm', 'music')
|
self.coin_overlay = CoinOverlay()
|
||||||
self.fade_in = FadeIn(str(global_data.player_num))
|
self.allnet_indicator = AllNetIcon()
|
||||||
self.fade_out = tex.get_animation(0)
|
self.start_ms = get_current_ms()
|
||||||
self.coin_overlay = CoinOverlay()
|
self.is_skipped = False
|
||||||
self.allnet_indicator = AllNetIcon()
|
self.background = Background(str(global_data.player_num), 1280)
|
||||||
self.start_ms = get_current_ms()
|
self.player_1 = ResultPlayer(str(global_data.player_num), False, False)
|
||||||
self.is_skipped = False
|
|
||||||
self.background = Background(str(global_data.player_num), self.width)
|
|
||||||
self.player_1 = ResultPlayer(str(global_data.player_num), False, False)
|
|
||||||
|
|
||||||
def on_screen_end(self, next_screen: str):
|
def on_screen_end(self, next_screen: str):
|
||||||
self.screen_init = False
|
|
||||||
global_data.songs_played += 1
|
global_data.songs_played += 1
|
||||||
tex.unload_textures()
|
|
||||||
audio.stop_sound('bgm')
|
|
||||||
audio.unload_all_sounds()
|
|
||||||
audio.unload_all_music()
|
|
||||||
reset_session()
|
reset_session()
|
||||||
return next_screen
|
return super().on_screen_end(next_screen)
|
||||||
|
|
||||||
def handle_input(self):
|
def handle_input(self):
|
||||||
if is_r_don_pressed() or is_l_don_pressed():
|
if is_r_don_pressed() or is_l_don_pressed():
|
||||||
@@ -63,7 +51,7 @@ class ResultScreen:
|
|||||||
audio.play_sound('don', 'sound')
|
audio.play_sound('don', 'sound')
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super().update()
|
||||||
current_time = get_current_ms()
|
current_time = get_current_ms()
|
||||||
self.fade_in.update(current_time)
|
self.fade_in.update(current_time)
|
||||||
self.player_1.update(current_time, self.fade_in.is_finished, self.is_skipped)
|
self.player_1.update(current_time, self.fade_in.is_finished, self.is_skipped)
|
||||||
@@ -78,7 +66,7 @@ class ResultScreen:
|
|||||||
|
|
||||||
def draw_overlay(self):
|
def draw_overlay(self):
|
||||||
self.fade_in.draw()
|
self.fade_in.draw()
|
||||||
ray.draw_rectangle(0, 0, self.width, self.height, ray.fade(ray.BLACK, self.fade_out.attribute))
|
ray.draw_rectangle(0, 0, 1280, 720, ray.fade(ray.BLACK, self.fade_out.attribute))
|
||||||
self.coin_overlay.draw()
|
self.coin_overlay.draw()
|
||||||
self.allnet_indicator.draw()
|
self.allnet_indicator.draw()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import logging
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
|
from libs.screen import Screen
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
global_data,
|
global_data,
|
||||||
is_l_don_pressed,
|
is_l_don_pressed,
|
||||||
@@ -10,10 +12,12 @@ from libs.utils import (
|
|||||||
save_config,
|
save_config,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SettingsScreen:
|
|
||||||
def __init__(self):
|
class SettingsScreen(Screen):
|
||||||
self.screen_init = False
|
def on_screen_start(self):
|
||||||
|
super().on_screen_start()
|
||||||
self.config = global_data.config
|
self.config = global_data.config
|
||||||
self.headers = list(self.config.keys())
|
self.headers = list(self.config.keys())
|
||||||
self.headers.append('Exit')
|
self.headers.append('Exit')
|
||||||
@@ -23,13 +27,7 @@ class SettingsScreen:
|
|||||||
self.editing_key = False
|
self.editing_key = False
|
||||||
self.editing_gamepad = False
|
self.editing_gamepad = False
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_end(self, next_screen: str):
|
||||||
if not self.screen_init:
|
|
||||||
audio.list_host_apis()
|
|
||||||
self.screen_init = True
|
|
||||||
|
|
||||||
def on_screen_end(self):
|
|
||||||
self.screen_init = False
|
|
||||||
save_config(self.config)
|
save_config(self.config)
|
||||||
global_data.config = self.config
|
global_data.config = self.config
|
||||||
audio.close_audio_device()
|
audio.close_audio_device()
|
||||||
@@ -41,7 +39,8 @@ class SettingsScreen:
|
|||||||
audio.buffer_size = global_data.config["audio"]["buffer_size"]
|
audio.buffer_size = global_data.config["audio"]["buffer_size"]
|
||||||
audio.volume_presets = global_data.config["volume"]
|
audio.volume_presets = global_data.config["volume"]
|
||||||
audio.init_audio_device()
|
audio.init_audio_device()
|
||||||
return "ENTRY"
|
logger.info("Settings saved and audio device re-initialized")
|
||||||
|
return next_screen
|
||||||
|
|
||||||
def get_current_settings(self):
|
def get_current_settings(self):
|
||||||
"""Get the current section's settings as a list"""
|
"""Get the current section's settings as a list"""
|
||||||
@@ -53,6 +52,7 @@ class SettingsScreen:
|
|||||||
def handle_boolean_toggle(self, section, key):
|
def handle_boolean_toggle(self, section, key):
|
||||||
"""Toggle boolean values"""
|
"""Toggle boolean values"""
|
||||||
self.config[section][key] = not self.config[section][key]
|
self.config[section][key] = not self.config[section][key]
|
||||||
|
logger.info(f"Toggled boolean setting: {section}.{key} -> {self.config[section][key]}")
|
||||||
|
|
||||||
def handle_numeric_change(self, section, key, increment):
|
def handle_numeric_change(self, section, key, increment):
|
||||||
"""Handle numeric value changes"""
|
"""Handle numeric value changes"""
|
||||||
@@ -81,6 +81,7 @@ class SettingsScreen:
|
|||||||
new_value = valid_sizes[new_idx]
|
new_value = valid_sizes[new_idx]
|
||||||
|
|
||||||
self.config[section][key] = new_value
|
self.config[section][key] = new_value
|
||||||
|
logger.info(f"Changed numeric setting: {section}.{key} -> {new_value}")
|
||||||
|
|
||||||
def handle_string_cycle(self, section, key):
|
def handle_string_cycle(self, section, key):
|
||||||
"""Cycle through predefined string values"""
|
"""Cycle through predefined string values"""
|
||||||
@@ -98,10 +99,12 @@ class SettingsScreen:
|
|||||||
self.config[section][key] = values[new_idx]
|
self.config[section][key] = values[new_idx]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.config[section][key] = values[0]
|
self.config[section][key] = values[0]
|
||||||
|
logger.info(f"Cycled string setting: {section}.{key} -> {self.config[section][key]}")
|
||||||
|
|
||||||
def handle_key_binding(self, section, key):
|
def handle_key_binding(self, section, key):
|
||||||
"""Handle key binding changes"""
|
"""Handle key binding changes"""
|
||||||
self.editing_key = True
|
self.editing_key = True
|
||||||
|
logger.info(f"Started key binding edit for: {section}.{key}")
|
||||||
|
|
||||||
def update_key_binding(self):
|
def update_key_binding(self):
|
||||||
"""Update key binding based on input"""
|
"""Update key binding based on input"""
|
||||||
@@ -116,11 +119,14 @@ class SettingsScreen:
|
|||||||
setting_key, _ = settings[self.setting_index]
|
setting_key, _ = settings[self.setting_index]
|
||||||
self.config[current_header][setting_key] = [new_key]
|
self.config[current_header][setting_key] = [new_key]
|
||||||
self.editing_key = False
|
self.editing_key = False
|
||||||
|
logger.info(f"Key binding updated: {current_header}.{setting_key} -> {new_key}")
|
||||||
elif key_pressed == ray.KeyboardKey.KEY_ESCAPE:
|
elif key_pressed == ray.KeyboardKey.KEY_ESCAPE:
|
||||||
self.editing_key = False
|
self.editing_key = False
|
||||||
|
logger.info("Key binding edit cancelled")
|
||||||
|
|
||||||
def handle_gamepad_binding(self, section, key):
|
def handle_gamepad_binding(self, section, key):
|
||||||
self.editing_gamepad = True
|
self.editing_gamepad = True
|
||||||
|
logger.info(f"Started gamepad binding edit for: {section}.{key}")
|
||||||
|
|
||||||
def update_gamepad_binding(self):
|
def update_gamepad_binding(self):
|
||||||
"""Update gamepad binding based on input"""
|
"""Update gamepad binding based on input"""
|
||||||
@@ -132,11 +138,13 @@ class SettingsScreen:
|
|||||||
setting_key, _ = settings[self.setting_index]
|
setting_key, _ = settings[self.setting_index]
|
||||||
self.config[current_header][setting_key] = [button_pressed]
|
self.config[current_header][setting_key] = [button_pressed]
|
||||||
self.editing_gamepad = False
|
self.editing_gamepad = False
|
||||||
|
logger.info(f"Gamepad binding updated: {current_header}.{setting_key} -> {button_pressed}")
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
||||||
self.editing_gamepad = False
|
self.editing_gamepad = False
|
||||||
|
logger.info("Gamepad binding edit cancelled")
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super().update()
|
||||||
|
|
||||||
# Handle key binding editing
|
# Handle key binding editing
|
||||||
if self.editing_key:
|
if self.editing_key:
|
||||||
@@ -151,18 +159,22 @@ class SettingsScreen:
|
|||||||
|
|
||||||
# Exit handling
|
# Exit handling
|
||||||
if current_header == 'Exit' and (is_l_don_pressed() or is_r_don_pressed()):
|
if current_header == 'Exit' and (is_l_don_pressed() or is_r_don_pressed()):
|
||||||
return self.on_screen_end()
|
logger.info("Exiting settings screen")
|
||||||
|
return self.on_screen_end("ENTRY")
|
||||||
|
|
||||||
# Navigation between sections
|
# Navigation between sections
|
||||||
if not self.in_setting_edit:
|
if not self.in_setting_edit:
|
||||||
if is_r_kat_pressed():
|
if is_r_kat_pressed():
|
||||||
self.header_index = (self.header_index + 1) % len(self.headers)
|
self.header_index = (self.header_index + 1) % len(self.headers)
|
||||||
self.setting_index = 0
|
self.setting_index = 0
|
||||||
|
logger.info(f"Navigated to next section: {self.headers[self.header_index]}")
|
||||||
elif is_l_kat_pressed():
|
elif is_l_kat_pressed():
|
||||||
self.header_index = (self.header_index - 1) % len(self.headers)
|
self.header_index = (self.header_index - 1) % len(self.headers)
|
||||||
self.setting_index = 0
|
self.setting_index = 0
|
||||||
|
logger.info(f"Navigated to previous section: {self.headers[self.header_index]}")
|
||||||
elif (is_l_don_pressed() or is_r_don_pressed()) and current_header != 'Exit':
|
elif (is_l_don_pressed() or is_r_don_pressed()) and current_header != 'Exit':
|
||||||
self.in_setting_edit = True
|
self.in_setting_edit = True
|
||||||
|
logger.info(f"Entered section edit: {current_header}")
|
||||||
else:
|
else:
|
||||||
# Navigation within settings
|
# Navigation within settings
|
||||||
settings = self.get_current_settings()
|
settings = self.get_current_settings()
|
||||||
@@ -172,8 +184,10 @@ class SettingsScreen:
|
|||||||
|
|
||||||
if is_r_kat_pressed():
|
if is_r_kat_pressed():
|
||||||
self.setting_index = (self.setting_index + 1) % len(settings)
|
self.setting_index = (self.setting_index + 1) % len(settings)
|
||||||
|
logger.info(f"Navigated to next setting: {settings[self.setting_index][0]}")
|
||||||
elif is_l_kat_pressed():
|
elif is_l_kat_pressed():
|
||||||
self.setting_index = (self.setting_index - 1) % len(settings)
|
self.setting_index = (self.setting_index - 1) % len(settings)
|
||||||
|
logger.info(f"Navigated to previous setting: {settings[self.setting_index][0]}")
|
||||||
elif is_r_don_pressed():
|
elif is_r_don_pressed():
|
||||||
# Modify setting value
|
# Modify setting value
|
||||||
setting_key, setting_value = settings[self.setting_index]
|
setting_key, setting_value = settings[self.setting_index]
|
||||||
@@ -209,6 +223,7 @@ class SettingsScreen:
|
|||||||
|
|
||||||
elif ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
elif ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
||||||
self.in_setting_edit = False
|
self.in_setting_edit = False
|
||||||
|
logger.info("Exited section edit")
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
# Draw title
|
# Draw title
|
||||||
@@ -237,7 +252,8 @@ class SettingsScreen:
|
|||||||
display_value = ', '.join(map(str, value))
|
display_value = ', '.join(map(str, value))
|
||||||
else:
|
else:
|
||||||
display_value = str(value)
|
display_value = str(value)
|
||||||
|
if key == 'device_type':
|
||||||
|
display_value = f'{display_value} ({audio.get_host_api_name(value)})'
|
||||||
ray.draw_text(f'{key}: {display_value}', 250, i*25 + 70, 20, color)
|
ray.draw_text(f'{key}: {display_value}', 250, i*25 + 70, 20, color)
|
||||||
|
|
||||||
# Draw instructions
|
# Draw instructions
|
||||||
@@ -255,5 +271,3 @@ class SettingsScreen:
|
|||||||
else:
|
else:
|
||||||
# Draw exit instruction
|
# Draw exit instruction
|
||||||
ray.draw_text("Press Don to exit settings", 250, 100, 20, ray.GREEN)
|
ray.draw_text("Press Don to exit settings", 250, 100, 20, ray.GREEN)
|
||||||
def draw_3d(self):
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from dataclasses import fields
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pyray as ray
|
import pyray as ray
|
||||||
|
import logging
|
||||||
|
|
||||||
from libs.file_navigator import navigator
|
from libs.file_navigator import navigator
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
@@ -10,6 +11,7 @@ from libs.chara_2d import Chara2D
|
|||||||
from libs.file_navigator import Directory, SongBox, SongFile
|
from libs.file_navigator import Directory, SongBox, SongFile
|
||||||
from libs.global_data import Modifiers
|
from libs.global_data import Modifiers
|
||||||
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate, Indicator, Timer
|
from libs.global_objects import AllNetIcon, CoinOverlay, Nameplate, Indicator, Timer
|
||||||
|
from libs.screen import Screen
|
||||||
from libs.texture import tex
|
from libs.texture import tex
|
||||||
from libs.transition import Transition
|
from libs.transition import Transition
|
||||||
from libs.utils import (
|
from libs.utils import (
|
||||||
@@ -22,63 +24,59 @@ from libs.utils import (
|
|||||||
is_r_kat_pressed,
|
is_r_kat_pressed,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class State:
|
class State:
|
||||||
BROWSING = 0
|
BROWSING = 0
|
||||||
SONG_SELECTED = 1
|
SONG_SELECTED = 1
|
||||||
DIFF_SORTING = 2
|
DIFF_SORTING = 2
|
||||||
|
|
||||||
class SongSelectScreen:
|
class SongSelectScreen(Screen):
|
||||||
BOX_CENTER = 444
|
BOX_CENTER = 444
|
||||||
def __init__(self, screen_width: int = 1280):
|
|
||||||
self.screen_init = False
|
|
||||||
self.screen_width = screen_width
|
|
||||||
self.indicator = Indicator(Indicator.State.SELECT)
|
|
||||||
self.navigator = navigator
|
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
super().on_screen_start()
|
||||||
tex.load_screen_textures('song_select')
|
audio.set_sound_volume('ura_switch', 0.25)
|
||||||
audio.load_screen_sounds('song_select')
|
audio.set_sound_volume('add_favorite', 3.0)
|
||||||
audio.set_sound_volume('ura_switch', 0.25)
|
audio.play_sound('bgm', 'music')
|
||||||
audio.set_sound_volume('add_favorite', 3.0)
|
audio.play_sound('voice_enter', 'voice')
|
||||||
audio.play_sound('bgm', 'music')
|
self.navigator = navigator
|
||||||
audio.play_sound('voice_enter', 'voice')
|
self.background_move = tex.get_animation(0)
|
||||||
self.background_move = tex.get_animation(0)
|
self.move_away = tex.get_animation(1)
|
||||||
self.move_away = tex.get_animation(1)
|
self.diff_fade_out = tex.get_animation(2)
|
||||||
self.diff_fade_out = tex.get_animation(2)
|
self.text_fade_out = tex.get_animation(3)
|
||||||
self.text_fade_out = tex.get_animation(3)
|
self.text_fade_in = tex.get_animation(4)
|
||||||
self.text_fade_in = tex.get_animation(4)
|
self.background_fade_change = tex.get_animation(5)
|
||||||
self.background_fade_change = tex.get_animation(5)
|
self.blue_arrow_fade = tex.get_animation(29)
|
||||||
self.blue_arrow_fade = tex.get_animation(29)
|
self.blue_arrow_move = tex.get_animation(30)
|
||||||
self.blue_arrow_move = tex.get_animation(30)
|
self.blue_arrow_fade.start()
|
||||||
self.blue_arrow_fade.start()
|
self.blue_arrow_move.start()
|
||||||
self.blue_arrow_move.start()
|
self.state = State.BROWSING
|
||||||
self.state = State.BROWSING
|
self.game_transition = None
|
||||||
self.game_transition = None
|
self.demo_song = None
|
||||||
self.demo_song = None
|
self.diff_sort_selector = None
|
||||||
self.diff_sort_selector = None
|
self.coin_overlay = CoinOverlay()
|
||||||
self.coin_overlay = CoinOverlay()
|
self.allnet_indicator = AllNetIcon()
|
||||||
self.allnet_indicator = AllNetIcon()
|
self.indicator = Indicator(Indicator.State.SELECT)
|
||||||
self.texture_index = SongBox.DEFAULT_INDEX
|
self.texture_index = SongBox.DEFAULT_INDEX
|
||||||
self.last_texture_index = SongBox.DEFAULT_INDEX
|
self.last_texture_index = SongBox.DEFAULT_INDEX
|
||||||
self.last_moved = get_current_ms()
|
self.last_moved = get_current_ms()
|
||||||
self.timer_browsing = Timer(100, get_current_ms(), self.navigator.select_current_item)
|
self.timer_browsing = Timer(100, get_current_ms(), self.navigator.select_current_item)
|
||||||
self.timer_selected = Timer(40, get_current_ms(), self._confirm_selection_wrapper)
|
self.timer_selected = Timer(40, get_current_ms(), self._confirm_selection_wrapper)
|
||||||
self.screen_init = True
|
self.screen_init = True
|
||||||
self.ura_switch_animation = UraSwitchAnimation()
|
self.ura_switch_animation = UraSwitchAnimation()
|
||||||
|
|
||||||
self.player_1 = SongSelectPlayer(str(global_data.player_num), self.text_fade_in)
|
self.player_1 = SongSelectPlayer(str(global_data.player_num), self.text_fade_in)
|
||||||
|
|
||||||
if self.navigator.items == []:
|
if self.navigator.items == []:
|
||||||
return self.on_screen_end("ENTRY")
|
logger.warning("No navigator items found, returning to ENTRY screen")
|
||||||
|
return self.on_screen_end("ENTRY")
|
||||||
|
|
||||||
if str(global_data.selected_song) in self.navigator.all_song_files:
|
if str(global_data.selected_song) in self.navigator.all_song_files:
|
||||||
self.navigator.mark_crowns_dirty_for_song(self.navigator.all_song_files[str(global_data.selected_song)])
|
self.navigator.mark_crowns_dirty_for_song(self.navigator.all_song_files[str(global_data.selected_song)])
|
||||||
|
|
||||||
self.navigator.reset_items()
|
curr_item = self.navigator.get_current_item()
|
||||||
curr_item = self.navigator.get_current_item()
|
curr_item.box.get_scores()
|
||||||
curr_item.box.get_scores()
|
self.navigator.add_recent()
|
||||||
self.navigator.add_recent()
|
|
||||||
|
|
||||||
def finalize_song(self):
|
def finalize_song(self):
|
||||||
global_data.selected_song = self.navigator.get_current_item().path
|
global_data.selected_song = self.navigator.get_current_item().path
|
||||||
@@ -88,13 +86,10 @@ class SongSelectScreen:
|
|||||||
def on_screen_end(self, next_screen):
|
def on_screen_end(self, next_screen):
|
||||||
self.screen_init = False
|
self.screen_init = False
|
||||||
self.reset_demo_music()
|
self.reset_demo_music()
|
||||||
self.navigator.reset_items()
|
|
||||||
self.finalize_song()
|
self.finalize_song()
|
||||||
audio.unload_all_sounds()
|
|
||||||
audio.unload_all_music()
|
|
||||||
tex.unload_textures()
|
|
||||||
self.player_1.nameplate.unload()
|
self.player_1.nameplate.unload()
|
||||||
return next_screen
|
self.navigator.get_current_item().box.yellow_box.create_anim()
|
||||||
|
return super().on_screen_end(next_screen)
|
||||||
|
|
||||||
def reset_demo_music(self):
|
def reset_demo_music(self):
|
||||||
"""Reset the preview music to the song select bgm."""
|
"""Reset the preview music to the song select bgm."""
|
||||||
@@ -199,7 +194,7 @@ class SongSelectScreen:
|
|||||||
"""Wrapper for timer callback"""
|
"""Wrapper for timer callback"""
|
||||||
self._confirm_selection()
|
self._confirm_selection()
|
||||||
|
|
||||||
def _confirm_selection(self):
|
def _confirm_selection(self, player_selected: int = 1):
|
||||||
"""Confirm song selection and create game transition"""
|
"""Confirm song selection and create game transition"""
|
||||||
audio.play_sound('don', 'sound')
|
audio.play_sound('don', 'sound')
|
||||||
audio.play_sound(f'voice_start_song_{global_data.player_num}p', 'voice')
|
audio.play_sound(f'voice_start_song_{global_data.player_num}p', 'voice')
|
||||||
@@ -214,7 +209,8 @@ class SongSelectScreen:
|
|||||||
self.player_1.update(current_time)
|
self.player_1.update(current_time)
|
||||||
if self.text_fade_out.is_finished:
|
if self.text_fade_out.is_finished:
|
||||||
self.player_1.selected_song = True
|
self.player_1.selected_song = True
|
||||||
return "GAME"
|
next_screen = "GAME"
|
||||||
|
return next_screen
|
||||||
|
|
||||||
def check_for_selection(self):
|
def check_for_selection(self):
|
||||||
if self.player_1.selected_diff_highlight_fade.is_finished and not audio.is_sound_playing(f'voice_start_song_{global_data.player_num}p') and self.game_transition is None:
|
if self.player_1.selected_diff_highlight_fade.is_finished and not audio.is_sound_playing(f'voice_start_song_{global_data.player_num}p') and self.game_transition is None:
|
||||||
@@ -230,7 +226,7 @@ class SongSelectScreen:
|
|||||||
self.game_transition.start()
|
self.game_transition.start()
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
ret_val = self.on_screen_start()
|
ret_val = super().update()
|
||||||
if ret_val is not None:
|
if ret_val is not None:
|
||||||
return ret_val
|
return ret_val
|
||||||
current_time = get_current_ms()
|
current_time = get_current_ms()
|
||||||
@@ -288,12 +284,14 @@ class SongSelectScreen:
|
|||||||
audio.play_music_stream(self.demo_song, 'music')
|
audio.play_music_stream(self.demo_song, 'music')
|
||||||
audio.seek_music_stream(self.demo_song, song.tja.metadata.demostart)
|
audio.seek_music_stream(self.demo_song, song.tja.metadata.demostart)
|
||||||
audio.stop_sound('bgm')
|
audio.stop_sound('bgm')
|
||||||
|
logger.info(f"Demo song loaded and playing for {song.tja.metadata.title}")
|
||||||
if song.box.is_open:
|
if song.box.is_open:
|
||||||
current_box = song.box
|
current_box = song.box
|
||||||
if not current_box.is_back and get_current_ms() >= song.box.wait + (83.33*3):
|
if not current_box.is_back and get_current_ms() >= song.box.wait + (83.33*3):
|
||||||
self.texture_index = current_box.texture_index
|
self.texture_index = current_box.texture_index
|
||||||
|
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
||||||
|
logger.info("Escape key pressed, returning to ENTRY screen")
|
||||||
return self.on_screen_end('ENTRY')
|
return self.on_screen_end('ENTRY')
|
||||||
|
|
||||||
def draw_background_diffs(self):
|
def draw_background_diffs(self):
|
||||||
@@ -315,7 +313,7 @@ class SongSelectScreen:
|
|||||||
|
|
||||||
for item in self.navigator.items:
|
for item in self.navigator.items:
|
||||||
box = item.box
|
box = item.box
|
||||||
if -156 <= box.position <= self.screen_width + 144:
|
if -156 <= box.position <= 1280 + 144:
|
||||||
if box.position <= 500:
|
if box.position <= 500:
|
||||||
box.draw(box.position - int(self.move_away.attribute), 95, self.player_1.is_ura, fade_override=self.diff_fade_out.attribute)
|
box.draw(box.position - int(self.move_away.attribute), 95, self.player_1.is_ura, fade_override=self.diff_fade_out.attribute)
|
||||||
else:
|
else:
|
||||||
@@ -534,6 +532,7 @@ class SongSelectPlayer:
|
|||||||
raise Exception("Directory was chosen instead of song")
|
raise Exception("Directory was chosen instead of song")
|
||||||
diffs = sorted(selected_song.tja.metadata.course_data)
|
diffs = sorted(selected_song.tja.metadata.course_data)
|
||||||
prev_diff = self.selected_difficulty
|
prev_diff = self.selected_difficulty
|
||||||
|
ret_val = None
|
||||||
|
|
||||||
if is_l_kat_pressed(self.player_num):
|
if is_l_kat_pressed(self.player_num):
|
||||||
ret_val = self._navigate_difficulty_left(diffs)
|
ret_val = self._navigate_difficulty_left(diffs)
|
||||||
@@ -616,7 +615,7 @@ class SongSelectPlayer:
|
|||||||
self.selected_difficulty = 7 - self.selected_difficulty
|
self.selected_difficulty = 7 - self.selected_difficulty
|
||||||
return "ura_toggle"
|
return "ura_toggle"
|
||||||
|
|
||||||
def draw_selector(self, state: State, is_half: bool):
|
def draw_selector(self, is_half: bool):
|
||||||
fade = 0.5 if (self.neiro_selector is not None or self.modifier_selector is not None) else self.text_fade_in.attribute
|
fade = 0.5 if (self.neiro_selector is not None or self.modifier_selector is not None) else self.text_fade_in.attribute
|
||||||
direction = 1 if self.diff_select_move_right else -1
|
direction = 1 if self.diff_select_move_right else -1
|
||||||
if self.selected_difficulty <= -1 or self.prev_diff == -1:
|
if self.selected_difficulty <= -1 or self.prev_diff == -1:
|
||||||
@@ -660,7 +659,7 @@ class SongSelectPlayer:
|
|||||||
name = f'{self.player_num}p_outline_half' if is_half else f'{self.player_num}p_outline'
|
name = f'{self.player_num}p_outline_half' if is_half else f'{self.player_num}p_outline'
|
||||||
tex.draw_texture('diff_select', name, x=(difficulty * 115))
|
tex.draw_texture('diff_select', name, x=(difficulty * 115))
|
||||||
|
|
||||||
def draw_background_diffs(self, state: State):
|
def draw_background_diffs(self, state: int):
|
||||||
if (self.selected_song and state == State.SONG_SELECTED and self.selected_difficulty >= 0):
|
if (self.selected_song and state == State.SONG_SELECTED and self.selected_difficulty >= 0):
|
||||||
if self.player_num == '2':
|
if self.player_num == '2':
|
||||||
tex.draw_texture('global', 'background_diff', frame=self.selected_difficulty, fade=min(0.5, self.selected_diff_fadein.attribute), x=1025, y=-self.selected_diff_bounce.attribute, y2=self.selected_diff_bounce.attribute)
|
tex.draw_texture('global', 'background_diff', frame=self.selected_difficulty, fade=min(0.5, self.selected_diff_fadein.attribute), x=1025, y=-self.selected_diff_bounce.attribute, y2=self.selected_diff_bounce.attribute)
|
||||||
@@ -677,9 +676,9 @@ class SongSelectPlayer:
|
|||||||
tex.draw_texture('global', 'bg_diff_text_bg', fade=min(0.5, self.selected_diff_text_fadein.attribute), scale=self.selected_diff_text_resize.attribute, center=True)
|
tex.draw_texture('global', 'bg_diff_text_bg', fade=min(0.5, self.selected_diff_text_fadein.attribute), scale=self.selected_diff_text_resize.attribute, center=True)
|
||||||
tex.draw_texture('global', 'bg_diff_text', frame=min(3, self.selected_difficulty), fade=self.selected_diff_text_fadein.attribute, scale=self.selected_diff_text_resize.attribute, center=True)
|
tex.draw_texture('global', 'bg_diff_text', frame=min(3, self.selected_difficulty), fade=self.selected_diff_text_fadein.attribute, scale=self.selected_diff_text_resize.attribute, center=True)
|
||||||
|
|
||||||
def draw(self, state: State, is_half: bool = False):
|
def draw(self, state: int, is_half: bool = False):
|
||||||
if (self.selected_song and state == State.SONG_SELECTED):
|
if (self.selected_song and state == State.SONG_SELECTED):
|
||||||
self.draw_selector(state, is_half)
|
self.draw_selector(is_half)
|
||||||
|
|
||||||
offset = 0
|
offset = 0
|
||||||
if self.neiro_selector is not None:
|
if self.neiro_selector is not None:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import random
|
import random
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -12,15 +13,18 @@ from libs.utils import (
|
|||||||
is_r_don_pressed,
|
is_r_don_pressed,
|
||||||
)
|
)
|
||||||
from libs.video import VideoPlayer
|
from libs.video import VideoPlayer
|
||||||
|
from libs.screen import Screen
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class State:
|
class State:
|
||||||
OP_VIDEO = 0
|
OP_VIDEO = 0
|
||||||
WARNING = 1
|
WARNING = 1
|
||||||
ATTRACT_VIDEO = 2
|
ATTRACT_VIDEO = 2
|
||||||
|
|
||||||
class TitleScreen:
|
class TitleScreen(Screen):
|
||||||
def __init__(self):
|
def __init__(self, name: str):
|
||||||
|
super().__init__(name)
|
||||||
#normalize to accept both stings and lists in toml
|
#normalize to accept both stings and lists in toml
|
||||||
#maybe normalize centrally? but it's used only here
|
#maybe normalize centrally? but it's used only here
|
||||||
vp = global_data.config["paths"]["video_path"]
|
vp = global_data.config["paths"]["video_path"]
|
||||||
@@ -31,33 +35,27 @@ class TitleScreen:
|
|||||||
base = Path(base)
|
base = Path(base)
|
||||||
self.op_video_list += list((base/"op_videos").glob("**/*.mp4"))
|
self.op_video_list += list((base/"op_videos").glob("**/*.mp4"))
|
||||||
self.attract_video_list += list((base/"attract_videos").glob("**/*.mp4"))
|
self.attract_video_list += list((base/"attract_videos").glob("**/*.mp4"))
|
||||||
self.screen_init = False
|
|
||||||
self.coin_overlay = CoinOverlay()
|
self.coin_overlay = CoinOverlay()
|
||||||
self.allnet_indicator = AllNetIcon()
|
self.allnet_indicator = AllNetIcon()
|
||||||
self.entry_overlay = EntryOverlay()
|
self.entry_overlay = EntryOverlay()
|
||||||
|
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
super().on_screen_start()
|
||||||
self.screen_init = True
|
self.state = State.OP_VIDEO
|
||||||
tex.load_screen_textures('title')
|
self.op_video = None
|
||||||
audio.load_screen_sounds('title')
|
self.attract_video = None
|
||||||
self.state = State.OP_VIDEO
|
self.warning_board = None
|
||||||
self.op_video = None
|
self.fade_out = tex.get_animation(13)
|
||||||
self.attract_video = None
|
self.text_overlay_fade = tex.get_animation(14)
|
||||||
self.warning_board = None
|
|
||||||
self.fade_out = tex.get_animation(13)
|
|
||||||
self.text_overlay_fade = tex.get_animation(14)
|
|
||||||
|
|
||||||
def on_screen_end(self) -> str:
|
def on_screen_end(self, next_screen) -> str:
|
||||||
if self.op_video is not None:
|
if self.op_video is not None:
|
||||||
self.op_video.stop()
|
self.op_video.stop()
|
||||||
|
logger.info("OP video stopped")
|
||||||
if self.attract_video is not None:
|
if self.attract_video is not None:
|
||||||
self.attract_video.stop()
|
self.attract_video.stop()
|
||||||
audio.unload_all_sounds()
|
logger.info("Attract video stopped")
|
||||||
audio.unload_all_music()
|
return super().on_screen_end(next_screen)
|
||||||
tex.unload_textures()
|
|
||||||
self.screen_init = False
|
|
||||||
return "ENTRY"
|
|
||||||
|
|
||||||
def scene_manager(self, current_time):
|
def scene_manager(self, current_time):
|
||||||
"""Manage the scene transitions"""
|
"""Manage the scene transitions"""
|
||||||
@@ -65,38 +63,44 @@ class TitleScreen:
|
|||||||
if self.op_video is None:
|
if self.op_video is None:
|
||||||
self.op_video = VideoPlayer(random.choice(self.op_video_list))
|
self.op_video = VideoPlayer(random.choice(self.op_video_list))
|
||||||
self.op_video.start(current_time)
|
self.op_video.start(current_time)
|
||||||
|
logger.info("Started OP video")
|
||||||
self.op_video.update()
|
self.op_video.update()
|
||||||
if self.op_video.is_finished():
|
if self.op_video.is_finished():
|
||||||
self.op_video.stop()
|
self.op_video.stop()
|
||||||
self.op_video = None
|
self.op_video = None
|
||||||
self.state = State.WARNING
|
self.state = State.WARNING
|
||||||
|
logger.info("OP video finished, transitioning to WARNING state")
|
||||||
elif self.state == State.WARNING:
|
elif self.state == State.WARNING:
|
||||||
if self.warning_board is None:
|
if self.warning_board is None:
|
||||||
self.warning_board = WarningScreen(current_time)
|
self.warning_board = WarningScreen(current_time)
|
||||||
|
logger.info("Warning screen started")
|
||||||
self.warning_board.update(current_time)
|
self.warning_board.update(current_time)
|
||||||
if self.warning_board.is_finished:
|
if self.warning_board.is_finished:
|
||||||
self.state = State.ATTRACT_VIDEO
|
self.state = State.ATTRACT_VIDEO
|
||||||
self.warning_board = None
|
self.warning_board = None
|
||||||
|
logger.info("Warning finished, transitioning to ATTRACT_VIDEO state")
|
||||||
elif self.state == State.ATTRACT_VIDEO:
|
elif self.state == State.ATTRACT_VIDEO:
|
||||||
if self.attract_video is None:
|
if self.attract_video is None:
|
||||||
self.attract_video = VideoPlayer(random.choice(self.attract_video_list))
|
self.attract_video = VideoPlayer(random.choice(self.attract_video_list))
|
||||||
self.attract_video.start(current_time)
|
self.attract_video.start(current_time)
|
||||||
|
logger.info("Started attract video")
|
||||||
self.attract_video.update()
|
self.attract_video.update()
|
||||||
if self.attract_video.is_finished():
|
if self.attract_video.is_finished():
|
||||||
self.attract_video.stop()
|
self.attract_video.stop()
|
||||||
self.attract_video = None
|
self.attract_video = None
|
||||||
self.state = State.OP_VIDEO
|
self.state = State.OP_VIDEO
|
||||||
|
logger.info("Attract video finished, transitioning to OP_VIDEO state")
|
||||||
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super().update()
|
||||||
current_time = get_current_ms()
|
current_time = get_current_ms()
|
||||||
|
|
||||||
self.text_overlay_fade.update(current_time)
|
self.text_overlay_fade.update(current_time)
|
||||||
self.fade_out.update(current_time)
|
self.fade_out.update(current_time)
|
||||||
if self.fade_out.is_finished:
|
if self.fade_out.is_finished:
|
||||||
self.fade_out.update(current_time)
|
self.fade_out.update(current_time)
|
||||||
return self.on_screen_end()
|
return self.on_screen_end("ENTRY")
|
||||||
|
|
||||||
self.scene_manager(current_time)
|
self.scene_manager(current_time)
|
||||||
if is_l_don_pressed() or is_r_don_pressed():
|
if is_l_don_pressed() or is_r_don_pressed():
|
||||||
@@ -120,9 +124,6 @@ class TitleScreen:
|
|||||||
global_tex.draw_texture('overlay', 'hit_taiko_to_start', index=0, fade=self.text_overlay_fade.attribute)
|
global_tex.draw_texture('overlay', 'hit_taiko_to_start', index=0, fade=self.text_overlay_fade.attribute)
|
||||||
global_tex.draw_texture('overlay', 'hit_taiko_to_start', index=1, fade=self.text_overlay_fade.attribute)
|
global_tex.draw_texture('overlay', 'hit_taiko_to_start', index=1, fade=self.text_overlay_fade.attribute)
|
||||||
|
|
||||||
def draw_3d(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class WarningScreen:
|
class WarningScreen:
|
||||||
"""Warning screen for the game"""
|
"""Warning screen for the game"""
|
||||||
class X:
|
class X:
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
import copy
|
import copy
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from libs.tja import TJAParser
|
from libs.tja import TJAParser
|
||||||
@@ -8,15 +9,16 @@ from libs.video import VideoPlayer
|
|||||||
import pyray as ray
|
import pyray as ray
|
||||||
from scenes.game import ClearAnimation, FCAnimation, FailAnimation, GameScreen, Player, Background, SCREEN_WIDTH, ResultTransition
|
from scenes.game import ClearAnimation, FCAnimation, FailAnimation, GameScreen, Player, Background, SCREEN_WIDTH, ResultTransition
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class TwoPlayerGameScreen(GameScreen):
|
class TwoPlayerGameScreen(GameScreen):
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
super().on_screen_start()
|
||||||
super().on_screen_start()
|
scene_preset = self.tja.metadata.scene_preset
|
||||||
scene_preset = self.tja.metadata.scene_preset
|
if self.background is not None:
|
||||||
if self.background is not None:
|
self.background.unload()
|
||||||
self.background.unload()
|
self.background = Background(3, self.bpm, scene_preset=scene_preset)
|
||||||
self.background = Background(3, self.bpm, scene_preset=scene_preset)
|
self.result_transition = ResultTransition(3)
|
||||||
self.result_transition = ResultTransition(3)
|
|
||||||
|
|
||||||
def load_hitsounds(self):
|
def load_hitsounds(self):
|
||||||
"""Load the hit sounds"""
|
"""Load the hit sounds"""
|
||||||
@@ -26,12 +28,15 @@ class TwoPlayerGameScreen(GameScreen):
|
|||||||
if global_data.hit_sound[0] == -1:
|
if global_data.hit_sound[0] == -1:
|
||||||
audio.load_sound(Path('none.wav'), 'hitsound_don_1p')
|
audio.load_sound(Path('none.wav'), 'hitsound_don_1p')
|
||||||
audio.load_sound(Path('none.wav'), 'hitsound_kat_1p')
|
audio.load_sound(Path('none.wav'), 'hitsound_kat_1p')
|
||||||
|
logger.info("Loaded default (none) hit sounds for 1P")
|
||||||
elif global_data.hit_sound[0] == 0:
|
elif global_data.hit_sound[0] == 0:
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.wav", 'hitsound_don_1p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.wav", 'hitsound_don_1p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.wav", 'hitsound_kat_1p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.wav", 'hitsound_kat_1p')
|
||||||
|
logger.info("Loaded wav hit sounds for 1P")
|
||||||
else:
|
else:
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.ogg", 'hitsound_don_1p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "don.ogg", 'hitsound_don_1p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.ogg", 'hitsound_kat_1p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[0]) / "ka.ogg", 'hitsound_kat_1p')
|
||||||
|
logger.info("Loaded ogg hit sounds for 1P")
|
||||||
audio.set_sound_pan('hitsound_don_1p', 1.0)
|
audio.set_sound_pan('hitsound_don_1p', 1.0)
|
||||||
audio.set_sound_pan('hitsound_kat_1p', 1.0)
|
audio.set_sound_pan('hitsound_kat_1p', 1.0)
|
||||||
|
|
||||||
@@ -39,12 +44,15 @@ class TwoPlayerGameScreen(GameScreen):
|
|||||||
if global_data.hit_sound[1] == -1:
|
if global_data.hit_sound[1] == -1:
|
||||||
audio.load_sound(Path('none.wav'), 'hitsound_don_2p')
|
audio.load_sound(Path('none.wav'), 'hitsound_don_2p')
|
||||||
audio.load_sound(Path('none.wav'), 'hitsound_kat_2p')
|
audio.load_sound(Path('none.wav'), 'hitsound_kat_2p')
|
||||||
|
logger.info("Loaded default (none) hit sounds for 2P")
|
||||||
elif global_data.hit_sound[1] == 0:
|
elif global_data.hit_sound[1] == 0:
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don_2p.wav", 'hitsound_don_2p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don_2p.wav", 'hitsound_don_2p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka_2p.wav", 'hitsound_kat_2p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka_2p.wav", 'hitsound_kat_2p')
|
||||||
|
logger.info("Loaded wav hit sounds for 2P")
|
||||||
else:
|
else:
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don.ogg", 'hitsound_don_2p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "don.ogg", 'hitsound_don_2p')
|
||||||
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka.ogg", 'hitsound_kat_2p')
|
audio.load_sound(sounds_dir / "hit_sounds" / str(global_data.hit_sound[1]) / "ka.ogg", 'hitsound_kat_2p')
|
||||||
|
logger.info("Loaded ogg hit sounds for 2P")
|
||||||
audio.set_sound_pan('hitsound_don_2p', 0.0)
|
audio.set_sound_pan('hitsound_don_2p', 0.0)
|
||||||
audio.set_sound_pan('hitsound_kat_2p', 0.0)
|
audio.set_sound_pan('hitsound_kat_2p', 0.0)
|
||||||
|
|
||||||
@@ -55,10 +63,12 @@ class TwoPlayerGameScreen(GameScreen):
|
|||||||
self.init_tja(global_data.selected_song)
|
self.init_tja(global_data.selected_song)
|
||||||
audio.play_sound('restart', 'sound')
|
audio.play_sound('restart', 'sound')
|
||||||
self.song_started = False
|
self.song_started = False
|
||||||
|
logger.info("F1 pressed: song restarted")
|
||||||
|
|
||||||
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
if ray.is_key_pressed(ray.KeyboardKey.KEY_ESCAPE):
|
||||||
if self.song_music is not None:
|
if self.song_music is not None:
|
||||||
audio.stop_music_stream(self.song_music)
|
audio.stop_music_stream(self.song_music)
|
||||||
|
logger.info("Escape pressed: returning to SONG_SELECT_2P")
|
||||||
return self.on_screen_end('SONG_SELECT_2P')
|
return self.on_screen_end('SONG_SELECT_2P')
|
||||||
|
|
||||||
def init_tja(self, song: Path):
|
def init_tja(self, song: Path):
|
||||||
@@ -77,6 +87,7 @@ class TwoPlayerGameScreen(GameScreen):
|
|||||||
self.player_1 = Player(self.tja, 1, global_data.session_data[0].selected_difficulty, False, global_data.modifiers[0])
|
self.player_1 = Player(self.tja, 1, global_data.session_data[0].selected_difficulty, False, global_data.modifiers[0])
|
||||||
self.player_2 = Player(tja_copy, 2, global_data.session_data[1].selected_difficulty, True, global_data.modifiers[1])
|
self.player_2 = Player(tja_copy, 2, global_data.session_data[1].selected_difficulty, True, global_data.modifiers[1])
|
||||||
self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000)
|
self.start_ms = (get_current_ms() - self.tja.metadata.offset*1000)
|
||||||
|
logger.info(f"TJA initialized for two-player song: {song}")
|
||||||
|
|
||||||
def spawn_ending_anims(self):
|
def spawn_ending_anims(self):
|
||||||
if global_data.session_data[0].result_bad == 0:
|
if global_data.session_data[0].result_bad == 0:
|
||||||
@@ -94,7 +105,7 @@ class TwoPlayerGameScreen(GameScreen):
|
|||||||
self.player_2.ending_anim = FailAnimation(self.player_2.is_2p)
|
self.player_2.ending_anim = FailAnimation(self.player_2.is_2p)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super(GameScreen, self).update()
|
||||||
current_time = get_current_ms()
|
current_time = get_current_ms()
|
||||||
self.transition.update(current_time)
|
self.transition.update(current_time)
|
||||||
self.current_ms = current_time - self.start_ms
|
self.current_ms = current_time - self.start_ms
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
|
import logging
|
||||||
from libs.utils import get_current_ms
|
from libs.utils import get_current_ms
|
||||||
from scenes.result import Background, FadeIn, ResultPlayer, ResultScreen
|
from scenes.result import Background, FadeIn, ResultPlayer, ResultScreen
|
||||||
|
|
||||||
class TwoPlayerResultScreen(ResultScreen):
|
logger = logging.getLogger(__name__)
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
|
class TwoPlayerResultScreen(ResultScreen):
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
super().on_screen_start()
|
||||||
super().on_screen_start()
|
self.background = Background('3', 1280)
|
||||||
self.background = Background('3', self.width)
|
self.fade_in = FadeIn('3')
|
||||||
self.fade_in = FadeIn('3')
|
self.player_1 = ResultPlayer('1', True, False)
|
||||||
self.player_1 = ResultPlayer('1', True, False)
|
self.player_2 = ResultPlayer('2', True, True)
|
||||||
self.player_2 = ResultPlayer('2', True, True)
|
logger.info("TwoPlayerResultScreen started, background and players initialized")
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
self.on_screen_start()
|
super(ResultScreen, self).update()
|
||||||
current_time = get_current_ms()
|
current_time = get_current_ms()
|
||||||
self.fade_in.update(current_time)
|
self.fade_in.update(current_time)
|
||||||
self.player_1.update(current_time, self.fade_in.is_finished, self.is_skipped)
|
self.player_1.update(current_time, self.fade_in.is_finished, self.is_skipped)
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
|
import logging
|
||||||
from libs.file_navigator import SongFile
|
from libs.file_navigator import SongFile
|
||||||
from libs.transition import Transition
|
from libs.transition import Transition
|
||||||
from scenes.song_select import DiffSortSelect, SongSelectPlayer, SongSelectScreen, State
|
from scenes.song_select import DiffSortSelect, SongSelectPlayer, SongSelectScreen, State
|
||||||
from libs.utils import get_current_ms, global_data
|
from libs.utils import get_current_ms, global_data
|
||||||
from libs.audio import audio
|
from libs.audio import audio
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class TwoPlayerSongSelectScreen(SongSelectScreen):
|
class TwoPlayerSongSelectScreen(SongSelectScreen):
|
||||||
def on_screen_start(self):
|
def on_screen_start(self):
|
||||||
if not self.screen_init:
|
super().on_screen_start()
|
||||||
super().on_screen_start()
|
self.player_1 = SongSelectPlayer('1', self.text_fade_in)
|
||||||
self.player_1 = SongSelectPlayer('1', self.text_fade_in)
|
self.player_2 = SongSelectPlayer('2', self.text_fade_in)
|
||||||
self.player_2 = SongSelectPlayer('2', self.text_fade_in)
|
|
||||||
|
|
||||||
def finalize_song(self):
|
def finalize_song(self):
|
||||||
global_data.selected_song = self.navigator.get_current_item().path
|
global_data.selected_song = self.navigator.get_current_item().path
|
||||||
global_data.session_data[0].genre_index = self.navigator.get_current_item().box.name_texture_index
|
global_data.session_data[0].genre_index = self.navigator.get_current_item().box.name_texture_index
|
||||||
|
logger.info(f"Finalized song selection: {global_data.selected_song}")
|
||||||
|
|
||||||
def handle_input_browsing(self):
|
def handle_input_browsing(self):
|
||||||
"""Handle input for browsing songs."""
|
"""Handle input for browsing songs."""
|
||||||
@@ -79,24 +82,25 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
|
|||||||
return
|
return
|
||||||
p2_result = True
|
p2_result = True
|
||||||
if result is not None:
|
if result is not None:
|
||||||
print(result, p2_result)
|
logger.info(f"Difficulty selection result: {result}, p2_result={p2_result}")
|
||||||
if result == "cancel":
|
if result == "cancel":
|
||||||
self._cancel_selection()
|
self._cancel_selection()
|
||||||
|
logger.info("Selection cancelled")
|
||||||
elif result == "confirm":
|
elif result == "confirm":
|
||||||
if p2_result:
|
if p2_result:
|
||||||
self._confirm_selection(2)
|
self._confirm_selection(2)
|
||||||
else:
|
else:
|
||||||
self._confirm_selection(1)
|
self._confirm_selection(1)
|
||||||
|
logger.info("Selection confirmed")
|
||||||
elif result == "ura_toggle":
|
elif result == "ura_toggle":
|
||||||
if p2_result:
|
if p2_result:
|
||||||
self.ura_switch_animation.start(not self.player_2.is_ura)
|
self.ura_switch_animation.start(not self.player_2.is_ura)
|
||||||
else:
|
else:
|
||||||
self.ura_switch_animation.start(not self.player_1.is_ura)
|
self.ura_switch_animation.start(not self.player_1.is_ura)
|
||||||
|
logger.info("Ura toggled")
|
||||||
|
|
||||||
def handle_input_diff_sort(self):
|
def handle_input_diff_sort(self):
|
||||||
"""
|
"""Handle input for sorting difficulty."""
|
||||||
Handle input for sorting difficulty.
|
|
||||||
"""
|
|
||||||
if self.diff_sort_selector is None:
|
if self.diff_sort_selector is None:
|
||||||
raise Exception("Diff sort selector was not able to be created")
|
raise Exception("Diff sort selector was not able to be created")
|
||||||
|
|
||||||
@@ -108,6 +112,7 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
|
|||||||
self.state = State.BROWSING
|
self.state = State.BROWSING
|
||||||
self.text_fade_out.reset()
|
self.text_fade_out.reset()
|
||||||
self.text_fade_in.reset()
|
self.text_fade_in.reset()
|
||||||
|
logger.info(f"Diff sort selected: diff={diff}, level={level}")
|
||||||
if diff != -1:
|
if diff != -1:
|
||||||
if level != -1:
|
if level != -1:
|
||||||
self.navigator.diff_sort_diff = diff
|
self.navigator.diff_sort_diff = diff
|
||||||
@@ -117,7 +122,7 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
|
|||||||
def _cancel_selection(self):
|
def _cancel_selection(self):
|
||||||
"""Reset to browsing state"""
|
"""Reset to browsing state"""
|
||||||
super()._cancel_selection()
|
super()._cancel_selection()
|
||||||
self.player_2.selected_song = None
|
self.player_2.selected_song = False
|
||||||
|
|
||||||
def _confirm_selection(self, player_selected: int):
|
def _confirm_selection(self, player_selected: int):
|
||||||
"""Confirm song selection and create game transition"""
|
"""Confirm song selection and create game transition"""
|
||||||
@@ -133,6 +138,7 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
|
|||||||
self.player_2.selected_diff_highlight_fade.start()
|
self.player_2.selected_diff_highlight_fade.start()
|
||||||
self.player_2.selected_diff_text_resize.start()
|
self.player_2.selected_diff_text_resize.start()
|
||||||
self.player_2.selected_diff_text_fadein.start()
|
self.player_2.selected_diff_text_fadein.start()
|
||||||
|
logger.info(f"Confirmed selection for player {player_selected}")
|
||||||
|
|
||||||
def check_for_selection(self):
|
def check_for_selection(self):
|
||||||
if (self.player_1.selected_diff_highlight_fade.is_finished and
|
if (self.player_1.selected_diff_highlight_fade.is_finished and
|
||||||
@@ -148,6 +154,7 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
|
|||||||
global_data.config['general']['language'], '')
|
global_data.config['general']['language'], '')
|
||||||
self.game_transition = Transition(title, subtitle)
|
self.game_transition = Transition(title, subtitle)
|
||||||
self.game_transition.start()
|
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):
|
||||||
self.player_1.update(current_time)
|
self.player_1.update(current_time)
|
||||||
@@ -155,7 +162,8 @@ class TwoPlayerSongSelectScreen(SongSelectScreen):
|
|||||||
if self.text_fade_out.is_finished:
|
if self.text_fade_out.is_finished:
|
||||||
self.player_1.selected_song = True
|
self.player_1.selected_song = True
|
||||||
self.player_2.selected_song = True
|
self.player_2.selected_song = True
|
||||||
return "GAME_2P"
|
next_screen = "GAME_2P"
|
||||||
|
return next_screen
|
||||||
|
|
||||||
def draw_background_diffs(self):
|
def draw_background_diffs(self):
|
||||||
self.player_1.draw_background_diffs(self.state)
|
self.player_1.draw_background_diffs(self.state)
|
||||||
|
|||||||
317
uv.lock
generated
317
uv.lock
generated
@@ -1,54 +1,38 @@
|
|||||||
version = 1
|
version = 1
|
||||||
revision = 3
|
revision = 3
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.14"
|
||||||
resolution-markers = [
|
|
||||||
"python_full_version >= '3.13'",
|
|
||||||
"python_full_version < '3.13'",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cffi"
|
name = "cffi"
|
||||||
version = "1.17.1"
|
version = "2.0.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "pycparser" },
|
{ name = "pycparser", marker = "implementation_name != 'PyPy'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" },
|
{ url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" },
|
{ url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" },
|
{ url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" },
|
{ url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" },
|
{ url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" },
|
{ url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" },
|
{ url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" },
|
{ url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" },
|
{ url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" },
|
{ url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" },
|
{ url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" },
|
{ url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" },
|
{ url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" },
|
{ url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" },
|
{ url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" },
|
{ url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" },
|
{ url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" },
|
{ url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" },
|
{ url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" },
|
{ url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" },
|
{ url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" },
|
{ url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -114,62 +98,29 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/9a/73/7d3b2010baa0b5eb1e4dfa9e4385e89b6716be76f2fa21a6c0fe34b68e5a/moviepy-2.2.1-py3-none-any.whl", hash = "sha256:6b56803fec2ac54b557404126ac1160e65448e03798fa282bd23e8fab3795060", size = 129871, upload-time = "2025-05-21T19:31:50.11Z" },
|
{ url = "https://files.pythonhosted.org/packages/9a/73/7d3b2010baa0b5eb1e4dfa9e4385e89b6716be76f2fa21a6c0fe34b68e5a/moviepy-2.2.1-py3-none-any.whl", hash = "sha256:6b56803fec2ac54b557404126ac1160e65448e03798fa282bd23e8fab3795060", size = 129871, upload-time = "2025-05-21T19:31:50.11Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nuitka"
|
||||||
|
version = "2.8.4"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "ordered-set" },
|
||||||
|
{ name = "zstandard" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/6f/87/f20ffda1b6dc04361fa95390f4d47d974ee194e6e1e7688f13d324f3d89b/Nuitka-2.8.4.tar.gz", hash = "sha256:06b020ef33be97194f888dcfcd4c69c8452ceb61b31c7622e610d5156eb7923d", size = 3885111, upload-time = "2025-10-21T10:28:45.499Z" }
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/db/8e12381333aea300890829a0a36bfa738cac95475d88982d538725143fd9/numpy-2.3.0.tar.gz", hash = "sha256:581f87f9e9e9db2cba2141400e160e9dd644ee248788d6f90636eeb8fd9260a6", size = 20382813, upload-time = "2025-06-07T14:54:32.608Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/db/8e12381333aea300890829a0a36bfa738cac95475d88982d538725143fd9/numpy-2.3.0.tar.gz", hash = "sha256:581f87f9e9e9db2cba2141400e160e9dd644ee248788d6f90636eeb8fd9260a6", size = 20382813, upload-time = "2025-06-07T14:54:32.608Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-set"
|
||||||
|
version = "4.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/4c/ca/bfac8bc689799bcca4157e0e0ced07e70ce125193fc2e166d2e685b7e2fe/ordered-set-4.1.0.tar.gz", hash = "sha256:694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8", size = 12826, upload-time = "2022-01-26T14:38:56.6Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/fd/5f/df67435257d827eb3b8af66f585223dc2c3f2eb7ad0b50cb1dae2f35f494/numpy-2.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c3c9fdde0fa18afa1099d6257eb82890ea4f3102847e692193b54e00312a9ae9", size = 21199688, upload-time = "2025-06-07T14:36:52.067Z" },
|
{ url = "https://files.pythonhosted.org/packages/33/55/af02708f230eb77084a299d7b08175cff006dea4f2721074b92cdb0296c0/ordered_set-4.1.0-py3-none-any.whl", hash = "sha256:046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562", size = 7634, upload-time = "2022-01-26T14:38:48.677Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/ce/aad219575055d6c9ef29c8c540c81e1c38815d3be1fe09cdbe53d48ee838/numpy-2.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46d16f72c2192da7b83984aa5455baee640e33a9f1e61e656f29adf55e406c2b", size = 14359277, upload-time = "2025-06-07T14:37:15.325Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/29/6b/2d31da8e6d2ec99bed54c185337a87f8fbeccc1cd9804e38217e92f3f5e2/numpy-2.3.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a0be278be9307c4ab06b788f2a077f05e180aea817b3e41cebbd5aaf7bd85ed3", size = 5376069, upload-time = "2025-06-07T14:37:25.636Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7d/2a/6c59a062397553ec7045c53d5fcdad44e4536e54972faa2ba44153bca984/numpy-2.3.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:99224862d1412d2562248d4710126355d3a8db7672170a39d6909ac47687a8a4", size = 6913057, upload-time = "2025-06-07T14:37:37.215Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d5/5a/8df16f258d28d033e4f359e29d3aeb54663243ac7b71504e89deeb813202/numpy-2.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2393a914db64b0ead0ab80c962e42d09d5f385802006a6c87835acb1f58adb96", size = 14568083, upload-time = "2025-06-07T14:37:59.337Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0a/92/0528a563dfc2cdccdcb208c0e241a4bb500d7cde218651ffb834e8febc50/numpy-2.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:7729c8008d55e80784bd113787ce876ca117185c579c0d626f59b87d433ea779", size = 16929402, upload-time = "2025-06-07T14:38:24.343Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e4/2f/e7a8c8d4a2212c527568d84f31587012cf5497a7271ea1f23332142f634e/numpy-2.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:06d4fb37a8d383b769281714897420c5cc3545c79dc427df57fc9b852ee0bf58", size = 15879193, upload-time = "2025-06-07T14:38:48.007Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e2/c3/dada3f005953847fe35f42ac0fe746f6e1ea90b4c6775e4be605dcd7b578/numpy-2.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c39ec392b5db5088259c68250e342612db82dc80ce044cf16496cf14cf6bc6f8", size = 18665318, upload-time = "2025-06-07T14:39:15.794Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3b/ae/3f448517dedefc8dd64d803f9d51a8904a48df730e00a3c5fb1e75a60620/numpy-2.3.0-cp311-cp311-win32.whl", hash = "sha256:ee9d3ee70d62827bc91f3ea5eee33153212c41f639918550ac0475e3588da59f", size = 6601108, upload-time = "2025-06-07T14:39:27.176Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8c/4a/556406d2bb2b9874c8cbc840c962683ac28f21efbc9b01177d78f0199ca1/numpy-2.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:43c55b6a860b0eb44d42341438b03513cf3879cb3617afb749ad49307e164edd", size = 13021525, upload-time = "2025-06-07T14:39:46.637Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ed/ee/bf54278aef30335ffa9a189f869ea09e1a195b3f4b93062164a3b02678a7/numpy-2.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:2e6a1409eee0cb0316cb64640a49a49ca44deb1a537e6b1121dc7c458a1299a8", size = 10170327, upload-time = "2025-06-07T14:40:02.703Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/89/59/9df493df81ac6f76e9f05cdbe013cdb0c9a37b434f6e594f5bd25e278908/numpy-2.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:389b85335838155a9076e9ad7f8fdba0827496ec2d2dc32ce69ce7898bde03ba", size = 20897025, upload-time = "2025-06-07T14:40:33.558Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2f/86/4ff04335901d6cf3a6bb9c748b0097546ae5af35e455ae9b962ebff4ecd7/numpy-2.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9498f60cd6bb8238d8eaf468a3d5bb031d34cd12556af53510f05fcf581c1b7e", size = 14129882, upload-time = "2025-06-07T14:40:55.034Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/8d/a942cd4f959de7f08a79ab0c7e6cecb7431d5403dce78959a726f0f57aa1/numpy-2.3.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:622a65d40d8eb427d8e722fd410ac3ad4958002f109230bc714fa551044ebae2", size = 5110181, upload-time = "2025-06-07T14:41:04.4Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/5d/45850982efc7b2c839c5626fb67fbbc520d5b0d7c1ba1ae3651f2f74c296/numpy-2.3.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:b9446d9d8505aadadb686d51d838f2b6688c9e85636a0c3abaeb55ed54756459", size = 6647581, upload-time = "2025-06-07T14:41:14.695Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1a/c0/c871d4a83f93b00373d3eebe4b01525eee8ef10b623a335ec262b58f4dc1/numpy-2.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:50080245365d75137a2bf46151e975de63146ae6d79f7e6bd5c0e85c9931d06a", size = 14262317, upload-time = "2025-06-07T14:41:35.862Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b7/f6/bc47f5fa666d5ff4145254f9e618d56e6a4ef9b874654ca74c19113bb538/numpy-2.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c24bb4113c66936eeaa0dc1e47c74770453d34f46ee07ae4efd853a2ed1ad10a", size = 16633919, upload-time = "2025-06-07T14:42:00.622Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f5/b4/65f48009ca0c9b76df5f404fccdea5a985a1bb2e34e97f21a17d9ad1a4ba/numpy-2.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4d8d294287fdf685281e671886c6dcdf0291a7c19db3e5cb4178d07ccf6ecc67", size = 15567651, upload-time = "2025-06-07T14:42:24.429Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f1/62/5367855a2018578e9334ed08252ef67cc302e53edc869666f71641cad40b/numpy-2.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6295f81f093b7f5769d1728a6bd8bf7466de2adfa771ede944ce6711382b89dc", size = 18361723, upload-time = "2025-06-07T14:42:51.167Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/d4/75/5baed8cd867eabee8aad1e74d7197d73971d6a3d40c821f1848b8fab8b84/numpy-2.3.0-cp312-cp312-win32.whl", hash = "sha256:e6648078bdd974ef5d15cecc31b0c410e2e24178a6e10bf511e0557eed0f2570", size = 6318285, upload-time = "2025-06-07T14:43:02.052Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/49/d5781eaa1a15acb3b3a3f49dc9e2ff18d92d0ce5c2976f4ab5c0a7360250/numpy-2.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:0898c67a58cdaaf29994bc0e2c65230fd4de0ac40afaf1584ed0b02cd74c6fdd", size = 12732594, upload-time = "2025-06-07T14:43:21.071Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c2/1c/6d343e030815c7c97a1f9fbad00211b47717c7fe446834c224bd5311e6f1/numpy-2.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:bd8df082b6c4695753ad6193018c05aac465d634834dca47a3ae06d4bb22d9ea", size = 9891498, upload-time = "2025-06-07T14:43:36.332Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/73/fc/1d67f751fd4dbafc5780244fe699bc4084268bad44b7c5deb0492473127b/numpy-2.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5754ab5595bfa2c2387d241296e0381c21f44a4b90a776c3c1d39eede13a746a", size = 20889633, upload-time = "2025-06-07T14:44:06.839Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/95/73ffdb69e5c3f19ec4530f8924c4386e7ba097efc94b9c0aff607178ad94/numpy-2.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d11fa02f77752d8099573d64e5fe33de3229b6632036ec08f7080f46b6649959", size = 14151683, upload-time = "2025-06-07T14:44:28.847Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/64/d5/06d4bb31bb65a1d9c419eb5676173a2f90fd8da3c59f816cc54c640ce265/numpy-2.3.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:aba48d17e87688a765ab1cd557882052f238e2f36545dfa8e29e6a91aef77afe", size = 5102683, upload-time = "2025-06-07T14:44:38.417Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/12/8b/6c2cef44f8ccdc231f6b56013dff1d71138c48124334aded36b1a1b30c5a/numpy-2.3.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4dc58865623023b63b10d52f18abaac3729346a7a46a778381e0e3af4b7f3beb", size = 6640253, upload-time = "2025-06-07T14:44:49.359Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/aa/fca4bf8de3396ddb59544df9b75ffe5b73096174de97a9492d426f5cd4aa/numpy-2.3.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:df470d376f54e052c76517393fa443758fefcdd634645bc9c1f84eafc67087f0", size = 14258658, upload-time = "2025-06-07T14:45:10.156Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1c/12/734dce1087eed1875f2297f687e671cfe53a091b6f2f55f0c7241aad041b/numpy-2.3.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:87717eb24d4a8a64683b7a4e91ace04e2f5c7c77872f823f02a94feee186168f", size = 16628765, upload-time = "2025-06-07T14:45:35.076Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/48/03/ffa41ade0e825cbcd5606a5669962419528212a16082763fc051a7247d76/numpy-2.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fa264d56882b59dcb5ea4d6ab6f31d0c58a57b41aec605848b6eb2ef4a43e8", size = 15564335, upload-time = "2025-06-07T14:45:58.797Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/07/58/869398a11863310aee0ff85a3e13b4c12f20d032b90c4b3ee93c3b728393/numpy-2.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e651756066a0eaf900916497e20e02fe1ae544187cb0fe88de981671ee7f6270", size = 18360608, upload-time = "2025-06-07T14:46:25.687Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2f/8a/5756935752ad278c17e8a061eb2127c9a3edf4ba2c31779548b336f23c8d/numpy-2.3.0-cp313-cp313-win32.whl", hash = "sha256:e43c3cce3b6ae5f94696669ff2a6eafd9a6b9332008bafa4117af70f4b88be6f", size = 6310005, upload-time = "2025-06-07T14:50:13.138Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/08/60/61d60cf0dfc0bf15381eaef46366ebc0c1a787856d1db0c80b006092af84/numpy-2.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:81ae0bf2564cf475f94be4a27ef7bcf8af0c3e28da46770fc904da9abd5279b5", size = 12729093, upload-time = "2025-06-07T14:50:31.82Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/31/2f2f2d2b3e3c32d5753d01437240feaa32220b73258c9eef2e42a0832866/numpy-2.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:c8738baa52505fa6e82778580b23f945e3578412554d937093eac9205e845e6e", size = 9885689, upload-time = "2025-06-07T14:50:47.888Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f1/89/c7828f23cc50f607ceb912774bb4cff225ccae7131c431398ad8400e2c98/numpy-2.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:39b27d8b38942a647f048b675f134dd5a567f95bfff481f9109ec308515c51d8", size = 20986612, upload-time = "2025-06-07T14:46:56.077Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/dd/46/79ecf47da34c4c50eedec7511e53d57ffdfd31c742c00be7dc1d5ffdb917/numpy-2.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0eba4a1ea88f9a6f30f56fdafdeb8da3774349eacddab9581a21234b8535d3d3", size = 14298953, upload-time = "2025-06-07T14:47:18.053Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/59/44/f6caf50713d6ff4480640bccb2a534ce1d8e6e0960c8f864947439f0ee95/numpy-2.3.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:b0f1f11d0a1da54927436505a5a7670b154eac27f5672afc389661013dfe3d4f", size = 5225806, upload-time = "2025-06-07T14:47:27.524Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/43/e1fd1aca7c97e234dd05e66de4ab7a5be54548257efcdd1bc33637e72102/numpy-2.3.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:690d0a5b60a47e1f9dcec7b77750a4854c0d690e9058b7bef3106e3ae9117808", size = 6735169, upload-time = "2025-06-07T14:47:38.057Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/84/89/f76f93b06a03177c0faa7ca94d0856c4e5c4bcaf3c5f77640c9ed0303e1c/numpy-2.3.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:8b51ead2b258284458e570942137155978583e407babc22e3d0ed7af33ce06f8", size = 14330701, upload-time = "2025-06-07T14:47:59.113Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/f5/4858c3e9ff7a7d64561b20580cf7cc5d085794bd465a19604945d6501f6c/numpy-2.3.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:aaf81c7b82c73bd9b45e79cfb9476cb9c29e937494bfe9092c26aece812818ad", size = 16692983, upload-time = "2025-06-07T14:48:24.196Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/08/17/0e3b4182e691a10e9483bcc62b4bb8693dbf9ea5dc9ba0b77a60435074bb/numpy-2.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f420033a20b4f6a2a11f585f93c843ac40686a7c3fa514060a97d9de93e5e72b", size = 15641435, upload-time = "2025-06-07T14:48:47.712Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/4e/d5/463279fda028d3c1efa74e7e8d507605ae87f33dbd0543cf4c4527c8b882/numpy-2.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d344ca32ab482bcf8735d8f95091ad081f97120546f3d250240868430ce52555", size = 18433798, upload-time = "2025-06-07T14:49:14.866Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0e/1e/7a9d98c886d4c39a2b4d3a7c026bffcf8fbcaf518782132d12a301cfc47a/numpy-2.3.0-cp313-cp313t-win32.whl", hash = "sha256:48a2e8eaf76364c32a1feaa60d6925eaf32ed7a040183b807e02674305beef61", size = 6438632, upload-time = "2025-06-07T14:49:25.67Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/ab/66fc909931d5eb230107d016861824f335ae2c0533f422e654e5ff556784/numpy-2.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ba17f93a94e503551f154de210e4d50c5e3ee20f7e7a1b5f6ce3f22d419b93bb", size = 12868491, upload-time = "2025-06-07T14:49:44.898Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ee/e8/2c8a1c9e34d6f6d600c83d5ce5b71646c32a13f34ca5c518cc060639841c/numpy-2.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:f14e016d9409680959691c109be98c436c6249eaf7f118b424679793607b5944", size = 9935345, upload-time = "2025-06-07T14:50:02.311Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/a2/f8c1133f90eaa1c11bbbec1dc28a42054d0ce74bc2c9838c5437ba5d4980/numpy-2.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80b46117c7359de8167cc00a2c7d823bdd505e8c7727ae0871025a86d668283b", size = 21070759, upload-time = "2025-06-07T14:51:18.241Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/e0/4c05fc44ba28463096eee5ae2a12832c8d2759cc5bcec34ae33386d3ff83/numpy-2.3.0-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:5814a0f43e70c061f47abd5857d120179609ddc32a613138cbb6c4e9e2dbdda5", size = 5301054, upload-time = "2025-06-07T14:51:27.413Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8a/3b/6c06cdebe922bbc2a466fe2105f50f661238ea223972a69c7deb823821e7/numpy-2.3.0-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:ef6c1e88fd6b81ac6d215ed71dc8cd027e54d4bf1d2682d362449097156267a2", size = 6817520, upload-time = "2025-06-07T14:51:38.015Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9d/a3/1e536797fd10eb3c5dbd2e376671667c9af19e241843548575267242ea02/numpy-2.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33a5a12a45bb82d9997e2c0b12adae97507ad7c347546190a18ff14c28bbca12", size = 14398078, upload-time = "2025-06-07T14:52:00.122Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7c/61/9d574b10d9368ecb1a0c923952aa593510a20df4940aa615b3a71337c8db/numpy-2.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:54dfc8681c1906d239e95ab1508d0a533c4a9505e52ee2d71a5472b04437ef97", size = 16751324, upload-time = "2025-06-07T14:52:25.077Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/39/de/bcad52ce972dc26232629ca3a99721fd4b22c1d2bda84d5db6541913ef9c/numpy-2.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e017a8a251ff4d18d71f139e28bdc7c31edba7a507f72b1414ed902cbe48c74d", size = 12924237, upload-time = "2025-06-07T14:52:44.713Z" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -177,59 +128,6 @@ name = "pillow"
|
|||||||
version = "11.2.1"
|
version = "11.2.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707, upload-time = "2025-04-12T17:50:03.289Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707, upload-time = "2025-04-12T17:50:03.289Z" }
|
||||||
wheels = [
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/68/08/3fbf4b98924c73037a8e8b4c2c774784805e0fb4ebca6c5bb60795c40125/pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70", size = 3198450, upload-time = "2025-04-12T17:47:37.135Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/84/92/6505b1af3d2849d5e714fc75ba9e69b7255c05ee42383a35a4d58f576b16/pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf", size = 3030550, upload-time = "2025-04-12T17:47:39.345Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3c/8c/ac2f99d2a70ff966bc7eb13dacacfaab57c0549b2ffb351b6537c7840b12/pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7", size = 4415018, upload-time = "2025-04-12T17:47:41.128Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/e3/0a58b5d838687f40891fff9cbaf8669f90c96b64dc8f91f87894413856c6/pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8", size = 4498006, upload-time = "2025-04-12T17:47:42.912Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/21/f5/6ba14718135f08fbfa33308efe027dd02b781d3f1d5c471444a395933aac/pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600", size = 4517773, upload-time = "2025-04-12T17:47:44.611Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/20/f2/805ad600fc59ebe4f1ba6129cd3a75fb0da126975c8579b8f57abeb61e80/pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788", size = 4607069, upload-time = "2025-04-12T17:47:46.46Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/6b/4ef8a288b4bb2e0180cba13ca0a519fa27aa982875882392b65131401099/pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e", size = 4583460, upload-time = "2025-04-12T17:47:49.255Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/ae/f29c705a09cbc9e2a456590816e5c234382ae5d32584f451c3eb41a62062/pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e", size = 4661304, upload-time = "2025-04-12T17:47:51.067Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6e/1a/c8217b6f2f73794a5e219fbad087701f412337ae6dbb956db37d69a9bc43/pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6", size = 2331809, upload-time = "2025-04-12T17:47:54.425Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e2/72/25a8f40170dc262e86e90f37cb72cb3de5e307f75bf4b02535a61afcd519/pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193", size = 2676338, upload-time = "2025-04-12T17:47:56.535Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/06/9e/76825e39efee61efea258b479391ca77d64dbd9e5804e4ad0fa453b4ba55/pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7", size = 2414918, upload-time = "2025-04-12T17:47:58.217Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/40/052610b15a1b8961f52537cc8326ca6a881408bc2bdad0d852edeb6ed33b/pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f", size = 3190185, upload-time = "2025-04-12T17:48:00.417Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/7e/b86dbd35a5f938632093dc40d1682874c33dcfe832558fc80ca56bfcb774/pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b", size = 3030306, upload-time = "2025-04-12T17:48:02.391Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/5c/467a161f9ed53e5eab51a42923c33051bf8d1a2af4626ac04f5166e58e0c/pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d", size = 4416121, upload-time = "2025-04-12T17:48:04.554Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/73/972b7742e38ae0e2ac76ab137ca6005dcf877480da0d9d61d93b613065b4/pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4", size = 4501707, upload-time = "2025-04-12T17:48:06.831Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/e4/3a/427e4cb0b9e177efbc1a84798ed20498c4f233abde003c06d2650a6d60cb/pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d", size = 4522921, upload-time = "2025-04-12T17:48:09.229Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/7c/d8b1330458e4d2f3f45d9508796d7caf0c0d3764c00c823d10f6f1a3b76d/pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4", size = 4612523, upload-time = "2025-04-12T17:48:11.631Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/2f/65738384e0b1acf451de5a573d8153fe84103772d139e1e0bdf1596be2ea/pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443", size = 4587836, upload-time = "2025-04-12T17:48:13.592Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/c5/e795c9f2ddf3debb2dedd0df889f2fe4b053308bb59a3cc02a0cd144d641/pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c", size = 4669390, upload-time = "2025-04-12T17:48:15.938Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/96/ae/ca0099a3995976a9fce2f423166f7bff9b12244afdc7520f6ed38911539a/pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3", size = 2332309, upload-time = "2025-04-12T17:48:17.885Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/7c/18/24bff2ad716257fc03da964c5e8f05d9790a779a8895d6566e493ccf0189/pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941", size = 2676768, upload-time = "2025-04-12T17:48:19.655Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/bb/e8d656c9543276517ee40184aaa39dcb41e683bca121022f9323ae11b39d/pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb", size = 2415087, upload-time = "2025-04-12T17:48:21.991Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/9c/447528ee3776e7ab8897fe33697a7ff3f0475bb490c5ac1456a03dc57956/pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28", size = 3190098, upload-time = "2025-04-12T17:48:23.915Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b5/09/29d5cd052f7566a63e5b506fac9c60526e9ecc553825551333e1e18a4858/pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830", size = 3030166, upload-time = "2025-04-12T17:48:25.738Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/5d/446ee132ad35e7600652133f9c2840b4799bbd8e4adba881284860da0a36/pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0", size = 4408674, upload-time = "2025-04-12T17:48:27.908Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/69/5f/cbe509c0ddf91cc3a03bbacf40e5c2339c4912d16458fcb797bb47bcb269/pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1", size = 4496005, upload-time = "2025-04-12T17:48:29.888Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f9/b3/dd4338d8fb8a5f312021f2977fb8198a1184893f9b00b02b75d565c33b51/pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f", size = 4518707, upload-time = "2025-04-12T17:48:31.874Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/eb/2552ecebc0b887f539111c2cd241f538b8ff5891b8903dfe672e997529be/pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155", size = 4610008, upload-time = "2025-04-12T17:48:34.422Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/d1/924ce51bea494cb6e7959522d69d7b1c7e74f6821d84c63c3dc430cbbf3b/pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14", size = 4585420, upload-time = "2025-04-12T17:48:37.641Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/43/ab/8f81312d255d713b99ca37479a4cb4b0f48195e530cdc1611990eb8fd04b/pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b", size = 4667655, upload-time = "2025-04-12T17:48:39.652Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/86/8f2e9d2dc3d308dfd137a07fe1cc478df0a23d42a6c4093b087e738e4827/pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2", size = 2332329, upload-time = "2025-04-12T17:48:41.765Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/ec/1179083b8d6067a613e4d595359b5fdea65d0a3b7ad623fee906e1b3c4d2/pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691", size = 2676388, upload-time = "2025-04-12T17:48:43.625Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/23/f1/2fc1e1e294de897df39fa8622d829b8828ddad938b0eaea256d65b84dd72/pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c", size = 2414950, upload-time = "2025-04-12T17:48:45.475Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c4/3e/c328c48b3f0ead7bab765a84b4977acb29f101d10e4ef57a5e3400447c03/pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22", size = 3192759, upload-time = "2025-04-12T17:48:47.866Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/18/0e/1c68532d833fc8b9f404d3a642991441d9058eccd5606eab31617f29b6d4/pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7", size = 3033284, upload-time = "2025-04-12T17:48:50.189Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b7/cb/6faf3fb1e7705fd2db74e070f3bf6f88693601b0ed8e81049a8266de4754/pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16", size = 4445826, upload-time = "2025-04-12T17:48:52.346Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/07/94/8be03d50b70ca47fb434a358919d6a8d6580f282bbb7af7e4aa40103461d/pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b", size = 4527329, upload-time = "2025-04-12T17:48:54.403Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/fd/a4/bfe78777076dc405e3bd2080bc32da5ab3945b5a25dc5d8acaa9de64a162/pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406", size = 4549049, upload-time = "2025-04-12T17:48:56.383Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/65/4d/eaf9068dc687c24979e977ce5677e253624bd8b616b286f543f0c1b91662/pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91", size = 4635408, upload-time = "2025-04-12T17:48:58.782Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1d/26/0fd443365d9c63bc79feb219f97d935cd4b93af28353cba78d8e77b61719/pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751", size = 4614863, upload-time = "2025-04-12T17:49:00.709Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/49/65/dca4d2506be482c2c6641cacdba5c602bc76d8ceb618fd37de855653a419/pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9", size = 4692938, upload-time = "2025-04-12T17:49:02.946Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/92/1ca0c3f09233bd7decf8f7105a1c4e3162fb9142128c74adad0fb361b7eb/pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd", size = 2335774, upload-time = "2025-04-12T17:49:04.889Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a5/ac/77525347cb43b83ae905ffe257bbe2cc6fd23acb9796639a1f56aa59d191/pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e", size = 2681895, upload-time = "2025-04-12T17:49:06.635Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/67/32/32dc030cfa91ca0fc52baebbba2e009bb001122a1daa8b6a79ad830b38d3/pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681", size = 2417234, upload-time = "2025-04-12T17:49:08.399Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/ad/2613c04633c7257d9481ab21d6b5364b59fc5d75faafd7cb8693523945a3/pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed", size = 3181734, upload-time = "2025-04-12T17:49:46.789Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/fd/dcdda4471ed667de57bb5405bb42d751e6cfdd4011a12c248b455c778e03/pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c", size = 2999841, upload-time = "2025-04-12T17:49:48.812Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ac/89/8a2536e95e77432833f0db6fd72a8d310c8e4272a04461fb833eb021bf94/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd", size = 3437470, upload-time = "2025-04-12T17:49:50.831Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/9d/8f/abd47b73c60712f88e9eda32baced7bfc3e9bd6a7619bb64b93acff28c3e/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076", size = 3460013, upload-time = "2025-04-12T17:49:53.278Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f6/20/5c0a0aa83b213b7a07ec01e71a3d6ea2cf4ad1d2c686cc0168173b6089e7/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b", size = 3527165, upload-time = "2025-04-12T17:49:55.164Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/58/0e/2abab98a72202d91146abc839e10c14f7cf36166f12838ea0c4db3ca6ecb/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f", size = 3571586, upload-time = "2025-04-12T17:49:57.171Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/21/2c/5e05f58658cf49b6667762cca03d6e7d85cededde2caf2ab37b81f80e574/pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044", size = 2674751, upload-time = "2025-04-12T17:49:59.628Z" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proglog"
|
name = "proglog"
|
||||||
@@ -258,30 +156,6 @@ version = "5.1.1"
|
|||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/80/ce/824ee634994e612156f7b84eaf50b8523c676ebfed8d8dd12939a82f4c15/pyinstrument-5.1.1.tar.gz", hash = "sha256:bc401cda990b3c1cfe8e0e0473cbd605df3c63b73478a89ac4ab108f2184baa8", size = 264730, upload-time = "2025-08-12T11:35:43.426Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/80/ce/824ee634994e612156f7b84eaf50b8523c676ebfed8d8dd12939a82f4c15/pyinstrument-5.1.1.tar.gz", hash = "sha256:bc401cda990b3c1cfe8e0e0473cbd605df3c63b73478a89ac4ab108f2184baa8", size = 264730, upload-time = "2025-08-12T11:35:43.426Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/52/65/dc0fcc6122e6f484ffa48260d1023e1fe90e53da8d69a7de656205af91ba/pyinstrument-5.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5272cff6eea21163b2105f6a80c907315e0f567720621e6d5672dc01bf71ee48", size = 130287, upload-time = "2025-08-12T11:34:32.436Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/90/96/8a6cab312342f1ad7322b459dcbdb2e041251b7bbe4c1d0dd38ccbf2ae20/pyinstrument-5.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4e7dc5a4aee37a44ff2e63db3127f2044dd95edcae240cb95915adbf223d4be", size = 122879, upload-time = "2025-08-12T11:34:33.506Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8a/89/1ad1ae703951832a34ec6b32354c6df1d0690b0333b7b8396c92afcdc23e/pyinstrument-5.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:602d55121df1d88aeb6d8ebc801597fdcb9718f78d602ae81458d65c56f25d24", size = 146412, upload-time = "2025-08-12T11:34:34.975Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a5/70/588ec07eeaa5d5d4aff2d47c8010379e9b39a7aee7e3fda625a0ce4f5838/pyinstrument-5.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:63b5a788ff955e0597bc95463e64d5fa3747017524fdc02a0f5d12d5117cf2b9", size = 144885, upload-time = "2025-08-12T11:34:36.546Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0a/8f/119ad44d454edb927434bb53d8a69904ecaa47ec56f95c688c557a9590de/pyinstrument-5.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7f66038ec55a12e5510689240cdc745f8e98c90b93363f745106976e5cfb7397", size = 145530, upload-time = "2025-08-12T11:34:37.726Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8e/31/d53b20d1967ba78574807c5940251c0f238e8e3515ee9c4f20207eb09199/pyinstrument-5.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:110a08b6e7fa9542eb37c337e79467913d364a03bc2062f85566ba96bc82f54e", size = 144708, upload-time = "2025-08-12T11:34:38.855Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/48/18/78ccb35dd265e83c0b7404a501004387b2e2390a0a44b6e4a004307931d1/pyinstrument-5.1.1-cp311-cp311-win32.whl", hash = "sha256:a223d5e9226ccede5bf2fbd4d13ce0aeb5120501b633ba85290ed94df37d3623", size = 124151, upload-time = "2025-08-12T11:34:40.392Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/43/c0/3eb94aa2c2f0b8d49e290d4df662e21e707eb4a23f3b938239634fbfdc17/pyinstrument-5.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:16ce582a7b56287d338a8b59688458341aab5c6abda970ba50b2f7b3fd69f89d", size = 124942, upload-time = "2025-08-12T11:34:41.564Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/3a/7824caf1fb419d0108f375a15b28cdd7ace8593f1ea56ef8276fddce9526/pyinstrument-5.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bcd6a03bdf180d73bc8dc7371e09dda089a48057095584e5f2818df1c820525b", size = 130306, upload-time = "2025-08-12T11:34:42.624Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3a/54/60ddd5eae617e29b58de774d178f4e4f7cdffd07ed1de36f976927ce69d3/pyinstrument-5.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ffa0948c1e268356dcf930c128624f34037ce92ee865fa4c056dee067aee4c5", size = 122817, upload-time = "2025-08-12T11:34:44.182Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/35/12/35b694bfa58050607eedc80a68f64e6195c738249101a0dcbed0657147e7/pyinstrument-5.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c95adf98a920f2039eb0065966f980452a7af794bab387e9bfe8af3c681affa0", size = 148053, upload-time = "2025-08-12T11:34:45.589Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5d/4a/338b891f9119cf747153301d5d095942f378032309cd385e53857d03c2d2/pyinstrument-5.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bcb46ca8596b375c27850d4d06a1ce94ed78074774d35cbed3ccd28b663c5ba6", size = 146817, upload-time = "2025-08-12T11:34:46.668Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3b/cc/186cdb048fee445bbf9bd18819287a61b57b66ec68cfc47bc3c1e38b1ae6/pyinstrument-5.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3fc16597d26b24a46bf3455686300c0b8a3eb565ebc82396f402c031dccc0145", size = 146914, upload-time = "2025-08-12T11:34:47.878Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/d1/533309830dd356d43e54d7feebaffab357f08568972285c609e98f7e6119/pyinstrument-5.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5aa135b4bd9667ddcb25fa582f4db77c5117ef207cb10ae901a8e4c5d5cde0e0", size = 146533, upload-time = "2025-08-12T11:34:49.015Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/df/2a656d6b1bd68ecfbb73c557906274a40ec7219dd92980fc1324997cf93e/pyinstrument-5.1.1-cp312-cp312-win32.whl", hash = "sha256:d15e37f8074b3043fca7aa985cb2079d2c221ccb0d27f059451ede800c801645", size = 124286, upload-time = "2025-08-12T11:34:50.285Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/51/af/144d331cc9734e9141ac1a75f3ce904074ebc93dfe43cab44049ba8c8c28/pyinstrument-5.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:5c27d5cef0e809f213e5a94143c397d948650f5142c91dcce3611f584779183e", size = 125032, upload-time = "2025-08-12T11:34:51.369Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/d4/b94f47aa7d301f6cdf5924bb75caacd0d0a1852bd4e876e3a64fc5798dad/pyinstrument-5.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:45af421c60c943a7f1619afabeba4951d4cc16b4206490d7d5b7ef5a4e2dfd42", size = 130315, upload-time = "2025-08-12T11:34:52.91Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1e/42/1bc2f28e139f69a0918d5d5dc1d59e65c640d4da9dd153fa48c2a8a87dd9/pyinstrument-5.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2603db3d745a65de66c96929ab9b0fcce050511eb24e32856ea2458785b8917f", size = 122805, upload-time = "2025-08-12T11:34:54.201Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/a8/85/2f0c9115cd8a01e0a18d0650d9f3f20ff71e8ca17bd4af60dd3a0cb76f8a/pyinstrument-5.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2fe32492100efaa1b0a488c237fe420fdaf141646733a31a97f96c4e1fa6bbf8", size = 148210, upload-time = "2025-08-12T11:34:55.662Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/62/3c73a63e6913378cc7e9ffb5af1e50836511eee83b7c7bf252fad7ec24e4/pyinstrument-5.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:999b5373f8b1e846357923063ae5c9275ad8a85ed4e0a42960a349288d1f5007", size = 146995, upload-time = "2025-08-12T11:34:57.133Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ab/8b/d21f4b6d8849881e9572967818e3e6d2dcb212e7dfa89e4e356d359db32b/pyinstrument-5.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:58a2f69052178ec624e4df0cf546eda48b3a381572ac1cb3272b4c163888af9d", size = 147029, upload-time = "2025-08-12T11:34:58.255Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/8a/4d/1e43cecf2bcf4a3dd1100f4fc7a3da6438a65d0b95ca7b8ab5d094ea7c0b/pyinstrument-5.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4d9bbc00d2e258edbefeb39b61ad4636099b08acd1effdd40d76883a13e7bf5a", size = 146668, upload-time = "2025-08-12T11:34:59.401Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/34/48/00322b48e7adb665d04303b487454eb0c13a76ec0af8da20f452098fcc12/pyinstrument-5.1.1-cp313-cp313-win32.whl", hash = "sha256:cf2d8933e2aeaa02d4cb6279d83ef11ee882fb243fff96e3378153a730aadd6e", size = 124288, upload-time = "2025-08-12T11:35:00.514Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f5/14/d56515a110f74799aefc7489c1578ce4d99a4d731309559a427f954e7abc/pyinstrument-5.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:2402683a92617066b13a6d48f904396dcd15938016875b392534df027660eed4", size = 125041, upload-time = "2025-08-12T11:35:01.913Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/18/2b/e4bdcabb5ae67de2ec3fa1f6e4eb4ae707b0bf460f895d4594792cdc919b/pyinstrument-5.1.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:688acba1c00cad73e43254e610f8e384a53ced3b0dbb5268fb44636e2b99663e", size = 130358, upload-time = "2025-08-12T11:35:03.569Z" },
|
{ url = "https://files.pythonhosted.org/packages/18/2b/e4bdcabb5ae67de2ec3fa1f6e4eb4ae707b0bf460f895d4594792cdc919b/pyinstrument-5.1.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:688acba1c00cad73e43254e610f8e384a53ced3b0dbb5268fb44636e2b99663e", size = 130358, upload-time = "2025-08-12T11:35:03.569Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/20/36/616f8db63997c096d3fb65e657cdf5bd2a63b53ed24a14750770dc500979/pyinstrument-5.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:116f5ad8cec4d6f5626305d7c1a104f5845a084bfb4b192d231eb8c41ea81f9a", size = 122827, upload-time = "2025-08-12T11:35:04.661Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/36/616f8db63997c096d3fb65e657cdf5bd2a63b53ed24a14750770dc500979/pyinstrument-5.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:116f5ad8cec4d6f5626305d7c1a104f5845a084bfb4b192d231eb8c41ea81f9a", size = 122827, upload-time = "2025-08-12T11:35:04.661Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/af/7a/4f5d2bbc7c2466d46eb5ff47c6e667464eead47140e01a64be45215a59d4/pyinstrument-5.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d139d12a637001d3884344330054ce8335b2c8165dc3dd239726e1b358576bd", size = 147947, upload-time = "2025-08-12T11:35:05.786Z" },
|
{ url = "https://files.pythonhosted.org/packages/af/7a/4f5d2bbc7c2466d46eb5ff47c6e667464eead47140e01a64be45215a59d4/pyinstrument-5.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d139d12a637001d3884344330054ce8335b2c8165dc3dd239726e1b358576bd", size = 147947, upload-time = "2025-08-12T11:35:05.786Z" },
|
||||||
@@ -302,23 +176,37 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytaiko"
|
name = "pytaiko"
|
||||||
version = "0.1.0"
|
version = "0.9.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "moviepy" },
|
{ name = "moviepy" },
|
||||||
{ name = "pyinstrument" },
|
|
||||||
{ name = "raylib-sdl" },
|
{ name = "raylib-sdl" },
|
||||||
{ name = "tomlkit" },
|
{ name = "tomlkit" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[package.dev-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "nuitka" },
|
||||||
|
{ name = "pyinstrument" },
|
||||||
|
{ name = "ruff" },
|
||||||
|
{ name = "vulture" },
|
||||||
|
]
|
||||||
|
|
||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "moviepy", specifier = ">=2.1.2" },
|
{ name = "moviepy", specifier = ">=2.1.2" },
|
||||||
{ name = "pyinstrument", specifier = ">=5.1.1" },
|
{ name = "raylib-sdl", path = "raylib_sdl-5.5.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" },
|
||||||
{ name = "raylib-sdl", specifier = ">=5.5.0.2" },
|
|
||||||
{ name = "tomlkit", specifier = ">=0.13.3" },
|
{ name = "tomlkit", specifier = ">=0.13.3" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [
|
||||||
|
{ name = "nuitka", specifier = ">=2.8.4" },
|
||||||
|
{ name = "pyinstrument", specifier = ">=5.1.1" },
|
||||||
|
{ name = "ruff", specifier = ">=0.14.2" },
|
||||||
|
{ name = "vulture", specifier = ">=2.14" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -330,29 +218,42 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raylib-sdl"
|
name = "raylib-sdl"
|
||||||
version = "5.5.0.2"
|
version = "5.5.0.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { path = "raylib_sdl-5.5.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cffi" },
|
{ name = "cffi" },
|
||||||
]
|
]
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/32/b6/24c241f86ed6101f277d600c8f69cd12368848f1e94ed82d21b4d9dfba11/raylib_sdl-5.5.0.2-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:265a312ea73d8987a4c58075db7f27e356e217d52b22383ccfacf07f6eeb3556", size = 2287593, upload-time = "2024-11-26T11:11:13.524Z" },
|
{ filename = "raylib_sdl-5.5.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fdd57c75ca760ceceea12f25ae6e22df1b3f11b322257a9272bbf25dea0bac93" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/db/22/cada7093a7fc22ba8a68c032850175e7480b0e4149e782ee6093dca04006/raylib_sdl-5.5.0.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:8e86aa9ee0190cf02ae44bace9dc87379d171141a62daddd963dea40d40dbca7", size = 1745212, upload-time = "2025-01-04T20:21:04.281Z" },
|
]
|
||||||
{ url = "https://files.pythonhosted.org/packages/22/a2/387b20de1be19ece354a6c2cda30dc369948438dd824095b7da36ed974e7/raylib_sdl-5.5.0.2-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:3e2a91fef2525cc9a5a13fb3dbbd77e6c614b4d33f446c6047720516628b80d4", size = 2827982, upload-time = "2024-11-26T11:11:15.736Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/1c/b4/f96cfb79981ac8e692975ae06ca224043d92b386b7f8a80cb515a85775c3/raylib_sdl-5.5.0.2-cp311-cp311-manylinux2014_x86_64.whl", hash = "sha256:5263010953358beffabca8f7f1dfedcccc0f931afb91cfb242fd7783c875d12c", size = 2967405, upload-time = "2024-11-26T11:11:18.039Z" },
|
[package.metadata]
|
||||||
{ url = "https://files.pythonhosted.org/packages/5b/6c/c26425f317392a98c414c1f14974f511b1abf7f36d54069c80026ce505a3/raylib_sdl-5.5.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:4dcb099fa0bfa3048585d76445fe15cae3b2418c919f5777c54f429e1d3eb888", size = 1617306, upload-time = "2024-11-26T11:11:20.774Z" },
|
requires-dist = [{ name = "cffi", specifier = ">=2.0.0" }]
|
||||||
{ url = "https://files.pythonhosted.org/packages/f9/9d/8cd7466084f93b125c052f1825bc505d2822c19539dc5b3a2ac6a588fcaa/raylib_sdl-5.5.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:48e374f5c20e618f4c7c5664ac9e4f39f53245ffb9b62d6d133b8676716363b0", size = 2290643, upload-time = "2024-11-26T11:11:23.67Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/cf/b0/1891f9712bed1083f1360d7f57f042a48bed110b5d5224256a33eeb9f302/raylib_sdl-5.5.0.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:6cd980a3fabdbe88a6449acf7ab24686854dce258dea9ff5b0eb46b7eae981c0", size = 1746303, upload-time = "2024-11-26T11:11:26.032Z" },
|
[[package]]
|
||||||
{ url = "https://files.pythonhosted.org/packages/24/de/6848b61e1df0eda838a61cb9e7060bd10d4af9616974c4360257c65ff8ff/raylib_sdl-5.5.0.2-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:a8e0fd9399188943c81dadf60d3d13198da1f9e0d84cc2aefa9e0c0d5c6266d6", size = 2840025, upload-time = "2024-11-26T11:11:29.705Z" },
|
name = "ruff"
|
||||||
{ url = "https://files.pythonhosted.org/packages/5e/b8/d41eacab8666fb955877cb5e3d4afea7ba4d01f668d9e91aa1716c1230cb/raylib_sdl-5.5.0.2-cp312-cp312-manylinux2014_x86_64.whl", hash = "sha256:92407aad5382958ec684c35d3a28c8fc091faca3b58fc5dd8b3495a1065520ff", size = 2985567, upload-time = "2024-11-26T11:11:32.887Z" },
|
version = "0.14.2"
|
||||||
{ url = "https://files.pythonhosted.org/packages/00/07/d9f26daeda03ccd2d5b637fc3da25d039b39c27f1c2dde0ae9eeb2c40861/raylib_sdl-5.5.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:ab31941d2247a043beb545f34ebef1844f1d9c5fac749032e991ee8c18439c5a", size = 1619555, upload-time = "2024-11-26T11:11:35.387Z" },
|
source = { registry = "https://pypi.org/simple" }
|
||||||
{ url = "https://files.pythonhosted.org/packages/06/9c/e3d596db50bf4fb35f39478f1f529446dded5a7142c0583dbd8b19d52fe4/raylib_sdl-5.5.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bc6fe38110da1c98c341ede7064277ff79fb1b2a607787bd772974b4e4105d9a", size = 2290691, upload-time = "2024-11-26T11:11:38.045Z" },
|
sdist = { url = "https://files.pythonhosted.org/packages/ee/34/8218a19b2055b80601e8fd201ec723c74c7fe1ca06d525a43ed07b6d8e85/ruff-0.14.2.tar.gz", hash = "sha256:98da787668f239313d9c902ca7c523fe11b8ec3f39345553a51b25abc4629c96", size = 5539663, upload-time = "2025-10-23T19:37:00.956Z" }
|
||||||
{ url = "https://files.pythonhosted.org/packages/d9/d3/70d418057bb162d04df5cc5249ff83c38d02b55dbfe9363334518f2276b6/raylib_sdl-5.5.0.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:696ff487d3688a6c36c05c0cfcad1cd891351268739e5dfc9037692e958caa56", size = 1746153, upload-time = "2024-11-26T11:11:41.109Z" },
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/56/8b/ccea24888331953eb43f2aa869d0a757093ebe88036d5234d1e83ef1785e/raylib_sdl-5.5.0.2-cp313-cp313-manylinux2014_x86_64.whl", hash = "sha256:10672ac9c3b3bac2da95d99b1e128b7ebded8aff4f3325063544ea55c0712a62", size = 2985152, upload-time = "2024-11-26T11:11:44.078Z" },
|
{ url = "https://files.pythonhosted.org/packages/16/dd/23eb2db5ad9acae7c845700493b72d3ae214dce0b226f27df89216110f2b/ruff-0.14.2-py3-none-linux_armv6l.whl", hash = "sha256:7cbe4e593505bdec5884c2d0a4d791a90301bc23e49a6b1eb642dd85ef9c64f1", size = 12533390, upload-time = "2025-10-23T19:36:18.044Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/15/d2/3a5e650d8c8dc3670a50ca000b6bed8f10f86872090eaa2a3450595f1528/raylib_sdl-5.5.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:29d7888a7ff42273a91b44520b209d24f20a9fd5eae0d9ac18851e52797c5d8b", size = 1619604, upload-time = "2024-11-26T11:11:46.22Z" },
|
{ url = "https://files.pythonhosted.org/packages/5a/8c/5f9acff43ddcf3f85130d0146d0477e28ccecc495f9f684f8f7119b74c0d/ruff-0.14.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:8d54b561729cee92f8d89c316ad7a3f9705533f5903b042399b6ae0ddfc62e11", size = 12887187, upload-time = "2025-10-23T19:36:22.664Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d9/2d/d531187e2c21d724fb07707dd71ac28d9e103d616ae595017f9b4679e8e2/raylib_sdl-5.5.0.2-pp311-pypy311_pp73-macosx_10_13_x86_64.whl", hash = "sha256:51017cb725fce7da0b8f220839f6db91e20bbb3ba58e7debe3b1fd67f4468188", size = 1809261, upload-time = "2025-02-12T04:22:11.465Z" },
|
{ url = "https://files.pythonhosted.org/packages/99/fa/047646491479074029665022e9f3dc6f0515797f40a4b6014ea8474c539d/ruff-0.14.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5c8753dfa44ebb2cde10ce5b4d2ef55a41fb9d9b16732a2c5df64620dbda44a3", size = 11925177, upload-time = "2025-10-23T19:36:24.778Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f0/c5/81ec5b8e0c9b89e95b85d20fd4685368dabc0d7fedc8050efdfe3bbcc2f2/raylib_sdl-5.5.0.2-pp311-pypy311_pp73-manylinux2014_x86_64.whl", hash = "sha256:9453c29fc28b08dcae8a6432aeb07f13fbf8504fb1351941df64b9fb8ba0bac3", size = 2180109, upload-time = "2025-02-12T04:22:14.472Z" },
|
{ url = "https://files.pythonhosted.org/packages/15/8b/c44cf7fe6e59ab24a9d939493a11030b503bdc2a16622cede8b7b1df0114/ruff-0.14.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d0bbeffb8d9f4fccf7b5198d566d0bad99a9cb622f1fc3467af96cb8773c9e3", size = 12358285, upload-time = "2025-10-23T19:36:26.979Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/4f/8ba71611c74d6e3ff5e95d2935c1f5f98fc61183ebf70d4dfb09547a5767/raylib_sdl-5.5.0.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fd3841ab8d8d6ca24e4fbffc9514c58c0cf5bd29e3f2406006eba872416325b3", size = 1499920, upload-time = "2025-02-12T04:22:16.996Z" },
|
{ url = "https://files.pythonhosted.org/packages/45/01/47701b26254267ef40369aea3acb62a7b23e921c27372d127e0f3af48092/ruff-0.14.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7047f0c5a713a401e43a88d36843d9c83a19c584e63d664474675620aaa634a8", size = 12303832, upload-time = "2025-10-23T19:36:29.192Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/5c/ae7244ca4fbdf2bee9d6405dcd5bc6ae51ee1df66eb7a9884b77b8af856d/ruff-0.14.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bf8d2f9aa1602599217d82e8e0af7fd33e5878c4d98f37906b7c93f46f9a839", size = 13036995, upload-time = "2025-10-23T19:36:31.861Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/27/4c/0860a79ce6fd4c709ac01173f76f929d53f59748d0dcdd662519835dae43/ruff-0.14.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1c505b389e19c57a317cf4b42db824e2fca96ffb3d86766c1c9f8b96d32048a7", size = 14512649, upload-time = "2025-10-23T19:36:33.915Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7f/7f/d365de998069720a3abfc250ddd876fc4b81a403a766c74ff9bde15b5378/ruff-0.14.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a307fc45ebd887b3f26b36d9326bb70bf69b01561950cdcc6c0bdf7bb8e0f7cc", size = 14088182, upload-time = "2025-10-23T19:36:36.983Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/ea/d8e3e6b209162000a7be1faa41b0a0c16a133010311edc3329753cc6596a/ruff-0.14.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:61ae91a32c853172f832c2f40bd05fd69f491db7289fb85a9b941ebdd549781a", size = 13599516, upload-time = "2025-10-23T19:36:39.208Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/ea/c7810322086db68989fb20a8d5221dd3b79e49e396b01badca07b433ab45/ruff-0.14.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1967e40286f63ee23c615e8e7e98098dedc7301568bd88991f6e544d8ae096", size = 13272690, upload-time = "2025-10-23T19:36:41.453Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/39/10b05acf8c45786ef501d454e00937e1b97964f846bf28883d1f9619928a/ruff-0.14.2-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2877f02119cdebf52a632d743a2e302dea422bfae152ebe2f193d3285a3a65df", size = 13496497, upload-time = "2025-10-23T19:36:43.61Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/a1/1f25f8301e13751c30895092485fada29076e5e14264bdacc37202e85d24/ruff-0.14.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e681c5bc777de5af898decdcb6ba3321d0d466f4cb43c3e7cc2c3b4e7b843a05", size = 12266116, upload-time = "2025-10-23T19:36:45.625Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/fa/0029bfc9ce16ae78164e6923ef392e5f173b793b26cc39aa1d8b366cf9dc/ruff-0.14.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e21be42d72e224736f0c992cdb9959a2fa53c7e943b97ef5d081e13170e3ffc5", size = 12281345, upload-time = "2025-10-23T19:36:47.618Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a5/ab/ece7baa3c0f29b7683be868c024f0838770c16607bea6852e46b202f1ff6/ruff-0.14.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b8264016f6f209fac16262882dbebf3f8be1629777cf0f37e7aff071b3e9b92e", size = 12629296, upload-time = "2025-10-23T19:36:49.789Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/7f/638f54b43f3d4e48c6a68062794e5b367ddac778051806b9e235dfb7aa81/ruff-0.14.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5ca36b4cb4db3067a3b24444463ceea5565ea78b95fe9a07ca7cb7fd16948770", size = 13371610, upload-time = "2025-10-23T19:36:51.882Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/35/3654a973ebe5b32e1fd4a08ed2d46755af7267da7ac710d97420d7b8657d/ruff-0.14.2-py3-none-win32.whl", hash = "sha256:41775927d287685e08f48d8eb3f765625ab0b7042cc9377e20e64f4eb0056ee9", size = 12415318, upload-time = "2025-10-23T19:36:53.961Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/30/3758bcf9e0b6a4193a6f51abf84254aba00887dfa8c20aba18aa366c5f57/ruff-0.14.2-py3-none-win_amd64.whl", hash = "sha256:0df3424aa5c3c08b34ed8ce099df1021e3adaca6e90229273496b839e5a7e1af", size = 13565279, upload-time = "2025-10-23T19:36:56.578Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/5d/aa883766f8ef9ffbe6aa24f7192fb71632f31a30e77eb39aa2b0dc4290ac/ruff-0.14.2-py3-none-win_arm64.whl", hash = "sha256:ea9d635e83ba21569fbacda7e78afbfeb94911c9434aff06192d9bc23fd5495a", size = 12554956, upload-time = "2025-10-23T19:36:58.714Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -375,3 +276,35 @@ sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e
|
|||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
|
{ url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vulture"
|
||||||
|
version = "2.14"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8e/25/925f35db758a0f9199113aaf61d703de891676b082bd7cf73ea01d6000f7/vulture-2.14.tar.gz", hash = "sha256:cb8277902a1138deeab796ec5bef7076a6e0248ca3607a3f3dee0b6d9e9b8415", size = 58823, upload-time = "2024-12-08T17:39:43.319Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/56/0cc15b8ff2613c1d5c3dc1f3f576ede1c43868c1bc2e5ccaa2d4bcd7974d/vulture-2.14-py2.py3-none-any.whl", hash = "sha256:d9a90dba89607489548a49d557f8bac8112bd25d3cbc8aeef23e860811bd5ed9", size = 28915, upload-time = "2024-12-08T17:39:40.573Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstandard"
|
||||||
|
version = "0.25.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/fd/aa/3e0508d5a5dd96529cdc5a97011299056e14c6505b678fd58938792794b1/zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b", size = 711513, upload-time = "2025-09-14T22:15:54.002Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/5c/f8923b595b55fe49e30612987ad8bf053aef555c14f05bb659dd5dbe3e8a/zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3", size = 795887, upload-time = "2025-09-14T22:17:54.198Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8d/09/d0a2a14fc3439c5f874042dca72a79c70a532090b7ba0003be73fee37ae2/zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f", size = 640658, upload-time = "2025-09-14T22:17:55.423Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/7c/8b6b71b1ddd517f68ffb55e10834388d4f793c49c6b83effaaa05785b0b4/zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c", size = 5379849, upload-time = "2025-09-14T22:17:57.372Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a4/86/a48e56320d0a17189ab7a42645387334fba2200e904ee47fc5a26c1fd8ca/zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439", size = 5058095, upload-time = "2025-09-14T22:17:59.498Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f8/ad/eb659984ee2c0a779f9d06dbfe45e2dc39d99ff40a319895df2d3d9a48e5/zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043", size = 5551751, upload-time = "2025-09-14T22:18:01.618Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/61/b3/b637faea43677eb7bd42ab204dfb7053bd5c4582bfe6b1baefa80ac0c47b/zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859", size = 6364818, upload-time = "2025-09-14T22:18:03.769Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/31/dc/cc50210e11e465c975462439a492516a73300ab8caa8f5e0902544fd748b/zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0", size = 5560402, upload-time = "2025-09-14T22:18:05.954Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/ae/56523ae9c142f0c08efd5e868a6da613ae76614eca1305259c3bf6a0ed43/zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7", size = 4955108, upload-time = "2025-09-14T22:18:07.68Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/98/cf/c899f2d6df0840d5e384cf4c4121458c72802e8bda19691f3b16619f51e9/zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2", size = 5269248, upload-time = "2025-09-14T22:18:09.753Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/c0/59e912a531d91e1c192d3085fc0f6fb2852753c301a812d856d857ea03c6/zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344", size = 5430330, upload-time = "2025-09-14T22:18:11.966Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a0/1d/7e31db1240de2df22a58e2ea9a93fc6e38cc29353e660c0272b6735d6669/zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c", size = 5811123, upload-time = "2025-09-14T22:18:13.907Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f6/49/fac46df5ad353d50535e118d6983069df68ca5908d4d65b8c466150a4ff1/zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088", size = 5359591, upload-time = "2025-09-14T22:18:16.465Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/38/f249a2050ad1eea0bb364046153942e34abba95dd5520af199aed86fbb49/zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12", size = 444513, upload-time = "2025-09-14T22:18:20.61Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3a/43/241f9615bcf8ba8903b3f0432da069e857fc4fd1783bd26183db53c4804b/zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2", size = 516118, upload-time = "2025-09-14T22:18:17.849Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/ef/da163ce2450ed4febf6467d77ccb4cd52c4c30ab45624bad26ca0a27260c/zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d", size = 476940, upload-time = "2025-09-14T22:18:19.088Z" },
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user