Add Lua scripting support to desktop emulator
- Created emulator-specific lua_game_emulator.cpp using filesystem instead of FatFS - Created lua_game_loader_emulator.cpp to scan games/lua_examples directory - Updated CMakeLists.txt to include Lua 5.4 engine and bindings - Updated to SFML 3.0 API compatibility (event handling, sprite initialization) - Updated Game class to use public members for Lua bindings - Updated GameLauncher to use std::function for lambda captures - Added continuous 60 FPS rendering for smooth display - Emulator now loads and runs all three example Lua games
This commit is contained in:
159
emulator/lua_game_loader_emulator.cpp
Normal file
159
emulator/lua_game_loader_emulator.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
// ============================================================================
|
||||
// LUA GAME LOADER - EMULATOR IMPLEMENTATION
|
||||
// ============================================================================
|
||||
// Discovers Lua scripts from filesystem and integrates with game launcher
|
||||
|
||||
#include "../games/lua_game_loader.h"
|
||||
#include "../games/lua_game.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// Structure to hold script path for factory closure
|
||||
struct LuaGameFactoryData {
|
||||
char script_path[256];
|
||||
};
|
||||
|
||||
static std::vector<LuaGameFactoryData*> factory_data_list;
|
||||
|
||||
bool LuaGameLoader::parse_metadata(const char* script_path, char* name, char* description) {
|
||||
// Default name from filename
|
||||
fs::path path(script_path);
|
||||
std::string filename = path.stem().string(); // Get filename without extension
|
||||
strncpy(name, filename.c_str(), 63);
|
||||
name[63] = '\0';
|
||||
|
||||
// Default empty description
|
||||
description[0] = '\0';
|
||||
|
||||
// Try to open file and parse metadata comments
|
||||
std::ifstream file(script_path);
|
||||
if (!file.is_open()) {
|
||||
printf("LuaGameLoader: Warning - could not open %s for metadata\n", script_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read first 512 bytes to look for metadata comments
|
||||
char buffer[512];
|
||||
file.read(buffer, sizeof(buffer) - 1);
|
||||
std::streamsize bytes_read = file.gcount();
|
||||
file.close();
|
||||
|
||||
if (bytes_read == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer[bytes_read] = '\0';
|
||||
|
||||
// Parse metadata comments: -- NAME: Game Name
|
||||
char* line = buffer;
|
||||
while (line && (line - buffer) < bytes_read) {
|
||||
char* next_line = strchr(line, '\n');
|
||||
if (next_line) *next_line = '\0';
|
||||
|
||||
// Check for -- NAME:
|
||||
if (strncmp(line, "-- NAME:", 8) == 0) {
|
||||
const char* value = line + 8;
|
||||
while (*value == ' ') value++; // Skip spaces
|
||||
strncpy(name, value, 63);
|
||||
name[63] = '\0';
|
||||
}
|
||||
// Check for -- DESC:
|
||||
else if (strncmp(line, "-- DESC:", 8) == 0) {
|
||||
const char* value = line + 8;
|
||||
while (*value == ' ') value++;
|
||||
strncpy(description, value, 127);
|
||||
description[127] = '\0';
|
||||
}
|
||||
|
||||
if (next_line) {
|
||||
line = next_line + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int LuaGameLoader::register_all_games(GameLauncher* launcher) {
|
||||
int count = 0;
|
||||
|
||||
printf("LuaGameLoader: Scanning games/lua_examples directory for .lua scripts...\n");
|
||||
|
||||
// Path to lua examples relative to emulator binary
|
||||
const char* search_paths[] = {
|
||||
"../games/lua_examples",
|
||||
"games/lua_examples",
|
||||
"./lua_examples"
|
||||
};
|
||||
|
||||
fs::path games_dir;
|
||||
bool found_dir = false;
|
||||
|
||||
// Try to find the lua_examples directory
|
||||
for (const char* search_path : search_paths) {
|
||||
if (fs::exists(search_path) && fs::is_directory(search_path)) {
|
||||
games_dir = fs::path(search_path);
|
||||
found_dir = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_dir) {
|
||||
printf("LuaGameLoader: Could not find games/lua_examples directory\n");
|
||||
printf("LuaGameLoader: Tried: ../games/lua_examples, games/lua_examples, ./lua_examples\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("LuaGameLoader: Found directory: %s\n", games_dir.string().c_str());
|
||||
|
||||
// Scan for .lua files
|
||||
try {
|
||||
for (const auto& entry : fs::directory_iterator(games_dir)) {
|
||||
if (!entry.is_regular_file()) continue;
|
||||
|
||||
// Check for .lua extension
|
||||
if (entry.path().extension() != ".lua") continue;
|
||||
|
||||
std::string script_path = entry.path().string();
|
||||
|
||||
// Parse metadata
|
||||
char name[64];
|
||||
char description[128];
|
||||
parse_metadata(script_path.c_str(), name, description);
|
||||
|
||||
printf("LuaGameLoader: Found %s - '%s'\n", entry.path().filename().string().c_str(), name);
|
||||
|
||||
// Create factory data (persistent for game lifetime)
|
||||
LuaGameFactoryData* data = new LuaGameFactoryData();
|
||||
strncpy(data->script_path, script_path.c_str(), sizeof(data->script_path) - 1);
|
||||
data->script_path[sizeof(data->script_path) - 1] = '\0';
|
||||
factory_data_list.push_back(data);
|
||||
|
||||
// Register with launcher - using lambda factory pattern
|
||||
launcher->register_game(
|
||||
name,
|
||||
description[0] ? description : "Lua Script",
|
||||
[data](uint16_t width, uint16_t height, LowLevelRenderer* renderer,
|
||||
LowLevelGUI* gui, InputManager* input_manager) -> Game* {
|
||||
return new LuaGame(data->script_path, width, height, renderer, gui, input_manager);
|
||||
}
|
||||
);
|
||||
|
||||
count++;
|
||||
}
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
printf("LuaGameLoader: Error scanning directory: %s\n", e.what());
|
||||
return count;
|
||||
}
|
||||
|
||||
printf("LuaGameLoader: Registered %d Lua games\n", count);
|
||||
return count;
|
||||
}
|
||||
Reference in New Issue
Block a user