Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 529e51009c | |||
| 2e958fa1ec |
Vendored
+2
-1
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"*.h": "c",
|
||||
"xstring": "cpp"
|
||||
"xstring": "cpp",
|
||||
"iostream": "cpp"
|
||||
}
|
||||
}
|
||||
+14
-2
@@ -25,8 +25,18 @@ target_include_directories(scriptstdstring
|
||||
PUBLIC external/angelscript/sdk/angelscript/include
|
||||
)
|
||||
|
||||
# ------------------------
|
||||
# debugger add-on
|
||||
# ------------------------
|
||||
add_library(debugger STATIC
|
||||
external/angelscript/sdk/add_on/debugger/debugger.cpp
|
||||
)
|
||||
|
||||
target_include_directories(debugger PUBLIC
|
||||
external/angelscript/sdk/angelscript/include
|
||||
)
|
||||
# -------------------------
|
||||
# 3️⃣.1️⃣ scriptbuilder add-on
|
||||
# scriptbuilder add-on
|
||||
# -------------------------
|
||||
add_library(scriptbuilder STATIC
|
||||
external/angelscript/sdk/add_on/scriptbuilder/scriptbuilder.cpp
|
||||
@@ -37,7 +47,7 @@ target_include_directories(scriptbuilder
|
||||
)
|
||||
|
||||
# -------------------------
|
||||
# 4️⃣ Main executable
|
||||
# Main executable
|
||||
# -------------------------
|
||||
add_executable(simian
|
||||
main.cpp
|
||||
@@ -55,6 +65,7 @@ target_include_directories(simian PUBLIC
|
||||
external/angelscript/sdk/angelscript/include
|
||||
external/angelscript/sdk/add_on/scriptstdstring
|
||||
external/angelscript/sdk/add_on/scriptbuilder
|
||||
external/angelscript/sdk/add_on/debugger
|
||||
)
|
||||
|
||||
target_link_libraries(simian
|
||||
@@ -62,6 +73,7 @@ target_link_libraries(simian
|
||||
angelscript
|
||||
scriptstdstring
|
||||
scriptbuilder
|
||||
debugger
|
||||
)
|
||||
|
||||
# -------------------------
|
||||
|
||||
+4
-10
@@ -5,20 +5,14 @@
|
||||
|
||||
class HotReload {
|
||||
public:
|
||||
// Accept either a single script file or a directory to watch. If a directory is
|
||||
// provided, any change to any file in the directory will trigger a reload.
|
||||
HotReload(const std::string& pathToWatch);
|
||||
|
||||
HotReload(const std::string& filename);
|
||||
|
||||
bool CheckForChanges();
|
||||
void UpdateLastWriteTime();
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
std::string scriptFile;
|
||||
std::time_t lastWriteTime;
|
||||
|
||||
|
||||
std::time_t GetFileWriteTime(const std::string& filename);
|
||||
// Return the most recent write time found in the watched path. If `path` is a
|
||||
// directory, this scans all files (non-recursive) and returns the newest
|
||||
// modification time. If it's a file, it returns that file's write time.
|
||||
std::time_t GetLatestWriteTimeInPath();
|
||||
};
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "angelscript.h"
|
||||
#include "scriptbuilder.h"
|
||||
#include <string>
|
||||
#include "debugger.h"
|
||||
|
||||
class ScriptEngine {
|
||||
public:
|
||||
@@ -17,6 +18,8 @@ public:
|
||||
asIScriptEngine* GetEngine() const { return engine; }
|
||||
asIScriptFunction* GetUpdateFunction() const { return updateFunc; }
|
||||
asIScriptFunction* GetDrawFunction() const { return drawFunc; }
|
||||
void AddFileBreakPoint(const std::string& file, int line);
|
||||
void AddFuncBreakPoint(const std::string& func);
|
||||
|
||||
private:
|
||||
asIScriptEngine* engine;
|
||||
@@ -24,6 +27,7 @@ private:
|
||||
asIScriptFunction* drawFunc;
|
||||
asIScriptModule* currentModule;
|
||||
bool hasValidScript;
|
||||
CDebugger* debugger = nullptr;
|
||||
|
||||
static void MessageCallback(const asSMessageInfo* msg, void* param);
|
||||
static int IncludeCallback(const char* include, const char* from, CScriptBuilder* builder, void* userParam);
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ float x = 50;
|
||||
float y = 100;
|
||||
|
||||
void Update(float dt) {
|
||||
x += 500 * dt;
|
||||
x += 50 * dt;
|
||||
if (x > 800) {
|
||||
x = 0;
|
||||
Print("X position reset!");
|
||||
@@ -10,4 +10,4 @@ void Update(float dt) {
|
||||
Log(LOG_WARNING, "Log WARNING: reset happened");
|
||||
Log(LOG_ERROR, "Log ERROR: reset happened");
|
||||
}
|
||||
}//
|
||||
}
|
||||
+2
-9
@@ -2,7 +2,6 @@
|
||||
#include "raylib.h"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <filesystem>
|
||||
#include "log/log.h"
|
||||
const char* Application::WINDOW_TITLE = "Raylib + AngelScript";
|
||||
const char* Application::SCRIPT_FILE = "scripts/test.as";
|
||||
@@ -29,14 +28,8 @@ bool Application::Initialize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize hot reload to watch the scripts directory so any script change
|
||||
// (not just the main file) triggers a reload.
|
||||
{
|
||||
std::filesystem::path p(SCRIPT_FILE);
|
||||
std::string watchPath = p.parent_path().string();
|
||||
if (watchPath.empty()) watchPath = ".";
|
||||
hotReload = new HotReload(watchPath);
|
||||
}
|
||||
// Initialize hot reload
|
||||
hotReload = new HotReload(SCRIPT_FILE);
|
||||
|
||||
// Compile initial script
|
||||
scriptCompilationError = !scriptEngine.CompileScript(SCRIPT_FILE);
|
||||
|
||||
+5
-29
@@ -3,21 +3,21 @@
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
HotReload::HotReload(const std::string& pathToWatch) : path(pathToWatch), lastWriteTime(0) {
|
||||
HotReload::HotReload(const std::string& filename) : scriptFile(filename), lastWriteTime(0) {
|
||||
UpdateLastWriteTime();
|
||||
}
|
||||
|
||||
bool HotReload::CheckForChanges() {
|
||||
std::time_t current = GetLatestWriteTimeInPath();
|
||||
if (current != lastWriteTime) {
|
||||
lastWriteTime = current;
|
||||
std::time_t currentWriteTime = GetFileWriteTime(scriptFile);
|
||||
if (currentWriteTime != lastWriteTime) {
|
||||
lastWriteTime = currentWriteTime;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HotReload::UpdateLastWriteTime() {
|
||||
lastWriteTime = GetLatestWriteTimeInPath();
|
||||
lastWriteTime = GetFileWriteTime(scriptFile);
|
||||
}
|
||||
|
||||
std::time_t HotReload::GetFileWriteTime(const std::string& filename) {
|
||||
@@ -29,28 +29,4 @@ std::time_t HotReload::GetFileWriteTime(const std::string& filename) {
|
||||
} catch (const std::exception&) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::time_t HotReload::GetLatestWriteTimeInPath() {
|
||||
try {
|
||||
fs::path p(path);
|
||||
if (fs::is_regular_file(p)) {
|
||||
return GetFileWriteTime(path);
|
||||
}
|
||||
|
||||
// If it's a directory, scan files (non-recursively) and return the
|
||||
// newest write time found.
|
||||
if (fs::is_directory(p)) {
|
||||
std::time_t newest = 0;
|
||||
for (auto &entry : fs::directory_iterator(p)) {
|
||||
if (!fs::is_regular_file(entry.path())) continue;
|
||||
std::time_t t = GetFileWriteTime(entry.path().string());
|
||||
if (t > newest) newest = t;
|
||||
}
|
||||
return newest;
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
// fall through
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -22,6 +22,9 @@ bool ScriptEngine::Initialize() {
|
||||
return false;
|
||||
}
|
||||
|
||||
debugger = new CDebugger();
|
||||
debugger->SetEngine(engine);
|
||||
|
||||
// Register std::string
|
||||
RegisterStdString(engine);
|
||||
|
||||
@@ -40,6 +43,11 @@ bool ScriptEngine::Initialize() {
|
||||
|
||||
void ScriptEngine::Shutdown() {
|
||||
ClearCachedFunctions();
|
||||
if (debugger) {
|
||||
debugger->SetEngine(nullptr);
|
||||
delete debugger;
|
||||
debugger = nullptr;
|
||||
}
|
||||
if (engine) {
|
||||
engine->ShutDownAndRelease();
|
||||
engine = nullptr;
|
||||
@@ -110,6 +118,11 @@ bool ScriptEngine::CompileScript(const std::string& filename) {
|
||||
updateFunc = currentModule->GetFunctionByName("Update");
|
||||
drawFunc = currentModule->GetFunctionByName("Draw");
|
||||
hasValidScript = true;
|
||||
// If debugger is present, add a function breakpoint on Update to stop when Update is entered
|
||||
// The debugger will transform function breakpoints into file breakpoints when the function is entered
|
||||
if (debugger && updateFunc) {
|
||||
debugger->AddFuncBreakPoint("Update");
|
||||
}
|
||||
log_info("Script compiled and cached: %s", filename.c_str());
|
||||
return true;
|
||||
}
|
||||
@@ -120,6 +133,10 @@ void ScriptEngine::CallScriptFunction(asIScriptFunction* func, float dt) {
|
||||
asIScriptContext* ctx = engine->CreateContext();
|
||||
if (!ctx) return;
|
||||
|
||||
if (debugger) {
|
||||
ctx->SetLineCallback(asMETHOD(CDebugger, LineCallback), debugger, asCALL_THISCALL);
|
||||
}
|
||||
|
||||
int r = ctx->Prepare(func);
|
||||
if (r < 0) {
|
||||
ctx->Release();
|
||||
@@ -152,6 +169,13 @@ void ScriptEngine::GarbageCollect() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ScriptEngine::AddFileBreakPoint(const std::string &file, int line) {
|
||||
if (debugger) debugger->AddFileBreakPoint(file, line);
|
||||
}
|
||||
void ScriptEngine::AddFuncBreakPoint(const std::string &func) {
|
||||
if (debugger) debugger->AddFuncBreakPoint(func);
|
||||
}
|
||||
void ScriptEngine::MessageCallback(const asSMessageInfo* msg, void*) {
|
||||
// Map AngelScript message types to log levels
|
||||
if (msg->type == asMSGTYPE_ERROR) {
|
||||
|
||||
+5
-18
@@ -21,7 +21,6 @@
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include <string.h> // for memcpy
|
||||
|
||||
#define MAX_CALLBACKS 32
|
||||
|
||||
@@ -188,14 +187,6 @@ static void init_event(log_Event *ev, void *udata)
|
||||
}
|
||||
|
||||
void log_log(int level, const char *file, int line, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
log_vlog(level, file, line, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void log_vlog(int level, const char *file, int line, const char *fmt, va_list ap)
|
||||
{
|
||||
log_Event ev = {
|
||||
.fmt = fmt,
|
||||
@@ -209,11 +200,9 @@ void log_vlog(int level, const char *file, int line, const char *fmt, va_list ap
|
||||
if (!L.quiet && level >= L.level)
|
||||
{
|
||||
init_event(&ev, stderr);
|
||||
va_list ap_copy;
|
||||
va_copy(ap_copy, ap);
|
||||
memcpy(&ev.ap, &ap_copy, sizeof(va_list));
|
||||
va_start(ev.ap, fmt);
|
||||
stdout_callback(&ev);
|
||||
va_end(ap_copy);
|
||||
va_end(ev.ap);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_CALLBACKS && L.callbacks[i].fn; i++)
|
||||
@@ -222,11 +211,9 @@ void log_vlog(int level, const char *file, int line, const char *fmt, va_list ap
|
||||
if (level >= cb->level)
|
||||
{
|
||||
init_event(&ev, cb->udata);
|
||||
va_list ap_copy;
|
||||
va_copy(ap_copy, ap);
|
||||
memcpy(&ev.ap, &ap_copy, sizeof(va_list));
|
||||
va_start(ev.ap, fmt);
|
||||
cb->fn(&ev);
|
||||
va_end(ap_copy);
|
||||
va_end(ev.ap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,5 +222,5 @@ void log_vlog(int level, const char *file, int line, const char *fmt, va_list ap
|
||||
|
||||
void raylib_log(int msgType, const char *text, va_list args)
|
||||
{
|
||||
log_vlog(msgType, NULL, 0, text, args);
|
||||
log_log(msgType, NULL, 0, text, args);
|
||||
}
|
||||
@@ -48,8 +48,6 @@ int log_add_callback(log_LogFn fn, void *udata, int level);
|
||||
int log_add_fp(FILE *fp, int level);
|
||||
|
||||
void log_log(int level, const char *file, int line, const char *fmt, ...);
|
||||
// Variant that accepts a va_list for backends that already receive va_list
|
||||
void log_vlog(int level, const char *file, int line, const char *fmt, va_list ap);
|
||||
|
||||
|
||||
void raylib_log(int msgType, const char *text, va_list args);
|
||||
|
||||
Reference in New Issue
Block a user