fix: resolve crashes on invalid script hot reload
This commit is contained in:
+67
-16
@@ -6,7 +6,7 @@
|
||||
#include <sstream>
|
||||
#include <assert.h>
|
||||
|
||||
ScriptEngine::ScriptEngine() : engine(nullptr), updateFunc(nullptr), drawFunc(nullptr) {
|
||||
ScriptEngine::ScriptEngine() : engine(nullptr), updateFunc(nullptr), drawFunc(nullptr), currentModule(nullptr), hasValidScript(false) {
|
||||
}
|
||||
|
||||
ScriptEngine::~ScriptEngine() {
|
||||
@@ -37,54 +37,105 @@ bool ScriptEngine::Initialize() {
|
||||
}
|
||||
|
||||
void ScriptEngine::Shutdown() {
|
||||
ClearCachedFunctions();
|
||||
if (engine) {
|
||||
engine->ShutDownAndRelease();
|
||||
engine = nullptr;
|
||||
}
|
||||
updateFunc = nullptr;
|
||||
drawFunc = nullptr;
|
||||
currentModule = nullptr;
|
||||
hasValidScript = false;
|
||||
}
|
||||
|
||||
bool ScriptEngine::CompileScript(const std::string& filename) {
|
||||
if (!engine) return false;
|
||||
|
||||
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;
|
||||
// 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());
|
||||
if (r < 0) {
|
||||
std::cerr << "Failed to add script section for: " << filename << "\n";
|
||||
engine->DiscardModule("temp");
|
||||
return false;
|
||||
}
|
||||
|
||||
r = mod->Build();
|
||||
if (r < 0) return false;
|
||||
r = tempMod->Build();
|
||||
if (r < 0) {
|
||||
std::cerr << "Failed to build script: " << filename << "\n";
|
||||
engine->DiscardModule("temp");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cache Update(float dt) and Draw() functions if they exist
|
||||
updateFunc = mod->GetFunctionByName("Update");
|
||||
drawFunc = mod->GetFunctionByName("Draw");
|
||||
// If we get here, compilation succeeded
|
||||
// Now safely replace the main module
|
||||
if (currentModule) {
|
||||
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());
|
||||
if (r >= 0) {
|
||||
r = currentModule->Build();
|
||||
}
|
||||
|
||||
// Clean up temp module
|
||||
engine->DiscardModule("temp");
|
||||
|
||||
if (r < 0) {
|
||||
// This shouldn't happen since we already tested compilation
|
||||
std::cerr << "Unexpected error when creating main module\n";
|
||||
ClearCachedFunctions();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cache new functions
|
||||
updateFunc = currentModule->GetFunctionByName("Update");
|
||||
drawFunc = currentModule->GetFunctionByName("Draw");
|
||||
hasValidScript = true;
|
||||
|
||||
std::cout << "Script compiled and cached: " << filename << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptEngine::CallScriptFunction(asIScriptFunction* func, float dt) {
|
||||
if (!func || !engine) return;
|
||||
if (!func || !engine || !hasValidScript) return;
|
||||
|
||||
asIScriptContext* ctx = engine->CreateContext();
|
||||
ctx->Prepare(func);
|
||||
if (!ctx) return;
|
||||
|
||||
int r = ctx->Prepare(func);
|
||||
if (r < 0) {
|
||||
ctx->Release();
|
||||
return;
|
||||
}
|
||||
|
||||
if (func->GetParamCount() == 1) {
|
||||
ctx->SetArgFloat(0, dt);
|
||||
}
|
||||
|
||||
ctx->Execute();
|
||||
r = ctx->Execute();
|
||||
if (r != asEXECUTION_FINISHED) {
|
||||
if (r == asEXECUTION_EXCEPTION) {
|
||||
std::cerr << "Script exception: " << ctx->GetExceptionString() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
ctx->Release();
|
||||
}
|
||||
|
||||
void ScriptEngine::ClearCachedFunctions() {
|
||||
updateFunc = nullptr;
|
||||
drawFunc = nullptr;
|
||||
hasValidScript = false;
|
||||
}
|
||||
|
||||
void ScriptEngine::GarbageCollect() {
|
||||
if (engine) {
|
||||
engine->GarbageCollect();
|
||||
|
||||
Reference in New Issue
Block a user