Skip to content

Commit

Permalink
Initial support for LeGo/Ikarus
Browse files Browse the repository at this point in the history
  • Loading branch information
Try committed Dec 27, 2021
1 parent d9e1ef1 commit 27f10cd
Show file tree
Hide file tree
Showing 8 changed files with 435 additions and 28 deletions.
150 changes: 128 additions & 22 deletions game/game/compatibility/ikarus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,35 @@

using namespace Tempest;

enum {
GothicFirstInstructionAddress = 4198400, // 0x401000
ContentParserAddress = 11223232, // 0xAB40C0
vfxParserPointerAddress = 9234156, // 0x8CE6EC
menuParserPointerAddress = 9248360, // 0x8D1E68
pfxParserPointerAddress = 9278004, // 0x8D9234

MEMINT_oGame_Pointer_Address = 11208836, //0xAB0884
MEMINT_zTimer_Address = 10073044, //0x99B3D4
MEMINT_oCInformationManager_Address = 11191384, //0xAAC458
MEMINT_gameMan_Pointer_address = 9185624, //0x8C2958
};

Ikarus::Ikarus(GameScript& /*owner*/, Daedalus::DaedalusVM& vm)
/*:owner(owner)*/ {
Log::i("DMA mod detected: Ikarus");

// build-in data with assumed address
versionHint = 504628679; // G2
allocator.pin(&versionHint, GothicFirstInstructionAddress, 4, "MEMINT_ReportVersionCheck");
allocator.pin(&oGame_Pointer, MEMINT_oGame_Pointer_Address, 4, "oGame*");
allocator.pin(&parserProxy, ContentParserAddress, sizeof(parserProxy), "zCParser proxy");

// build-in data without assumed address
oGame_Pointer = allocator.pin(&gameProxy, 0, sizeof(gameProxy), "oGame");

// Note: no inline asm
vm.registerInternalFunction("ASMINT_Push", [](Daedalus::DaedalusVM&){});
vm.registerInternalFunction("ASMINT_Pop", [](Daedalus::DaedalusVM&){});
vm.registerInternalFunction("ASMINT_MyExternal", [](Daedalus::DaedalusVM&){});
vm.registerInternalFunction("ASMINT_CallMyExternal", [](Daedalus::DaedalusVM&){});
vm.registerInternalFunction("ASMINT_Init", [](Daedalus::DaedalusVM&){});
Expand All @@ -18,21 +42,35 @@ Ikarus::Ikarus(GameScript& /*owner*/, Daedalus::DaedalusVM& vm)
vm.registerInternalFunction("ASM_Run", [](Daedalus::DaedalusVM&){});
vm.registerInternalFunction("ASM_RunOnce", [](Daedalus::DaedalusVM&){});

vm.registerInternalFunction("MEM_ReadInt", [this](Daedalus::DaedalusVM& vm){ mem_readint(vm); });
vm.registerInternalFunction("MEM_WriteInt", [this](Daedalus::DaedalusVM& vm){ mem_writeint(vm); });
vm.registerInternalFunction("MEM_SearchVobByName", [this](Daedalus::DaedalusVM& vm){ mem_searchvobbyname(vm); });
vm.registerInternalFunction("MEMINT_SetupExceptionHandler", [this](Daedalus::DaedalusVM& vm){ mem_setupexceptionhandler(vm); });
vm.registerInternalFunction("MEMINT_ReplaceSlowFunctions", [ ](Daedalus::DaedalusVM& ) { });
vm.registerInternalFunction("MEM_GetAddress_Init", [this](Daedalus::DaedalusVM& vm){ mem_getaddress_init(vm); });
vm.registerInternalFunction("MEM_PrintStackTrace", [this](Daedalus::DaedalusVM& vm){ mem_printstacktrace_implementation(vm); });
vm.registerInternalFunction("MEM_GetFuncPtr", [this](Daedalus::DaedalusVM& vm){ mem_getfuncptr(vm); });
vm.registerInternalFunction("MEM_ReplaceFunc", [this](Daedalus::DaedalusVM& vm){ mem_replacefunc(vm); });
vm.registerInternalFunction("MEM_SearchVobByName", [this](Daedalus::DaedalusVM& vm){ mem_searchvobbyname(vm); });

// ## Basic Read Write ##
vm.registerInternalFunction("MEM_ReadInt", [this](Daedalus::DaedalusVM& vm){ mem_readint(vm); });
vm.registerInternalFunction("MEM_WriteInt", [this](Daedalus::DaedalusVM& vm){ mem_writeint(vm); });
vm.registerInternalFunction("MEM_CopyBytes", [this](Daedalus::DaedalusVM& vm){ mem_copybytes(vm); });
vm.registerInternalFunction("MEM_GetCommandLine", [this](Daedalus::DaedalusVM& vm){ mem_getcommandline(vm); });

// ## Basic zCParser related functions ##
vm.registerInternalFunction("MEM_GetIntAddress", [this](Daedalus::DaedalusVM& vm){ _takeref(vm); });
vm.registerInternalFunction("MEM_PtrToInst", [this](Daedalus::DaedalusVM& vm){ mem_ptrtoinst(vm); });
vm.registerInternalFunction("_@", [this](Daedalus::DaedalusVM& vm){ _takeref(vm); });
vm.registerInternalFunction("_@s", [this](Daedalus::DaedalusVM& vm){ _takeref_s(vm); });
vm.registerInternalFunction("_@f", [this](Daedalus::DaedalusVM& vm){ _takeref_f(vm); });

vm.registerInternalFunction("CALL__stdcall", [this](Daedalus::DaedalusVM& vm){ call__stdcall(vm); });
// ## Preliminary MEM_Alloc and MEM_Free ##
vm.registerInternalFunction("MEM_Alloc", [this](Daedalus::DaedalusVM& vm){ mem_alloc(vm); });
vm.registerInternalFunction("MEM_Free", [this](Daedalus::DaedalusVM& vm){ mem_free(vm); });

// Get and set instance offsets
vm.registerInternalFunction("_^", [this](Daedalus::DaedalusVM& vm){ _deref(vm); });

// Address Operator
vm.registerInternalFunction("MEM_GetIntAddress", [this](Daedalus::DaedalusVM& vm){ _takeref(vm); });
vm.registerInternalFunction("CALL__stdcall", [this](Daedalus::DaedalusVM& vm){ call__stdcall(vm); });

vm.registerInternalFunction("_@", [this](Daedalus::DaedalusVM& vm){ _takeref(vm); });
vm.registerInternalFunction("_@s", [this](Daedalus::DaedalusVM& vm){ _takeref_s(vm); });
vm.registerInternalFunction("_@f", [this](Daedalus::DaedalusVM& vm){ _takeref_f(vm); });
// vm.disAsm(vm.getDATFile().getSymbolIndexByName("MEMINT_GetAddress_Init"));
}

