#include #include #include #include #include "raylib.h" #include "angelscript.h" #include "scriptstdstring.h" #include #include #include namespace fs = std::filesystem; asIScriptEngine* engine = nullptr; std::string scriptFile = "scripts/test.as"; std::time_t lastWriteTime = 0; // Cached script functions asIScriptFunction* updateFunc = nullptr; asIScriptFunction* drawFunc = nullptr; // ------------------------- // Functions exposed to AngelScript // ------------------------- void Print(const std::string &msg) { std::cout << "[Script] " << msg << std::endl; } Color ColorFromUInt(unsigned int c) { Color col; col.r = (c >> 24) & 0xFF; col.g = (c >> 16) & 0xFF; col.b = (c >> 8) & 0xFF; col.a = c & 0xFF; return col; } void AS_DrawText(const std::string &text, int x, int y, int fontSize, unsigned int color) { DrawText(text.c_str(), x, y, fontSize, ColorFromUInt(color)); } // ------------------------- // AngelScript message callback // ------------------------- void AngelScriptMessageCallback(const asSMessageInfo* msg, void* param) { std::cout << msg->section << " (" << msg->row << "): " << msg->message << std::endl; } // ------------------------- // Utility to read script files // ------------------------- std::string ReadFile(const std::string &filename) { std::ifstream file(filename); if (!file) return ""; std::stringstream ss; ss << file.rdbuf(); return ss.str(); } // ------------------------- // Compile script and cache Update/Draw // ------------------------- bool compileScript(const std::string& filename) { engine->GarbageCollect(); asIScriptModule* mod = engine->GetModule("main", asGM_ALWAYS_CREATE); std::string code = ReadFile(filename); if (code.empty()) { std::cerr << "Failed to read script file: " << filename << "\n"; return false; } int r = mod->AddScriptSection(filename.c_str(), code.c_str()); if (r < 0) return false; r = mod->Build(); if (r < 0) return false; // Cache Update(float dt) and Draw() functions if they exist updateFunc = mod->GetFunctionByName("Update"); drawFunc = mod->GetFunctionByName("Draw"); std::cout << "Script compiled and cached: " << filename << "\n"; return true; } // ------------------------- // Hot reload check // ------------------------- void checkHotReload() { auto ftime = fs::last_write_time(scriptFile); auto sctp = std::chrono::time_point_cast(ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now()); std::time_t t = std::chrono::system_clock::to_time_t(sctp); if (t != lastWriteTime) { lastWriteTime = t; compileScript(scriptFile); } } // ------------------------- // Call a cached script function // ------------------------- void callScriptFunction(asIScriptFunction* func, float dt = 0.0f) { if (!func) return; asIScriptContext* ctx = engine->CreateContext(); ctx->Prepare(func); if (func->GetParamCount() == 1) { ctx->SetArgFloat(0, dt); } ctx->Execute(); ctx->Release(); } // ------------------------- // Main // ------------------------- int main() { // Initialize Raylib InitWindow(800, 600, "Raylib + AngelScript"); SetTargetFPS(60); // Initialize AngelScript engine = asCreateScriptEngine(); assert(engine); RegisterStdString(engine); engine->RegisterGlobalFunction("void DrawText(const string &in, int, int, int, uint)", asFUNCTION(AS_DrawText), asCALL_CDECL); int r = engine->SetMessageCallback(asFUNCTION(AngelScriptMessageCallback), nullptr, asCALL_CDECL); assert(r >= 0); r = engine->RegisterGlobalFunction("void Print(const string &in)", asFUNCTION(Print), asCALL_CDECL); assert(r >= 0); compileScript(scriptFile); // Main loop while (!WindowShouldClose()) { float dt = GetFrameTime(); checkHotReload(); callScriptFunction(updateFunc, dt); BeginDrawing(); ClearBackground(RAYWHITE); DrawText("Modify scripts/test.as to hot-reload!", 50, 50, 20, DARKGRAY); callScriptFunction(drawFunc); EndDrawing(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } CloseWindow(); engine->ShutDownAndRelease(); }