Python command emulation
This commit is contained in:
parent
a44b8c93e9
commit
763fa201f0
17 changed files with 704 additions and 74 deletions
157
src/CommandLineParser.cpp
Normal file
157
src/CommandLineParser.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
#include "CommandLineParser.h"
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
|
||||
CommandLineParser::CommandLineParser(int argc, char* argv[])
|
||||
: argc(argc), argv(argv) {}
|
||||
|
||||
CommandLineParser::ParseResult CommandLineParser::parse(McRogueFaceConfig& config) {
|
||||
ParseResult result;
|
||||
current_arg = 1; // Reset for each parse
|
||||
|
||||
// Detect if running as Python interpreter
|
||||
std::filesystem::path exec_name = std::filesystem::path(argv[0]).filename();
|
||||
if (exec_name.string().find("python") == 0) {
|
||||
config.headless = true;
|
||||
config.python_mode = true;
|
||||
}
|
||||
|
||||
while (current_arg < argc) {
|
||||
std::string arg = argv[current_arg];
|
||||
|
||||
// Handle Python-style single-letter flags
|
||||
if (arg == "-h" || arg == "--help") {
|
||||
print_help();
|
||||
result.should_exit = true;
|
||||
result.exit_code = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (arg == "-V" || arg == "--version") {
|
||||
print_version();
|
||||
result.should_exit = true;
|
||||
result.exit_code = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Python execution modes
|
||||
if (arg == "-c") {
|
||||
config.python_mode = true;
|
||||
current_arg++;
|
||||
if (current_arg >= argc) {
|
||||
std::cerr << "Argument expected for the -c option" << std::endl;
|
||||
result.should_exit = true;
|
||||
result.exit_code = 1;
|
||||
return result;
|
||||
}
|
||||
config.python_command = argv[current_arg];
|
||||
current_arg++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "-m") {
|
||||
config.python_mode = true;
|
||||
current_arg++;
|
||||
if (current_arg >= argc) {
|
||||
std::cerr << "Argument expected for the -m option" << std::endl;
|
||||
result.should_exit = true;
|
||||
result.exit_code = 1;
|
||||
return result;
|
||||
}
|
||||
config.python_module = argv[current_arg];
|
||||
current_arg++;
|
||||
// Collect remaining args as module args
|
||||
while (current_arg < argc) {
|
||||
config.script_args.push_back(argv[current_arg]);
|
||||
current_arg++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "-i") {
|
||||
config.interactive_mode = true;
|
||||
config.python_mode = true;
|
||||
current_arg++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// McRogueFace specific flags
|
||||
if (arg == "--headless") {
|
||||
config.headless = true;
|
||||
config.audio_enabled = false;
|
||||
current_arg++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--audio-off") {
|
||||
config.audio_enabled = false;
|
||||
current_arg++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--audio-on") {
|
||||
config.audio_enabled = true;
|
||||
current_arg++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg == "--screenshot") {
|
||||
config.take_screenshot = true;
|
||||
current_arg++;
|
||||
if (current_arg < argc && argv[current_arg][0] != '-') {
|
||||
config.screenshot_path = argv[current_arg];
|
||||
current_arg++;
|
||||
} else {
|
||||
config.screenshot_path = "screenshot.png";
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If no flags matched, treat as positional argument (script name)
|
||||
if (arg[0] != '-') {
|
||||
config.script_path = arg;
|
||||
config.python_mode = true;
|
||||
current_arg++;
|
||||
// Remaining args are script args
|
||||
while (current_arg < argc) {
|
||||
config.script_args.push_back(argv[current_arg]);
|
||||
current_arg++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Unknown flag
|
||||
std::cerr << "Unknown option: " << arg << std::endl;
|
||||
result.should_exit = true;
|
||||
result.exit_code = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CommandLineParser::print_help() {
|
||||
std::cout << "usage: mcrogueface [option] ... [-c cmd | -m mod | file | -] [arg] ...\n"
|
||||
<< "Options:\n"
|
||||
<< " -c cmd : program passed in as string (terminates option list)\n"
|
||||
<< " -h : print this help message and exit (also --help)\n"
|
||||
<< " -i : inspect interactively after running script\n"
|
||||
<< " -m mod : run library module as a script (terminates option list)\n"
|
||||
<< " -V : print the Python version number and exit (also --version)\n"
|
||||
<< "\n"
|
||||
<< "McRogueFace specific options:\n"
|
||||
<< " --headless : run without creating a window (implies --audio-off)\n"
|
||||
<< " --audio-off : disable audio\n"
|
||||
<< " --audio-on : enable audio (even in headless mode)\n"
|
||||
<< " --screenshot [path] : take a screenshot in headless mode\n"
|
||||
<< "\n"
|
||||
<< "Arguments:\n"
|
||||
<< " file : program read from script file\n"
|
||||
<< " - : program read from stdin\n"
|
||||
<< " arg ...: arguments passed to program in sys.argv[1:]\n";
|
||||
}
|
||||
|
||||
void CommandLineParser::print_version() {
|
||||
std::cout << "Python 3.12.0 (McRogueFace embedded)\n";
|
||||
}
|
||||
30
src/CommandLineParser.h
Normal file
30
src/CommandLineParser.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef COMMAND_LINE_PARSER_H
|
||||
#define COMMAND_LINE_PARSER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "McRogueFaceConfig.h"
|
||||
|
||||
class CommandLineParser {
|
||||
public:
|
||||
struct ParseResult {
|
||||
bool should_exit = false;
|
||||
int exit_code = 0;
|
||||
};
|
||||
|
||||
CommandLineParser(int argc, char* argv[]);
|
||||
ParseResult parse(McRogueFaceConfig& config);
|
||||
|
||||
private:
|
||||
int argc;
|
||||
char** argv;
|
||||
int current_arg = 1; // Skip program name
|
||||
|
||||
bool has_flag(const std::string& short_flag, const std::string& long_flag = "");
|
||||
std::string get_next_arg(const std::string& flag_name);
|
||||
void parse_positional_args(McRogueFaceConfig& config);
|
||||
void print_help();
|
||||
void print_version();
|
||||
};
|
||||
|
||||
#endif // COMMAND_LINE_PARSER_H
|
||||
|
|
@ -5,14 +5,32 @@
|
|||
#include "UITestScene.h"
|
||||
#include "Resources.h"
|
||||
|
||||
GameEngine::GameEngine()
|
||||
GameEngine::GameEngine() : GameEngine(McRogueFaceConfig{})
|
||||
{
|
||||
}
|
||||
|
||||
GameEngine::GameEngine(const McRogueFaceConfig& cfg)
|
||||
: config(cfg), headless(cfg.headless)
|
||||
{
|
||||
Resources::font.loadFromFile("./assets/JetbrainsMono.ttf");
|
||||
Resources::game = this;
|
||||
window_title = "Crypt of Sokoban - 7DRL 2025, McRogueface Engine";
|
||||
window.create(sf::VideoMode(1024, 768), window_title, sf::Style::Titlebar | sf::Style::Close);
|
||||
visible = window.getDefaultView();
|
||||
window.setFramerateLimit(60);
|
||||
|
||||
// Initialize rendering based on headless mode
|
||||
if (headless) {
|
||||
headless_renderer = std::make_unique<HeadlessRenderer>();
|
||||
if (!headless_renderer->init(1024, 768)) {
|
||||
throw std::runtime_error("Failed to initialize headless renderer");
|
||||
}
|
||||
render_target = &headless_renderer->getRenderTarget();
|
||||
} else {
|
||||
window = std::make_unique<sf::RenderWindow>();
|
||||
window->create(sf::VideoMode(1024, 768), window_title, sf::Style::Titlebar | sf::Style::Close);
|
||||
window->setFramerateLimit(60);
|
||||
render_target = window.get();
|
||||
}
|
||||
|
||||
visible = render_target->getDefaultView();
|
||||
scene = "uitest";
|
||||
scenes["uitest"] = new UITestScene(this);
|
||||
|
||||
|
|
@ -25,6 +43,13 @@ GameEngine::GameEngine()
|
|||
runtime.restart();
|
||||
}
|
||||
|
||||
GameEngine::~GameEngine()
|
||||
{
|
||||
for (auto& [name, scene] : scenes) {
|
||||
delete scene;
|
||||
}
|
||||
}
|
||||
|
||||
Scene* GameEngine::currentScene() { return scenes[scene]; }
|
||||
void GameEngine::changeScene(std::string s)
|
||||
{
|
||||
|
|
@ -37,13 +62,24 @@ void GameEngine::changeScene(std::string s)
|
|||
void GameEngine::quit() { running = false; }
|
||||
void GameEngine::setPause(bool p) { paused = p; }
|
||||
sf::Font & GameEngine::getFont() { /*return font; */ return Resources::font; }
|
||||
sf::RenderWindow & GameEngine::getWindow() { return window; }
|
||||
sf::RenderWindow & GameEngine::getWindow() {
|
||||
if (!window) {
|
||||
throw std::runtime_error("Window not available in headless mode");
|
||||
}
|
||||
return *window;
|
||||
}
|
||||
|
||||
sf::RenderTarget & GameEngine::getRenderTarget() {
|
||||
return *render_target;
|
||||
}
|
||||
|
||||
void GameEngine::createScene(std::string s) { scenes[s] = new PyScene(this); }
|
||||
|
||||
void GameEngine::setWindowScale(float multiplier)
|
||||
{
|
||||
window.setSize(sf::Vector2u(1024 * multiplier, 768 * multiplier)); // 7DRL 2024: window scaling
|
||||
if (!headless && window) {
|
||||
window->setSize(sf::Vector2u(1024 * multiplier, 768 * multiplier)); // 7DRL 2024: window scaling
|
||||
}
|
||||
//window.create(sf::VideoMode(1024 * multiplier, 768 * multiplier), window_title, sf::Style::Titlebar | sf::Style::Close);
|
||||
}
|
||||
|
||||
|
|
@ -55,18 +91,40 @@ void GameEngine::run()
|
|||
{
|
||||
currentScene()->update();
|
||||
testTimers();
|
||||
sUserInput();
|
||||
if (!headless) {
|
||||
sUserInput();
|
||||
}
|
||||
if (!paused)
|
||||
{
|
||||
}
|
||||
currentScene()->render();
|
||||
|
||||
// Display the frame
|
||||
if (headless) {
|
||||
headless_renderer->display();
|
||||
// Take screenshot if requested
|
||||
if (config.take_screenshot) {
|
||||
headless_renderer->saveScreenshot(config.screenshot_path.empty() ? "screenshot.png" : config.screenshot_path);
|
||||
config.take_screenshot = false; // Only take one screenshot
|
||||
}
|
||||
} else {
|
||||
window->display();
|
||||
}
|
||||
|
||||
currentFrame++;
|
||||
frameTime = clock.restart().asSeconds();
|
||||
fps = 1 / frameTime;
|
||||
int whole_fps = (int)fps;
|
||||
int tenth_fps = int(fps * 100) % 10;
|
||||
//window.setTitle(window_title + " " + std::to_string(fps) + " FPS");
|
||||
window.setTitle(window_title + " " + std::to_string(whole_fps) + "." + std::to_string(tenth_fps) + " FPS");
|
||||
|
||||
if (!headless && window) {
|
||||
window->setTitle(window_title + " " + std::to_string(whole_fps) + "." + std::to_string(tenth_fps) + " FPS");
|
||||
}
|
||||
|
||||
// In windowed mode, check if window was closed
|
||||
if (!headless && window && !window->isOpen()) {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +169,7 @@ void GameEngine::testTimers()
|
|||
void GameEngine::sUserInput()
|
||||
{
|
||||
sf::Event event;
|
||||
while (window.pollEvent(event))
|
||||
while (window && window->pollEvent(event))
|
||||
{
|
||||
std::string actionType;
|
||||
int actionCode = 0;
|
||||
|
|
|
|||
|
|
@ -6,10 +6,16 @@
|
|||
#include "IndexTexture.h"
|
||||
#include "Timer.h"
|
||||
#include "PyCallable.h"
|
||||
#include "McRogueFaceConfig.h"
|
||||
#include "HeadlessRenderer.h"
|
||||
#include <memory>
|
||||
|
||||
class GameEngine
|
||||
{
|
||||
sf::RenderWindow window;
|
||||
std::unique_ptr<sf::RenderWindow> window;
|
||||
std::unique_ptr<HeadlessRenderer> headless_renderer;
|
||||
sf::RenderTarget* render_target;
|
||||
|
||||
sf::Font font;
|
||||
std::map<std::string, Scene*> scenes;
|
||||
bool running = true;
|
||||
|
|
@ -19,6 +25,9 @@ class GameEngine
|
|||
sf::Clock clock;
|
||||
float frameTime;
|
||||
std::string window_title;
|
||||
|
||||
bool headless = false;
|
||||
McRogueFaceConfig config;
|
||||
|
||||
sf::Clock runtime;
|
||||
//std::map<std::string, Timer> timers;
|
||||
|
|
@ -28,6 +37,8 @@ class GameEngine
|
|||
public:
|
||||
std::string scene;
|
||||
GameEngine();
|
||||
GameEngine(const McRogueFaceConfig& cfg);
|
||||
~GameEngine();
|
||||
Scene* currentScene();
|
||||
void changeScene(std::string);
|
||||
void createScene(std::string);
|
||||
|
|
@ -35,6 +46,7 @@ public:
|
|||
void setPause(bool);
|
||||
sf::Font & getFont();
|
||||
sf::RenderWindow & getWindow();
|
||||
sf::RenderTarget & getRenderTarget();
|
||||
void run();
|
||||
void sUserInput();
|
||||
int getFrame() { return currentFrame; }
|
||||
|
|
@ -42,6 +54,7 @@ public:
|
|||
sf::View getView() { return visible; }
|
||||
void manageTimer(std::string, PyObject*, int);
|
||||
void setWindowScale(float);
|
||||
bool isHeadless() const { return headless; }
|
||||
|
||||
// global textures for scripts to access
|
||||
std::vector<IndexTexture> textures;
|
||||
|
|
|
|||
27
src/HeadlessRenderer.cpp
Normal file
27
src/HeadlessRenderer.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include "HeadlessRenderer.h"
|
||||
#include <iostream>
|
||||
|
||||
bool HeadlessRenderer::init(int width, int height) {
|
||||
if (!render_texture.create(width, height)) {
|
||||
std::cerr << "Failed to create headless render texture" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
sf::RenderTarget& HeadlessRenderer::getRenderTarget() {
|
||||
return render_texture;
|
||||
}
|
||||
|
||||
void HeadlessRenderer::saveScreenshot(const std::string& path) {
|
||||
sf::Image screenshot = render_texture.getTexture().copyToImage();
|
||||
if (!screenshot.saveToFile(path)) {
|
||||
std::cerr << "Failed to save screenshot to: " << path << std::endl;
|
||||
} else {
|
||||
std::cout << "Screenshot saved to: " << path << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void HeadlessRenderer::display() {
|
||||
render_texture.display();
|
||||
}
|
||||
20
src/HeadlessRenderer.h
Normal file
20
src/HeadlessRenderer.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef HEADLESS_RENDERER_H
|
||||
#define HEADLESS_RENDERER_H
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class HeadlessRenderer {
|
||||
private:
|
||||
sf::RenderTexture render_texture;
|
||||
|
||||
public:
|
||||
bool init(int width = 1024, int height = 768);
|
||||
sf::RenderTarget& getRenderTarget();
|
||||
void saveScreenshot(const std::string& path);
|
||||
void display(); // Finalize the current frame
|
||||
bool isOpen() const { return true; } // Always "open" in headless mode
|
||||
};
|
||||
|
||||
#endif // HEADLESS_RENDERER_H
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
#include "GameEngine.h"
|
||||
#include "UI.h"
|
||||
#include "Resources.h"
|
||||
#include <filesystem>
|
||||
#include <cstring>
|
||||
|
||||
std::map<std::string, PyObject*> McRFPy_API::callbacks;
|
||||
std::vector<sf::SoundBuffer> McRFPy_API::soundbuffers;
|
||||
|
|
@ -160,6 +162,68 @@ PyStatus init_python(const char *program_name)
|
|||
return status;
|
||||
}
|
||||
|
||||
PyStatus McRFPy_API::init_python_with_config(const McRogueFaceConfig& config, int argc, char** argv)
|
||||
{
|
||||
PyStatus status;
|
||||
PyConfig pyconfig;
|
||||
PyConfig_InitIsolatedConfig(&pyconfig);
|
||||
|
||||
// CRITICAL: Pass actual command line arguments to Python
|
||||
status = PyConfig_SetBytesArgv(&pyconfig, argc, argv);
|
||||
if (PyStatus_Exception(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
// Check if we're in a virtual environment
|
||||
auto exe_path = std::filesystem::path(argv[0]);
|
||||
auto exe_dir = exe_path.parent_path();
|
||||
auto venv_root = exe_dir.parent_path();
|
||||
|
||||
if (std::filesystem::exists(venv_root / "pyvenv.cfg")) {
|
||||
// We're running from within a venv!
|
||||
// Add venv's site-packages to module search paths
|
||||
auto site_packages = venv_root / "lib" / "python3.12" / "site-packages";
|
||||
PyWideStringList_Append(&pyconfig.module_search_paths,
|
||||
site_packages.wstring().c_str());
|
||||
pyconfig.module_search_paths_set = 1;
|
||||
}
|
||||
|
||||
// Set Python home to our bundled Python
|
||||
auto python_home = executable_path() + L"/lib/Python";
|
||||
PyConfig_SetString(&pyconfig, &pyconfig.home, python_home.c_str());
|
||||
|
||||
// Set up module search paths
|
||||
#if __PLATFORM_SET_PYTHON_SEARCH_PATHS == 1
|
||||
if (!pyconfig.module_search_paths_set) {
|
||||
pyconfig.module_search_paths_set = 1;
|
||||
}
|
||||
|
||||
// search paths for python libs/modules/scripts
|
||||
const wchar_t* str_arr[] = {
|
||||
L"/scripts",
|
||||
L"/lib/Python/lib.linux-x86_64-3.12",
|
||||
L"/lib/Python",
|
||||
L"/lib/Python/Lib",
|
||||
L"/venv/lib/python3.12/site-packages"
|
||||
};
|
||||
|
||||
for(auto s : str_arr) {
|
||||
status = PyWideStringList_Append(&pyconfig.module_search_paths, (executable_path() + s).c_str());
|
||||
if (PyStatus_Exception(status)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Register mcrfpy module before initialization
|
||||
PyImport_AppendInittab("mcrfpy", &PyInit_mcrfpy);
|
||||
|
||||
status = Py_InitializeFromConfig(&pyconfig);
|
||||
PyConfig_Clear(&pyconfig);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
void McRFPy_API::setSpriteTexture(int ti)
|
||||
{
|
||||
|
|
@ -200,6 +264,33 @@ void McRFPy_API::api_init() {
|
|||
//setSpriteTexture(0);
|
||||
}
|
||||
|
||||
void McRFPy_API::api_init(const McRogueFaceConfig& config, int argc, char** argv) {
|
||||
// Initialize Python with proper argv - this is CRITICAL
|
||||
PyStatus status = init_python_with_config(config, argc, argv);
|
||||
if (PyStatus_Exception(status)) {
|
||||
Py_ExitStatusException(status);
|
||||
}
|
||||
|
||||
McRFPy_API::mcrf_module = PyImport_ImportModule("mcrfpy");
|
||||
|
||||
// For -m module execution, let Python handle it
|
||||
if (!config.python_module.empty() && config.python_module != "venv") {
|
||||
// Py_RunMain() will handle -m execution
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute based on mode - this is handled in main.cpp now
|
||||
// The actual execution logic is in run_python_interpreter()
|
||||
|
||||
// Set up default resources only if in game mode
|
||||
if (!config.python_mode) {
|
||||
//PyModule_AddObject(McRFPy_API::mcrf_module, "default_font", McRFPy_API::default_font->pyObject());
|
||||
PyObject_SetAttrString(McRFPy_API::mcrf_module, "default_font", McRFPy_API::default_font->pyObject());
|
||||
//PyModule_AddObject(McRFPy_API::mcrf_module, "default_texture", McRFPy_API::default_texture->pyObject());
|
||||
PyObject_SetAttrString(McRFPy_API::mcrf_module, "default_texture", McRFPy_API::default_texture->pyObject());
|
||||
}
|
||||
}
|
||||
|
||||
void McRFPy_API::executeScript(std::string filename)
|
||||
{
|
||||
FILE* PScriptFile = fopen(filename.c_str(), "r");
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "PyFont.h"
|
||||
#include "PyTexture.h"
|
||||
#include "McRogueFaceConfig.h"
|
||||
|
||||
class GameEngine; // forward declared (circular members)
|
||||
|
||||
|
|
@ -27,6 +28,8 @@ public:
|
|||
//static void setSpriteTexture(int);
|
||||
inline static GameEngine* game;
|
||||
static void api_init();
|
||||
static void api_init(const McRogueFaceConfig& config, int argc, char** argv);
|
||||
static PyStatus init_python_with_config(const McRogueFaceConfig& config, int argc, char** argv);
|
||||
static void api_shutdown();
|
||||
// Python API functionality - use mcrfpy.* in scripts
|
||||
//static PyObject* _drawSprite(PyObject*, PyObject*);
|
||||
|
|
|
|||
30
src/McRogueFaceConfig.h
Normal file
30
src/McRogueFaceConfig.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef MCROGUEFACE_CONFIG_H
|
||||
#define MCROGUEFACE_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
struct McRogueFaceConfig {
|
||||
// McRogueFace specific
|
||||
bool headless = false;
|
||||
bool audio_enabled = true;
|
||||
|
||||
// Python interpreter emulation
|
||||
bool python_mode = false;
|
||||
std::string python_command; // -c command
|
||||
std::string python_module; // -m module
|
||||
bool interactive_mode = false; // -i flag
|
||||
bool show_version = false; // -V flag
|
||||
bool show_help = false; // -h flag
|
||||
|
||||
// Script execution
|
||||
std::filesystem::path script_path;
|
||||
std::vector<std::string> script_args;
|
||||
|
||||
// Screenshot functionality for headless mode
|
||||
std::string screenshot_path;
|
||||
bool take_screenshot = false;
|
||||
};
|
||||
|
||||
#endif // MCROGUEFACE_CONFIG_H
|
||||
|
|
@ -21,6 +21,11 @@ void PyScene::update()
|
|||
|
||||
void PyScene::do_mouse_input(std::string button, std::string type)
|
||||
{
|
||||
// In headless mode, mouse input is not available
|
||||
if (game->isHeadless()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto unscaledmousepos = sf::Mouse::getPosition(game->getWindow());
|
||||
auto mousepos = game->getWindow().mapPixelToCoords(unscaledmousepos);
|
||||
UIDrawable* target;
|
||||
|
|
@ -62,7 +67,7 @@ void PyScene::doAction(std::string name, std::string type)
|
|||
|
||||
void PyScene::render()
|
||||
{
|
||||
game->getWindow().clear();
|
||||
game->getRenderTarget().clear();
|
||||
|
||||
auto vec = *ui_elements;
|
||||
for (auto e: vec)
|
||||
|
|
@ -71,5 +76,5 @@ void PyScene::render()
|
|||
e->render();
|
||||
}
|
||||
|
||||
game->getWindow().display();
|
||||
// Display is handled by GameEngine
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ void UIDrawable::click_unregister()
|
|||
|
||||
void UIDrawable::render()
|
||||
{
|
||||
render(sf::Vector2f(), Resources::game->getWindow());
|
||||
render(sf::Vector2f(), Resources::game->getRenderTarget());
|
||||
}
|
||||
|
||||
PyObject* UIDrawable::get_click(PyObject* self, void* closure) {
|
||||
|
|
|
|||
|
|
@ -156,8 +156,8 @@ void UITestScene::doAction(std::string name, std::string type)
|
|||
|
||||
void UITestScene::render()
|
||||
{
|
||||
game->getWindow().clear();
|
||||
game->getWindow().draw(text);
|
||||
game->getRenderTarget().clear();
|
||||
game->getRenderTarget().draw(text);
|
||||
|
||||
// draw all UI elements
|
||||
//for (auto e: ui_elements)
|
||||
|
|
@ -175,7 +175,7 @@ void UITestScene::render()
|
|||
|
||||
//e1.render(sf::Vector2f(-100, -100));
|
||||
|
||||
game->getWindow().display();
|
||||
// Display is handled by GameEngine
|
||||
|
||||
//McRFPy_API::REPL();
|
||||
}
|
||||
|
|
|
|||
115
src/main.cpp
115
src/main.cpp
|
|
@ -1,8 +1,117 @@
|
|||
#include <SFML/Graphics.hpp>
|
||||
#include "GameEngine.h"
|
||||
#include "CommandLineParser.h"
|
||||
#include "McRogueFaceConfig.h"
|
||||
#include "McRFPy_API.h"
|
||||
#include <Python.h>
|
||||
#include <iostream>
|
||||
#include <filesystem>
|
||||
|
||||
int main()
|
||||
// Forward declarations
|
||||
int run_game_engine(const McRogueFaceConfig& config);
|
||||
int run_python_interpreter(const McRogueFaceConfig& config, int argc, char* argv[]);
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
GameEngine g;
|
||||
g.run();
|
||||
McRogueFaceConfig config;
|
||||
CommandLineParser parser(argc, argv);
|
||||
|
||||
// Parse arguments
|
||||
auto parse_result = parser.parse(config);
|
||||
if (parse_result.should_exit) {
|
||||
return parse_result.exit_code;
|
||||
}
|
||||
|
||||
// Special handling for -m module: let Python handle modules properly
|
||||
if (!config.python_module.empty()) {
|
||||
config.python_mode = true;
|
||||
}
|
||||
|
||||
// Initialize based on configuration
|
||||
if (config.python_mode) {
|
||||
return run_python_interpreter(config, argc, argv);
|
||||
} else {
|
||||
return run_game_engine(config);
|
||||
}
|
||||
}
|
||||
|
||||
int run_game_engine(const McRogueFaceConfig& config)
|
||||
{
|
||||
GameEngine g(config);
|
||||
g.run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int run_python_interpreter(const McRogueFaceConfig& config, int argc, char* argv[])
|
||||
{
|
||||
// Initialize Python with configuration
|
||||
McRFPy_API::init_python_with_config(config, argc, argv);
|
||||
|
||||
// Handle different Python modes
|
||||
if (!config.python_command.empty()) {
|
||||
// Execute command from -c
|
||||
int result = PyRun_SimpleString(config.python_command.c_str());
|
||||
Py_Finalize();
|
||||
return result;
|
||||
}
|
||||
else if (!config.python_module.empty()) {
|
||||
// Execute module using runpy
|
||||
std::string run_module_code =
|
||||
"import sys\n"
|
||||
"import runpy\n"
|
||||
"sys.argv = ['" + config.python_module + "'";
|
||||
|
||||
for (const auto& arg : config.script_args) {
|
||||
run_module_code += ", '" + arg + "'";
|
||||
}
|
||||
run_module_code += "]\n";
|
||||
run_module_code += "runpy.run_module('" + config.python_module + "', run_name='__main__', alter_sys=True)\n";
|
||||
|
||||
int result = PyRun_SimpleString(run_module_code.c_str());
|
||||
Py_Finalize();
|
||||
return result;
|
||||
}
|
||||
else if (!config.script_path.empty()) {
|
||||
// Execute script file
|
||||
FILE* fp = fopen(config.script_path.string().c_str(), "r");
|
||||
if (!fp) {
|
||||
std::cerr << "mcrogueface: can't open file '" << config.script_path << "': ";
|
||||
std::cerr << "[Errno " << errno << "] " << strerror(errno) << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set up sys.argv
|
||||
wchar_t** python_argv = new wchar_t*[config.script_args.size() + 1];
|
||||
python_argv[0] = Py_DecodeLocale(config.script_path.string().c_str(), nullptr);
|
||||
for (size_t i = 0; i < config.script_args.size(); i++) {
|
||||
python_argv[i + 1] = Py_DecodeLocale(config.script_args[i].c_str(), nullptr);
|
||||
}
|
||||
PySys_SetArgvEx(config.script_args.size() + 1, python_argv, 0);
|
||||
|
||||
int result = PyRun_SimpleFile(fp, config.script_path.string().c_str());
|
||||
fclose(fp);
|
||||
|
||||
// Clean up
|
||||
for (size_t i = 0; i <= config.script_args.size(); i++) {
|
||||
PyMem_RawFree(python_argv[i]);
|
||||
}
|
||||
delete[] python_argv;
|
||||
|
||||
if (config.interactive_mode && result == 0) {
|
||||
// Run interactive mode after script
|
||||
PyRun_InteractiveLoop(stdin, "<stdin>");
|
||||
}
|
||||
|
||||
Py_Finalize();
|
||||
return result;
|
||||
}
|
||||
else if (config.interactive_mode || config.python_mode) {
|
||||
// Interactive Python interpreter
|
||||
Py_InspectFlag = 1;
|
||||
PyRun_InteractiveLoop(stdin, "<stdin>");
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue