Some checks failed
Build Simulation and Test / Run All Tests (push) Failing after 8m17s
Major rewrite.
293 lines
11 KiB
Python
293 lines
11 KiB
Python
import pygame
|
|
import time
|
|
import sys
|
|
|
|
from pygame_gui import UIManager
|
|
|
|
from world.simulation_interface import Camera
|
|
from config.constants import *
|
|
from core.input_handler import InputHandler
|
|
from core.renderer import Renderer
|
|
from core.simulation_core import SimulationCore, SimulationConfig
|
|
from core.event_bus import EventBus
|
|
from ui.hud import HUD
|
|
|
|
import cProfile
|
|
import pstats
|
|
|
|
|
|
class SimulationEngine:
|
|
"""Interactive simulation engine with UI (wrapper around SimulationCore)."""
|
|
|
|
def __init__(self):
|
|
pygame.init()
|
|
self.event_bus = EventBus()
|
|
self._init_window()
|
|
self._init_simulation()
|
|
self._init_ui()
|
|
self.running = True
|
|
|
|
def _profile_single_tick(self):
|
|
"""Profile a single tick for performance analysis."""
|
|
profiler = cProfile.Profile()
|
|
profiler.enable()
|
|
self.simulation_core.world.tick_all()
|
|
profiler.disable()
|
|
profiler.dump_stats('profile_tick.prof') # Save to file
|
|
|
|
def _init_window(self):
|
|
info = pygame.display.Info()
|
|
self.window_width = int(info.current_w // 1.5)
|
|
self.window_height = int(info.current_h // 1.5)
|
|
self.screen = pygame.display.set_mode(
|
|
(self.window_width, self.window_height),
|
|
pygame.RESIZABLE, vsync=1
|
|
)
|
|
pygame.display.set_caption("Dynamic Abstraction System Testing")
|
|
self.clock = pygame.time.Clock()
|
|
|
|
def _init_ui(self):
|
|
self.ui_manager = UIManager((self.window_width, self.window_height))
|
|
self.hud = HUD(self.ui_manager, self.window_width, self.window_height)
|
|
self.hud.update_layout(self.window_width, self.window_height)
|
|
self._update_simulation_view()
|
|
|
|
def _init_simulation(self):
|
|
# Initialize default sim view rect (will be updated by _init_ui)
|
|
self.sim_view_width = self.window_width - 400 # Rough estimate for inspector width
|
|
self.sim_view_height = self.window_height - 200 # Rough estimate for control bar height
|
|
self.sim_view = pygame.Surface((self.sim_view_width, self.sim_view_height))
|
|
self.sim_view_rect = self.sim_view.get_rect(topleft=(200, 48)) # Rough estimate
|
|
|
|
# Create simulation core
|
|
sim_config = SimulationConfig(
|
|
grid_width=GRID_WIDTH,
|
|
grid_height=GRID_HEIGHT,
|
|
cell_size=CELL_SIZE,
|
|
initial_cells=50,
|
|
initial_food=FOOD_OBJECTS_COUNT,
|
|
food_spawning=FOOD_SPAWNING,
|
|
random_seed=RANDOM_SEED,
|
|
default_tps=DEFAULT_TPS
|
|
)
|
|
|
|
self.simulation_core = SimulationCore(sim_config, self.event_bus)
|
|
|
|
# Setup input handler with simulation core world
|
|
self.input_handler = InputHandler(
|
|
self.simulation_core.camera,
|
|
self.simulation_core.world,
|
|
self.sim_view_rect
|
|
)
|
|
self.input_handler.tps = self.simulation_core.timing.state.tps
|
|
self.input_handler.default_tps = DEFAULT_TPS
|
|
|
|
# Set up action callbacks for input handler
|
|
self.input_handler.set_action_callback('toggle_pause', self.simulation_core.toggle_pause)
|
|
self.input_handler.set_action_callback('step_forward', self.simulation_core.step)
|
|
self.input_handler.set_action_callback('set_speed', self.simulation_core.set_speed_multiplier)
|
|
self.input_handler.set_action_callback('set_custom_tps', self.simulation_core.set_tps)
|
|
self.input_handler.set_action_callback('toggle_sprint', self.simulation_core.toggle_sprint_mode)
|
|
|
|
# Setup renderer
|
|
self.renderer = Renderer(self.sim_view)
|
|
|
|
# Profile a single tick for performance analysis
|
|
self._profile_single_tick()
|
|
|
|
def _update_simulation_view(self):
|
|
viewport_rect = self.hud.get_viewport_rect()
|
|
self.sim_view_width = viewport_rect.width
|
|
self.sim_view_height = viewport_rect.height
|
|
self.sim_view = pygame.Surface((self.sim_view_width, self.sim_view_height))
|
|
self.sim_view_rect = self.sim_view.get_rect(topleft=(viewport_rect.left, viewport_rect.top))
|
|
|
|
self.ui_manager.set_window_resolution((self.window_width, self.window_height))
|
|
self.renderer = Renderer(self.sim_view)
|
|
|
|
# Update simulation core camera dimensions
|
|
self.simulation_core.camera.screen_width = self.sim_view_width
|
|
self.simulation_core.camera.screen_height = self.sim_view_height
|
|
|
|
# Update input handler simulation view rect
|
|
self.input_handler.update_sim_view_rect(self.sim_view_rect)
|
|
|
|
def _count_cells(self):
|
|
"""Count cells in the simulation."""
|
|
# Import locally to avoid circular import
|
|
from world.objects import DefaultCell
|
|
return self.simulation_core.count_entities_by_type(DefaultCell)
|
|
|
|
|
|
def run(self):
|
|
"""Run the interactive simulation engine."""
|
|
print(f"World buffer: {self.simulation_core.world.current_buffer}")
|
|
self.simulation_core.start()
|
|
|
|
while self.running:
|
|
self._handle_frame()
|
|
|
|
self.simulation_core.stop()
|
|
pygame.quit()
|
|
sys.exit()
|
|
|
|
def _handle_frame(self):
|
|
"""Handle a single frame in the interactive simulation."""
|
|
deltatime = self.clock.get_time() / 1000.0
|
|
|
|
# Handle events
|
|
events = pygame.event.get()
|
|
self.running = self.input_handler.handle_events(events, self.hud.manager)
|
|
|
|
# Process HUD events and window events
|
|
for event in events:
|
|
hud_action = self.hud.process_event(event)
|
|
self._handle_hud_actions(hud_action)
|
|
|
|
if event.type == pygame.VIDEORESIZE:
|
|
self._handle_window_resize(event)
|
|
|
|
# Sync input handler state with simulation core timing
|
|
self._sync_input_and_timing()
|
|
|
|
# Handle sprint mode
|
|
if self.input_handler.sprint_mode:
|
|
self._handle_sprint_mode()
|
|
return
|
|
|
|
# Update UI manager every frame
|
|
self.hud.manager.update(deltatime)
|
|
|
|
# Handle step-forward mode
|
|
if self.input_handler.is_stepping:
|
|
self.simulation_core.step()
|
|
self.input_handler.is_stepping = False
|
|
else:
|
|
# Update simulation using core
|
|
self.simulation_core.update(deltatime)
|
|
|
|
# Update selected objects in input handler
|
|
self.input_handler.update_selected_objects()
|
|
|
|
# Render frame
|
|
self._update(deltatime)
|
|
self._render()
|
|
|
|
def _sync_input_and_timing(self):
|
|
"""Synchronize input handler state with simulation core timing."""
|
|
timing_state = self.simulation_core.timing.state
|
|
|
|
# Sync TPS
|
|
self.input_handler.tps = timing_state.tps
|
|
|
|
# Sync pause state
|
|
self.input_handler.is_paused = timing_state.is_paused
|
|
|
|
# Sync sprint mode
|
|
self.input_handler.sprint_mode = timing_state.sprint_mode
|
|
|
|
# Sync speed multiplier
|
|
self.input_handler.speed_multiplier = timing_state.speed_multiplier
|
|
|
|
def _handle_window_resize(self, event):
|
|
"""Handle window resize event."""
|
|
self.window_width, self.window_height = event.w, event.h
|
|
self.screen = pygame.display.set_mode(
|
|
(self.window_width, self.window_height),
|
|
pygame.RESIZABLE
|
|
)
|
|
self._update_simulation_view()
|
|
self.hud.update_layout(self.window_width, self.window_height)
|
|
|
|
|
|
def _handle_hud_actions(self, action):
|
|
"""Handle actions from HUD simulation controls by forwarding to simulation core."""
|
|
if action == 'toggle_pause':
|
|
self.simulation_core.toggle_pause()
|
|
elif action == 'step_forward':
|
|
self.simulation_core.step()
|
|
elif action == 'toggle_sprint':
|
|
self.simulation_core.toggle_sprint_mode()
|
|
elif isinstance(action, tuple) and action[0] == 'set_speed':
|
|
self.simulation_core.set_speed_multiplier(action[1])
|
|
elif isinstance(action, tuple) and action[0] == 'set_custom_tps':
|
|
self.simulation_core.set_tps(action[1])
|
|
elif isinstance(action, tuple) and action[0] == 'reset_tps_display':
|
|
# Reset TPS display to current value
|
|
if self.hud.custom_tps_entry:
|
|
self.hud.custom_tps_entry.set_text(str(int(self.simulation_core.timing.state.tps)))
|
|
|
|
def _handle_sprint_mode(self):
|
|
"""Handle sprint mode by running multiple simulation ticks quickly."""
|
|
current_time = time.perf_counter()
|
|
while time.perf_counter() - current_time < 0.05: # 50ms of sprint
|
|
self.simulation_core.update(0.016) # Update simulation
|
|
self.input_handler.update_selected_objects()
|
|
pygame.event.pump() # Prevent event queue overflow
|
|
|
|
# Render sprint debug info
|
|
self.screen.fill(BLACK)
|
|
self.renderer.clear_screen()
|
|
cell_count = self._count_cells()
|
|
self.hud.render_sprint_debug(
|
|
self.screen,
|
|
self.simulation_core.state.actual_tps,
|
|
self.simulation_core.state.total_ticks,
|
|
cell_count
|
|
)
|
|
pygame.display.flip()
|
|
self.clock.tick(MAX_FPS)
|
|
|
|
def _update(self, deltatime):
|
|
"""Update camera based on input."""
|
|
keys = pygame.key.get_pressed()
|
|
self.input_handler.update_camera(keys, deltatime)
|
|
|
|
def _render(self):
|
|
"""Render the simulation frame."""
|
|
self.screen.fill(BLACK)
|
|
self.renderer.clear_screen()
|
|
|
|
if not self.hud.dragging_splitter:
|
|
# Render world
|
|
self.renderer.draw_grid(self.simulation_core.camera, self.input_handler.show_grid)
|
|
self.renderer.render_world(self.simulation_core.world, self.simulation_core.camera)
|
|
self.renderer.render_interaction_radius(
|
|
self.simulation_core.world,
|
|
self.simulation_core.camera,
|
|
self.input_handler.selected_objects,
|
|
self.input_handler.show_interaction_radius
|
|
)
|
|
self.renderer.render_selection_rectangle(
|
|
self.input_handler.get_selection_rect(),
|
|
self.sim_view_rect
|
|
)
|
|
self.renderer.render_selected_objects_outline(
|
|
self.input_handler.selected_objects,
|
|
self.simulation_core.camera
|
|
)
|
|
self.screen.blit(self.sim_view, (self.sim_view_rect.left, self.sim_view_rect.top))
|
|
|
|
# Update HUD displays with simulation core state
|
|
self.hud.update_simulation_controls(self.simulation_core)
|
|
|
|
# Draw UI elements
|
|
self.hud.manager.draw_ui(self.screen)
|
|
self.hud.draw_splitters(self.screen)
|
|
|
|
# Render HUD overlays
|
|
self.hud.render_fps(self.screen, self.clock)
|
|
self.hud.render_tps(self.screen, self.simulation_core.state.actual_tps)
|
|
self.hud.render_selected_objects_info(self.screen, self.input_handler.selected_objects)
|
|
self.hud.render_legend(self.screen, self.input_handler.show_legend)
|
|
self.hud.render_pause_indicator(self.screen, self.simulation_core.timing.state.is_paused)
|
|
|
|
# Render neural network visualization for selected object
|
|
if self.input_handler.selected_objects:
|
|
self.hud.render_neural_network_visualization(
|
|
self.screen,
|
|
self.input_handler.selected_objects[0]
|
|
)
|
|
|
|
pygame.display.flip()
|
|
self.clock.tick(MAX_FPS) |