Skip to content

Commit

Permalink
Add callbacks for opcode processing events (#7)
Browse files Browse the repository at this point in the history
  • Loading branch information
MiranDMC authored Oct 26, 2023
1 parent a912845 commit 7b17b20
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 26 deletions.
5 changes: 4 additions & 1 deletion cleo_sdk/CLEO.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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*);
Expand Down
70 changes: 45 additions & 25 deletions source/CCustomOpcodeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -221,7 +241,7 @@ namespace CLEO {

for (void* func : GetInstance().GetCallbacks(eCallbackId::ScriptsFinalize))
{
typedef void callback(void);
typedef void WINAPI callback(void);
((callback*)func)();
}

Expand Down

0 comments on commit 7b17b20

Please sign in to comment.