3#include <zenkit/DaedalusScript.hh>
12using namespace Tempest;
28 std::memcpy(&i, &f,
sizeof(i));
34 std::memcpy(&f, &i,
sizeof(f));
38void DirectMemory::memory_instance::set_int(
const zenkit::DaedalusSymbol& sym, uint16_t index, int32_t value) {
39 if(sym.name()==
"ZCARRAY.NUMINARRAY" && value>1024)
42 owner.mem32.writeInt(addr, value);
45int32_t DirectMemory::memory_instance::get_int(
const zenkit::DaedalusSymbol& sym, uint16_t index)
const {
47 int32_t v = owner.mem32.readInt(addr);
51void DirectMemory::memory_instance::set_float(
const zenkit::DaedalusSymbol& sym, uint16_t index,
float value) {
53 owner.mem32.writeInt(addr, *
reinterpret_cast<const int32_t*
>(&value));
56float DirectMemory::memory_instance::get_float(
const zenkit::DaedalusSymbol& sym, uint16_t index)
const {
58 int32_t v = owner.mem32.readInt(addr);
61 std::memcpy(&f, &v, 4);
65void DirectMemory::memory_instance::set_string(
const zenkit::DaedalusSymbol& sym, uint16_t index, std::string_view value) {
67 if(
auto* s = owner.mem32.deref<
zString>(addr))
68 owner.memAssignString(*s, value);
71const std::string& DirectMemory::memory_instance::get_string(
const zenkit::DaedalusSymbol& sym, uint16_t index)
const {
74 if(
auto zs = owner.mem32.deref<
const zString>(addr)) {
75 static std::string ret;
76 owner.memFromString(ret, *zs);
80 Log::d(
"TODO: memory_instance::get_string ", sym.name());
82 static std::string empty;
88 if(
auto v = vm.find_symbol_by_name(
"Ikarus_Version")) {
89 const int version = v->type()==zenkit::DaedalusDataType::INT ? v->get_int() : 0;
90 Log::i(
"DMA mod detected: Ikarus v", version);
92 if(
auto v = vm.find_symbol_by_name(
"LeGo_Version")) {
93 const char* version = v->type()==zenkit::DaedalusDataType::STRING ? v->get_string().c_str() :
"LeGo";
94 Log::i(
"DMA mod detected: ", version);
103 vm.override_function(
"ASMINT_Init", [
this]() { ASMINT_Init(); });
104 vm.override_function(
"ASMINT_MyExternal", [](){});
105 vm.override_function(
"ASMINT_CallMyExternal", [
this]() { ASMINT_CallMyExternal(); });
108 setupMemoryFunctions();
111 setupDirectFunctions();
113 setupWinapiFunctions();
115 setupUtilityFunctions();
120 setupMathFunctions();
121 setupStringsFunctions();
123 setupzCParserFunctions();
125 setupInitFileFunctions();
127 setupFontFunctions();
129 setupWorldFunctions();
132 vm.override_function(
"MEM_PrintStackTrace", [
this](){ memPrintstacktraceImplementation(); });
133 vm.override_function(
"MEM_SendToSpy", [
this](
int cat, std::string_view msg){
return memSendToSpy(cat,msg); });
134 vm.override_function(
"MEM_ReplaceFunc", [
this](zenkit::DaedalusFunction dest, zenkit::DaedalusFunction func){ memReplaceFunc(dest, func); });
136 vm.override_function(
"MEMINT_SetupExceptionHandler", [](){ });
137 vm.override_function(
"MEMINT_ReplaceSlowFunctions", [](){ });
139 vm.override_function(
"MEM_InitStatArrs", [](){ });
140 vm.override_function(
"MEM_InitRepeat", [](){ });
141 vm.override_function(
"MEM_GetCommandLine", [](){
return std::string(
""); });
143 auto safeOverrideFunction = [&](std::string_view name,
auto hook) {
144 auto f = vm.find_symbol_by_name(name);
145 if(f==
nullptr || f->type()!=zenkit::DaedalusDataType::FUNCTION)
147 vm.override_function(name, hook);
150 safeOverrideFunction(
"_RENDER_INIT", []() {
152 Log::e(
"not implemented call [_RENDER_INIT]");
154 safeOverrideFunction(
"PRINT_FIXPS", [](){
159 safeOverrideFunction(
"TELEPORTNPCTOWP", [
this](
int npcId, std::string_view wpName){
160 auto wp = gameScript.
world().findPoint(wpName,
false);
162 Log::d(
"TeleportNpcToWP: invalid waypoint: ", wpName);
165 auto npcRef = this->vm.find_symbol_by_index(uint32_t(npcId))->get_instance();
166 if(npcRef==
nullptr || npcRef->user_ptr==
nullptr)
168 auto& npc = *
reinterpret_cast<Npc*
>(npcRef->user_ptr);
170 npc.setDirection(wp->direction());
173 safeOverrideFunction(
"LOG_MOVETOTOP", [](std::string_view topic) {
175 Log::e(
"not implemented call [LOG_MOVETOTOP]");
179 auto dummyfy = [&](std::string_view name,
auto hook) {
180 auto f = vm.find_symbol_by_name(name);
181 if(f==
nullptr || f->type()!=zenkit::DaedalusDataType::FUNCTION)
183 vm.override_function(name, hook);
185 dummyfy(
"WRITENOP", [](
int,
int){});
186 dummyfy(
"MEM_SETKEYS", [](std::string_view,
int,
int){});
187 dummyfy(
"INIT_QUIVERS_ALWAYS", [](){});
192 vm.find_symbol_by_name(
"Ikarus_Version") !=
nullptr &&
193 vm.find_symbol_by_name(
"MEM_InitAll") !=
nullptr &&
194 vm.find_symbol_by_name(
"MEM_ReadInt") !=
nullptr &&
195 vm.find_symbol_by_name(
"MEM_WriteInt") !=
nullptr &&
196 vm.find_symbol_by_name(
"_@") !=
nullptr &&
197 vm.find_symbol_by_name(
"_^") !=
nullptr;
202 if(
auto* sym = vm.find_symbol_by_name(
"_FF_Hook")) {
203 vm.call_function(sym);
212 if(ani.find(
"CALL ")!=0)
217 if(
auto* sym = vm.find_symbol_by_name(
"_AI_FUNCTION_EVENT")) {
219 vm.call_function(sym);
226 auto toInt = [](std::string_view ss) {
228 auto err = std::from_chars(ss.data(), ss.data()+ss.size(), i).ec;
234 auto toStr = [](std::string_view ss) {
236 ret.reserve(ss.size());
237 for(
size_t i=0; i<ss.size(); ++i) {
238 if(ss[i]==
'\\' && i+1<ss.size()) {
245 ret.push_back(ss[i]);
250 auto v = ani.substr(5);
251 auto tok = v.substr(0, v.find(
' '));
252 v = v.substr(v.find(
' ')+1);
254 std::string_view args[10];
255 for(
int i=0; i<10; ++i) {
256 size_t n = v.find(
' ');
257 args[i] = v.substr(0, n);
258 if(n==std::string_view::npos)
263 if(tok.size()>0 && std::isdigit(tok[0])) {
264 auto fncID = toInt(args[0]);
265 if(
auto* sym = vm.find_symbol_by_index(uint32_t(fncID))) {
266 vm.call_function(sym);
271 auto fncID = toInt(args[1]);
272 if(
auto* sym = vm.find_symbol_by_index(uint32_t(fncID))) {
273 vm.call_function(sym, toInt(args[0]));
278 auto fncID = toInt(args[1]);
279 if(
auto* sym = vm.find_symbol_by_index(uint32_t(fncID))) {
281 std::string arg0 = toStr(args[0]);
282 vm.call_function(sym, std::string_view(arg0));
287 auto fncID = toInt(args[2]);
288 if(
auto* sym = vm.find_symbol_by_index(uint32_t(fncID))) {
289 std::string arg0 = toStr(args[0]);
290 std::string arg1 = toStr(args[1]);
291 vm.call_function(sym, std::string_view(arg0), std::string_view(arg1));
296 auto fncID = toInt(args[4]);
297 auto npcID = toInt(args[0]);
298 auto npcS = vm.find_symbol_by_index(uint32_t(npcID));
299 auto inst = (npcS!=
nullptr && npcS->type()==zenkit::DaedalusDataType::INSTANCE) ? npcS->get_instance() :
nullptr;
300 if(
auto* sym = vm.find_symbol_by_index(uint32_t(fncID))) {
308 Log::d(
"Ikarus: skip ai-call: ", ani);
311void DirectMemory::setupFunctionTable() {
312 for(
auto& i:vm.symbols()) {
313 if(i.type()!=zenkit::DaedalusDataType::FUNCTION)
317 symbolsByAddress.push_back(&i);
320 std::sort(symbolsByAddress.begin(), symbolsByAddress.end(), [](
const zenkit::DaedalusSymbol* l,
const zenkit::DaedalusSymbol* r){
321 return l->address() < r->address();
325void DirectMemory::setupIkarusLoops() {
327 if(
auto end = vm.find_symbol_by_name(
"END")) {
328 end->set_access_trap_enable(
true);
330 if(
auto break_ = vm.find_symbol_by_name(
"BREAK")) {
331 break_->set_access_trap_enable(
true);
333 if(
auto continue_ = vm.find_symbol_by_name(
"CONTINUE")) {
334 continue_->set_access_trap_enable(
true);
337 auto end = vm.find_symbol_by_name(
"END");
338 auto rep = vm.find_symbol_by_name(
"REPEAT");
339 auto whl = vm.find_symbol_by_name(
"WHILE");
340 auto continue_ = vm.find_symbol_by_name(
"CONTINUE");
342 uint32_t endIdx = (end!=
nullptr ? end->index() : uint32_t(-1));
343 uint32_t cntIdx = (continue_!=
nullptr ? continue_->index() : uint32_t(-1));
344 uint32_t repAddr = (rep!=
nullptr ? rep->address() : uint32_t(-1));
345 uint32_t whlAddr = (whl!=
nullptr ? whl->address() : uint32_t(-1));
350 vm.override_function(
"repeat", [
this](zenkit::DaedalusVm& vm) {
return repeat(vm); });
351 vm.override_function(
"while", [
this](zenkit::DaedalusVm& vm) {
return while_(vm); });
352 vm.override_function(
"mem_goto", [
this](zenkit::DaedalusVm& vm) {
return mem_goto(vm); });
353 vm.register_access_trap([
this](zenkit::DaedalusSymbol& i) {
return loop_trap(&i); });
355 for(
auto& i:vm.symbols()) {
356 if(i.type()!=zenkit::DaedalusDataType::FUNCTION)
362 uint32_t backJmp = 0;
365 std::vector<LoopDecr> loopStk;
366 for(uint32_t i=0; i<vm.size();) {
368 auto instr = vm.instruction_at(i);
371 if(instr.op==zenkit::DaedalusOpcode::PUSHV && instr.symbol==endIdx) {
372 auto loop = loopStk.back();
373 loopBacktrack[loop.pc] = i;
374 loopBacktrack[pc] = loop.backJmp;
377 else if(instr.op==zenkit::DaedalusOpcode::PUSHV && instr.symbol==cntIdx) {
378 if(!loopStk.empty()) {
379 auto func = findSymbolByAddress(pc); (void)func;
380 auto loop = loopStk.back();
381 loopBacktrack[pc] = loop.pc;
384 else if(instr.op==zenkit::DaedalusOpcode::BL && (instr.address==repAddr || instr.address==whlAddr)) {
386 if(instr.address==whlAddr) {
387 d.backJmp = traceBackExpression(vm, pc);
390 else if(instr.address==repAddr) {
394 loopStk.push_back(d);
399void DirectMemory::setupEngineMemory() {
404 memoryCallback(v,
id, std::memory_order::acquire);
407 memoryCallback(v,
id, std::memory_order::release);
410 memoryCallback(p,
id, std::memory_order::acquire);
413 memoryCallback(p,
id, std::memory_order::release);
416 const ptr32_t BAD_BUILTIN_PTR = 0xBAD40000;
417 const ptr32_t GothicFirstInstructionAddress = 4198400;
418 const ptr32_t MEMINT_oGame_Pointer_Address = 11208836;
419 const ptr32_t MEMINT_zTimer_Address = 10073044;
420 const ptr32_t MEMINT_gameMan_Pointer_Address = 9185624;
421 const ptr32_t ZFACTORY = 9276912;
422 const ptr32_t ContentParserAddress = 11223232;
423 const ptr32_t ZFONTMAN = 11221460;
424 const ptr32_t OCNPCFOCUS__FOCUSLIST_G2 = 11208440;
426 mem32.
pin(&versionHint, GothicFirstInstructionAddress, 4,
"MEMINT_ReportVersionCheck");
427 mem32.
pin(&oGame_Pointer, MEMINT_oGame_Pointer_Address, 4,
"oGame*");
428 mem32.
pin(&gameman_Ptr, MEMINT_gameMan_Pointer_Address, 4,
"GameMan*");
429 mem32.
pin(&zTimer, MEMINT_zTimer_Address,
sizeof(zTimer),
"zTimer");
430 mem32.
pin(&zFactory_Ptr, ZFACTORY, 4,
"zFactory*");
431 mem32.
pin(&fontMan_Ptr, ZFONTMAN, 4,
"zCFontMan*");
433 mem32.
pin(&focusList, OCNPCFOCUS__FOCUSLIST_G2,
sizeof(focusList),
"OCNPCFOCUS__FOCUSLIST_G2");
435 const ptr32_t INGAME_MENU_INSTANCE = 8980576;
436 mem32.
pin(menuName, INGAME_MENU_INSTANCE,
sizeof(menuName)-1,
"MENU_NAME");
439 const ptr32_t ZERRPTR = 9231568;
442 const ptr32_t LODENABLED = 8596020;
443 mem32.
alloc(LODENABLED, 4,
"LODENABLED");
445 const ptr32_t AMBIENTVOBSENABLED = 9079488;
446 mem32.
alloc(AMBIENTVOBSENABLED, 4,
"AMBIENTVOBSENABLED");
448 const ptr32_t GAME_HOLDTIME_ADDRESS = 11208840;
449 mem32.
alloc(GAME_HOLDTIME_ADDRESS, 4,
"GAME_HOLDTIME_ADDRESS");
451 if(
auto p = mem32.
deref<std::array<ptr32_t,6>>(OCNPCFOCUS__FOCUSLIST_G2)) {
453 (*p)[5] = BAD_BUILTIN_PTR;
457 const ptr32_t SPAWN_INSERTRANGE = 9153744;
458 mem32.
pin(&spawnRange, SPAWN_INSERTRANGE,
sizeof(spawnRange),
"spawnRange");
465 oGame_Pointer = mem32.
pin(&memGame,
sizeof(memGame),
"oGame");
471 mem_world.
WAYNET = BAD_BUILTIN_PTR;
472 mem_world.VOBLIST_NPCS = 0;
475 if(
auto v = vm.find_symbol_by_name(
"CurrSymbolTableLength")) {
476 v->set_int(
int(vm.symbols().size()));
495void DirectMemory::setupEngineText() {
497 const uint32_t OCNPC__ENABLE_EQUIPBESTWEAPONS = 7626662;
498 mem32.
alloc(OCNPC__ENABLE_EQUIPBESTWEAPONS, 18,
"OCNPC__ENABLE_EQUIPBESTWEAPONS");
500 const uint32_t OCNPC__GETNEXTENEMY = 7556941;
501 mem32.
alloc(OCNPC__GETNEXTENEMY, 48,
"OCNPC__GETNEXTENEMY");
503 const uint32_t OCITEMCONTAINER__CHECKSELECTEDITEM_ISACTIVE = 7378665;
504 mem32.
alloc(OCITEMCONTAINER__CHECKSELECTEDITEM_ISACTIVE, 5,
".text");
506 const uint32_t OCITEMCONTAINER__CHECKSELECTEDITEM_ISACTIVEP = 7378700;
507 mem32.
alloc(OCITEMCONTAINER__CHECKSELECTEDITEM_ISACTIVEP, 5,
".text");
509 const int OCSTEALCONTAINER__CREATELIST_ISARMOR_SP18 = 7384908;
510 mem32.
alloc(OCSTEALCONTAINER__CREATELIST_ISARMOR_SP18, 8,
".text");
512 const int OCNPCCONTAINER__CREATELIST_ISARMOR_SP18 = 7386812;
513 mem32.
alloc(OCNPCCONTAINER__CREATELIST_ISARMOR_SP18, 8,
".text");
515 const int OCSTEALCONTAINER__CREATELIST_ISARMOR = 7384900;
516 mem32.
alloc(OCSTEALCONTAINER__CREATELIST_ISARMOR, 8,
".text");
518 const int OCNPCCONTAINER__CREATELIST_ISARMOR = 7386805;
519 mem32.
alloc(OCNPCCONTAINER__CREATELIST_ISARMOR, 5,
".text");
521 const int OCNPCCONTAINER__HANDLEEVENT_ISEMPTY = 7387581;
522 mem32.
alloc(OCNPCCONTAINER__HANDLEEVENT_ISEMPTY, 5,
".text");
524 const int OCNPCINVENTORY__HANDLEEVENT_KEYWEAPONJZ = 7402077;
525 mem32.
alloc(OCNPCINVENTORY__HANDLEEVENT_KEYWEAPONJZ, 4,
".text");
527 const int OCNPCINVENTORY__HANDLEEVENT_KEYWEAPON = 7402065;
528 mem32.
alloc(OCNPCINVENTORY__HANDLEEVENT_KEYWEAPON, 8,
".text");
530 const int OCAIHUMAN__CHANGECAMMODEBYSITUATION_SWITCHMOBCAM = 6935573;
531 mem32.
alloc(OCAIHUMAN__CHANGECAMMODEBYSITUATION_SWITCHMOBCAM, 8,
".text");
534 const int INIT_RESTOREMOBFIRESTATES_P0 = 7482368;
535 const int INIT_RESTOREMOBFIRESTATES_P1 = 7482688;
536 mem32.
alloc(INIT_RESTOREMOBFIRESTATES_P0, 4,
".text");
537 mem32.
alloc(INIT_RESTOREMOBFIRESTATES_P1, 4,
".text");
540zenkit::DaedalusNakedCall DirectMemory::repeat(zenkit::DaedalusVm& vm) {
541 const int len = vm.pop_int();
542 zenkit::DaedalusSymbol* i = std::get<zenkit::DaedalusSymbol*>(vm.pop_reference());
544 auto rp = vm.instruction_at(vm.pc());
545 if(len==0 || i==
nullptr) {
546 auto jmp = loopBacktrack[vm.pc()];
547 vm.unsafe_jump(jmp-rp.size);
548 return zenkit::DaedalusNakedCall();
551 auto& pl = loopPayload[vm.pc()];
557 return zenkit::DaedalusNakedCall();
560zenkit::DaedalusNakedCall DirectMemory::while_(zenkit::DaedalusVm& vm) {
561 const int cond = vm.pop_int();
564 return zenkit::DaedalusNakedCall();
566 auto rp = vm.instruction_at(vm.pc());
567 auto jmp = loopBacktrack[vm.pc()];
568 vm.unsafe_jump(jmp-rp.size);
569 return zenkit::DaedalusNakedCall();
572zenkit::DaedalusNakedCall DirectMemory::mem_goto(zenkit::DaedalusVm& vm) {
573 const int idx = vm.pop_int();
576 auto func = findSymbolByAddress(at);
578 Log::e(
"Ikarus: invalid vm state");
579 return zenkit::DaedalusNakedCall();
582 auto rp = vm.instruction_at(at);
583 auto label = vm.find_symbol_by_name(
"mem_label");
584 uint32_t lblAddr = (label!=
nullptr ? label->address() : uint32_t(-1));
585 uint32_t pc = func->address();
587 for(uint32_t i=0, prev=0; i<at; ++i) {
588 auto instr = vm.instruction_at(pc);
589 if(instr.op==zenkit::DaedalusOpcode::BL && instr.address==lblAddr) {
590 auto lId = vm.instruction_at(prev);
591 if(lId.immediate==idx) {
592 vm.unsafe_jump(pc + instr.size - rp.size);
593 return zenkit::DaedalusNakedCall();
600 Log::e(
"Ikarus: invalid goto");
601 return zenkit::DaedalusNakedCall();
604void DirectMemory::loop_trap(zenkit::DaedalusSymbol* i) {
605 auto instr = vm.instruction_at(vm.pc());
606 if(instr.op != zenkit::DaedalusOpcode::PUSHV)
609 auto end = vm.find_symbol_by_name(
"END");
610 if(end!=
nullptr && instr.symbol==end->index()) {
611 auto bt = loopBacktrack[vm.pc()];
613 if(loopPayload.find(bt)==loopPayload.end()) {
615 vm.unsafe_jump(bt-instr.size);
619 auto& pl = loopPayload[bt];
621 Log::e(
"bad loop end");
625 const int32_t i = pl.i->get_int();
628 const uint32_t BLsize = 5;
629 vm.unsafe_jump(bt-instr.size+BLsize);
631 loopPayload.erase(bt);
636 if(loopBacktrack.find(vm.pc())!=loopBacktrack.end()) {
637 Log::e(
"bad loop trap");
642uint32_t DirectMemory::traceBackExpression(zenkit::DaedalusVm& vm, uint32_t pc) {
658 auto func = findSymbolByAddress(pc);
665 std::vector<zenkit::DaedalusInstruction> icodes;
666 for(uint32_t i=func->address(); i<pc && i<vm.size();) {
667 auto instr = vm.instruction_at(i);
669 icodes.push_back(instr);
675 int paramsNeeded = 1;
676 int instancesNeed = 0;
677 size_t at = icodes.size();
678 while((paramsNeeded>0 || instancesNeed>0) && at>0) {
680 const auto instr = icodes[at];
681 if(zenkit::DaedalusOpcode::ADD <= instr.op && instr.op <= zenkit::DaedalusOpcode::DIVMOVI)
683 else if(instr.op==zenkit::DaedalusOpcode::PUSHI) {
686 else if(instr.op==zenkit::DaedalusOpcode::PUSHV || instr.op==zenkit::DaedalusOpcode::PUSHVI) {
687 auto* sym = vm.find_symbol_by_index(instr.symbol);
688 if(sym!=
nullptr && sym->is_member())
692 else if(instr.op==zenkit::DaedalusOpcode::GMOVI) {
695 else if(instr.op==zenkit::DaedalusOpcode::BL) {
696 auto sym = vm.find_symbol_by_address(instr.address);
700 paramsNeeded += sym->count();
701 if(sym->has_return())
713 pc = func->address();
714 for(uint32_t i=0; i<at; ++i) {
715 auto instr = vm.instruction_at(pc);
722const zenkit::DaedalusSymbol* DirectMemory::findSymbolByAddress(uint32_t addr) {
723 auto fn = std::lower_bound(symbolsByAddress.begin(), symbolsByAddress.end(), addr, [](
const zenkit::DaedalusSymbol* l, uint32_t r){
724 return l->address()<r;
727 if(fn==symbolsByAddress.end())
728 return symbolsByAddress.back();
729 if((*fn)->address()==addr)
731 if(fn==symbolsByAddress.begin())
738 for(
auto& i:vm.symbols()) {
739 if(!i.is_const() || i.is_member())
741 if(i.type()!=zenkit::DaedalusDataType::INT)
743 if(ptr32_t(i.get_int())!=addr)
754void DirectMemory::memoryCallback(
zCParser& p, std::memory_order ord) {
755 if(ord==std::memory_order::acquire) {
764 v[i] = scriptSymbols + uint32_t(i)*uint32_t(
sizeof(
zCPar_Symbol));
773 auto trap = vm.instruction_at(vm.pc());
777 auto instr = vm.instruction_at(vm.pc());
779 auto src = findSymbolByAddress(vm.pc() - instr.size);
782 if(src!=dst || dst==
nullptr) {
783 if(src!=
nullptr && dst!=
nullptr)
784 Log::e(
"FIXME: unsafe jump: `\"", src->name(),
"\" -> \"", dst->name(),
"\"");
else
785 Log::e(
"FIXME: unsafe jump!");
792void DirectMemory::memoryCallback(ScriptVar& v, uint32_t index, std::memory_order ord) {
793 if(index>=vm.symbols().size()) {
795 Log::d(
"ikarus: symbol table is corrupted");
801 auto& sym = *vm.find_symbol_by_index(index);
802 if(sym.is_member()) {
803 Log::e(
"Ikarus: accessing member symbol (\"", sym.name(),
"\")");
807 switch (sym.type()) {
808 case zenkit::DaedalusDataType::FLOAT: {
809 if(ord==std::memory_order::release) {
811 Log::e(
"Ikarus: unable to write to mapped symbol (\"", sym.name(),
"\")");
813 auto val = sym.get_float();
815 Log::d(
"VAR: ", sym.name(),
" -> ", val);
819 case zenkit::DaedalusDataType::INT: {
820 if(ord==std::memory_order::release) {
821 sym.set_int(str._VTBL);
823 auto val = sym.get_int();
828 case zenkit::DaedalusDataType::STRING: {
829 if(ord==std::memory_order::release) {
837 Log::e(
"Ikarus: unable to write to mapped symbol (\"", sym.name(),
"\")");
839 auto& cstr = sym.get_string();
840 memAssignString(str, cstr);
846 Log::e(
"Ikarus: unable to map symbol (\"", sym.name(),
"\") to virtual memory");
851void DirectMemory::memoryCallback(
zCPar_Symbol& s, uint32_t index, std::memory_order ord) {
852 if(index>=vm.symbols().size()) {
854 Log::e(
"ikarus: symbol table is corrupted");
859 if(ord!=std::memory_order::acquire) {
860 auto& sym = *vm.find_symbol_by_index(index);
861 Log::e(
"ikarus: write to symbol ", sym.name(),
" table is not implemented");
865 auto symBitfield = [](zenkit::DaedalusSymbol& sym) {
868 flags |= zenkit::DaedalusSymbolFlag::CONST;
870 flags |= zenkit::DaedalusSymbolFlag::RETURN;
872 flags |= zenkit::DaedalusSymbolFlag::MEMBER;
873 if(sym.is_external())
874 flags |= zenkit::DaedalusSymbolFlag::EXTERNAL;
876 flags |= zenkit::DaedalusSymbolFlag::MERGED;
878 int32_t bitfield = 0;
879 bitfield |= (sym.count() & 0xFFF);
880 bitfield |= (int32_t(sym.type()) << 12);
881 bitfield |= (flags << 16);
885 auto symOffset = [](zenkit::DaedalusSymbol& sym) {
886 if(sym.is_member()) {
887 return int32_t(sym.offset_as_member());
889 else if(sym.type()==zenkit::DaedalusDataType::CLASS) {
891 return int32_t(sym.class_size());
893 else if(sym.type()==zenkit::DaedalusDataType::FUNCTION) {
895 return int32_t(sym.rtype());
901 auto symContent = [](zenkit::DaedalusSymbol& sym) {
902 switch (sym.type()) {
903 case zenkit::DaedalusDataType::VOID:
905 case zenkit::DaedalusDataType::FLOAT:
907 case zenkit::DaedalusDataType::INT:
908 return int32_t(sym.get_int());
909 case zenkit::DaedalusDataType::FUNCTION:
911 return int32_t(sym.address());
912 return int32_t(sym.get_int());
913 case zenkit::DaedalusDataType::STRING:
914 case zenkit::DaedalusDataType::CLASS:
915 case zenkit::DaedalusDataType::PROTOTYPE:
916 case zenkit::DaedalusDataType::INSTANCE:
923 auto& sym = *vm.find_symbol_by_index(index);
924 memAssignString(s.
name, sym.name());
928 s.
offset = symOffset(sym);
931 s.
filenr = int32_t(sym.file_index());
932 s.
line = int32_t(sym.line_start());
933 s.
line_anz = int32_t(sym.line_count());
934 s.
pos_beg = int32_t(sym.char_start());
935 s.
pos_anz = int32_t(sym.char_count());
943void DirectMemory::memAssignString(
zString& str, std::string_view cstr) {
945 str.
len = int32_t(cstr.size());
947 auto* chr =
reinterpret_cast<char*
>(mem32.
derefv(str.
ptr, uint32_t(str.
len)));
948 std::memcpy(chr, cstr.data(), cstr.length());
952void DirectMemory::memFromString(std::string& dst,
const zString& str) {
958 if(
const char* chr =
reinterpret_cast<const char*
>(mem32.
deref(str.
ptr, uint32_t(str.
len)))) {
959 dst.resize(
size_t(str.
len));
960 std::memcpy(dst.data(), chr, dst.size());
965void DirectMemory::memPrintstacktraceImplementation() {
966 static bool enable =
true;
969 Log::e(
"[start of stacktrace]");
970 vm.print_stack_trace();
971 Log::e(
"[end of stacktrace]");
974void DirectMemory::memSendToSpy(
int cat, std::string_view msg) {
975 Log::d(
"[zpy]: ", msg);
978void DirectMemory::memReplaceFunc(zenkit::DaedalusFunction dest, zenkit::DaedalusFunction func) {
979 auto* sf = func.value;
980 auto* sd = dest.value;
981 if(sd->name()==
"MEM_SENDTOSPY")
983 if(sd->name()==
"MEM_PRINTSTACKTRACE")
985 Log::d(
"mem_replacefunc: ",sd->name(),
" -> ",sf->name());
988void DirectMemory::ASMINT_Init() {
989 const int ASMINT_InternalStackSize = 1024;
991 if(!ASMINT_InternalStack) {
992 ASMINT_InternalStack = mem32.
alloc(4 * ASMINT_InternalStackSize);
994 if(
auto sym = vm.find_symbol_by_name(
"ASMINT_InternalStack")) {
995 if(sym->type()==zenkit::DaedalusDataType::INT)
996 sym->set_int(int32_t(ASMINT_InternalStack));
999 auto p = mem32.
pin(&ASMINT_CallTarget,
sizeof(ASMINT_CallTarget),
"ASMINT_CallTarget");
1000 if(
auto sym = vm.find_symbol_by_name(
"ASMINT_CallTarget")) {
1001 if(sym->type()==zenkit::DaedalusDataType::INT)
1002 sym->set_int(int32_t(p));
1006void DirectMemory::ASMINT_CallMyExternal() {
1007 auto mem = mem32.
deref(ASMINT_CallTarget);
1008 auto ins =
reinterpret_cast<const uint8_t*
>(std::get<0>(mem));
1009 auto len = std::get<1>(mem);
1011 cpu.
exec(ASMINT_CallTarget, ins, len);
1014void DirectMemory::setupMemoryFunctions() {
1015 vm.override_function(
"MEM_GetAddress_Init", [ ](){ });
1017 vm.override_function(
"MEM_PtrToInst", [
this](
int address) {
return mem_ptrtoinst(
ptr32_t(address)); });
1018 vm.override_function(
"_^", [
this](
int address) {
return mem_ptrtoinst(
ptr32_t(address)); });
1019 vm.override_function(
"MEM_InstToPtr", [
this](
int index) {
return mem_insttoptr(index); });
1020 vm.override_function(
"MEM_GetIntAddress", [
this](zenkit::DaedalusVm& vm){
return _takeref(vm); });
1021 vm.override_function(
"_@", [
this](zenkit::DaedalusVm& vm){
return _takeref(vm); });
1022 vm.override_function(
"MEM_GetStringAddress", [
this](zenkit::DaedalusVm& vm){
return _takeref(vm); });
1023 vm.override_function(
"_@s", [
this](zenkit::DaedalusVm& vm){
return _takeref(vm); });
1024 vm.override_function(
"MEM_GetFloatAddress", [
this](zenkit::DaedalusVm& vm){
return _takeref(vm); });
1025 vm.override_function(
"_@f", [
this](zenkit::DaedalusVm& vm){
return _takeref(vm); });
1027 vm.override_function(
"MEM_ReadInt", [
this](
int address){
return mem_readint(address); });
1028 vm.override_function(
"MEM_WriteInt", [
this](
int address,
int val){ mem_writeint(address, val); });
1029 vm.override_function(
"MEM_CopyBytes", [
this](
int src,
int dst,
int size){ mem_copybytes(src, dst, size); });
1030 vm.override_function(
"MEM_ReadString", [
this](
int sym){
return mem_readstring(sym); });
1031 vm.override_function(
"MEM_ReadStatArr", [
this](zenkit::DaedalusVm& vm){
return mem_readstatarr(vm); });
1032 vm.override_function(
"MEM_WriteStatArr", [
this](zenkit::DaedalusVm& vm){
return mem_writestatarr(vm); });
1035 vm.override_function(
"MEM_Alloc", [
this](
int amount ) {
return mem_alloc(amount); });
1036 vm.override_function(
"MEM_Free", [
this](
int address) { mem_free(address); });
1037 vm.override_function(
"MEM_Realloc", [
this](
int address,
int oldsz,
int size) {
return mem_realloc(address,oldsz,size); });
1040auto DirectMemory::_takeref(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1041 if(vm.top_is_reference()) {
1042 auto [ref, idx, context] = vm.pop_reference();
1044 Log::e(
"Ikarus: _takeref - unable take reference to array element");
1045 vm.push_int(int32_t(0xBAD10000));
1046 return zenkit::DaedalusNakedCall();
1049 if(ref->is_member()) {
1050 if(
auto d =
dynamic_cast<memory_instance*
>(context.get())) {
1051 const ptr32_t ptr = d->address;
1052 vm.push_int(int32_t(ptr + ref->offset_as_member()));
1053 return zenkit::DaedalusNakedCall();
1055 Log::e(
"Ikarus: _takeref - unable take reference to struct element");
1056 vm.push_int(int32_t(0xBAD10000));
1057 return zenkit::DaedalusNakedCall();
1060 const uint32_t
id = ref->index();
1061 const ptr32_t ptr = scriptVariables +
id*
ptr32_t(
sizeof(ScriptVar));
1062 if(
false && ref->type()==zenkit::DaedalusDataType::STRING) {
1063 if(
auto* s = mem32.deref<
zString>(ptr))
1064 memAssignString(*s, ref->get_string(0));
1065 ref->set_instance(std::make_shared<memory_instance>(*
this, ptr));
1067 vm.push_int(int32_t(ptr));
1068 return zenkit::DaedalusNakedCall();
1071 auto symbol = vm.pop_int();
1072 auto sym = vm.find_symbol_by_index(uint32_t(symbol));
1074 Log::e(
"Ikarus: _takeref - unable to resolve symbol");
1075 vm.push_int(int32_t(0xBAD10000));
1076 return zenkit::DaedalusNakedCall();
1079 if(sym->type()==zenkit::DaedalusDataType::INSTANCE) {
1080 auto inst = sym->get_instance().get();
1081 if(
auto d =
dynamic_cast<memory_instance*
>(inst)) {
1082 const ptr32_t ptr = d->address;
1083 vm.push_int(int32_t(ptr));
1084 return zenkit::DaedalusNakedCall();
1086 else if(inst!=
nullptr) {
1088 const ptr32_t ptr = scriptVariables + inst->symbol_index()*
ptr32_t(
sizeof(ScriptVar));
1089 vm.push_int(int32_t(ptr));
1090 return zenkit::DaedalusNakedCall();
1094 if(sym->type()==zenkit::DaedalusDataType::STRING) {
1095 Log::e(
"Ikarus: _takeref - not a memory-instance: ", sym->name());
1096 vm.push_int(int32_t(0xBAD20000));
1097 return zenkit::DaedalusNakedCall();
1100 Log::e(
"Ikarus: _takeref - not a memory-instance: ", sym->name());
1101 vm.push_int(int32_t(0xBAD20000));
1102 return zenkit::DaedalusNakedCall();
1105std::shared_ptr<zenkit::DaedalusInstance> DirectMemory::mem_ptrtoinst(
ptr32_t address) {
1107 Log::d(
"mem_ptrtoinst: address is null");
1108 if(scriptVariables<=address && address<scriptVariables +
ptr32_t(vm.symbols().size())*
ptr32_t(
sizeof(ScriptVar))) {
1110 uint32_t sId = (address-scriptVariables)/
ptr32_t(
sizeof(ScriptVar));
1111 auto sym = vm.find_symbol_by_index(sId);
1112 if(sym!=
nullptr && sym->type()==zenkit::DaedalusDataType::INSTANCE)
1113 return sym->get_instance();
1115 return std::make_shared<memory_instance>(*
this, address);
1118int DirectMemory::mem_insttoptr(
int index) {
1119 auto* sym = vm.find_symbol_by_index(uint32_t(index));
1120 if(sym==
nullptr || sym->type() != zenkit::DaedalusDataType::INSTANCE) {
1121 Log::e(
"MEM_InstToPtr: Invalid instance: ", index);
1125 const std::shared_ptr<zenkit::DaedalusInstance>& inst = sym->get_instance();
1126 if(
auto mem =
dynamic_cast<memory_instance*
>(inst.get())) {
1127 return int32_t(mem->address);
1132 const ptr32_t ptr = scriptVariables + inst->symbol_index()*
ptr32_t(
sizeof(ScriptVar));
1133 return int32_t(ptr);
1136int DirectMemory::mem_readint(
int address) {
1140void DirectMemory::mem_writeint(
int address,
int val) {
1141 mem32.
writeInt(uint32_t(address),val);
1144void DirectMemory::mem_copybytes(
int src,
int dst,
int size) {
1148std::string DirectMemory::mem_readstring(
int address) {
1151 memFromString(str, *s);
1157zenkit::DaedalusNakedCall DirectMemory::mem_readstatarr(zenkit::DaedalusVm& vm) {
1158 const int index = vm.pop_int();
1159 auto [ref, idx, context] = vm.pop_reference();
1161 const int ret = vm.get_int(context, ref, uint16_t(idx+index));
1164 return zenkit::DaedalusNakedCall();
1167auto DirectMemory::mem_writestatarr(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1168 const int value = vm.pop_int();
1169 const int index = vm.pop_int();
1170 auto [ref, idx, context] = vm.pop_reference();
1172 vm.set_int(context, ref, uint16_t(idx+index), value);
1173 return zenkit::DaedalusNakedCall();
1176int DirectMemory::mem_alloc(
int amount) {
1178 Log::d(
"alocation zero bytes");
1181 auto ptr = mem32.
alloc(uint32_t(amount));
1182 return int32_t(ptr);
1185int DirectMemory::mem_alloc(
int amount,
const char* comment) {
1187 Log::d(
"alocation zero bytes");
1190 auto ptr = mem32.
alloc(uint32_t(amount), comment);
1191 return int32_t(ptr);
1194void DirectMemory::mem_free(
int ptr) {
1198int DirectMemory::mem_realloc(
int address,
int oldsz,
int size) {
1200 return int32_t(ptr);
1204void DirectMemory::setupDirectFunctions() {
1205 vm.override_function(
"MEM_GetFuncIdByOffset", [
this](
int off) {
return mem_getfuncidbyoffset(off); });
1206 vm.override_function(
"MEM_AssignInst", [
this](
int index,
int ptr) { mem_assigninst(index, ptr); });
1208 vm.override_function(
"MEM_CallByID", [
this](zenkit::DaedalusVm& vm) {
return mem_callbyid(vm); });
1209 vm.override_function(
"MEM_CallByPtr", [
this](zenkit::DaedalusVm& vm) {
return mem_callbyptr(vm); });
1211 vm.override_function(
"memint_stackpushint", [
this](zenkit::DaedalusVm& vm) {
return memint_stackpushint (vm); });
1212 vm.override_function(
"memint_stackpushinst", [
this](zenkit::DaedalusVm& vm) {
return memint_stackpushinst(vm); });
1213 vm.override_function(
"memint_stackpushvar", [
this](zenkit::DaedalusVm& vm) {
return memint_stackpushvar (vm); });
1215 vm.override_function(
"memint_popstring", [
this](zenkit::DaedalusVm& vm) {
return memint_popstring(vm); });
1217 vm.override_function(
"mem_popintresult", [
this](zenkit::DaedalusVm& vm) {
return mem_popintresult(vm); });
1218 vm.override_function(
"mem_popstringresult", [
this](zenkit::DaedalusVm& vm) {
return mem_popstringresult(vm); });
1219 vm.override_function(
"mem_popinstresult", [
this](zenkit::DaedalusVm& vm) {
return mem_popinstresult(vm); });
1222int DirectMemory::mem_getfuncidbyoffset(
int off) {
1227 Log::e(
"TODO: mem_getfuncidbyoffset ", off);
1231void DirectMemory::mem_assigninst(
int index,
int ptr) {
1232 auto* sym = vm.find_symbol_by_index(uint32_t(index));
1234 Log::e(
"MEM_AssignInst: Invalid instance: ",index);
1237 sym->set_instance(std::make_shared<memory_instance>(*
this,
ptr32_t(ptr)));
1240void DirectMemory::directCall(zenkit::DaedalusVm& vm, zenkit::DaedalusSymbol& func) {
1241 if(func.type()!=zenkit::DaedalusDataType::FUNCTION) {
1242 Log::e(
"Bad unsafe function call");
1246 std::span<zenkit::DaedalusSymbol> params = vm.find_parameters_for_function(&func);
1251 vm.unsafe_call(&func);
1254zenkit::DaedalusNakedCall DirectMemory::mem_callbyid(zenkit::DaedalusVm& vm) {
1255 const uint32_t symbId = uint32_t(vm.pop_int());
1256 auto* sym = vm.find_symbol_by_index(symbId);
1257 if(sym==
nullptr || sym->type()!=zenkit::DaedalusDataType::FUNCTION) {
1258 Log::e(
"MEM_CallByID: Provided symbol is not callable (not function, prototype or instance): ", symbId);
1259 return zenkit::DaedalusNakedCall();
1261 directCall(vm, *sym);
1262 return zenkit::DaedalusNakedCall();
1265zenkit::DaedalusNakedCall DirectMemory::mem_callbyptr(zenkit::DaedalusVm& vm) {
1267 const auto address = uint32_t(vm.pop_int());
1268 auto sym = vm.find_symbol_by_address(address);
1269 if(sym==
nullptr || sym->type()!=zenkit::DaedalusDataType::FUNCTION) {
1271 std::snprintf(buf,
sizeof(buf),
"%x", address);
1272 Log::e(
"MEM_CallByPtr: Provided symbol is not callable (not function, prototype or instance): 0x", buf);
1273 return zenkit::DaedalusNakedCall();
1275 directCall(vm, *sym);
1276 return zenkit::DaedalusNakedCall();
1279auto DirectMemory::memint_stackpushint(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1280 return zenkit::DaedalusNakedCall();
1283auto DirectMemory::memint_stackpushinst(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1284 int id = vm.pop_int();
1285 auto sym = vm.find_symbol_by_index(uint32_t(
id));
1286 if(sym!=
nullptr && sym->type()==zenkit::DaedalusDataType::INSTANCE) {
1287 vm.push_instance(sym->get_instance());
1288 return zenkit::DaedalusNakedCall();
1290 vm.push_instance(
nullptr);
1291 return zenkit::DaedalusNakedCall();
1294auto DirectMemory::memint_stackpushvar(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1296 const int ptr = vm.pop_int(); (void)ptr;
1297 Log::d(
"TODO: memint_stackpushvar");
1298 return zenkit::DaedalusNakedCall();
1301auto DirectMemory::memint_popstring(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1302 return zenkit::DaedalusNakedCall();
1305auto DirectMemory::mem_popintresult(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1306 return zenkit::DaedalusNakedCall();
1309auto DirectMemory::mem_popstringresult(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1310 return zenkit::DaedalusNakedCall();
1313auto DirectMemory::mem_popinstresult(zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1314 return zenkit::DaedalusNakedCall();
1317void DirectMemory::setupMathFunctions() {
1318 vm.override_function(
"MKF", [](
int i) {
return mkf(i); });
1319 vm.override_function(
"TRUNCF", [](
int i) {
return truncf(i); });
1320 vm.override_function(
"ROUNDF", [](
int i) {
return roundf(i); });
1321 vm.override_function(
"ADDF", [](
int a,
int b) {
return addf(a,b); });
1322 vm.override_function(
"SUBF", [](
int a,
int b) {
return subf(a,b); });
1323 vm.override_function(
"MULF", [](
int a,
int b) {
return mulf(a,b); });
1324 vm.override_function(
"DIVF", [](
int a,
int b) {
return divf(a,b); });
1327int DirectMemory::mkf(
int v) {
1331int DirectMemory::truncf(
int v) {
1333 ret = std::truncf(ret);
1337int DirectMemory::roundf(
int v) {
1339 ret = std::roundf(ret);
1343int DirectMemory::addf(
int ia,
int ib) {
1349int DirectMemory::subf(
int ia,
int ib) {
1355int DirectMemory::mulf(
int ia,
int ib) {
1361int DirectMemory::divf(
int ia,
int ib) {
1367void DirectMemory::setupStringsFunctions() {
1369 vm.override_function(
"STR_SubStr", [](std::string_view str,
int start,
int count) -> std::string {
1370 if(start < 0 || (count < 0)) {
1371 Log::e(
"STR_SubStr: start and count may not be negative.");
1375 if(
size_t(start)>=str.size()) {
1376 Log::e(
"STR_SubStr: The desired start of the substring lies beyond the end of the string.");
1380 return std::string(str.substr(
size_t(start),
size_t(count)));
1385 vm.override_function(
"STR_Upper", [](std::string_view str){
1386 std::string s = std::string(str);
1388 c = char(std::toupper(c));
1393 vm.override_function(
"SB_TOSTRING", [
this]() -> std::string {
1394 struct StringBuilder {
1399 const auto _SB_CURRENT = this->vm.find_symbol_by_name(
"_SB_CURRENT");
1400 if(_SB_CURRENT==
nullptr || _SB_CURRENT->type()!=zenkit::DaedalusDataType::INT)
1403 auto text = mem32.
deref<StringBuilder>(
ptr32_t(_SB_CURRENT->get_int()));
1404 if(text->cln<=0 || text->ptr==0)
1406 auto cstr =
reinterpret_cast<const char*
>(mem32.
deref(text->ptr, uint32_t(text->cln)));
1407 return std::string(cstr,
size_t(text->cln));
1410 const ptr32_t STR_FROMCHAR = 4198592;
1412 if(self<scriptVariables)
1415 const uint32_t
id = (self - scriptVariables)/
ptr32_t(
sizeof(ScriptVar));
1416 const auto sx = vm.find_symbol_by_index(
id);
1417 if(sx==
nullptr || sx->type()!=zenkit::DaedalusDataType::STRING)
1420 auto [ptr, size] = mem32.
deref(pchr);
1421 const char* chr =
reinterpret_cast<const char*
>(ptr);
1422 if(chr==
nullptr || size==0) {
1427 while(chr[strsz] && strsz<size)
1429 sx->set_string(std::string(chr, strsz));
1433void DirectMemory::setupWinapiFunctions() {
1434 const ptr32_t WINAPI__LOADLIBRARY_ptr = 8577604;
1435 const ptr32_t WINAPI__GETPROCADDRESS_ptr = 8577688;
1436 mem32.
alloc(WINAPI__LOADLIBRARY_ptr, 4,
"WINAPI__LOADLIBRARY*");
1437 mem32.
alloc(WINAPI__GETPROCADDRESS_ptr, 4,
"WINAPI__GETPROCADDRESS*");
1440 mem32.
writeInt(WINAPI__LOADLIBRARY_ptr, int32_t(WINAPI__LOADLIBRARY));
1443 mem32.
writeInt(WINAPI__GETPROCADDRESS_ptr, int32_t(WINAPI__GETPROCADDRESS));
1446 auto [ptr, size] = mem32.
deref(pname);
1447 auto name = std::string_view(
reinterpret_cast<const char*
>(ptr),
reinterpret_cast<const char*
>(ptr)+size);
1448 Log::d(
"suppress LoadLibrary: ", name);
1453 auto [ptr, size] = mem32.
deref(pname);
1454 auto name = std::string_view(
reinterpret_cast<const char*
>(ptr),
reinterpret_cast<const char*
>(ptr)+size);
1455 Log::d(
"suppress GetProcAddress: ",name);
1459 const ptr32_t GETUSERNAMEA = 8080162;
1461 std::string_view uname =
"OpenGothic";
1463 const uint32_t max = pcbBuffer ? uint32_t(mem32.
readInt(pcbBuffer)) : 0;
1464 if(
auto ptr =
reinterpret_cast<char*
>(mem32.
derefv(lpBuffer, max))) {
1465 if(max>=uname.size()) {
1466 std::strncpy(
reinterpret_cast<char*
>(ptr),
"OpenGothic", max);
1467 ptr[uname.size()] =
'\0';
1472 mem32.
writeInt(pcbBuffer, int32_t(uname.size()+1));
1476 const ptr32_t GETLOCALTIME = 8079184;
1481 uint16_t wDayOfWeek;
1486 uint16_t wMilliseconds;
1489 if(
auto ptr = mem32.
deref<SystemTime>(lpSystemTime)) {
1490 const auto timePoint = std::chrono::system_clock::now();
1491 const std::time_t time = std::chrono::system_clock::to_time_t(timePoint);
1492 const auto t = std::localtime(&time);
1493 const auto ms = std::chrono::time_point_cast<std::chrono::milliseconds>(timePoint);
1495 ptr->wYear = uint16_t(t->tm_year + 1900);
1496 ptr->wMonth = uint16_t(t->tm_mon + 1);
1497 ptr->wDayOfWeek = uint16_t(t->tm_wday);
1498 ptr->wDay = uint16_t(t->tm_mday);
1499 ptr->wHour = uint16_t(t->tm_hour);
1500 ptr->wMinute = uint16_t(t->tm_min);
1501 ptr->wSecond = uint16_t(t->tm_sec);
1502 ptr->wMilliseconds = uint16_t(ms.time_since_epoch().count()%1000);
1507void DirectMemory::setupUtilityFunctions() {
1508 static auto generateCrcTable = []() {
1509 std::array<uint32_t, 256> table;
1510 uint32_t polynomial = 0xEDB88320;
1511 for (uint32_t i = 0; i < 256; i++) {
1513 for (
size_t j = 0; j < 8; j++) {
1515 c = polynomial ^ (c >> 1);
1525 const ptr32_t GETBUFFERCRC32_G2 = 6265360;
1527 if(buf==0 || bufLen<=0)
1530 const auto ptr =
reinterpret_cast<const uint8_t*
>(mem32.
deref(buf,uint32_t(bufLen)));
1531 static auto table = generateCrcTable();
1533 uint32_t initial = 0;
1534 uint32_t c = initial ^ 0xFFFFFFFF;
1535 for(
int i = 0; i < bufLen; ++i) {
1536 c = table[(c ^ ptr[i]) & 0xFF] ^ (c >> 8);
1538 return int32_t(c ^ 0xFFFFFFFF);
1541 const ptr32_t QSORT_G2 = 8195951;
1543 Log::e(
"LeGo: TODO: QSORT_G2(...)");
1546 const ptr32_t ZERROR__SETTARGET = 4513616;
1551 const int SYSGETTIMEPTR_G2 = 5264000;
1553 return uint32_t(gameScript.
tickCount());
1557void DirectMemory::setupHookEngine() {
1558 vm.override_function(
"HookEngineI", [](
int address,
int oldInstr, zenkit::DaedalusFunction function){
1559 auto sym = function.value;
1560 auto name = sym==
nullptr ?
"" : sym->name().c_str();
1561 Log::e(
"not implemented call [HookEngineI] (",
reinterpret_cast<void*
>(uint64_t(address)),
1565 const ptr32_t ZCCONSOLE__REGISTER = 7875296;
1575 vm.override_function(
"LOCALS", [
this](zenkit::DaedalusVm& vm) -> zenkit::DaedalusNakedCall {
1576 auto sym = findSymbolByAddress(vm.pc());
1578 auto sx = vm.find_symbol_by_index(sym->index());
1579 sx->set_local_variables_enable(
true);
1581 return zenkit::DaedalusNakedCall();
1583 vm.override_function(
"FINAL", []() {
1584 Log::e(
"LeGo: 'final' is not implemented");
1590void DirectMemory::setupzCParserFunctions() {
1591 const ptr32_t ZCPARSER__GETINDEX_G2 = 7943280;
1593 if(
auto s = vm.find_symbol_by_name(sym))
1594 return int32_t(s->index());
1598 const ptr32_t ZCPARSER__CREATEINSTANCE = 7942048;
1600 auto *sym = vm.find_symbol_by_index(uint32_t(instId));
1602 if(sym !=
nullptr && sym->type() == zenkit::DaedalusDataType::INSTANCE) {
1603 cls = vm.find_symbol_by_index(sym->parent());
1606 if(sym==
nullptr || cls ==
nullptr) {
1607 Log::e(
"LeGo::createInstance invalid symbold id (", instId,
")");
1611 auto inst = std::make_shared<memory_instance>(*
this, ptr);
1613 auto self = vm.find_symbol_by_name(
"SELF");
1614 auto prevSelf = self !=
nullptr ? self->get_instance() :
nullptr;
1615 auto prevGi = vm.unsafe_get_gi();
1617 self->set_instance(inst);
1619 vm.unsafe_set_gi(inst);
1620 vm.unsafe_call(sym);
1622 vm.unsafe_set_gi(prevGi);
1624 self->set_instance(prevSelf);
1626 sym->set_instance(inst);
1631void DirectMemory::setupInitFileFunctions() {
1632 vm.override_function(
"MEM_GetGothOpt", [](std::string_view sec, std::string_view opt) {
1633 return std::string(
Gothic::inst().settingsGetS(sec, opt));
1635 vm.override_function(
"MEM_GetModOpt", [](std::string_view sec, std::string_view opt) {
1636 Log::e(
"TODO: mem_getmodopt(", sec,
", ", opt,
")");
1637 return std::string(
"");
1639 vm.override_function(
"MEM_GothOptSectionExists", [](std::string_view sec) {
1640 Log::e(
"TODO: mem_gothoptaectionexists(", sec,
")");
1643 vm.override_function(
"MEM_GothOptExists", [](std::string_view sec, std::string_view opt) {
1644 if(sec==
"INTERNAL" && opt==
"UnionActivated") {
1648 Log::e(
"TODO: mem_gothoptexists(", sec,
", ", opt,
")");
1651 vm.override_function(
"MEM_ModOptSectionExists", [](std::string_view sec) {
1652 Log::e(
"TODO: mem_modoptsectionexists(", sec,
")");
1655 vm.override_function(
"MEM_ModOptExists", [](std::string_view sec, std::string_view opt) {
1656 Log::e(
"TODO: mem_modoptexists(", sec,
", ", opt,
")");
1659 vm.override_function(
"MEM_SetGothOpt", [](std::string_view sec, std::string_view opt, std::string_view v) {
1660 Log::e(
"TODO: mem_setgothopt(", sec,
", ", opt,
", ", v,
")");
1664void DirectMemory::setupUiFunctions() {
1666 const int ZCVIEW__ZCVIEW = 8017664;
1667 const int ZCVIEW__OPEN = 8023040;
1668 const int ZCVIEW__CLOSE = 8023600;
1669 const int ZCVIEW_TOP = 8021904;
1670 const int ZCVIEW__SETSIZE = 8026016;
1671 const int zCVIEW__MOVE = 8025824;
1672 const int ZCVIEW__INSERTBACK = 8020272;
1676 Log::e(
"LeGo: zCView__zCView - unable to resolve address");
1682 view->VSIZEX = x2-x1;
1683 view->VSIZEY = y2-y1;
1689 Log::e(
"LeGo: zCView__Open - unable to resolve address");
1692 Log::e(
"LeGo: zCView__Open");
1698 Log::e(
"LeGo: zCView__Close - unable to resolve address");
1706 Log::e(
"LeGo: zCView__Top - unable to resolve address");
1714 Log::e(
"LeGo: zCView__SetSize - unable to resolve address");
1725 Log::e(
"LeGo: zCView__Move - unable to resolve address");
1735 Log::e(
"LeGo: zCView__InsertBack - unable to resolve address");
1738 Log::e(
"LeGo: zCView__InsertBack: ", img);
1742 const int ZCTEXTURE__LOAD = 6239904;
1744 Log::e(
"LeGo: zCTexture__Load: ", img);
1749void DirectMemory::setupFontFunctions() {
1750 const ptr32_t ZCFONTMAN__LOAD = 7897808;
1751 const ptr32_t ZCFONTMAN__GETFONT = 7898288;
1753 Log::e(
"LeGo: zCFontMan__Load");
1757 Log::e(
"LeGo: zCFontMan__GetFont");
1762void DirectMemory::tickUi(uint64_t dt) {
1765 vScreen->PSIZEX = 800;
1766 vScreen->PSIZEY = 600;
1771 auto* vList = vPrint->TEXTLINES_NEXT!=0 ? mem32.
deref<
const zCList>(vPrint->TEXTLINES_NEXT) : nullptr;
1772 while(vList!=
nullptr) {
1775 memFromString(dst, textView->text);
1778 vList = vList->next!=0 ? mem32.
deref<
const zCList>(vList->next) : 0;
1783void DirectMemory::setupNpcFunctions() {
1784 const ptr32_t OCNPC__GETSLOTITEM = 7544720;
1786 Log::e(
"LeGo: OCNPC__GETSLOTITEM(", slot,
")");
1790 const ptr32_t OCNPC__EQUIPWEAPON = 7577648;
1792 Log::e(
"LeGo: OCNPC__EQUIPWEAPON(", pItem,
")");
1796void DirectMemory::setupWorldFunctions() {
1797 const ptr32_t OCWORLD__SEARCHVOBBYNAME_G2 = 7865872;
1799 Log::e(
"LeGo: OCWORLD__SEARCHVOBBYNAME_G2(", vob,
")");
1802 const ptr32_t OCWORLD__SEARCHVOBLISTBYNAME_G2 = 7866048;
1804 Log::e(
"LeGo: OCWORLD__SEARCHVOBLISTBYNAME_G2(", vob,
")");
void exec(const ptr32_t basePc, const uint8_t *code, size_t len)
void register_cdecl(ptr32_t addr, const std::function< R(Args...)> &callback)
void register_stdcall(ptr32_t addr, const std::function< R(Args...)> &callback)
void register_thiscall(ptr32_t addr, const std::function< R(Args...)> &callback)
DirectMemory(GameScript &owner, zenkit::DaedalusVm &vm)
static bool isRequired(zenkit::DaedalusScript &vm)
void eventPlayAni(std::string_view ani)
auto demangleAddress(uint32_t addr) -> std::string_view
auto menuMain() const -> std::string_view
const zenkit::IFocus & focusMage() const
uint64_t tickCount() const
const World & world() const
Compatibility::ptr32_t ptr32_t
void setCallbackW(Type t, const T &fn)
int32_t readInt(ptr32_t address)
void * derefv(ptr32_t address, uint32_t size)
ptr32_t alloc(uint32_t size, const char *comment=nullptr)
ptr32_t realloc(ptr32_t address, uint32_t size)
ptr32_t pin(void *mem, ptr32_t address, uint32_t size, const char *comment=nullptr)
void setCallbackR(Type t, const T &fn)
void copyBytes(ptr32_t src, ptr32_t dst, uint32_t size)
auto deref(ptr32_t address) -> std::tuple< void *, uint32_t >
void writeInt(ptr32_t address, int32_t v)
bool setPosition(float x, float y, float z)
static float intBitsToFloat(int32_t i)
static int32_t floatBitsToInt(float f)
static uint32_t nextPot(uint32_t x)
ptr32_t _ZCSESSION_VIEWPORT