Skip to content

Commit

Permalink
Introducing cleo modules (#101)
Browse files Browse the repository at this point in the history
* cleo_call and cleo_return scope now save and restore GOSUB call stack and stack pointer.

* Introduced CModuleSystem class.

* Working prototype.

* Support of path resolving for modules.

* Path normalization updated.

* Review fixes.

* Disabled virtual absolute paths feature.

* Fixed script  location and name related functions.

* Used game's APIs to resolve paths.

Figured out using plugin_sdk classes in project.

* Names case insensitive handling.

* Modules reloading.

* Automatic modules reloading.
  • Loading branch information
MiranDMC authored Sep 30, 2023
1 parent efe00ef commit 98a4911
Show file tree
Hide file tree
Showing 13 changed files with 904 additions and 40 deletions.
21 changes: 21 additions & 0 deletions CLEO4.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,37 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="source\CCodeInjector.cpp" />
<ClCompile Include="$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\CFileMgr.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\CGame.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\shared\DynAddress.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\shared\GameVersion.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\shared\Patch.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\shared\PluginBase.cpp">
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<ClCompile Include="source\CCustomOpcodeSystem.cpp" />
<ClCompile Include="source\CDebug.cpp" />
<ClCompile Include="source\CDmaFix.cpp" />
<ClCompile Include="source\CGameMenu.cpp" />
<ClCompile Include="source\CGameVersionManager.cpp" />
<ClCompile Include="source\CLegacy.cpp" />
<ClCompile Include="source\cleo.cpp" />
<ClCompile Include="source\CModuleSystem.cpp" />
<ClCompile Include="source\crc32.cpp" />
<ClCompile Include="source\CScriptEngine.cpp" />
<ClCompile Include="source\CSoundSystem.cpp" />
<ClCompile Include="source\CTextManager.cpp" />
<ClCompile Include="source\CTheScripts.cpp" />
<ClCompile Include="source\dllmain.cpp" />
<ClCompile Include="source\PluginSdkExternals.cpp" />
<ClCompile Include="source\stdafx.cpp">
Expand All @@ -40,6 +60,7 @@
<ClInclude Include="source\CGameVersionManager.h" />
<ClInclude Include="source\CLegacy.h" />
<ClInclude Include="source\cleo.h" />
<ClInclude Include="source\CModuleSystem.h" />
<ClInclude Include="source\CPluginSystem.h" />
<ClInclude Include="source\crc32.h" />
<ClInclude Include="source\CScriptEngine.h" />
Expand Down
30 changes: 30 additions & 0 deletions CLEO4.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
<Filter Include="cleo_sdk">
<UniqueIdentifier>{d188d452-fbc6-48b5-bd49-d4036c989109}</UniqueIdentifier>
</Filter>
<Filter Include="plugin_sdk">
<UniqueIdentifier>{5cead5cc-9a75-4d2e-99b5-ebbc8f9d6d86}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="source\CCodeInjector.cpp">
Expand Down Expand Up @@ -54,6 +57,30 @@
<ClCompile Include="source\PluginSdkExternals.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="source\CModuleSystem.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="source\CTheScripts.cpp">
<Filter>source</Filter>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\CFileMgr.cpp">
<Filter>plugin_sdk</Filter>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\plugin_sa\game_sa\CGame.cpp">
<Filter>plugin_sdk</Filter>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\shared\DynAddress.cpp">
<Filter>plugin_sdk</Filter>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\shared\GameVersion.cpp">
<Filter>plugin_sdk</Filter>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\shared\Patch.cpp">
<Filter>plugin_sdk</Filter>
</ClCompile>
<ClCompile Include="$(PLUGIN_SDK_DIR)\shared\PluginBase.cpp">
<Filter>plugin_sdk</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\CCodeInjector.h">
Expand Down Expand Up @@ -113,6 +140,9 @@
<ClInclude Include="source\resource.h">
<Filter>source</Filter>
</ClInclude>
<ClInclude Include="source\CModuleSystem.h">
<Filter>source</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="source\cleo.def">
Expand Down
93 changes: 89 additions & 4 deletions source/CCustomOpcodeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "CTextManager.h"
#include "CModelInfo.h"

#include <filesystem>

namespace CLEO {
DWORD FUNC_fopen;
DWORD FUNC_fclose;
Expand Down Expand Up @@ -829,6 +831,7 @@ namespace CLEO {
struct ScmFunction
{
unsigned short prevScmFunctionId, thisScmFunctionId;
void* savedBaseIP;
BYTE *retnAddress;
BYTE* savedStack[8]; // gosub stack
WORD savedSP;
Expand All @@ -839,7 +842,9 @@ namespace CLEO {
bool savedNotFlag;
static const size_t store_size = 0x400;
static ScmFunction *Store[store_size];
static size_t allocationPlace; // contains an index of last allocated object
static size_t allocationPlace; // contains an index of last allocated object
std::string savedScriptFileDir; // modules switching
std::string savedScriptFileName; // modules switching

void *operator new(size_t size)
{
Expand All @@ -866,6 +871,7 @@ namespace CLEO {
auto cs = reinterpret_cast<CCustomScript*>(thread);

// create snapshot of current scope
savedBaseIP = cs->BaseIP;
std::copy(std::begin(cs->Stack), std::end(cs->Stack), std::begin(savedStack));
savedSP = cs->SP;

Expand All @@ -876,6 +882,9 @@ namespace CLEO {
savedLogicalOp = cs->LogicalOp;
savedNotFlag = cs->NotFlag;

savedScriptFileDir = thread->GetScriptFileDir();
savedScriptFileName = thread->GetScriptFileName();

// init new scope
std::fill(std::begin(cs->Stack), std::end(cs->Stack), nullptr);
cs->SP = 0;
Expand All @@ -891,6 +900,7 @@ namespace CLEO {
auto cs = reinterpret_cast<CCustomScript*>(thread);

// restore parent scope's gosub call stack
cs->BaseIP = savedBaseIP;
std::copy(std::begin(savedStack), std::end(savedStack), std::begin(cs->Stack));
cs->SP = savedSP;

Expand All @@ -917,6 +927,9 @@ namespace CLEO {
cs->LogicalOp = savedLogicalOp;
}

thread->SetScriptFileDir(savedScriptFileDir.c_str());
thread->SetScriptFileName(savedScriptFileName.c_str());

cs->SetIp(retnAddress);
cs->SetScmFunction(prevScmFunctionId);
}
Expand Down Expand Up @@ -1649,8 +1662,77 @@ namespace CLEO {
//0AB1=-1,call_scm_func %1p%
OpcodeResult __stdcall opcode_0AB1(CRunningScript *thread)
{
int label;
*thread >> label;
BYTE* base = nullptr;
int label = 0;

char* moduleTxt = nullptr;
switch (*thread->GetBytePointer())
{
// label of current script
case DT_DWORD:
case DT_WORD:
case DT_BYTE:
case DT_VAR:
case DT_LVAR:
case DT_VAR_ARRAY:
case DT_LVAR_ARRAY:
base = thread->GetBasePointer(); // current script
*thread >> label;
break;

// string with module and export name
case DT_VAR_STRING:
case DT_LVAR_STRING:
case DT_VAR_TEXTLABEL:
case DT_LVAR_TEXTLABEL:
moduleTxt = GetScriptParamPointer(thread)->pcParam;
break;

case DT_STRING:
case DT_TEXTLABEL:
case DT_VARLEN_STRING:
moduleTxt = readString(thread);
break;

default:
{
std::string err(128, '\0');
sprintf(err.data(), "Invalid first argument type (%02X) of 0AB1 opcode in script '%s'", *thread->GetBytePointer(), thread->GetScriptFileName());
Error(err.data());
return OR_INTERRUPT;
}
}

// parse module reference text
if (moduleTxt != nullptr)
{
std::string str(moduleTxt);
auto pos = str.find('@');
if (pos == str.npos)
{
std::string err(128, '\0');
sprintf(err.data(), "Invalid module reference '%s' in 0AB1 opcode in script '%s'", str.c_str(), thread->GetScriptFileName());
Error(err.data());
return OR_INTERRUPT;
}
str[pos] = '\0'; // split into two texts

// get module's absolute path
std::string modulePath(&str[pos + 1]);
modulePath = ResolvePath(modulePath.c_str(), thread->GetScriptFileDir());

auto scriptRef = GetInstance().ModuleSystem.GetExport(modulePath.c_str(), &str[0]);
if (!scriptRef.Valid())
{
std::string err(128, '\0');
sprintf(err.data(), "Not found module '%s' export '%s', requested by 0AB1 opcode in script '%s'", modulePath.c_str(), &str[0], thread->GetScriptFileName());
Error(err.data());
return OR_INTERRUPT;
}

base = (BYTE*)scriptRef.base;
label = scriptRef.offset;
}

DWORD nParams = 0;
if(*thread->GetBytePointer()) *thread >> nParams;
Expand Down Expand Up @@ -1722,13 +1804,16 @@ namespace CLEO {
}

// jump to label
ThreadJump(thread, label);
thread->SetBaseIp(base); // script space
ThreadJump(thread, label); // script offset
return OR_CONTINUE;
}

//0AB2=-1,ret
OpcodeResult __stdcall opcode_0AB2(CRunningScript *thread)
{
GetInstance().ModuleSystem.ReleaseModuleRef((char*)thread->GetBasePointer()); // release module if one used

ScmFunction *scmFunc = ScmFunction::Store[reinterpret_cast<CCustomScript*>(thread)->GetScmFunction()];

DWORD nRetParams = 0;
Expand Down
4 changes: 4 additions & 0 deletions source/CCustomOpcodeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ namespace CLEO
bool is_legacy_handle(DWORD dwHandle);
FILE * convert_handle_to_file(DWORD dwHandle);

extern const char* (__cdecl* GetUserDirectory)();
extern void(__cdecl* ChangeToUserDir)();
extern void(__cdecl* ChangeToProgramDir)(const char*);

class CCustomOpcodeSystem : public VInjectible
{
friend OpcodeResult __stdcall opcode_0A9A(CRunningScript *pScript);
Expand Down
5 changes: 5 additions & 0 deletions source/CDebug.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <mutex>

#define TRACE __noop

Expand All @@ -11,6 +12,8 @@ const char szLogFileName[] = "cleo.log";

class CDebug
{
std::mutex mutex;

#ifdef DEBUGIT
std::ofstream m_hFile;
#endif
Expand All @@ -30,6 +33,8 @@ class CDebug

void Trace(const char *format, ...)
{
std::lock_guard<std::mutex> guard(mutex);

SYSTEMTIME t;
static char szBuf[1024];

Expand Down
Loading

0 comments on commit 98a4911

Please sign in to comment.