From a337b9002f5f48c5b734d5593db22384b3acba6e Mon Sep 17 00:00:00 2001 From: Nick Koirala Date: Thu, 6 Nov 2025 14:37:35 +1300 Subject: [PATCH] feat: improve logging output, add #include support to AngelScript --- CMakeLists.txt | 13 +++++++ include/ScriptBindings.h | 2 +- include/ScriptEngine.h | 2 + scripts/test.as | 8 +--- scripts/update.as | 10 +++++ src/ScriptBindings.cpp | 31 +++++++++++++-- src/ScriptEngine.cpp | 84 +++++++++++++++++++++++++++++++++------- src/log/log.c | 24 ++++++++++-- 8 files changed, 146 insertions(+), 28 deletions(-) create mode 100644 scripts/update.as diff --git a/CMakeLists.txt b/CMakeLists.txt index d60dd8f..29afaa0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,17 @@ target_include_directories(scriptstdstring PUBLIC external/angelscript/sdk/angelscript/include ) +# ------------------------- +# 3️⃣.1️⃣ scriptbuilder add-on +# ------------------------- +add_library(scriptbuilder STATIC + external/angelscript/sdk/add_on/scriptbuilder/scriptbuilder.cpp +) + +target_include_directories(scriptbuilder + PUBLIC external/angelscript/sdk/angelscript/include +) + # ------------------------- # 4️⃣ Main executable # ------------------------- @@ -43,12 +54,14 @@ target_include_directories(simian PUBLIC external/raylib/src external/angelscript/sdk/angelscript/include external/angelscript/sdk/add_on/scriptstdstring + external/angelscript/sdk/add_on/scriptbuilder ) target_link_libraries(simian raylib angelscript scriptstdstring + scriptbuilder ) # ------------------------- diff --git a/include/ScriptBindings.h b/include/ScriptBindings.h index 7a96483..388e0f5 100644 --- a/include/ScriptBindings.h +++ b/include/ScriptBindings.h @@ -7,6 +7,6 @@ public: static void RegisterAll(asIScriptEngine* engine); private: - static void Print(const std::string &msg); + static void Print(asIScriptGeneric* gen); static void AS_DrawText(const std::string &text, int x, int y, int fontSize, unsigned int color); }; \ No newline at end of file diff --git a/include/ScriptEngine.h b/include/ScriptEngine.h index b6f294f..f083941 100644 --- a/include/ScriptEngine.h +++ b/include/ScriptEngine.h @@ -1,5 +1,6 @@ #pragma once #include "angelscript.h" +#include "scriptbuilder.h" #include class ScriptEngine { @@ -25,6 +26,7 @@ private: bool hasValidScript; static void MessageCallback(const asSMessageInfo* msg, void* param); + static int IncludeCallback(const char* include, const char* from, CScriptBuilder* builder, void* userParam); std::string ReadFile(const std::string& filename); void ClearCachedFunctions(); }; \ No newline at end of file diff --git a/scripts/test.as b/scripts/test.as index 209cfb9..734eb8f 100644 --- a/scripts/test.as +++ b/scripts/test.as @@ -1,10 +1,4 @@ -float x = 50; -float y = 100; - -void Update(float dt) { - x += 50 * dt; - if (x > 800) x = 0; -} +#include "update.as" void Draw() { DrawText("Hello from AngelScript - Working perfectly!", int(x), int(y), 20, 0xFF0000FF); diff --git a/scripts/update.as b/scripts/update.as new file mode 100644 index 0000000..2c9c18f --- /dev/null +++ b/scripts/update.as @@ -0,0 +1,10 @@ +float x = 50; +float y = 100; + +void Update(float dt) { + x += 50 * dt; + if (x > 800) { + x = 0; + Print("X position reset!"); + } +} \ No newline at end of file diff --git a/src/ScriptBindings.cpp b/src/ScriptBindings.cpp index 57376bf..60f1f8a 100644 --- a/src/ScriptBindings.cpp +++ b/src/ScriptBindings.cpp @@ -5,9 +5,9 @@ #include "log/log.h" void ScriptBindings::RegisterAll(asIScriptEngine* engine) { - // Register Print function + // Register Print function with generic calling convention to access context int r = engine->RegisterGlobalFunction("void Print(const string &in)", - asFUNCTION(Print), asCALL_CDECL); + asFUNCTION(Print), asCALL_GENERIC); assert(r >= 0); // Register DrawText function @@ -16,8 +16,31 @@ void ScriptBindings::RegisterAll(asIScriptEngine* engine) { assert(r >= 0); } -void ScriptBindings::Print(const std::string &msg) { - log_info("%s", msg.c_str()); +void ScriptBindings::Print(asIScriptGeneric* gen) { + // Get the message parameter + std::string* msg = static_cast(gen->GetArgObject(0)); + + // Get the active context to retrieve script file and line number + asIScriptContext* ctx = asGetActiveContext(); + + if (ctx) { + const char* section = nullptr; + int line = 0; + + // Get the current line number and script section + line = ctx->GetLineNumber(0, nullptr, §ion); + + if (section && line > 0) { + // Log with script file and line number + log_log(LOG_INFO, section, line, "%s", msg->c_str()); + } else { + // Fallback if we can't get the info + log_info("%s", msg->c_str()); + } + } else { + // No context available, just log normally + log_info("%s", msg->c_str()); + } } Color ColorFromUInt(unsigned int c) { diff --git a/src/ScriptEngine.cpp b/src/ScriptEngine.cpp index cf02f6a..969ccd5 100644 --- a/src/ScriptEngine.cpp +++ b/src/ScriptEngine.cpp @@ -1,8 +1,10 @@ #include "ScriptEngine.h" #include "ScriptBindings.h" #include "scriptstdstring.h" +#include "scriptbuilder.h" #include #include +#include #include #include "log/log.h" @@ -49,23 +51,24 @@ void ScriptEngine::Shutdown() { bool ScriptEngine::CompileScript(const std::string& filename) { if (!engine) return false; - std::string code = ReadFile(filename); - if (code.empty()) { - log_error("Failed to read script file: %s", filename.c_str()); + // Try to compile in a temporary module first using CScriptBuilder + CScriptBuilder tempBuilder; + tempBuilder.SetIncludeCallback(IncludeCallback, nullptr); + + int r = tempBuilder.StartNewModule(engine, "temp"); + if (r < 0) { + log_error("Failed to start new temp module"); return false; } - // Try to compile in a temporary module first - asIScriptModule* tempMod = engine->GetModule("temp", asGM_ALWAYS_CREATE); - - int r = tempMod->AddScriptSection(filename.c_str(), code.c_str()); + r = tempBuilder.AddSectionFromFile(filename.c_str()); if (r < 0) { - log_error("Failed to add script section for: %s", filename.c_str()); + log_error("Failed to add script section from file: %s", filename.c_str()); engine->DiscardModule("temp"); return false; } - r = tempMod->Build(); + r = tempBuilder.BuildModule(); if (r < 0) { log_error("Failed to build script: %s", filename.c_str()); engine->DiscardModule("temp"); @@ -78,11 +81,16 @@ bool ScriptEngine::CompileScript(const std::string& filename) { engine->DiscardModule("main"); } - // Create new main module with the working code - currentModule = engine->GetModule("main", asGM_ALWAYS_CREATE); - r = currentModule->AddScriptSection(filename.c_str(), code.c_str()); + // Create new main module with the working code using CScriptBuilder + CScriptBuilder mainBuilder; + mainBuilder.SetIncludeCallback(IncludeCallback, nullptr); + + r = mainBuilder.StartNewModule(engine, "main"); if (r >= 0) { - r = currentModule->Build(); + r = mainBuilder.AddSectionFromFile(filename.c_str()); + } + if (r >= 0) { + r = mainBuilder.BuildModule(); } // Clean up temp module @@ -95,6 +103,9 @@ bool ScriptEngine::CompileScript(const std::string& filename) { return false; } + // Get the newly created module + currentModule = engine->GetModule("main"); + // Cache new functions updateFunc = currentModule->GetFunctionByName("Update"); drawFunc = currentModule->GetFunctionByName("Draw"); @@ -152,6 +163,53 @@ void ScriptEngine::MessageCallback(const asSMessageInfo* msg, void*) { } } +int ScriptEngine::IncludeCallback(const char* include, const char* from, CScriptBuilder* builder, void* userParam) { + // Extract just the filename from the from path for cleaner logging + const char* fromFile = from; + if (from) { + const char* lastSlash = strrchr(from, '/'); + const char* lastBackslash = strrchr(from, '\\'); + const char* lastSep = (lastSlash > lastBackslash) ? lastSlash : lastBackslash; + if (lastSep) { + fromFile = lastSep + 1; + } + } + + // Log the include request with clean filenames + log_info("Including: %s (from: %s)", include, fromFile ? fromFile : "main"); + + // Build the full path relative to the including file's directory + std::string fullPath; + + if (from && strlen(from) > 0) { + // Extract directory from the 'from' path + std::string fromPath(from); + size_t lastSlash = fromPath.find_last_of("/\\"); + + if (lastSlash != std::string::npos) { + // Get the directory part + std::string directory = fromPath.substr(0, lastSlash + 1); + fullPath = directory + include; + } else { + // No directory in from path, use include as-is + fullPath = include; + } + } else { + fullPath = include; + } + + // Try to add the included file + int r = builder->AddSectionFromFile(fullPath.c_str()); + + if (r < 0) { + log_error("Failed to include file: %s (tried path: %s)", include, fullPath.c_str()); + } else { + log_info("Successfully included: %s", include); + } + + return r; +} + std::string ScriptEngine::ReadFile(const std::string& filename) { std::ifstream file(filename); if (!file) return ""; diff --git a/src/log/log.c b/src/log/log.c index ffc1a8a..fd30a59 100644 --- a/src/log/log.c +++ b/src/log/log.c @@ -24,6 +24,24 @@ #define MAX_CALLBACKS 32 +// Helper function to extract just the filename from a full path +static const char* get_filename(const char* path) { + if (!path) return ""; + + const char* filename = path; + const char* p = path; + + // Find the last '/' or '\' in the path + while (*p) { + if (*p == '/' || *p == '\\') { + filename = p + 1; + } + p++; + } + + return filename; +} + typedef struct { log_LogFn fn; @@ -58,7 +76,7 @@ static void stdout_callback(log_Event *ev) fprintf( ev->udata, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", buf, level_colors[ev->level], level_strings[ev->level], - ev->file, ev->line); + get_filename(ev->file), ev->line); } else { @@ -71,7 +89,7 @@ static void stdout_callback(log_Event *ev) { fprintf( ev->udata, "%s %-5s %s:%d: ", - buf, level_strings[ev->level], ev->file, ev->line); + buf, level_strings[ev->level], get_filename(ev->file), ev->line); } else { @@ -92,7 +110,7 @@ static void file_callback(log_Event *ev) buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ev->time)] = '\0'; if (ev->file) { - fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], ev->file, ev->line); + fprintf(ev->udata, "%s %-5s %s:%d: ", buf, level_strings[ev->level], get_filename(ev->file), ev->line); } else {