From 3b690173060e32b46f1061eeccba31f9bf56e58f Mon Sep 17 00:00:00 2001 From: DiaLight Date: Tue, 8 Oct 2024 07:55:27 +0300 Subject: [PATCH] fixed single frame traces fixed crash on rooms limit added windowed option experimental options with rooms limit --- mapping/DKII_EXE_v170.sgmap | 191 ++++++++-------- src/CMakeLists.txt | 1 + src/dk2/CBridge.cpp | 125 ++++++++++ src/dk2/CDefaultPlayerInterface.cpp | 2 +- src/dk2/CRoom.cpp | 277 +++++++++++++++++++++-- src/dk2/MyComputerPlayer.cpp | 8 +- src/dk2/RegKey.cpp | 2 +- src/dk2/engine/draw_functions.cpp | 2 +- src/dk2/engine/window_proc_functions.cpp | 4 +- src/dk2/entities/CCreature.cpp | 2 +- src/dk2/entities/CPlayer.cpp | 2 +- src/dkii_exe_functions.cpp | 2 +- src/main.cpp | 48 +++- src/patches/gog_patch_dll/gog_patch.cpp | 13 +- src/patches/gog_patch_dll/gog_patch.h | 19 +- src/patches/micro_patches.cpp | 8 + src/patches/micro_patches.h | 7 + src/replace_globals.map | 9 + src/tools/bug_hunter.cpp | 169 +++++++++++--- src/tools/bug_hunter.h | 1 + tools/msvc_mangler/msvc_mangler.cpp | 6 + 21 files changed, 729 insertions(+), 169 deletions(-) create mode 100644 src/dk2/CBridge.cpp diff --git a/mapping/DKII_EXE_v170.sgmap b/mapping/DKII_EXE_v170.sgmap index 093d1d4..9c50d4e 100644 --- a/mapping/DKII_EXE_v170.sgmap +++ b/mapping/DKII_EXE_v170.sgmap @@ -282,7 +282,7 @@ struct: id=vtbl_0066CC94,name=CBridge,size=9855,vtable=instance_0066CC94,super=v field: name=f2CA_handlers1 type: kind=array,count=23 type: kind=int,size=4 - field: name=dword_arr_x4 + field: name=dword_arr_x4_objStart type: kind=array,count=4 type: kind=int,size=4 field: name=f336_effect_list @@ -378,13 +378,13 @@ struct: id=vtbl_0066CC94,name=CBridge,size=9855,vtable=instance_0066CC94,super=v type: kind=int,size=4 field: name=field_13A3 type: kind=int,size=4 - field: name=field_13A7 + field: name=f13A7__minX type: kind=int,size=4,signed=True - field: name=field_13AB + field: name=f13AB__minY type: kind=int,size=4,signed=True - field: name=field_13AF + field: name=f13AF__maxX type: kind=int,size=4,signed=True - field: name=field_13B3 + field: name=f13B3__maxY type: kind=int,size=4,signed=True field: name=field_13B7 type: kind=int,size=4,signed=True @@ -3490,11 +3490,12 @@ struct: id=instance_0066D1D4,name=CEngineInterface_vtbl,size=272 field: name=f64 type: kind=ptr type: kind=function,declspec=thiscall - ret: kind=void + ret: kind=int,size=4,signed=True arg: kind=ptr type: kind=void - arg: kind=int,size=4,signed=True - arg: kind=int,size=4,signed=True + arg: kind=int,size=2,signed=True + arg: kind=ptr + type: kind=struct,id=vec_xyz arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True field: name=f68 @@ -7580,7 +7581,7 @@ struct: id=instance_0066F7FC,name=CSoundSystem_vtbl,size=128 arg: kind=int,size=4,signed=True arg: kind=ptr,is_const=True type: kind=int,size=1,signed=True,winapi=char - field: name=CSoundSystem::fun_5678F0 + field: name=CSoundSystem_fun_5678F0 type: kind=ptr type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True @@ -7590,7 +7591,7 @@ struct: id=instance_0066F7FC,name=CSoundSystem_vtbl,size=128 arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=ptr - type: kind=void + type: kind=struct,id=vec_xyz field: name=CSoundSystem::fun_567810 type: kind=ptr type: kind=function,declspec=thiscall @@ -10746,7 +10747,7 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 type: kind=void arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True - field: name=loc_508DD0_getTerrainDataObj + field: name=f70_508DD0_getTerrainDataObj type: kind=ptr type: kind=function,declspec=thiscall ret: kind=ptr @@ -10810,7 +10811,7 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 arg: kind=ptr type: kind=int,size=4 arg: kind=int,size=1 - field: name=CWorld::fun_50D0B0 + field: name=f98_50D0B0_getMyRoomDataObj type: kind=ptr type: kind=function,declspec=thiscall ret: kind=ptr @@ -11066,7 +11067,7 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 arg: kind=ptr type: kind=int,size=4 arg: kind=int,size=1 - field: name=getDoorTypeData + field: name=f138_getMyDoorDataObj type: kind=ptr type: kind=function,declspec=thiscall ret: kind=ptr @@ -11131,7 +11132,7 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 arg: kind=ptr type: kind=int,size=4 arg: kind=int,size=1 - field: name=getTrapTypeData + field: name=f160_getMyTrapDataObj type: kind=ptr type: kind=function,declspec=thiscall ret: kind=ptr @@ -11195,7 +11196,7 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 arg: kind=ptr type: kind=void arg: kind=int,size=1 - field: name=findMyObjectDataObjByTypeId_50DB20 + field: name=f188_50DB20_getMyObjectDataObj type: kind=ptr type: kind=function,declspec=thiscall ret: kind=ptr @@ -11296,7 +11297,7 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 arg: kind=ptr type: kind=int,size=4 arg: kind=int,size=4,signed=True - field: name=findCreatureDataObjByTypeId_50E3A0 + field: name=f1C8_50E3A0_getMyCreatureDataObj type: kind=ptr type: kind=function,declspec=thiscall ret: kind=ptr @@ -11466,11 +11467,13 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 arg: kind=int,size=2,signed=True field: name=sub_509280 type: kind=ptr - type: kind=function,declspec=stdcall - ret: kind=int,size=4,signed=True - arg: kind=int,size=4,signed=True + type: kind=function,declspec=thiscall + ret: kind=int,size=4,signed=True,winapi=BOOL,fname=BOOL + arg: kind=ptr + type: kind=struct,id=vtbl_0066E3EC arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True + arg: kind=int,size=2,signed=True arg: kind=int,size=4,signed=True field: name=sub_509310 type: kind=ptr @@ -11779,7 +11782,7 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr - type: kind=int,size=1,signed=True,winapi=char + type: kind=void arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True field: name=CWorld::fun_510210 @@ -12066,8 +12069,10 @@ struct: id=instance_0066E3EC,path=dk2,name=CWorld_vtbl,size=920 arg: kind=int,size=4,signed=True field: name=sub_5092B0 type: kind=ptr - type: kind=function,declspec=stdcall - ret: kind=int,size=4,signed=True + type: kind=function,declspec=thiscall + ret: kind=int,size=4,signed=True,winapi=BOOL,fname=BOOL + arg: kind=ptr + type: kind=struct,id=vtbl_0066E3EC arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=int,size=2,signed=True @@ -16632,19 +16637,19 @@ struct: id=constructor_00506660,name=MyManufactureList,size=2056 type: kind=ptr type: kind=struct,id=vtbl_0066E3EC struct: id=constructor_00452B30,path=dk2/world/map,name=MyMapElement,size=16 - field: name=field_0 + field: name=f0_sceneObjIdx type: kind=int,size=2 - field: name=f2_roomId + field: name=f2__roomIdFFF type: kind=int,size=2 field: name=f4_nextSlab type: kind=struct,id=pos2ub field: name=field_6 type: kind=int,size=2 - field: name=f8__playerId + field: name=f8__playerIdFFF type: kind=int,size=2,signed=True field: name=fA_arr6DA4A8_idx type: kind=int,size=1 - field: name=fB_flags + field: name=fB_flags_and_burnLevel type: kind=int,size=1 field: name=field_C type: kind=int,size=1 @@ -17486,9 +17491,11 @@ struct: id=constructor_004EAB70,path=dk2/entities/data,name=MyRoomDataObj,size=1 field: name=field_439 type: kind=int,size=4,signed=True field: name=field_43D - type: kind=int,size=2,signed=True - field: name=field_43F - type: kind=int,size=2,signed=True + type: kind=int,size=1,signed=True,winapi=char + field: name=field_43E + type: kind=int,size=1,signed=True,winapi=char + field: name=f43F_moneyCost + type: kind=int,size=2 field: name=field_441 type: kind=int,size=2,signed=True field: name=field_443 @@ -17501,13 +17508,13 @@ struct: id=constructor_004EAB70,path=dk2/entities/data,name=MyRoomDataObj,size=1 type: kind=int,size=4,signed=True field: name=field_44D type: kind=int,size=1,signed=True,winapi=char - field: name=field_44E + field: name=f44E__terrainType type: kind=int,size=1,signed=True,winapi=char field: name=field_44F type: kind=int,size=1,signed=True,winapi=char field: name=field_450 type: kind=int,size=2,signed=True - field: name=field_452 + field: name=f452_someTy type: kind=int,size=1,signed=True,winapi=char field: name=field_453 type: kind=int,size=1,signed=True,winapi=char @@ -17556,9 +17563,9 @@ struct: id=constructor_004EBFE0,name=MyRooms,size=28 field: name=fE_firstRoomId type: kind=int,size=2 field: name=f10__nextRoomId - type: kind=int,size=2,signed=True + type: kind=int,size=2 field: name=f12__counter - type: kind=int,size=4,signed=True + type: kind=int,size=4 field: name=field_16 type: kind=int,size=4,signed=True field: name=f1A__roomSceneObjId @@ -18657,18 +18664,14 @@ struct: id=constructor_004F6570,path=dk2/entities/data,name=MyTerrainDataObj,siz type: kind=int,size=2,signed=True field: name=field_1B5 type: kind=int,size=4,signed=True - field: name=field_1B9 - type: kind=int,size=2,signed=True - field: name=field_1BB - type: kind=int,size=2,signed=True - field: name=field_1BD - type: kind=int,size=2,signed=True + field: name=f1B9__vec + type: kind=struct,id=vec3us field: name=field_1BF type: kind=int,size=4,signed=True field: name=field_1C3 type: kind=int,size=1,signed=True,winapi=char field: name=f1C4_arr6DA4A8_idx - type: kind=int,size=1,signed=True,winapi=char + type: kind=int,size=1 field: name=field_1C5 type: kind=int,size=1,signed=True,winapi=char field: name=field_1C6 @@ -20355,8 +20358,8 @@ struct: id=instance_006F2550,name=Obj6F2550,size=1202 type: kind=int,size=2,signed=True field: name=field_398 type: kind=int,size=2,signed=True - field: name=field_39A - type: kind=int,size=1,signed=True,winapi=char + field: name=f39A_salePriceMultiplier + type: kind=int,size=1 field: name=field_39B type: kind=int,size=1,signed=True,winapi=char field: name=field_39C @@ -26467,7 +26470,7 @@ global: va=0043C310,name=fun_43C310,size=2238,member_of=vtbl_0066CC94 arg: kind=int,size=4,signed=True arg: kind=ptr type: kind=ptr - type: kind=struct,id=vtbl_0066E3DC + type: kind=struct,id=constructor_004F6570 global: va=0043CBD0,name=sub_43CBD0,size=92 type: kind=function,declspec=thiscall ret: kind=void @@ -26578,14 +26581,13 @@ global: va=0043E2F0,name=allocateRenderObj,size=44,member_of=vtbl_0066CC94 arg: kind=int,size=4,signed=True global: va=0043E320,name=sub_43E320,size=276,member_of=vtbl_0066CC94 type: kind=function,declspec=thiscall - ret: kind=ptr - type: kind=void + ret: kind=void arg: kind=ptr type: kind=struct,id=vtbl_0066CC94 arg: kind=int,size=4 arg: kind=int,size=4 arg: kind=ptr - type: kind=struct,id=vtbl_0066E3DC + type: kind=struct,id=constructor_004F6570 arg: kind=ptr type: kind=struct,id=first_visited_0043A6D6 global: va=0043E440,name=sub_43E440,size=1001,member_of=vtbl_0066CC94 @@ -26842,9 +26844,10 @@ global: va=00441060,name=fun_441060,size=165,member_of=vtbl_0066CC94 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr - type: kind=int,size=4,signed=True + type: kind=struct,id=vtbl_0066CC94 arg: kind=int,size=2,signed=True - arg: kind=int,size=4,signed=True + arg: kind=ptr + type: kind=struct,id=vec_xyz arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True global: va=00441110,name=Bridge_cpp_441110,size=269 @@ -27020,7 +27023,7 @@ global: va=00441B00,name=fun_441B00,size=363,member_of=vtbl_0066CC94 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr - type: kind=int,size=4 + type: kind=struct,id=vtbl_0066CC94 arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True global: va=00441C70,name=setTexturesPath_441C70,size=69,member_of=vtbl_0066CC94 @@ -27041,7 +27044,8 @@ global: va=00441CD0,name=sub_441CD0,size=323,member_of=vtbl_0066CC94 ret: kind=int,size=4,signed=True arg: kind=ptr type: kind=struct,id=vtbl_0066CC94 - arg: kind=int,size=4,signed=True + arg: kind=ptr + type: kind=struct,id=constructor_00452B30 arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True global: va=00441E20,name=fun_441E20,size=14,member_of=vtbl_0066CC94 @@ -27488,8 +27492,7 @@ global: va=004435E0,name=sub_4435E0,size=47 arg: kind=int,size=4 global: va=00443610,name=sub_443610,size=701,member_of=vtbl_0066CC94 type: kind=function,declspec=thiscall - ret: kind=ptr - type: kind=struct,id=vtbl_0066E3DC + ret: kind=void arg: kind=ptr type: kind=struct,id=vtbl_0066CC94 arg: kind=int,size=4,signed=True @@ -27545,7 +27548,7 @@ global: va=00444970,name=sub_444970,size=1433,member_of=vtbl_0066CC94 type: kind=struct,id=first_visited_0043A6D6 global: va=00444F10,name=sub_444F10,size=4642,member_of=vtbl_0066CC94 type: kind=function,declspec=thiscall - ret: kind=int,size=4,signed=True + ret: kind=int,size=4 arg: kind=ptr type: kind=struct,id=vtbl_0066CC94 arg: kind=int,size=4,signed=True @@ -28655,18 +28658,20 @@ global: va=0044F5D0,name=hasPlayerRoomWithType,size=81,member_of=vtbl_0066D3E4 arg: kind=int,size=4,signed=True arg: kind=int,size=1,signed=True,winapi=char arg: kind=int,size=2,signed=True -global: va=0044F630,name=sub_44F630,size=313 +global: va=0044F630,name=sub_44F630,size=313,member_of=vtbl_0066D3E4 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True,winapi=BOOL,fname=BOOL - arg: kind=int,size=4,signed=True + arg: kind=ptr + type: kind=struct,id=vtbl_0066D3E4 arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=int,size=2,signed=True arg: kind=int,size=4,signed=True -global: va=0044F770,name=sub_44F770,size=141 +global: va=0044F770,name=sub_44F770,size=141,member_of=vtbl_0066D3E4 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True,winapi=BOOL,fname=BOOL - arg: kind=int,size=4,signed=True + arg: kind=ptr + type: kind=struct,id=vtbl_0066D3E4 arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=int,size=2,signed=True @@ -29095,14 +29100,16 @@ global: va=00452D80,name=sub_452D80,size=64 type: kind=int,size=1 arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True -global: va=00452DC0,name=sub_452DC0,size=254 +global: va=00452DC0,name=sub_452DC0,size=254,member_of=constructor_00452B30 type: kind=function,declspec=thiscall - ret: kind=int,size=4,signed=True - arg: kind=int,size=4,signed=True + ret: kind=int,size=4 + arg: kind=ptr + type: kind=struct,id=constructor_00452B30 arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=ptr - type: kind=int,size=4,signed=True + type: kind=ptr + type: kind=struct,id=constructor_004F6570 global: va=00452EC0,name=sub_452EC0,size=96 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True,winapi=BOOL,fname=BOOL @@ -29406,7 +29413,7 @@ global: va=004558F0,name=MyMapElement_calcChecksum,size=152 global: va=00455990,name=sub_455990,size=17,member_of=constructor_00452B30 type: kind=function,declspec=thiscall ret: kind=ptr - type: kind=struct,id=vtbl_0066E3DC + type: kind=struct,id=vtbl_0066D99C arg: kind=ptr type: kind=struct,id=constructor_00452B30 global: va=004559B0,name=getRoom,size=17,member_of=constructor_00452B30 @@ -36187,7 +36194,7 @@ global: va=004BA2D0,name=sub_4BA2D0,size=324 arg: kind=int,size=4 arg: kind=int,size=4 arg: kind=int,size=4 -global: va=004BA420,name=loadRooms_4BA420,size=767,member_of=vtbl_0066D99C +global: va=004BA420,name=moneyRoom_4BA420,size=767,member_of=vtbl_0066D99C type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -36195,8 +36202,7 @@ global: va=004BA420,name=loadRooms_4BA420,size=767,member_of=vtbl_0066D99C arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True - arg: kind=ptr - type: kind=struct,id=vtbl_0066D654 + arg: kind=int,size=4,signed=True global: va=004BA720,name=sub_4BA720,size=171,member_of=vtbl_0066D99C type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True @@ -37303,7 +37309,7 @@ global: va=004C5BE0,name=sub_4C5BE0,size=68 arg: kind=ptr type: kind=int,size=1 arg: kind=int,size=4,signed=True -global: va=004C5C30,name=fun_4C5C30,size=373,member_of=vtbl_0066D99C +global: va=004C5C30,name=fun_4C5C30_buildRoom,size=373,member_of=vtbl_0066D99C type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -37315,7 +37321,7 @@ global: va=004C5C30,name=fun_4C5C30,size=373,member_of=vtbl_0066D99C arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True -global: va=004C5DB0,name=fun_4C5DB0,size=407,member_of=vtbl_0066D99C +global: va=004C5DB0,name=destroyRoom,size=407,member_of=vtbl_0066D99C type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -40196,10 +40202,11 @@ global: va=004EBEF4,name=jpt_4EADC8,size=24 global: va=004EBF0C,name=idt_4EADC2,size=13 type: kind=array,count=13 type: kind=int,size=1 -global: va=004EBF20,name=sub_4EBF20,size=42 +global: va=004EBF20,name=_getSalePrice,size=42,member_of=constructor_004EAB70 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True - arg: kind=int,size=4,signed=True + arg: kind=ptr + type: kind=struct,id=constructor_004EAB70 global: va=004EBF50,name=sub_4EBF50,size=134 type: kind=function,declspec=thiscall ret: kind=ptr @@ -40269,7 +40276,7 @@ global: va=004EC490,name=createRoom,size=267,member_of=constructor_004EBFE0 arg: kind=int,size=2 arg: kind=ptr type: kind=int,size=2 -global: va=004EC5A0,name=sub_4EC5A0,size=176,member_of=constructor_004EBFE0 +global: va=004EC5A0,name=createRoomAndAttach,size=176,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -40280,7 +40287,7 @@ global: va=004EC5A0,name=sub_4EC5A0,size=176,member_of=constructor_004EBFE0 arg: kind=int,size=2,signed=True arg: kind=ptr type: kind=int,size=2 -global: va=004EC650,name=sub_4EC650,size=676,member_of=constructor_004EBFE0 +global: va=004EC650,name=sub_4EC650__reattach0,size=676,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -40290,7 +40297,7 @@ global: va=004EC650,name=sub_4EC650,size=676,member_of=constructor_004EBFE0 arg: kind=int,size=4,signed=True arg: kind=int,size=2,signed=True arg: kind=ptr - type: kind=int,size=1 + type: kind=int,size=1,signed=True,fname=int8_t arg: kind=ptr type: kind=ptr type: kind=struct,id=vtbl_0066DB7C @@ -40305,14 +40312,14 @@ global: va=004EC900,name=sub_4EC900,size=619 arg: kind=int,size=4,signed=True arg: kind=ptr type: kind=int,size=1 -global: va=004ECB70,name=updateNearRoom,size=388,member_of=constructor_004EBFE0 +global: va=004ECB70,name=removeNearRoom,size=388,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr type: kind=struct,id=constructor_004EBFE0 arg: kind=int,size=2 arg: kind=int,size=2 -global: va=004ECD00,name=fun_4ECD00,size=176,member_of=constructor_004EBFE0 +global: va=004ECD00,name=removeRoom,size=176,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -40334,7 +40341,7 @@ global: va=004ECEB0,name=fun_4ECEB0,size=745,member_of=constructor_004EBFE0 type: kind=struct,id=vtbl_0066DB7C arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True -global: va=004ED1A0,name=sub_4ED1A0,size=378,member_of=constructor_004EBFE0 +global: va=004ED1A0,name=sub_4ED1A0__reattach2,size=378,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -40342,12 +40349,12 @@ global: va=004ED1A0,name=sub_4ED1A0,size=378,member_of=constructor_004EBFE0 arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True - arg: kind=int,size=2,signed=True + arg: kind=int,size=2 arg: kind=int,size=2 arg: kind=ptr - type: kind=int,size=1 + type: kind=int,size=1,signed=True,fname=int8_t arg: kind=int,size=4,signed=True -global: va=004ED320,name=sub_4ED320,size=276,member_of=constructor_004EBFE0 +global: va=004ED320,name=sub_4ED320__reattach1,size=276,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -40358,14 +40365,14 @@ global: va=004ED320,name=sub_4ED320,size=276,member_of=constructor_004EBFE0 arg: kind=int,size=2,signed=True arg: kind=int,size=2 arg: kind=ptr - type: kind=int,size=1 + type: kind=int,size=1,signed=True,fname=int8_t arg: kind=ptr type: kind=ptr type: kind=struct,id=vtbl_0066DB7C arg: kind=ptr type: kind=ptr type: kind=struct,id=vtbl_0066DB7C -global: va=004ED440,name=sub_4ED440,size=873,member_of=constructor_004EBFE0 +global: va=004ED440,name=sub_4ED440__sailRoom2,size=873,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -40374,8 +40381,8 @@ global: va=004ED440,name=sub_4ED440,size=873,member_of=constructor_004EBFE0 arg: kind=int,size=4,signed=True arg: kind=int,size=1,signed=True,winapi=char arg: kind=ptr - type: kind=int,size=1 -global: va=004ED7B0,name=sub_4ED7B0,size=953,member_of=constructor_004EBFE0 + type: kind=int,size=1,signed=True,fname=int8_t +global: va=004ED7B0,name=sub_4ED7B0__sailRoom,size=953,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr @@ -40384,10 +40391,10 @@ global: va=004ED7B0,name=sub_4ED7B0,size=953,member_of=constructor_004EBFE0 arg: kind=int,size=4,signed=True arg: kind=int,size=1,signed=True,winapi=char arg: kind=ptr - type: kind=int,size=1 + type: kind=int,size=1,signed=True,fname=int8_t arg: kind=ptr type: kind=ptr - type: kind=struct,id=vtbl_0066DB7C + type: kind=struct,id=constructor_004EAB70 global: va=004EDB70,name=calcChecksum,size=60,member_of=constructor_004EBFE0 type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True @@ -42651,7 +42658,7 @@ global: va=00509280,name=fun_509280,size=34,member_of=vtbl_0066E3EC type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True,winapi=BOOL,fname=BOOL arg: kind=ptr - type: kind=void + type: kind=struct,id=vtbl_0066E3EC arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=int,size=2,signed=True @@ -42660,7 +42667,7 @@ global: va=005092B0,name=fun_5092B0,size=29,member_of=vtbl_0066E3EC type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True,winapi=BOOL,fname=BOOL arg: kind=ptr - type: kind=void + type: kind=struct,id=vtbl_0066E3EC arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=int,size=2,signed=True @@ -43651,7 +43658,8 @@ global: va=0050FB70,name=sub_50FB70,size=34,member_of=vtbl_0066E3EC arg: kind=ptr type: kind=struct,id=vtbl_0066E3EC arg: kind=int,size=4,signed=True - arg: kind=int,size=4,signed=True + arg: kind=ptr + type: kind=struct,id=vec_xyz arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True global: va=0050FBA0,name=fun_50FBA0,size=185,member_of=vtbl_0066E3EC @@ -43706,7 +43714,7 @@ global: va=005101C0,name=fun_5101C0,size=77,member_of=vtbl_0066E3EC type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr - type: kind=int,size=1,signed=True,winapi=char + type: kind=struct,id=vtbl_0066E3EC arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True global: va=00510210,name=fun_510210,size=23,member_of=vtbl_0066E3EC @@ -52780,7 +52788,7 @@ global: va=005678F0,name=fun_5678F0,size=277,member_of=vtbl_0066F7FC arg: kind=int,size=4,signed=True arg: kind=int,size=4,signed=True arg: kind=ptr - type: kind=int,size=4 + type: kind=struct,id=vec_xyz global: va=00567A10,name=fun_567A10,size=42,member_of=vtbl_0066F7FC type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True @@ -67830,7 +67838,7 @@ global: va=00608C20,name=fun_608C20,size=254,member_of=vtbl_0066F90C type: kind=function,declspec=thiscall ret: kind=int,size=4,signed=True arg: kind=ptr - type: kind=int,size=4 + type: kind=struct,id=vtbl_0066F90C arg: kind=int,size=4,signed=True arg: kind=ptr type: kind=int,size=4,signed=True @@ -68851,7 +68859,8 @@ global: va=0060DF70,name=sub_60DF70,size=97 arg: kind=int,size=4,signed=True global: va=0060E000,name=sub_60E000,size=18 type: kind=function,declspec=thiscall - ret: kind=void + ret: kind=ptr + type: kind=void arg: kind=ptr type: kind=int,size=4 global: va=0060E020,name=sub_60E020,size=6 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7130937..57e1215 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable(${TARGET} dk2/RegKey.cpp dk2/MyComputerPlayer.cpp dk2/CRoom.cpp + dk2/CBridge.cpp dk2/button/button_types.cpp dk2/button/CTextInput.cpp dk2/entities/entities_type.cpp diff --git a/src/dk2/CBridge.cpp b/src/dk2/CBridge.cpp new file mode 100644 index 0000000..43e5c8b --- /dev/null +++ b/src/dk2/CBridge.cpp @@ -0,0 +1,125 @@ +// +// Created by DiaLight on 07.10.2024. +// + +#include +#include "dk2/CBridge.h" +#include "dk2/CWorld.h" +#include "dk2/entities/CRoom.h" +#include "dk2/entities/data/MyRoomDataObj.h" +#include "dk2/entities/data/MyTerrainDataObj.h" +#include "dk2/world/map/MyMapElement.h" +#include "dk2_globals.h" +#include "dk2_functions.h" +#include "patches/micro_patches.h" + +void dk2::CBridge::sub_43E320( + unsigned int a2_x, + unsigned int a3_y, + MyTerrainDataObj *a4, + CEngineStaticMeshDataArrays *a5_arrays) { + CWorld *f14_cworld = this->f0_pMyProfiler->cworld; + MyMapElement *v7_mapElem = f14_cworld->getMapElem(a2_x, a3_y); + int v11_bool1 = this->v_fDC(a2_x, a3_y); + int v8_bool2 = 0; + BOOL v9_bool3 = CCamera_sub_44DB70(this->camera._mode); + BOOL v12_bool3 = v9_bool3; + if ((v7_mapElem->_playerIdFFF & 0x2000) == 0 && !v11_bool1 && !v9_bool3) { + if ((v7_mapElem->flags_and_burnLevel & 0x40) != 0) { + if ((g_MyTerrainDataObj_arr[v7_mapElem->arr6DA4A8_idx]->_flags & 0x1000000) != 0) { + v8_bool2 = 1; + } else { + a4 = f14_cworld->v_f70_508DD0_getTerrainDataObj(38); + v8_bool2 = 1; + } + } else { + a4 = f14_cworld->v_f70_508DD0_getTerrainDataObj(27); + v8_bool2 = 1; + } + } + if ((a4->_flags & 0x10) != 0) { + if ((v7_mapElem->_playerIdFFF & 0x2000) != 0 || v11_bool1 || v12_bool3) + this->sub_443610(a2_x, a3_y, v7_mapElem, a4, a5_arrays); + } else { + this->sub_43E860(a2_x, a3_y, v8_bool2, a4, a5_arrays); + } +} + + +void dk2::CBridge::sub_443610( + int a2_x, + unsigned int a3_y, + MyMapElement *a4, + MyTerrainDataObj *a5, + CEngineStaticMeshDataArrays *a6_arrs) { + CRoom *v7_room = a4->getRoom(); + if(override_max_room_count::enabled) { + if(v7_room == nullptr) { + return; // fix + } + } + MyRoomDataObj *f19_pRoomDataObj = v7_room->pRoomDataObj; + switch (f19_pRoomDataObj->someTy) { + case 1: { + CEngineStaticMeshData *v10 = &a6_arrs->field_1B4_CEngineStaticMeshData_arr[a6_arrs->field_2E8_CEngineStaticMeshData_count]; + v10->field_0_MyMeshResourceHolder_idx = f19_pRoomDataObj->f1B.fF; + v10->field_4_mat3x3f_idx = 0; + v10->byte_8_vec3b.x = 0; + v10->byte_8_vec3b.y = 0; + v10->byte_8_vec3b.z = 0; + v10->field_C_flags = 0; + v10->f10 = -1; + v10->field_11_scale = 0; + v10->field_15_eos = 0; + if ((a5->_flags & 0x20000000) != 0) { + Vec3b *p_byte_8_vec3b = &a6_arrs->field_1B4_CEngineStaticMeshData_arr[a6_arrs->field_2E8_CEngineStaticMeshData_count].byte_8_vec3b; + p_byte_8_vec3b->x = a5->_vec.x; + p_byte_8_vec3b->y = a5->_vec.y; + p_byte_8_vec3b->z = a5->_vec.z; + } + ++a6_arrs->field_2E8_CEngineStaticMeshData_count; + this->sub_444F10(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + } + case 2: + this->sub_443910(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + case 3: + this->sub_446140(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + case 4: + this->sub_446210(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + case 5: + this->sub_444970(a2_x, a3_y, a5, v7_room, a6_arrs); + this->sub_444F10(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + case 7: + this->sub_443F20(a2_x, a3_y, a5, v7_room, a6_arrs); + this->sub_444F10(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + case 8: + if ((v7_room->destroyed & 1) != 0) + this->sub_4463B0(a2_x, a3_y, a5, v7_room, a6_arrs); + else + this->sub_4462E0(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + case 9: + case 0xC: + this->sub_4464C0(a2_x, a3_y, a5, v7_room, a6_arrs); + this->sub_444F10(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + case 0xA: + this->sub_446640(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + case 0xB: + this->sub_446800(a2_x, a3_y, a4, a5, v7_room, a6_arrs); + break; + case 0xD: + this->sub_446800(a2_x, a3_y, a4, a5, v7_room, a6_arrs); + this->sub_444F10(a2_x, a3_y, a5, v7_room, a6_arrs); + break; + default: + return; + } +} diff --git a/src/dk2/CDefaultPlayerInterface.cpp b/src/dk2/CDefaultPlayerInterface.cpp index ed5cd4a..0878708 100644 --- a/src/dk2/CDefaultPlayerInterface.cpp +++ b/src/dk2/CDefaultPlayerInterface.cpp @@ -104,7 +104,7 @@ void dk2::CDefaultPlayerInterface::createSurfacesForView_42CDF0(RtGuiView *view) MySurface v15_surf; v15_surf.constructor(&v14_size, &view->surf.desc, linePos, lPitch); int _idx = x + view->width_128blocks * y; - if(gog::RtGuiView_fix::enable) { + if(gog::RtGuiView_fix::isEnabled()) { if(idx >= 93 && view == &dk2::CDefaultPlayerInterface_instance._allyWindowText) { idx = 0; } diff --git a/src/dk2/CRoom.cpp b/src/dk2/CRoom.cpp index f842e13..db19d6c 100644 --- a/src/dk2/CRoom.cpp +++ b/src/dk2/CRoom.cpp @@ -2,6 +2,7 @@ // Created by DiaLight on 30.09.2024. // +#include #include "dk2/entities/CRoom.h" #include "room_type.h" #include "dk2/entities/CPlayer.h" @@ -12,6 +13,7 @@ #include "dk2/world/map/MyMapElement.h" #include "tools/bug_hunter.h" #include "patches/micro_patches.h" +#include "dk2_functions.h" namespace dk2 { @@ -25,11 +27,11 @@ namespace dk2 { MyMapElement *mapElem; for (Pos2ub loc = _this->firstSlab; loc.x || loc.y; loc = mapElem->nextSlab) { mapElem = getMapElem(loc); - uint8_t burnLevel = (mapElem->flags >> 1) & 0xF; - if ((mapElem->_playerId & 0x1000) == 0) continue; + uint8_t burnLevel = (mapElem->flags_and_burnLevel >> 1) & 0xF; + if ((mapElem->_playerIdFFF & 0x1000) == 0) continue; if (burnLevel >= 9) continue; mapElem->roomSetBurnLevel(burnLevel + 1); - burnLevel = (mapElem->flags >> 1) & 0xF; + burnLevel = (mapElem->flags_and_burnLevel >> 1) & 0xF; if (burnLevel == 8) { *(DWORD *) _this->field_49_union_start = 1; // FlagToBurn mapElem->roomSetBurnLevel(9); @@ -64,11 +66,11 @@ int dk2::CRoom::tickWoodenBridge() { MyMapElement *mapElem; for (Pos2ub pos = this->firstSlab; pos.x || pos.y; pos = mapElem->nextSlab) { mapElem = getMapElem(pos); - if ((mapElem->_playerId & 0x1000) == 0) continue; - uint8_t burnLevel = (mapElem->flags >> 1) & 0xF; + if ((mapElem->_playerIdFFF & 0x1000) == 0) continue; + uint8_t burnLevel = (mapElem->flags_and_burnLevel >> 1) & 0xF; if (burnLevel != 9) continue; auto *player = (CPlayer *) sceneObjects[this->playerId]; - if (!player->fun_4C5DB0(pos.x, pos.y, 0)) continue; + if (!player->destroyRoom(pos.x, pos.y, 0)) continue; anyBridgesBurned = true; ++burnedCount; @@ -100,12 +102,12 @@ unsigned int dk2::CMap::attachToRoom( int v10_flags = g_MyTerrainDataObj_arr[v9_mapElem->arr6DA4A8_idx]->_flags; if ((v10_flags & 0x80u) == 0) { if ((v10_flags & 0x100) != 0) - v9_mapElem->_playerId |= 0x1000u; + v9_mapElem->_playerIdFFF |= 0x1000u; } else { - v9_mapElem->_playerId &= ~0x1000u; + v9_mapElem->_playerIdFFF &= ~0x1000u; } int typeId = ((CRoom *) sceneObjects[a4_roomObjId])->typeId; - if(wooden_bridge_burn_fix::enabled) { + if (wooden_bridge_burn_fix::enabled) { if (typeId != CRoom_typeId_WoodenBridge) { // ignore reset burn level at attach cell to room v9_mapElem->roomSetBurnLevel(0); } @@ -113,24 +115,23 @@ unsigned int dk2::CMap::attachToRoom( v9_mapElem->roomSetBurnLevel(0); } v9_mapElem->fun_4559D0(a5_playerId); - MyRoomDataObj *v11_roomDataObj = this->world->v_fun_50D0B0(typeId); - this->fun_44FC40(a2_x, v8_y, (int) v11_roomDataObj->f44E, v9_mapElem->_playerId & 0xFFF, 0, a7); + MyRoomDataObj *v11_roomDataObj = this->world->v_f98_50D0B0_getMyRoomDataObj(typeId); + this->fun_44FC40(a2_x, v8_y, (int) v11_roomDataObj->_terrainType, v9_mapElem->_playerIdFFF & 0xFFF, 0, a7); // v9_mapElem->roomId = v9_mapElem->roomId ^ ((v9_mapElem->roomId ^ a4_roomObjId) & 0xFFF); - v9_mapElem->roomId = (v9_mapElem->roomId & 0xF000) | (a4_roomObjId & 0xFFF); + v9_mapElem->_roomIdFFF = (v9_mapElem->_roomIdFFF & 0xF000) | (a4_roomObjId & 0xFFF); return this->sub_4522A0(a2_x, v8_y); } -int dk2::MyRooms::sub_4ED1A0( +int dk2::MyRooms::sub_4ED1A0__reattach2( int a2_x, int arg4_y, int a4_roomTypeId, - __int16 a5_playerId, + unsigned __int16 a5_playerId, unsigned __int16 a6_roomObjId, - BYTE *a7_pNearCountNeg, + int8_t *a7_pNearCountNeg, int a8) { if ((g_MyTerrainDataObj_arr[this->world->getMapElem(a2_x, arg4_y)->arr6DA4A8_idx]->_flags & 0x80) != 0) { - int *p_y; // esi - p_y = &g_deltaLocs[0].y; + int *p_y = &g_deltaLocs[0].y; do { int v11 = a2_x + *(p_y - 1); int v12 = *p_y + arg4_y; @@ -150,9 +151,9 @@ int dk2::MyRooms::sub_4ED1A0( CRoom *v19[4]; memset(v19, 0, sizeof(v19)); CRoom *a3 = 0; - int v14 = this->sub_4ED320(a2_x, arg4_y, a4_roomTypeId, a5_playerId, a6_roomObjId, a7_pNearCountNeg, &a3, v19); - if(wooden_bridge_burn_fix::enabled) { - if(((BYTE) a4_roomTypeId) == CRoom_typeId_WoodenBridge) { + int v14 = this->sub_4ED320__reattach1(a2_x, arg4_y, a4_roomTypeId, a5_playerId, a6_roomObjId, a7_pNearCountNeg, &a3, v19); + if (wooden_bridge_burn_fix::enabled) { + if (((BYTE) a4_roomTypeId) == CRoom_typeId_WoodenBridge) { CMap &map = this->world->cmap; map.mapElements[a2_x + arg4_y * map.width].roomSetBurnLevel(0); } @@ -175,6 +176,242 @@ int dk2::MyRooms::sub_4ED1A0( return arg4_ya; } +#define MaxRoomCount (96 * 7) // 0x2A0 + +int dk2::MyRooms::createRooms(CWorld *a2_world) { + static_assert(0xA9 == sizeof(CRoom)); + static_assert(0x1BBA4u == (sizeof(CRoom) * 0x2A0 + 4)); + DWORD *v3 = (DWORD *) __nh_malloc(sizeof(CRoom) * MaxRoomCount + 4, 1); //operator new(0x1BBA4u); + CRoom *v4; + if (v3) { + v4 = (CRoom *) (v3 + 1); + *v3 = MaxRoomCount; + typedef void (*___for_each_construct_t)(char *, uint32_t, int, void (__thiscall *)(void *), + void (__thiscall *)(void *)); + auto __for_each_construct = (___for_each_construct_t) 0x00635EC0; + __for_each_construct( + (char *) v3 + 4, + 0xA9u, + MaxRoomCount, + (void (__thiscall *)(void *)) 0x004E3790, // CRoom::constructor + (void (__thiscall *)(void *)) 0x004E37F0 // CRoom::destructor + ); + } else { + v4 = nullptr; + } + this->CRoom_arr_p = v4; + if (!v4) + return 0; + this->firstRoomId = 0; + this->_nextRoomId = 0; + this->changedAreaRoomList = 0; + unsigned int i; + for (i = 0; i < MaxRoomCount; ++i) { + CRoom *v7 = &this->CRoom_arr_p[i]; + unsigned __int16 f0_tagId = v7->f0_tagId; + v7->roomManagerNodeX = 0; + v7->roomManagerNodeY = 0; + CRoom *fA_CRoom_arr_p = this->CRoom_arr_p; + fA_CRoom_arr_p[i].playerRoomListNodeX = 0; + fA_CRoom_arr_p[i].playerRoomListNodeY = 0; + CRoom *v10 = this->CRoom_arr_p; + v10[i].changedAreaRoomListNodeX = 0; + v10[i].changedAreaRoomListNodeY = 0; + ((CRoom *) sceneObjects[f0_tagId])->roomManagerNodeY = this->_nextRoomId; + if (this->_nextRoomId) + ((CRoom *) sceneObjects[this->_nextRoomId])->roomManagerNodeX = f0_tagId; + this->_nextRoomId = f0_tagId; + } + this->world = a2_world; + g_CWorld_ptr = a2_world; + g_MyRooms_pInstance = this; + this->thingManager = 1; + return 1; +} + +int dk2::MyRooms::createRoom( + int a2_roomTypeId, + unsigned __int16 a3_playerId, + unsigned __int16 *a4_pRoomObjId) { + if (this->_counter >= MaxRoomCount) + return 0; + unsigned __int16 roomObjId; + if (this->f16) { + roomObjId = this->_roomSceneObjId; + this->f16 = 0; + this->_roomSceneObjId = 0; + } else { + roomObjId = this->_nextRoomId; + } + if (!((CRoom *) sceneObjects[roomObjId])->init(a2_roomTypeId, a3_playerId)) + return 0; + CRoom *v6 = (CRoom *) sceneObjects[roomObjId]; + // unlink X + if (v6->roomManagerNodeX) { + ((CRoom *) sceneObjects[((CRoom *) sceneObjects[roomObjId])->roomManagerNodeX])->roomManagerNodeY = v6->roomManagerNodeY; + } else { + this->_nextRoomId = v6->roomManagerNodeY; + } + // unlink Y + if (((CRoom *) sceneObjects[roomObjId])->roomManagerNodeY) { + ((CRoom *) sceneObjects[((CRoom *) sceneObjects[roomObjId])->roomManagerNodeY])->roomManagerNodeX = ((CRoom *) sceneObjects[roomObjId])->roomManagerNodeX; + } + CRoom *v7 = (CRoom *) sceneObjects[roomObjId]; + v7->roomManagerNodeX = 0; + v7->roomManagerNodeY = 0; + __int16 f10__nextRoomId = this->_nextRoomId; + if (roomObjId == f10__nextRoomId) + this->_nextRoomId = f10__nextRoomId - 1; + // link to list + ((CRoom *) sceneObjects[roomObjId])->roomManagerNodeY = this->firstRoomId; + if (this->firstRoomId) + ((CRoom *) sceneObjects[this->firstRoomId])->roomManagerNodeX = roomObjId; + this->firstRoomId = roomObjId; + this->_counter++; + *a4_pRoomObjId = roomObjId; + return 1; +} + + +int dk2::CPlayer::fun_4C5C30_buildRoom( + int a2_x, + int a3_y, + int a4_roomTypeId, + int a5_gameTick, + int a6_bool, + int a7_bool, + int a8_orientation) { + unsigned int v10_moneyCost = g_pCWorld->v_f98_50D0B0_getMyRoomDataObj(a4_roomTypeId)->moneyCost; + if (!a6_bool && v10_moneyCost > this->money) return 0; + if (!a7_bool) { + int v11_playerId_and_roomTypeId = this->f0_tagId | (a4_roomTypeId << 16); + if (!g_pCWorld->v_sub_509280(a2_x, a3_y, v11_playerId_and_roomTypeId, a4_roomTypeId)) + return 0; + } + size_t maxRoomLimit = 96; + if (override_max_room_count::enabled) { + maxRoomLimit = override_max_room_count::limit; + } + int v9_roomNum = maxRoomLimit - this->numberOfRooms; + int8_t roomsCountNeg; + if (!g_pCWorld->rooms.sub_4ED1A0__reattach2( + a2_x, + a3_y, + a4_roomTypeId, + this->f0_tagId, + v9_roomNum, + &roomsCountNeg, + a8_orientation)) + return 0; + this->numberOfRooms += roomsCountNeg; + if (a6_bool) + return 1; + this->moneyRoom_4BA420(-v10_moneyCost, 0, 0, 0); + this->statictics.moneySpent += v10_moneyCost; + if (g_pCWorld->getGameTick() == a5_gameTick) + return 1; + MyRoomDataObj *v12 = g_pCWorld->v_f98_50D0B0_getMyRoomDataObj(a4_roomTypeId); + int v13 = g_pCWorld->v_f70_508DD0_getTerrainDataObj(v12->_terrainType)->f195; + if (!v13) + return 1; + Vec3i v15_vec; + v15_vec.x = (a2_x << 12) + 2048; + v15_vec.y = (a3_y << 12) + 2048; + v15_vec.z = 0; + MySound_ptr->CSoundSystem::fun_5678F0(0, v13, 241, &v15_vec); + return 1; +} + +namespace dk2 { + bool hasPlayerRoomWithTypeExcept(int x, int y, char typeId, __int16 playerId, std::set &visited) { + CMap &cmap = g_pCWorld->cmap; + if(0 > x || x >= cmap.width) return false; + if(0 > y || y >= cmap.height) return false; + if(visited.contains(x | (y << 8))) return false; + return cmap.hasPlayerRoomWithType(x, y, typeId, playerId); + } + bool hasNearPlayerRoomWithTypeExcept(int x, int y, char typeId, __int16 playerId, std::set &visited) { + if(hasPlayerRoomWithTypeExcept(x, y - 1, typeId, playerId, visited)) return true; + if(hasPlayerRoomWithTypeExcept(x + 1, y, typeId, playerId, visited)) return true; + if(hasPlayerRoomWithTypeExcept(x, y + 1, typeId, playerId, visited)) return true; + if(hasPlayerRoomWithTypeExcept(x - 1, y, typeId, playerId, visited)) return true; + return false; + } + void travelRoom(int x, int y, char typeId, __int16 playerId, std::set &visited) { + if(!hasPlayerRoomWithTypeExcept(x, y, typeId, playerId, visited)) return; + visited.insert(x | (y << 8)); + travelRoom(x, y - 1, typeId, playerId, visited); + travelRoom(x + 1, y, typeId, playerId, visited); + travelRoom(x, y + 1, typeId, playerId, visited); + travelRoom(x - 1, y, typeId, playerId, visited); + } + int getNewRoomsCountIfRemove(int x, int y) { + CRoom &room = *g_pCWorld->v_getMapElem(x, y)->getRoom(); + CMap &cmap = g_pCWorld->cmap; + if(!cmap.hasNearPlayerRoomWithType(x, y, room.typeId, room.playerId)) return -1; + + std::set visited; + visited.insert(x | (y << 8)); + Pos2ub pos = room.firstSlab; + size_t splitCount = 0; + while(pos.x || pos.y) { + if(!visited.contains(pos.x | (pos.y << 8))) { + travelRoom(pos.x, pos.y, room.typeId, room.playerId, visited); + splitCount++; + } + pos = cmap.mapElements[pos.x + pos.y * cmap.width].nextSlab; + } + return splitCount - 1; + } +} + +int dk2::CPlayer::destroyRoom(int a2_x, int a3_y, int a4_bool) { + int v6_y = a3_y; + if (!g_pCWorld->v_sub_5092B0(a2_x, a3_y, this->f0_tagId) && a4_bool) + return 0; + MyMapElement *v7_mapElem = g_pCWorld->v_getMapElem(a2_x, v6_y); + CRoom *room = v7_mapElem->getRoom(); + int salePrice = (unsigned __int16) room->pRoomDataObj->_getSalePrice(); + size_t maxRoomLimit = 96; + if (override_max_room_count::enabled) { + maxRoomLimit = override_max_room_count::limit; + } + int v9_roomNum = maxRoomLimit - this->numberOfRooms; + + if(override_max_room_count::enabled && override_max_room_count::predictLimit) { + // trying predict limit reach on room destroy + if(v9_roomNum <= 4) { + int splitCount = getNewRoomsCountIfRemove(a2_x, a3_y); + if(v9_roomNum < splitCount) return false; + } + } + + uint8_t roomTypeId = room->typeId; // room obj will be released + int8_t roomsCountNeg; + if (!g_pCWorld->rooms.sub_4ED440__sailRoom2(a2_x, v6_y, v9_roomNum, &roomsCountNeg)) + return 0; + this->numberOfRooms += roomsCountNeg; + MyRoomDataObj *v9_roomDataObj = g_pCWorld->v_f98_50D0B0_getMyRoomDataObj(roomTypeId); + MyTerrainDataObj *v10_terrainDataObj = g_pCWorld->v_f70_508DD0_getTerrainDataObj(v9_roomDataObj->_terrainType); + Vec3i v15_vec; + v15_vec.x = (a2_x << 12) + 2048; + v15_vec.y = (v6_y << 12) + 2048; + v15_vec.z = 4096; + if (a4_bool) { + this->moneyRoom_4BA420(salePrice, 0, a2_x, v6_y); + g_pCWorld->sub_50FB70(this->f0_tagId, &v15_vec, salePrice, 0); + int v12 = v10_terrainDataObj->f195; + if (v12) { + MySound_ptr->v_CSoundSystem_fun_5678F0(0, v12, 245, &v15_vec); + return 1; + } + } else { + int v14 = v10_terrainDataObj->f195; + if (v14) + MySound_ptr->v_CSoundSystem_fun_5678F0(0, v14, 244, &v15_vec); + } + return 1; +} const char *CRoom_typeId_toString(int ty) { switch (ty) { diff --git a/src/dk2/MyComputerPlayer.cpp b/src/dk2/MyComputerPlayer.cpp index 8fbe73d..3422e45 100644 --- a/src/dk2/MyComputerPlayer.cpp +++ b/src/dk2/MyComputerPlayer.cpp @@ -102,7 +102,7 @@ namespace dk2 { v59_loc.x = (v29_locX << 12) + 2048; CWorld *fA_world = cp->world; v59_loc.y = (v30_locY << 12) + 2048; - if ((fA_world->v_getMapElem_2(&v59_loc)->_playerId & 0xFFF) != cp->cplayer->f0_tagId) { + if ((fA_world->v_getMapElem_2(&v59_loc)->_playerIdFFF & 0xFFF) != cp->cplayer->f0_tagId) { unsigned int v71_locX = 0; unsigned int v69_locY = 0; int v32_respondIdx = (cp->flags >> 14) & 0xF; @@ -129,7 +129,7 @@ namespace dk2 { if ((v42_cworld->cmap.pNavigationSystem->map.ptr_ui8[ v73_locY * v42_cworld->cmap.pNavigationSystem->map.width + v33_locX] & 8) == 0 && !v43_mapElement->sub_454110() - && (v43_mapElement->_playerId & 0xFFF) == cp->cplayer->f0_tagId) { + && (v43_mapElement->_playerIdFFF & 0xFFF) == cp->cplayer->f0_tagId) { v71_locX = v33_locX; v69_locY = v73_locY; v74_whileBool = false; @@ -154,7 +154,7 @@ namespace dk2 { v73_locY * v48_cworld->cmap.pNavigationSystem->map.width + v44_locX] & 8) == 0 && !v49_mapElem->sub_454110() - && (v49_mapElem->_playerId & 0xFFF) == cp->cplayer->f0_tagId) { + && (v49_mapElem->_playerIdFFF & 0xFFF) == cp->cplayer->f0_tagId) { break; } } @@ -179,7 +179,7 @@ namespace dk2 { v73_locY * v45_cworld->cmap.pNavigationSystem->map.width + v44_locX] & 8) == 0 && !v46_mapElem->sub_454110() - && (v46_mapElem->_playerId & 0xFFF) == cp->cplayer->f0_tagId) { + && (v46_mapElem->_playerIdFFF & 0xFFF) == cp->cplayer->f0_tagId) { break; } } diff --git a/src/dk2/RegKey.cpp b/src/dk2/RegKey.cpp index b75c4ad..780d77b 100644 --- a/src/dk2/RegKey.cpp +++ b/src/dk2/RegKey.cpp @@ -50,7 +50,7 @@ uint32_t *__thiscall dk2::RegKey::settings_readBytes(uint32_t *pstatus, LPCSTR l int *dk2::RegKey::settings_readValue(int *pstatus, LPCSTR lpValueName, uint32_t *pValue) { - if(gog::RegistryConfig_patch::enable) { + if(gog::RegistryConfig_patch::isEnabled()) { if (gog::cfg::patchRegistryConfig(pstatus, lpValueName, (DWORD *) pValue) != -1) return pstatus; } if (!lpValueName || this->key == NULL) { diff --git a/src/dk2/engine/draw_functions.cpp b/src/dk2/engine/draw_functions.cpp index 95298bf..979944f 100644 --- a/src/dk2/engine/draw_functions.cpp +++ b/src/dk2/engine/draw_functions.cpp @@ -54,7 +54,7 @@ void dk2::drawTexToSurfTriangles() { } void __cdecl dk2::renderer_setSurfaceHolder(SurfaceHolder *holder, uint32_t stage) { - if(gog::SurfaceHolder_setTexture_patch::enable) { + if(gog::SurfaceHolder_setTexture_patch::isEnabled()) { if(!holder) return; } if ( (mydd_scene.flags & 1) != 0 ) { // 3dengine == 4 diff --git a/src/dk2/engine/window_proc_functions.cpp b/src/dk2/engine/window_proc_functions.cpp index 0dc32c4..de61ab6 100644 --- a/src/dk2/engine/window_proc_functions.cpp +++ b/src/dk2/engine/window_proc_functions.cpp @@ -19,7 +19,7 @@ int __cdecl dk2::getCustomDefWindowProcA() { } typedef LRESULT (__stdcall *CustomDefWindowProcA_t)(HWND, UINT, WPARAM, LPARAM); -LRESULT dk2::CWindowTest_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { +LRESULT dk2::CWindowTest_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { // windowed proc // patch::BEFORE_WINDOW_PROC remember_window_location_and_size::window_proc(hWnd, Msg, wParam, lParam); replace_mouse_dinput_to_user32::emulate_dinput_from_user32(hWnd, Msg, wParam, lParam); @@ -61,7 +61,7 @@ LRESULT dk2::CWindowTest_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) return DefWindowProcA(hWnd, Msg, wParam, lParam); } -LRESULT dk2::BullfrogWindow_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { +LRESULT dk2::BullfrogWindow_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { // fullscreen proc replace_mouse_dinput_to_user32::emulate_dinput_from_user32(hWnd, Msg, wParam, lParam); use_wheel_to_zoom::window_proc(hWnd, Msg, wParam, lParam); fix_keyboard_state_on_alt_tab::window_proc(hWnd, Msg, wParam, lParam); diff --git a/src/dk2/entities/CCreature.cpp b/src/dk2/entities/CCreature.cpp index 7bb9456..00dcb5b 100644 --- a/src/dk2/entities/CCreature.cpp +++ b/src/dk2/entities/CCreature.cpp @@ -133,7 +133,7 @@ int dk2::CCreature::processDealDamage() { if ( v7_target->v_f28() ) this->setCurrentState_48AD30(239); } - this->field_2A = MySound_ptr->v_fun_5678F0( + this->field_2A = MySound_ptr->v_CSoundSystem_fun_5678F0( this->field_2A, this->creatureData->f6E3, 219, diff --git a/src/dk2/entities/CPlayer.cpp b/src/dk2/entities/CPlayer.cpp index 740fa76..5f3e3c5 100644 --- a/src/dk2/entities/CPlayer.cpp +++ b/src/dk2/entities/CPlayer.cpp @@ -52,7 +52,7 @@ int dk2::CPlayer::creatureDidWorkshopWork(int workMade, CCreature *a3_creature) memset(&a3a_item.pos, 0, sizeof(a3a_item.pos)); this->manufactures.getItem(&a3a_item); uint8_t typeId = this->manufactures.sub_506BA0(&a3a_item); - MyObjectDataObj *v7 = g_pCWorld->v_findMyObjectDataObjByTypeId_50DB20(typeId); + MyObjectDataObj *v7 = g_pCWorld->v_f188_50DB20_getMyObjectDataObj(typeId); CRoom *room; if (!this->sub_4C3B50(&a3a_item, 10, v7->f114, &room)) return 0; this->manufactureCompleted = 0; diff --git a/src/dkii_exe_functions.cpp b/src/dkii_exe_functions.cpp index 13bf307..e26aef3 100644 --- a/src/dkii_exe_functions.cpp +++ b/src/dkii_exe_functions.cpp @@ -69,7 +69,7 @@ void dk2::resolveDk2HomeDir() { } BOOL __cdecl dk2::parse_command_line(int argc, const char **argv) { - if(gog::parseCommandLine_patch::enable) { + if(gog::parseCommandLine_patch::isEnabled()) { dk2::MyResources_instance.video_settings.cmd_flag_32BITTEXTURES = 1; dk2::MyResources_instance.video_settings.zbuffer_bitnes = 32; dk2::MyResources_instance.video_settings.display_bitnes = 32; diff --git a/src/main.cpp b/src/main.cpp index 1515294..29dbe76 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,6 +8,8 @@ #include "gog_patch.h" #include "tools/bug_hunter.h" #include +#include +#include namespace dk2 { @@ -242,10 +244,52 @@ int dk2::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, CHAR *lpCmdLine, return dk2_main(g_argc, g_argv); } -int main() { - if(wcsstr(GetCommandLineW(), L" -console") == NULL) { + +const char *getCmdOption(const char **begin, const char **end, const std::string &option) { + const char **it = std::find(begin, end, option); + if (it != end && ++it != end) return *it; + return nullptr; +} + +bool hasCmdOption(const char **begin, const char **end, const std::string &option) { + return std::find(begin, end, option) != end; +} +int main(int argc, const char **argv) { + const char *roomsLimitStr = getCmdOption(argv, argv + argc, "-experimental_rooms_limit"); + if (roomsLimitStr != nullptr) { + try { + uint32_t roomsLimit = std::stoul(roomsLimitStr, nullptr, 10); + override_max_room_count::limit = roomsLimit; + } catch(std::invalid_argument &e) { + std::cout << "cant parse int \"" << roomsLimitStr << "\"" << std::endl; + exit(-1); + } + } + if(hasCmdOption(argv, argv + argc, "-experimental_predict_limit")) { + override_max_room_count::predictLimit = true; + } + if(!hasCmdOption(argv, argv + argc, "-console")) { ::ShowWindow(::GetConsoleWindow(), SW_HIDE); } + if(hasCmdOption(argv, argv + argc, "-windowed")) { + gog::enable = false; // gog is incompatible with windowed mode + control_windowed_mode::enabled = true; + if(!hasCmdOption(argv, argv + argc, "-no_initial_size")) { + // Finding the user's screen resolution + int screenWidth = GetSystemMetrics(SM_CXSCREEN); + int screenHeight = GetSystemMetrics(SM_CYSCREEN); + int height; + int width; + if(screenHeight < screenWidth) { + height = screenHeight * 5 / 6; + width = height * 12 / 9; + } else { + width = screenWidth * 5 / 6; + height = width * 9 / 12; + } + remember_window_location_and_size::setInitialSize(width, height); + } + } bug_hunter::init(); std::thread keyWatcher([] { bug_hunter::keyWatcher(); }); // call entry point of DKII.EXE, diff --git a/src/patches/gog_patch_dll/gog_patch.cpp b/src/patches/gog_patch_dll/gog_patch.cpp index 8220911..80f49d7 100644 --- a/src/patches/gog_patch_dll/gog_patch.cpp +++ b/src/patches/gog_patch_dll/gog_patch.cpp @@ -5,15 +5,16 @@ #include "gog_globals.h" #include "gog_debug.h" +bool gog::RtGuiView_fix::isEnabled() { return true; } +bool gog::SurfaceHolder_setTexture_patch::isEnabled() { return true; } + bool gog::enable = true; -bool gog::RtGuiView_fix::enable = gog::enable && true; -bool gog::RegistryConfig_patch::enable = gog::enable && true; -bool gog::parseCommandLine_patch::enable = gog::enable && true; -bool gog::SurfaceHolder_setTexture_patch::enable = gog::enable && true; +bool gog::RegistryConfig_patch::isEnabled() { return gog::enable; } +bool gog::parseCommandLine_patch::isEnabled() { return gog::enable; } -bool gog::BullfrogWindow_proc_patch::enable = gog::enable && true; +bool gog::BullfrogWindow_proc_patch::isEnabled() { return gog::enable; } bool gog::BullfrogWindow_proc_patch::window_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { - if (!enable) return false; + if (!isEnabled()) return false; switch (Msg) { case WM_KILLFOCUS: ShowWindow(gog::g_hWnd, SW_MINIMIZE); diff --git a/src/patches/gog_patch_dll/gog_patch.h b/src/patches/gog_patch_dll/gog_patch.h index 87eb295..aabec2c 100644 --- a/src/patches/gog_patch_dll/gog_patch.h +++ b/src/patches/gog_patch_dll/gog_patch.h @@ -9,23 +9,24 @@ namespace gog { + namespace RtGuiView_fix { + bool isEnabled(); + } + namespace SurfaceHolder_setTexture_patch { + bool isEnabled(); + } + extern bool enable; bool patch_init(); - namespace RtGuiView_fix { - extern bool enable; - } namespace RegistryConfig_patch { - extern bool enable; + bool isEnabled(); } namespace parseCommandLine_patch { - extern bool enable; - } - namespace SurfaceHolder_setTexture_patch { - extern bool enable; + bool isEnabled(); } namespace BullfrogWindow_proc_patch { - extern bool enable; + bool isEnabled(); bool window_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); } } diff --git a/src/patches/micro_patches.cpp b/src/patches/micro_patches.cpp index ea0e9b6..008684c 100644 --- a/src/patches/micro_patches.cpp +++ b/src/patches/micro_patches.cpp @@ -27,6 +27,10 @@ bool creatures_setup_lair_fix::enabled = true; bool wooden_bridge_burn_fix::enabled = true; bool max_host_port_number_fix::enabled = true; +bool override_max_room_count::enabled = true; +bool override_max_room_count::predictLimit = false; +size_t override_max_room_count::limit = 96; + void use_wasd_by_default_patch::useAlternativeName(LPCSTR &lpValueName) { if(!use_wasd_by_default_patch::enabled) return; if(lpValueName && strncmp(lpValueName, "Key Table", 12) == 0) { @@ -96,6 +100,10 @@ namespace { POINT window_size = {0, 0}; bool ignore_size = true; } +void remember_window_location_and_size::setInitialSize(int x, int y) { + window_size = {x, y}; +} + bool remember_window_location_and_size::window_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { switch(Msg) { case WM_DESTROY: { diff --git a/src/patches/micro_patches.h b/src/patches/micro_patches.h index 7fada12..e518922 100644 --- a/src/patches/micro_patches.h +++ b/src/patches/micro_patches.h @@ -60,6 +60,12 @@ namespace max_host_port_number_fix { extern bool enabled; } +namespace override_max_room_count { + extern bool enabled; + extern bool predictLimit; + extern size_t limit; +} + namespace use_wasd_by_default_patch { extern bool enabled; void useAlternativeName(LPCSTR &lpValueName); @@ -82,6 +88,7 @@ namespace hide_mouse_cursor_in_window { } namespace remember_window_location_and_size { + void setInitialSize(int x, int y); bool window_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); void patchWinLoc(int &xPos, int &yPos); void resizeWindow(HWND hWnd); diff --git a/src/replace_globals.map b/src/replace_globals.map index fd01f62..18d9c50 100644 --- a/src/replace_globals.map +++ b/src/replace_globals.map @@ -67,11 +67,20 @@ 004C3200 int creatureDidWorkshopWork(int, CCreature *); /* auto */ 004E8D30 void resetCreaturesState(); // ------------- /* auto */ +004C5C30 int fun_4C5C30_buildRoom(int, int, int, int, int, int, int); /* auto */ +004C5DB0 int destroyRoom(int, int, int); // --------- /* auto */ + # MyRooms.h 004ED1A0 int sub_4ED1A0(int, int, int, int16_t, uint16_t, uint8_t *, int); /* auto */ +004EC000 int createRooms(CWorld *); // -------------- /* auto */ # CRoom.h 004D5FA0 int tickWoodenBridge(); // ----------------- /* auto */ +004EC490 int createRoom(int, uint16_t, uint16_t *); /* auto */ + +# CBridge.h +0043E320 void sub_43E320(uint32_t, uint32_t, MyTerrainDataObj *, CEngineStaticMeshDataArrays *); /* auto */ +00443610 void sub_443610(int, uint32_t, MyMapElement *, MyTerrainDataObj *, CEngineStaticMeshDataArrays *); /* auto */ # CMap.h 00450770 uint32_t attachToRoom(int, int, uint16_t, int16_t, int, int); /* auto */ diff --git a/src/tools/bug_hunter.cpp b/src/tools/bug_hunter.cpp index 6d35547..80ea939 100644 --- a/src/tools/bug_hunter.cpp +++ b/src/tools/bug_hunter.cpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace fs = std::filesystem; @@ -215,6 +216,7 @@ void parseFpomap() { struct AppThread { DWORD tid = 0; HANDLE hThread = NULL; + bool suspended = false; AppThread() = default; AppThread(DWORD tid, HANDLE hThread) : tid(tid), hThread(hThread) {} @@ -243,11 +245,15 @@ struct AppThread { hThread = NULL; } - void suspend() const { + void suspend() { + if(suspended) return; SuspendThread(hThread); + suspended = true; } - void resume() const { + void resume() { + if(!suspended) return; ResumeThread(hThread); + suspended = false; } void terminate() const { __try{ @@ -339,6 +345,57 @@ std::ostream &operator<<(std::ostream &os, const StackFrame &frame) { return os; } +void dumpStackPart(StackLimits &limits, LoadedModules &modules, DWORD esp) { + DWORD *p = (DWORD *) esp; + for (; (DWORD) p < limits.high; ++p) { + DWORD val = *p; + std::stringstream ss; + ss << fmtHex(limits.high - (DWORD) p) << "->" << fmtHex32(val); + if(limits.contains(val)) { + ss << " " << "stack"; + ss << "+" << fmtHex(limits.high - val); + } else { + const char *appCode = nullptr; + if(bughunter::isDkiiCode(val)) { + appCode = "DKII"; + } + if(bughunter::isFlameCode(val)) { + appCode = "Flame"; + } + if(appCode) { + ss << " " << appCode; + auto it = bughunter::find_le(val); + if (it != bughunter::fpomap.end() && val < it->end) { + auto &fpo = *it; + ss << ":" << fpo.name << "+" << fmtHex(val - fpo.ptr); + } else { + ss << "+" << fmtHex(val - bughunter::base); + } + } else if (auto *mod = modules.find(val)) { + ss << " " << mod->name; + if (auto *exp = mod->find_export_le(val)) { + ss << ":" << exp->name << "+" << fmtHex(val - exp->addr); + } else { + ss << "+" << fmtHex(val - mod->base); + } + } else { + continue; + } + } +// if (auto *mod = modules.find(val)) { +// DWORD ebpCand = p[-1]; +// if(ebpCand && ebpCand >= (DWORD) p && limits.contains(ebpCand)) { +// if (auto *mod2 = modules.find(((DWORD *) ebpCand)[1])) { +// DWORD ebp = ebpCand; +// } +// } +// DWORD eip = *p++; +// break; +// } + std::cout << ss.str() << std::endl; + } +} + struct StackWalkerState { LoadedModules &modules; StackLimits &limits; @@ -353,35 +410,15 @@ struct StackWalkerState { if(!err) { BaseThreadInitThunk = modules.findBaseThreadInitThunk(); } +// dumpStackPart(limits, modules, ctx.Esp); } bool isAnyCode(DWORD eip) { if(eip == 0) return false; - if (auto *mod = modules.find(Eip)) return true; + if (auto *mod = modules.find(eip)) return true; return false; } - void dumpStackPart(DWORD esp) { - DWORD *p = (DWORD *) esp; - for (int i = -2; i < 6; ++i) { - DWORD val = p[i]; - std::stringstream ss; - ss << fmtHex(limits.high - (DWORD) &p[i]) << "->" << fmtHex32(val); - if(limits.contains(val)) { - ss << " " << "stack"; - ss << "+" << fmtHex(limits.high - val); - } else if (auto *mod = modules.find(val)) { - if (auto *exp = mod->find_export_le(val)) { - ss << " " << mod->name; - ss << ":" << exp->name << "+" << fmtHex(val - exp->addr); - } else { - ss << " " << mod->name; - ss << "+" << fmtHex(val - mod->base); - } - } - std::cout << ss.str() << std::endl; - } - } void setEbp(DWORD ebpCand) { Ebp = 0; if(ebpCand && ebpCand >= Esp && limits.contains(ebpCand)) { @@ -420,6 +457,12 @@ struct StackWalkerState { return; } StackFrame_reset(frame); + if(!(limits.low <= Esp && Esp < (limits.high + 0x1000))) { + std::stringstream ss; + ss << "invalid esp"; + err.set(ss.str()); + return; + } if(Esp >= limits.high) { std::stringstream ss; ss << "stack limit reached"; @@ -428,8 +471,6 @@ struct StackWalkerState { frame.eip = Eip; frame.esp = Esp; if(Ebp && Ebp >= Esp) frame.ebp = Ebp; - // todo: describe how we get here - // ebp can be invalid bool isAppCode = false; if(bughunter::isDkiiCode(Eip)) { @@ -474,9 +515,9 @@ struct StackWalkerState { if (auto *exp = mod->find_export_le(Eip)) { frame.symName = exp->name; frame.symAddr = exp->addr; -// printf("unwind lib %s:%s+%X\n", frame.libName.c_str(), frame.symName.c_str(), Eip - frame.symAddr); +// printf("unwind lib %s:%s+%X\n", frame.libName.c_str(), frame.symName.c_str(), Eip - frame.symAddr); } else { -// printf("unwind lib %s+%X\n", frame.libName.c_str(), Eip - frame.libBase); +// printf("unwind lib %s+%X\n", frame.libName.c_str(), Eip - frame.libBase); } } else { std::stringstream ss; @@ -486,7 +527,7 @@ struct StackWalkerState { } } // step - if(Ebp && Ebp >= Esp) { + if(Esp <= Ebp && Ebp < limits.high) { Esp = Ebp; auto *bp = (uint32_t *) Esp; setEbp(*bp++); @@ -559,6 +600,42 @@ void onlyImportantFrames(StackWalkerIter &&it, std::deque &frames, W } } + +std::string wide_string_to_string(const wchar_t *wide_string) { + if (wide_string == NULL || wide_string[0] == L'\0') return ""; + + size_t wlen = wcslen(wide_string); + const auto size_needed = WideCharToMultiByte(CP_UTF8, 0, wide_string, wlen, nullptr, 0, nullptr, nullptr); + if (size_needed <= 0) { + std::string ret(wlen, 0); + for (int i = 0; i < wlen; ++i) ret[i] = wide_string[i]; + return ret; + } + + std::string result(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, wide_string, wlen, result.data(), size_needed, nullptr, nullptr); + return result; +} +template +struct my_equal { + my_equal( const std::locale& loc ) : loc_(loc) {} + bool operator()(charT ch1, charT ch2) { + return std::toupper(ch1, loc_) == std::toupper(ch2, loc_); + } +private: + const std::locale& loc_; +}; + +// find substring (case insensitive) +template +int ci_find_substr( const T& str1, const T& str2, const std::locale& loc = std::locale() ) { + typename T::const_iterator it = std::search( + str1.begin(), str1.end(), str2.begin(), str2.end(), + my_equal(loc) ); + if ( it != str1.end() ) return it - str1.begin(); + else return -1; // not found +} + void formatHeader(std::stringstream &ss, FILETIME ×tamp) { ss << "timestamp: " << fmtHex32(timestamp.dwHighDateTime) << fmtHex32(timestamp.dwLowDateTime); { @@ -574,6 +651,10 @@ void formatHeader(std::stringstream &ss, FILETIME ×tamp) { std::string version = game_version_patch::getFileVersion(); std::replace(version.begin(), version.end(), '\n', ' '); ss << "version: " << version << std::endl; + std::string commandLine = wide_string_to_string(GetCommandLineW()); + int pos = ci_find_substr(commandLine, ".exe"); + if(pos != -1) commandLine = commandLine.substr(pos); + ss << "command line: " << commandLine << std::endl; } void formatModules(std::stringstream &ss, LoadedModules &modules) { @@ -652,8 +733,11 @@ LONG WINAPI TopLevelExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionIn } if(err) { ss << "[StackWalker ERROR]: " << err.str() << std::endl; + std::cout << ss.str() << std::endl; + MessageBoxA(NULL, "err", "err", MB_OK); } } + std::vector ntdllWorkers; for(auto &ts : states) { WalkerError err; StackLimits limits; @@ -671,12 +755,21 @@ LONG WINAPI TopLevelExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionIn DWORD lastError = GetLastError(); ss << "thread " << ts.tid << " stack=" << fmtHex32(limits.low) << "-" << fmtHex32(limits.high) << std::endl; ss << "[StackWalker ERROR]: GetThreadContext failed " << fmtHex32(lastError) << std::endl; + continue; } std::deque frames; StackWalker sw(modules, limits, ctx, err); for(auto &frame : sw) frames.push_back(frame); + // collect ntdll workers. dont know how to detect them properly + if(frames.size() >= 2) { + if(frames[frames.size() - 2].symName == "ZwWaitForWorkViaWorkerFactory") { + ntdllWorkers.push_back(ts.tid); + } + if(frames.size() == 2) continue; // dont log waiting ntdll workers + } + ss << std::endl; ss << "thread " << ts.tid << " stack=" << fmtHex32(limits.low) << "-" << fmtHex32(limits.high) << std::endl; for(auto &fr : frames) { @@ -687,6 +780,13 @@ LONG WINAPI TopLevelExceptionFilter(_In_ struct _EXCEPTION_POINTERS *ExceptionIn } } + // dont block ntdll workers. they are important for ShellExecuteA at least + for(auto &ts : states) { + // if(!ntdllWorkers.contains(ts.tid)) continue; + if (std::find(ntdllWorkers.begin(), ntdllWorkers.end(), ts.tid) == ntdllWorkers.end()) continue; + ts.resume(); + } + ss << std::endl; formatModules(ss, modules); @@ -749,6 +849,17 @@ void traceThread(HANDLE hThread, std::vector &frames, WalkerError &e for(auto &frame : sw) frames.push_back(frame); } +void dumpCurrentStack() { + std::vector frames; + WalkerError err; + traceCurrentStack(frames, err); + for(auto &fr : frames) { + std::cout << fr << std::endl; + } + if(err) { + std::cout << "[StackWalker ERROR]: " << err.str() << std::endl; + } +} void traceCurrentStack(std::vector &frames, WalkerError &err) { CONTEXT ctx; ZeroMemory(&ctx, sizeof(ctx)); diff --git a/src/tools/bug_hunter.h b/src/tools/bug_hunter.h index 820eea3..2865434 100644 --- a/src/tools/bug_hunter.h +++ b/src/tools/bug_hunter.h @@ -79,6 +79,7 @@ class StackWalker { }; +void dumpCurrentStack(); void traceCurrentStack(std::vector &frames, WalkerError &err); diff --git a/tools/msvc_mangler/msvc_mangler.cpp b/tools/msvc_mangler/msvc_mangler.cpp index cbee918..339101f 100644 --- a/tools/msvc_mangler/msvc_mangler.cpp +++ b/tools/msvc_mangler/msvc_mangler.cpp @@ -169,6 +169,12 @@ void mangleType(std::stringstream &ss, Type *ty, std::map & return; } } + if(intTy->size == 1 && intTy->is_signed) { + if(intTy->fname == "int8_t") { + ss << "C"; + return; + } + } // if 32 bit if(intTy->size == 4) { if(intTy->fname.starts_with("long") ||