writing attract sequence

This commit is contained in:
Yonokid
2024-09-08 16:15:44 -04:00
parent afb7f6bde5
commit cb20f408ac
4 changed files with 342 additions and 12 deletions

View File

@@ -6,6 +6,103 @@ from collections import deque
#TJA Format creator is unknown. I did not create the format, but I did write the parser though.
import cProfile
import pstats
import io
import sys
class Profiler:
def __init__(self):
self.profiler = cProfile.Profile()
self.stats = None
self.calls = 0
self.profiled_functions = set() # Track profiled functions
self.previous_order = [] # Track previous order of functions
def profile(self, func, *args, **kwargs):
func_name = func.__name__
self.calls += 1
# Start profiling
self.profiler.enable()
func(*args, **kwargs)
self.profiler.disable()
# Collect and update stats
if self.stats is None:
self.stats = pstats.Stats(self.profiler)
else:
self.stats.add(self.profiler)
# Get current order of functions
current_order = self.get_current_function_order()
# Check if a new function is added or if order has changed
if func_name not in self.profiled_functions or self.previous_order != current_order:
self.profiled_functions.add(func_name)
self.clear_screen()
# Update the previous order to the current one
self.previous_order = current_order
# Print the averaged stats
self.print_averaged_stats()
def clear_screen(self):
sys.stdout.write('\033[2J\033[H') # Clear screen and move cursor to the top
sys.stdout.flush()
def get_current_function_order(self):
# Capture stats output to determine the current order of functions
stream = io.StringIO()
stats = pstats.Stats(self.profiler, stream=stream)
stats.sort_stats(pstats.SortKey.TIME)
stats.print_stats()
# Extract function names from the stats output
content = stream.getvalue().splitlines()[5:] # Skip header lines
function_order = [line.split()[-1] for line in content if line.strip()]
return function_order
def print_averaged_stats(self):
# Prepare the output stream to capture stats
stream = io.StringIO()
stats = pstats.Stats(self.profiler, stream=stream)
stats.sort_stats(pstats.SortKey.TIME)
# Print the stats, but suppress the raw counts
stats.print_stats()
# Extract and process stats to average them
content = stream.getvalue().splitlines()
header = content[:5] # Keep the header
data = content[5:] # Data lines
if data:
# Update the total calls and times
avg_data = []
for line in data:
parts = line.split()
if len(parts) >= 6:
ncalls = int(parts[0].replace('/', '')) # Total calls
tottime = float(parts[1]) # Total time
percall = tottime / ncalls if ncalls > 0 else 0
cumtime = float(parts[3]) # Cumulative time
cumpercall = cumtime / ncalls if ncalls > 0 else 0
# Format and add the line
avg_data.append(
f"{ncalls:>9} {tottime / self.calls:>9.3f} {percall:>9.3f} "
f"{ncalls:>9} {cumtime / self.calls:>9.3f} {cumpercall:>9.3f} {line[90:]}"
)
# Move cursor to the start of the line before printing
sys.stdout.write('\033[F' * (len(header) + len(avg_data))) # Move cursor up to overwrite
# Print the header and averaged data
sys.stdout.write('\n'.join(header + avg_data) + '\n')
sys.stdout.flush()
def rounded(d):
sign = 1 if (d >= 0) else -1
d = abs(d)
@@ -68,6 +165,7 @@ class tja_parser:
self.scroll_modifier = 1
self.current_ms = 0
self.barline_display = True
self.gogo_time = False
def file_to_data(self):
with open(self.file_path, 'rt', encoding='utf-8-sig') as tja_file:
@@ -94,7 +192,11 @@ class tja_parser:
elif 'DEMOSTART' in item: self.demo_start = float(item.split(':')[1])
elif 'COURSE' in item:
course = str(item.split(':')[1]).lower()
if course == 'edit' or course == '4':
if course == 'tower' or course == '6':
self.course_data[6] = []
if course == 'dan' or course == '5':
self.course_data[5] = []
elif course == 'edit' or course == '4':
self.course_data[4] = []
elif course == 'oni' or course == '3':
self.course_data[3] = []
@@ -195,6 +297,12 @@ class tja_parser:
elif '#BARLINEON' in part:
self.barline_display = True
continue
elif '#GOGOSTART' in part:
self.gogo_time = True
continue
elif '#GOGOEND' in part:
self.gogo_time = False
continue
#Unrecognized commands will be skipped for now
elif '#' in part:
continue
@@ -255,7 +363,10 @@ class tja_parser:
if note in {'5', '6', '8'}:
play_note_list[-1]['color'] = 255
if note == '8' and play_note_list[-2]['note'] in ('7', '9'):
play_note_list[-1]['balloon'] = int(balloon[balloon_index])
if balloon_index >= len(balloon):
play_note_list[-1]['balloon'] = 0
else:
play_note_list[-1]['balloon'] = int(balloon[balloon_index])
balloon_index += 1
self.current_ms += increment
@@ -367,3 +478,67 @@ class Animation:
else:
self.attribute = 0
self.is_finished = True
import cv2
class VideoPlayer:
def __init__(self, path, loop_start=None):
video_path = path
audio_path = path[:-4] + '.ogg'
self.loop_start = loop_start
self.cap = cv2.VideoCapture(video_path)
fps = self.cap.get(cv2.CAP_PROP_FPS)
self.frame_texture = None
self.frame_time = (1.0 / fps) * 1000
self.start_ms = get_current_ms()
self.audio = ray.load_music_stream(audio_path)
if loop_start is None:
self.audio.looping = False
self.is_finished = [False, False]
ray.play_music_stream(self.audio)
if not self.cap.isOpened():
print("Error: Could not open video file.")
return
def update(self):
current_ms = get_current_ms()
elapsed_time = current_ms - self.start_ms
ray.update_music_stream(self.audio)
if not ray.is_music_stream_playing(self.audio):
self.is_finished[1] = True
if elapsed_time >= self.frame_time:
ret, frame = self.cap.read()
if not ret:
# Reset to the loop start frame
if self.loop_start == None:
self.is_finished[0] = True
else:
self.cap.set(cv2.CAP_PROP_POS_FRAMES, self.loop_start)
ret, frame = self.cap.read() # Read the frame at loop start
if not ret:
return # If still not successful, return
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
image = ray.Image(frame_rgb.tobytes(), frame_rgb.shape[1], frame_rgb.shape[0], 1, ray.PIXELFORMAT_UNCOMPRESSED_R8G8B8)
new_texture = ray.load_texture_from_image(image)
# Unload the previous texture if it exists
if self.frame_texture:
ray.unload_texture(self.frame_texture)
# Assign the new texture to the instance variable
self.frame_texture = new_texture
self.start_ms = current_ms
def draw(self):
if self.frame_texture:
ray.draw_texture(self.frame_texture, 0, 0, ray.WHITE)
def __del__(self):
# Ensure resources are cleaned up when the instance is deleted
if self.frame_texture:
ray.unload_texture(self.frame_texture)
self.cap.release()