diff --git a/src/GameEngine.cpp b/src/GameEngine.cpp index ae1422b..f82cd99 100644 --- a/src/GameEngine.cpp +++ b/src/GameEngine.cpp @@ -63,23 +63,31 @@ GameEngine::GameEngine(const McRogueFaceConfig& cfg) McRFPy_API::executePyString("import mcrfpy"); McRFPy_API::executeScript("scripts/game.py"); } - + + // Note: --exec scripts are NOT executed here. + // They are executed via executeStartupScripts() after the final engine is set up. + // This prevents double-execution when main.cpp creates multiple GameEngine instances. + + clock.restart(); + runtime.restart(); +} + +void GameEngine::executeStartupScripts() +{ // Execute any --exec scripts in order + // This is called ONCE from main.cpp after the final engine is set up if (!config.exec_scripts.empty()) { if (!Py_IsInitialized()) { McRFPy_API::api_init(); } McRFPy_API::executePyString("import mcrfpy"); - + for (const auto& exec_script : config.exec_scripts) { std::cout << "Executing script: " << exec_script << std::endl; McRFPy_API::executeScript(exec_script.string()); } std::cout << "All --exec scripts completed" << std::endl; } - - clock.restart(); - runtime.restart(); } GameEngine::~GameEngine() diff --git a/src/GameEngine.h b/src/GameEngine.h index 1015721..e212743 100644 --- a/src/GameEngine.h +++ b/src/GameEngine.h @@ -146,6 +146,7 @@ public: void run(); void sUserInput(); void cleanup(); // Clean up Python references before destruction + void executeStartupScripts(); // Execute --exec scripts (called once after final engine setup) int getFrame() { return currentFrame; } float getFrameTime() { return frameTime; } sf::View getView() { return visible; } diff --git a/src/main.cpp b/src/main.cpp index f0d8f7e..b0e9599 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -183,8 +183,8 @@ int run_python_interpreter(const McRogueFaceConfig& config) return 0; } else if (!config.exec_scripts.empty()) { - // With --exec, scripts were already executed by the first GameEngine constructor. - // Just configure auto-exit and run the existing engine to preserve timers/state. + // Execute startup scripts on the existing engine (not in constructor to prevent double-execution) + engine->executeStartupScripts(); if (config.headless) { engine->setAutoExitAfterExec(true); } diff --git a/tests/demo/demo_main.py b/tests/demo/demo_main.py index dfa1cb5..67bc94f 100644 --- a/tests/demo/demo_main.py +++ b/tests/demo/demo_main.py @@ -14,9 +14,6 @@ from mcrfpy import automation import sys import os -# Note: Engine runs --exec scripts twice - we use this to our advantage -# First run sets up scenes, second run's timer fires after game loop starts - # Add parent to path for imports sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) diff --git a/tests/unit/test_viewport_visual.py b/tests/unit/test_viewport_visual.py deleted file mode 100644 index 49ca076..0000000 --- a/tests/unit/test_viewport_visual.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python3 -"""Visual viewport test with screenshots""" - -import mcrfpy -from mcrfpy import Window, Frame, Caption, Color -import sys - -def test_viewport_visual(runtime): - """Visual test of viewport modes""" - mcrfpy.delTimer("test") - - print("Creating visual viewport test...") - - # Get window singleton - window = Window.get() - - # Create test scene - scene = mcrfpy.sceneUI("test") - - # Create visual elements at game resolution boundaries - game_res = window.game_resolution - - # Full boundary frame - boundary = Frame(pos=(0, 0), size=(game_res[0], game_res[1]), - fill_color=Color(40, 40, 80), - outline_color=Color(255, 255, 0), - outline=3) - scene.append(boundary) - - # Corner markers - corner_size = 100 - colors = [ - Color(255, 100, 100), # Red TL - Color(100, 255, 100), # Green TR - Color(100, 100, 255), # Blue BL - Color(255, 255, 100), # Yellow BR - ] - positions = [ - (0, 0), # Top-left - (game_res[0] - corner_size, 0), # Top-right - (0, game_res[1] - corner_size), # Bottom-left - (game_res[0] - corner_size, game_res[1] - corner_size) # Bottom-right - ] - labels = ["TL", "TR", "BL", "BR"] - - for (x, y), color, label in zip(positions, colors, labels): - corner = Frame(pos=(x, y), size=(corner_size, corner_size), - fill_color=color, - outline_color=Color(255, 255, 255), - outline=2) - scene.append(corner) - - text = Caption(text=label, pos=(x + 10, y + 10)) - text.font_size = 32 - text.fill_color = Color(0, 0, 0) - scene.append(text) - - # Center crosshair - center_x = game_res[0] // 2 - center_y = game_res[1] // 2 - h_line = Frame(pos=(0, center_y - 1), size=(game_res[0], 2), - fill_color=Color(255, 255, 255, 128)) - v_line = Frame(pos=(center_x - 1, 0), size=(2, game_res[1]), - fill_color=Color(255, 255, 255, 128)) - scene.append(h_line) - scene.append(v_line) - - # Mode text - mode_text = Caption(text=f"Mode: {window.scaling_mode}", - pos=(center_x - 100, center_y - 50)) - mode_text.font_size = 36 - mode_text.fill_color = Color(255, 255, 255) - scene.append(mode_text) - - # Resolution text - res_text = Caption(text=f"Game: {game_res[0]}x{game_res[1]}", - pos=(center_x - 150, center_y + 10)) - res_text.font_size = 24 - res_text.fill_color = Color(200, 200, 200) - scene.append(res_text) - - from mcrfpy import automation - - # Test different modes and window sizes - def test_sequence(runtime): - mcrfpy.delTimer("seq") - - # Test 1: Fit mode with original size - print("Test 1: Fit mode, original window size") - automation.screenshot("viewport_01_fit_original.png") - - # Test 2: Wider window - window.resolution = (1400, 768) - print(f"Test 2: Fit mode, wider window {window.resolution}") - automation.screenshot("viewport_02_fit_wide.png") - - # Test 3: Taller window - window.resolution = (1024, 900) - print(f"Test 3: Fit mode, taller window {window.resolution}") - automation.screenshot("viewport_03_fit_tall.png") - - # Test 4: Center mode - window.scaling_mode = "center" - mode_text.text = "Mode: center" - print(f"Test 4: Center mode {window.resolution}") - automation.screenshot("viewport_04_center.png") - - # Test 5: Stretch mode - window.scaling_mode = "stretch" - mode_text.text = "Mode: stretch" - window.resolution = (1280, 720) - print(f"Test 5: Stretch mode {window.resolution}") - automation.screenshot("viewport_05_stretch.png") - - # Test 6: Small window with fit - window.scaling_mode = "fit" - mode_text.text = "Mode: fit" - window.resolution = (640, 480) - print(f"Test 6: Fit mode, small window {window.resolution}") - automation.screenshot("viewport_06_fit_small.png") - - print("\nViewport visual test completed!") - print("Screenshots saved:") - print(" - viewport_01_fit_original.png") - print(" - viewport_02_fit_wide.png") - print(" - viewport_03_fit_tall.png") - print(" - viewport_04_center.png") - print(" - viewport_05_stretch.png") - print(" - viewport_06_fit_small.png") - - sys.exit(0) - - # Start test sequence after a short delay - mcrfpy.setTimer("seq", test_sequence, 500) - -# Main execution -print("Starting visual viewport test...") -mcrfpy.createScene("test") -mcrfpy.setScene("test") -mcrfpy.setTimer("test", test_viewport_visual, 100) -print("Test scheduled...") \ No newline at end of file