diff --git a/cleo_sdk/CLEO.h b/cleo_sdk/CLEO.h index a2835139..01fa7b09 100644 --- a/cleo_sdk/CLEO.h +++ b/cleo_sdk/CLEO.h @@ -131,6 +131,8 @@ enum class eCallbackId : DWORD ScriptRegister, // void WINAPI OnScriptRegister(CRunningScript* pScript); // called after script creation ScriptUnregister, // void WINAPI OnScriptUnregister(CRunningScript* pScript); // called before script deletion ScriptProcess, // bool WINAPI OnScriptProcess(CRunningScript* pScript); // return false to skip this script processing + ScriptOpcodeProcess, // OpcodeResult WINAPI OnScriptOpcodeProcess(CRunningScript* pScript, DWORD opcode); // return other than OR_NONE to signal that opcode was handled in the callback + ScriptOpcodeProcessFinished, // OpcodeResult WINAPI OnScriptOpcodeProcessFinished(CRunningScript* pScript, DWORD opcode, OpcodeResult result); // return other than OR_NONE to overwrite original result ScriptDraw, // void WINAPI OnScriptDraw(bool beforeFade); DrawingFinished, // void WINAPI OnDrawingFinished(); // called after game rendered everything and before presenting screen buffer Log, // void OnLog(eLogLevel level, const char* msg); @@ -275,9 +277,10 @@ static_assert(sizeof(CRunningScript) == 0xE0, "Invalid size of CRunningScript!") enum OpcodeResult : char { + OR_NONE = -2, + OR_ERROR = -1, OR_CONTINUE = 0, OR_INTERRUPT = 1, - OR_ERROR = -1, }; typedef OpcodeResult (CALLBACK* _pOpcodeHandler)(CRunningScript*); diff --git a/source/CCustomOpcodeSystem.cpp b/source/CCustomOpcodeSystem.cpp index fb858900..01fa355d 100644 --- a/source/CCustomOpcodeSystem.cpp +++ b/source/CCustomOpcodeSystem.cpp @@ -165,45 +165,65 @@ namespace CLEO { // opcode handler for custom opcodes OpcodeResult __fastcall CCustomOpcodeSystem::customOpcodeHandler(CRunningScript *thread, int dummy, WORD opcode) { - /*std::ostringstream ss; - ss << thread->GetName() << " opcode " << opcodeToStr(opcode) << std::endl; - OutputDebugStringA(ss.str().c_str());//*/ - lastScript = thread; lastOpcode = opcode; lastOpcodePtr = (WORD*)thread->GetBytePointer() - 1; // rewind to the opcode start - if(opcode > LastCustomOpcode) + // execute registered callbacks + OpcodeResult result = OR_NONE; + for (void* func : GetInstance().GetCallbacks(eCallbackId::ScriptOpcodeProcess)) { - SHOW_ERROR("Opcode [%04X] out of supported range! \nCalled in script %s\nScript suspended.", opcode, ((CCustomScript*)thread)->GetInfoStr().c_str()); - return ErrorSuspendScript(thread); + typedef OpcodeResult WINAPI callback(CRunningScript*, DWORD); + result = ((callback*)func)(thread, opcode); + + if(result != OR_NONE) + break; // processed } - CustomOpcodeHandler handler = customOpcodeProc[opcode]; - if(handler != nullptr) + if(result == OR_NONE) // opcode not proccessed yet { - lastCustomOpcode = opcode; - return handler(thread); - } + if(opcode > LastCustomOpcode) + { + SHOW_ERROR("Opcode [%04X] out of supported range! \nCalled in script %s\nScript suspended.", opcode, ((CCustomScript*)thread)->GetInfoStr().c_str()); + return ErrorSuspendScript(thread); + } - // Not registered as custom opcode. Call game's original handler + CustomOpcodeHandler handler = customOpcodeProc[opcode]; + if(handler != nullptr) + { + lastCustomOpcode = opcode; + return handler(thread); + } - if (opcode > LastOriginalOpcode) - { - SHOW_ERROR("Opcode [%04X] not registered! \nCalled in script %s\nScript suspended.", opcode, ((CCustomScript*)thread)->GetInfoStr().c_str()); - return ErrorSuspendScript(thread); - } + // Not registered as custom opcode. Call game's original handler - size_t tableIdx = opcode / 100; // 100 opcodes peer handler table - auto result = originalOpcodeHandlers[tableIdx](thread, opcode); + if (opcode > LastOriginalOpcode) + { + SHOW_ERROR("Opcode [%04X] not registered! \nCalled in script %s\nScript suspended.", opcode, ((CCustomScript*)thread)->GetInfoStr().c_str()); + return ErrorSuspendScript(thread); + } + + size_t tableIdx = opcode / 100; // 100 opcodes peer handler table + result = originalOpcodeHandlers[tableIdx](thread, opcode); - if(result == OR_ERROR) + if(result == OR_ERROR) + { + SHOW_ERROR("Opcode [%04X] not found! \nCalled in script %s\nScript suspended.", opcode, ((CCustomScript*)thread)->GetInfoStr().c_str()); + return ErrorSuspendScript(thread); + } + } + + // execute registered callbacks + OpcodeResult callbackResult = OR_NONE; + for (void* func : GetInstance().GetCallbacks(eCallbackId::ScriptOpcodeProcessFinished)) { - SHOW_ERROR("Opcode [%04X] not found! \nCalled in script %s\nScript suspended.", opcode, ((CCustomScript*)thread)->GetInfoStr().c_str()); - return ErrorSuspendScript(thread); + typedef OpcodeResult WINAPI callback(CRunningScript*, DWORD, OpcodeResult); + auto res = ((callback*)func)(thread, opcode, result); + + callbackResult = max(res, callbackResult); // store result with highest value from all callbacks } - return result; + return (callbackResult != OR_NONE) ? callbackResult : result; } OpcodeResult CCustomOpcodeSystem::ErrorSuspendScript(CRunningScript* thread) @@ -221,7 +241,7 @@ namespace CLEO { for (void* func : GetInstance().GetCallbacks(eCallbackId::ScriptsFinalize)) { - typedef void callback(void); + typedef void WINAPI callback(void); ((callback*)func)(); }