bool Ikarus::isRequired(Daedalus::DaedalusVM& vm) {
Expand All @@ -45,17 +83,74 @@ bool Ikarus::isRequired(Daedalus::DaedalusVM& vm) {
dat.hasSymbolName("_^");
}

void Ikarus::mem_setupexceptionhandler(Daedalus::DaedalusVM&) {
// disallow any SEH handlers and similar - that is not a script business!
}

void Ikarus::mem_getaddress_init(Daedalus::DaedalusVM&) { /* nop */ }

void Ikarus::mem_replacefunc(Daedalus::DaedalusVM& vm) {
int func = vm.popInt();
int dest = vm.popInt();
auto& sf = vm.getDATFile().getSymbolByIndex(func);
auto& sd = vm.getDATFile().getSymbolByIndex(dest);

if(sf.properties.elemProps.type!=Daedalus::EParType_Func) {
Log::e("mem_replacefunc: invalid function ptr");
return;
}
if(sd.properties.elemProps.type!=Daedalus::EParType_Func) {
Log::e("mem_replacefunc: invalid function ptr");
return;
}

Log::d("mem_replacefunc: ",sd.name," -> ",sf.name);
//auto& bin = vm.getDATFile().rawCode();
//bin[sd.address]->op = Daedalus::EParOp_Jump;
//bin[sd.address]->address = func;
}

void Ikarus::mem_printstacktrace_implementation(Daedalus::DaedalusVM &vm) {
Log::e("[start of stacktrace]");
auto stk = vm.getCallStack();
for(auto& i:stk)
Log::e(i);
Log::e("[end of stacktrace]");
}

void Ikarus::mem_getfuncptr(Daedalus::DaedalusVM& vm) {
auto func = vm.popInt();
auto& sym = vm.getDATFile().getSymbolByIndex(func);
if(sym.properties.elemProps.type!=Daedalus::EParType_Func) {
Log::e("mem_getfuncptr: invalid function ptr");
vm.setReturn(0);
return;
}
vm.setReturn(0);
}

void Ikarus::mem_readint(Daedalus::DaedalusVM& vm) {
auto address = vm.popInt();
(void)address;
vm.setReturn(0x1);
const auto address = vm.popInt();
int32_t v = allocator.readInt(address);
vm.setReturn(v);
}

void Ikarus::mem_writeint(Daedalus::DaedalusVM& vm) {
auto val = vm.popInt();
(void)val;
auto address = vm.popInt();
(void)address;
auto val = vm.popInt();
auto address = uint32_t(vm.popInt());
allocator.writeInt(address,val);
}

void Ikarus::mem_copybytes(Daedalus::DaedalusVM& vm) {
auto size = uint32_t(vm.popInt());
auto dst = uint32_t(vm.popInt());
auto src = uint32_t(vm.popInt());
allocator.copyBytes(src,dst,size);
}

void Ikarus::mem_getcommandline(Daedalus::DaedalusVM &vm) {
// TODO: return real commandline
vm.setReturn("");
}

void Ikarus::mem_searchvobbyname(Daedalus::DaedalusVM& vm) {
Expand All @@ -70,10 +165,10 @@ void Ikarus::call__stdcall(Daedalus::DaedalusVM& vm) {
(void)address;
}

void Ikarus::_deref(Daedalus::DaedalusVM& vm) {
auto val = vm.popInt();
(void)val;
vm.setReturn(0x1);
void Ikarus::mem_ptrtoinst(Daedalus::DaedalusVM& vm) {
auto address = vm.popInt();
// TODO: return an instance
vm.setReturn(address);
}

void Ikarus::_takeref(Daedalus::DaedalusVM& vm) {
Expand All @@ -93,3 +188,14 @@ void Ikarus::_takeref_f(Daedalus::DaedalusVM& vm) {
(void)val;
vm.setReturn(0x1);
}

void Ikarus::mem_alloc(Daedalus::DaedalusVM& vm) {
auto amount = vm.popInt();
auto ptr = allocator.alloc(amount);
vm.setReturn(int32_t(ptr));
}

void Ikarus::mem_free(Daedalus::DaedalusVM& vm) {
auto ptr = uint32_t(vm.popInt());
allocator.free(Mem32::ptr32_t(ptr));
}
47 changes: 42 additions & 5 deletions game/game/compatibility/ikarus.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <daedalus/DaedalusVM.h>

#include "scriptplugin.h"
#include "mem32.h"

class GameScript;

Expand All @@ -13,18 +14,54 @@ class Ikarus : public ScriptPlugin {
static bool isRequired(Daedalus::DaedalusVM& vm);

private:
void mem_readint (Daedalus::DaedalusVM &vm);
void mem_writeint (Daedalus::DaedalusVM &vm);
void mem_searchvobbyname(Daedalus::DaedalusVM &vm);
using ptr32_t = Mem32::ptr32_t;

void call__stdcall (Daedalus::DaedalusVM &vm);
struct oGame {
int data[16] = {};
};

struct zCParser {
uint8_t padd0[24] = {};
ptr32_t symtab_table_array = 0; // 24
uint8_t padd1[8] = {};
ptr32_t sorted_symtab_table_array = 0; // 36
uint8_t padd2[32] = {};
ptr32_t stack = 0; // 72
ptr32_t stack_stackPtr = 0; // 76
};

void mem_setupexceptionhandler (Daedalus::DaedalusVM &vm);
void mem_getaddress_init (Daedalus::DaedalusVM &vm);
void mem_printstacktrace_implementation(Daedalus::DaedalusVM &vm);
void mem_getfuncptr (Daedalus::DaedalusVM &vm);
void mem_replacefunc (Daedalus::DaedalusVM &vm);
void mem_searchvobbyname (Daedalus::DaedalusVM &vm);

// ## Basic Read Write ##
void mem_readint (Daedalus::DaedalusVM &vm);
void mem_writeint (Daedalus::DaedalusVM &vm);
void mem_copybytes (Daedalus::DaedalusVM &vm);
void mem_getcommandline (Daedalus::DaedalusVM &vm);

void _deref (Daedalus::DaedalusVM &vm);
// pointers
void mem_ptrtoinst (Daedalus::DaedalusVM &vm);

// ## Basic zCParser related functions ##
void _takeref (Daedalus::DaedalusVM &vm);
void _takeref_s (Daedalus::DaedalusVM &vm);
void _takeref_f (Daedalus::DaedalusVM &vm);

// ## Preliminary MEM_Alloc and MEM_Free ##
void mem_alloc (Daedalus::DaedalusVM &vm);
void mem_free (Daedalus::DaedalusVM &vm);

void call__stdcall (Daedalus::DaedalusVM &vm);

Mem32 allocator;
uint32_t versionHint = 0;
ptr32_t oGame_Pointer = 0;
oGame gameProxy;
zCParser parserProxy;
// GameScript& owner;
};

18 changes: 18 additions & 0 deletions game/game/compatibility/lego.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "lego.h"
#include "ikarus.h"

#include <Tempest/Log>

using namespace Tempest;

LeGo::LeGo(GameScript& /*owner*/, Daedalus::DaedalusVM& /*vm*/) {
Log::i("DMA mod detected: LeGo");
}

bool LeGo::isRequired(Daedalus::DaedalusVM& vm) {
auto& dat = vm.getDATFile();
return
dat.hasSymbolName("LeGo_InitFlags") &&
dat.hasSymbolName("LeGo_Init") &&
Ikarus::isRequired(vm);
}
15 changes: 15 additions & 0 deletions game/game/compatibility/lego.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <daedalus/DaedalusVM.h>

#include "scriptplugin.h"

class GameScript;

class LeGo : public ScriptPlugin {
public:
LeGo(GameScript& owner, Daedalus::DaedalusVM& vm);

static bool isRequired(Daedalus::DaedalusVM& vm);
};

Loading

0 comments on commit 27f10cd

Please sign in to comment.