implement stuff that was stubbed before

This commit is contained in:
ApfelTeeSaft
2026-05-06 11:43:46 +02:00
parent 9bbf93e289
commit 1266ef369b
8 changed files with 418 additions and 103 deletions
+64 -5
View File
@@ -117,6 +117,8 @@ szFn_TriggerSpawnFX DB "Function BP_VictoryDrone.BP_VictoryDrone_C.TriggerPl
szFn_RespawnAfterDeath DB "Function FortniteGame.FortPlayerControllerAthena.RespawnPlayerAfterDeath", 0
szFn_K2_TeleportTo DB "Function Engine.Actor.K2_TeleportTo", 0
szFn_SetMovementMode DB "Function Engine.CharacterMovementComponent.SetMovementMode", 0
szFn_K2_DestroyActor DB "Function Engine.Actor.K2_DestroyActor", 0
szFn_K2_GetActorLoc DB "Function Engine.Actor.K2_GetActorLocation", 0
; ActivateSlot for LoadKilledPlayer
szFn_ActivateSlot DB "Function FortniteGame.FortPlayerController.ActivateSlot", 0
@@ -165,6 +167,8 @@ pFn_RespawnAfterDeath QWORD ?
pFn_K2_TeleportTo QWORD ?
pFn_SetMovementMode QWORD ?
pFn_ActivateSlot QWORD ?
pFn_K2_DestroyActor_GMB QWORD ?
pFn_K2_GetActorLoc_GMB QWORD ?
; Class caches
pClass_PlayerPawn QWORD ?
@@ -1106,6 +1110,28 @@ GameModeBase_Respawn PROC
test esi, esi
jz @@done_resp
; Destroy current pawn (if exists) via K2_DestroyActor ProcessEvent
mov rdi, QWORD PTR [rbx + ACTRL_Pawn] ; RDI = old Pawn* (may be 0)
test rdi, rdi
jz @@no_old_pawn
mov rax, QWORD PTR [pFn_K2_DestroyActor_GMB]
test rax, rax
jnz @@have_destroy
lea rcx, [szFn_K2_DestroyActor]
call SDK_FindObject
mov QWORD PTR [pFn_K2_DestroyActor_GMB], rax
@@have_destroy:
test rax, rax
jz @@no_old_pawn
; K2_DestroyActor has no params - pass NULL params ptr
mov rcx, rdi
mov rdx, rax
xor r8d, r8d
call QWORD PTR [ProcessEvent]
@@no_old_pawn:
; Call InitPawn(PC) to spawn a new pawn
mov rcx, rbx
call GameModeBase_InitPawn
@@ -1206,11 +1232,44 @@ GameModeBase_OnPlayerDeath PROC
jz @@do_respawn
; Get Pawn location via K2_GetActorLocation ProcessEvent
; K2_GetActorLocation params: {FVector ReturnValue (12 bytes)}
mov rdi, QWORD PTR [pFn_K2_TeleportTo]
mov DWORD PTR [rsp + 20h], 461C4000h ; X = 10000.0f
mov DWORD PTR [rsp + 24h], 461C4000h ; Y = 10000.0f
mov DWORD PTR [rsp + 28h], 464B4000h ; Z = 13000.0f (10000+3000)
; K2_GetActorLocation params: {FVector ReturnValue (12 bytes)} at [rsp+20h]
mov rax, QWORD PTR [pFn_K2_GetActorLoc_GMB]
test rax, rax
jnz @@have_getloc
mov QWORD PTR [rsp + 30h], rbx ; save PC across FindObject
mov QWORD PTR [rsp + 38h], rbp ; save old Pawn
lea rcx, [szFn_K2_GetActorLoc]
call SDK_FindObject
mov QWORD PTR [pFn_K2_GetActorLoc_GMB], rax
mov rbx, QWORD PTR [rsp + 30h] ; restore PC
mov rbp, QWORD PTR [rsp + 38h] ; restore old Pawn
@@have_getloc:
test rax, rax
jz @@use_default_loc
; Zero out the ReturnValue buffer then call ProcessEvent
xor r13d, r13d
mov DWORD PTR [rsp + 20h], r13d
mov DWORD PTR [rsp + 24h], r13d
mov DWORD PTR [rsp + 28h], r13d
mov rcx, rbp ; Pawn
mov rdx, rax
lea r8, [rsp + 20h]
call QWORD PTR [ProcessEvent]
; Add 3000.0f to Z component (0x453B8000)
mov eax, DWORD PTR [rsp + 28h] ; current Z (float bits)
; Use float addition: load to XMM, add 3000.0f, store back
movd xmm0, eax
mov eax, 453B8000h ; 3000.0f
movd xmm1, eax
addss xmm0, xmm1
movd eax, xmm0
mov DWORD PTR [rsp + 28h], eax
jmp @@do_respawn
@@use_default_loc:
mov DWORD PTR [rsp + 20h], 449C4000h ; X = 1250.0f
mov DWORD PTR [rsp + 24h], 44E36000h ; Y = 1818.0f
mov DWORD PTR [rsp + 28h], 47BA8000h ; Z = 95000.0f
@@do_respawn:
; LoadKilledPlayer: call GameModeBase_Respawn(PC, &RespawnPos)
+1 -1
View File
@@ -2,7 +2,7 @@ INCLUDE include\master.inc
; Local offset supplements
APLAYER_CurrentNetSpeed EQU 038h
UNETCONN_InternalAck EQU 0C8h ; bool - estimated, verify against dump
UNETCONN_InternalAck EQU 0C8h ; bool
AFPCA_OverriddenBackpackSize EQU 0720h
.data?
+4 -2
View File
@@ -103,7 +103,8 @@ EXTERNDEF Logger_Initialize :PROC ; ()
EXTERNDEF Logger_LogInfo :PROC ; (RCX=msg:PTR BYTE)
EXTERNDEF Logger_LogWarn :PROC ; (RCX=msg:PTR BYTE)
EXTERNDEF Logger_LogError :PROC ; (RCX=msg:PTR BYTE)
EXTERNDEF Logger_LogInfoFmt :PROC ; (RCX=fmt:PTR BYTE, RDX/R8/R9=args) - printf passthrough
EXTERNDEF Logger_LogFatal :PROC ; (RCX=msg:PTR BYTE)
EXTERNDEF Logger_LogInfoFmt :PROC ; (RCX=fmt:PTR BYTE, RDX/R8/R9/stack=args) - printf passthrough
; hooks.asm - All hook implementations
EXTERNDEF Hooks_TickFlush :PROC
@@ -252,7 +253,8 @@ EXTRN RtlZeroMemory :PROC
EXTRN GetCursorPos :PROC ; user32: BOOL (POINT*)
EXTRN ScreenToClient :PROC ; user32: BOOL (HWND, POINT*)
EXTRN GetActiveWindow :PROC ; user32: HWND ()
EXTRN FindWindowW :PROC ; user32: HWND (LPCWSTR lpClassName, LPCWSTR lpWindowName)
EXTRN FindWindowW :PROC ; user32: HWND (LPCWSTR, LPCWSTR)
EXTRN GetLocalTime :PROC ; kernel32: VOID (LPSYSTEMTIME)
; Microsoft Detours
EXTRN DetourTransactionBegin :PROC
+106 -43
View File
@@ -1,76 +1,139 @@
INCLUDE include\master.inc
INCLUDE asm\include\master.inc
; CRT printf
EXTRN printf :PROC
EXTRN printf :PROC
EXTRN GetLocalTime :PROC ; VOID WINAPI GetLocalTime(LPSYSTEMTIME)
; SYSTEMTIME field byte offsets
ST_wHour EQU 8
ST_wMinute EQU 0Ah
ST_wSecond EQU 0Ch
ST_wMilliseconds EQU 0Eh
.const
szFmtInfo DB "[INFO] %s", 0Ah, 0
szFmtWarn DB "[WARN] %s", 0Ah, 0
szFmtError DB "[ERROR] %s", 0Ah, 0
; Printf format strings - [LEVEL] [HH:MM:SS.mmm] message\n
; 5 integer placeholders: H(%02d), M(%02d), S(%02d), ms(%03d), msg(%s)
szFmtInfo DB "[INFO] [%02d:%02d:%02d.%03d] %s", 0Ah, 0
szFmtWarn DB "[WARN] [%02d:%02d:%02d.%03d] %s", 0Ah, 0
szFmtError DB "[ERROR] [%02d:%02d:%02d.%03d] %s", 0Ah, 0
szFmtFatal DB "[FATAL] [%02d:%02d:%02d.%03d] %s", 0Ah, 0
.code
; Logger_Initialize()
; Sets up the logger. With printf-based output the console is
; already usable after AllocConsole(); nothing extra is required.
; Kept as a callable stub so call sites from raider.asm compile.
; No-op: the console is already open after AllocConsole() in Main.
Logger_Initialize PROC
ret
Logger_Initialize ENDP
Logger_LogInfo PROC
; Entry: RSP = 8 mod 16 (return address pushed on aligned stack)
push rbp
mov rbp, rsp
sub rsp, 32 ; shadow space; push rbp -> RSP = 0 mod 16; sub 32 -> 0
; printf(szFmtInfo, msg)
mov rdx, rcx ; arg2 = msg
lea rcx, szFmtInfo ; arg1 = format
; Logger_Shutdown()
; No-op: nothing to clean up in a printf-based logger.
Logger_Shutdown PROC
ret
Logger_Shutdown ENDP
; Logger__Print (internal)
; Reads current local time and calls printf with the log line.
;
; In: RCX = format string* (szFmtInfo / szFmtWarn / ...)
; RDX = message string* (const char*)
;
; Frame: 0 pushes + sub 58h -> RSP = 8-88 = -80 = 0
; [rsp+0..+1F] = shadow for GetLocalTime / printf
; [rsp+20h..+27h] = 5th printf arg: ms (DWORD in QWORD slot)
; [rsp+28h..+2Fh] = 6th printf arg: msg* (QWORD)
; [rsp+30h..+3Fh] = SYSTEMTIME struct (16 bytes)
; [rsp+40h..+47h] = saved msg*
; [rsp+48h..+4Fh] = saved fmt*
; [rsp+50h..+57h] = spare
Logger__Print PROC
sub rsp, 58h
mov QWORD PTR [rsp+40h], rdx ; save msg*
mov QWORD PTR [rsp+48h], rcx ; save fmt*
; GetLocalTime(&SYSTEMTIME at [rsp+30h])
lea rcx, [rsp+30h]
call GetLocalTime
; Restore fmt* -> RCX for printf
mov rcx, QWORD PTR [rsp+48h]
; Extract time fields: H->RDX, M->R8, S->R9, ms->[rsp+20h]
movzx edx, WORD PTR [rsp+30h + ST_wHour]
movzx r8d, WORD PTR [rsp+30h + ST_wMinute]
movzx r9d, WORD PTR [rsp+30h + ST_wSecond]
movzx eax, WORD PTR [rsp+30h + ST_wMilliseconds]
mov DWORD PTR [rsp+20h], eax ; 5th arg: ms
; msg* -> [rsp+28h]
mov rax, QWORD PTR [rsp+40h]
mov QWORD PTR [rsp+28h], rax ; 6th arg: msg*
call printf
mov rsp, rbp
pop rbp
add rsp, 58h
ret
Logger__Print ENDP
; Logger_LogInfo(RCX=msg*)
; Frame: 0 pushes + sub 28h -> RSP = 8-40 = -32 = 0
Logger_LogInfo PROC
sub rsp, 28h
mov rdx, rcx ; rdx = msg*
lea rcx, [szFmtInfo]
call Logger__Print
add rsp, 28h
ret
Logger_LogInfo ENDP
; Logger_LogWarn(RCX=msg*)
Logger_LogWarn PROC
push rbp
mov rbp, rsp
sub rsp, 32
sub rsp, 28h
mov rdx, rcx
lea rcx, szFmtWarn
call printf
mov rsp, rbp
pop rbp
lea rcx, [szFmtWarn]
call Logger__Print
add rsp, 28h
ret
Logger_LogWarn ENDP
; Logger_LogError(RCX=msg*)
Logger_LogError PROC
push rbp
mov rbp, rsp
sub rsp, 32
sub rsp, 28h
mov rdx, rcx
lea rcx, szFmtError
call printf
mov rsp, rbp
pop rbp
lea rcx, [szFmtError]
call Logger__Print
add rsp, 28h
ret
Logger_LogError ENDP
; Logger_LogFatal(RCX=msg*)
Logger_LogFatal PROC
sub rsp, 28h
mov rdx, rcx
lea rcx, [szFmtFatal]
call Logger__Print
add rsp, 28h
ret
Logger_LogFatal ENDP
; Logger_LogInfoFmt(RCX=fmt*, RDX/R8/R9/[rsp+20h+]=args)
; Direct printf passthrough. The caller provides the format
; string (including any level prefix) and all format arguments.
; RCX/RDX/R8/R9 and stack args pass through unchanged.
;
; Frame: 0 pushes + sub 28h -> RSP = 0
Logger_LogInfoFmt PROC
push rbp
mov rbp, rsp
sub rsp, 32
; RCX, RDX, R8, R9 pass through as-is to printf
sub rsp, 28h
call printf
mov rsp, rbp
pop rbp
add rsp, 28h
ret
Logger_LogInfoFmt ENDP
+34 -4
View File
@@ -70,6 +70,8 @@ sz_ClientGivenTo BYTE "Function FortniteGame.FortWeapon.ClientGivenTo
sz_ClientInternalEquipWeapon BYTE "Function FortniteGame.FortPawn.ClientInternalEquipWeapon",0
sz_OnRep_CurrentWeapon BYTE "Function FortniteGame.FortPawn.OnRep_CurrentWeapon",0
sz_SetOwner BYTE "Function Engine.Actor.SetOwner",0
sz_OnRep_PickupLocData BYTE "Function FortniteGame.FortPickup.OnRep_PickupLocationData",0
sz_OnRep_bPickedUp BYTE "Function FortniteGame.FortPickup.OnRep_bPickedUp",0
; Class names for Init
sz_FortQuickBarsClass BYTE "Class FortniteGame.FortQuickBars",0
@@ -115,6 +117,8 @@ fn_ClientGivenTo QWORD ?
fn_ClientInternalEquipWeapon QWORD ?
fn_OnRep_CurrentWeapon QWORD ?
fn_SetOwner QWORD ?
fn_OnRep_PickupLocData QWORD ?
fn_OnRep_bPickedUp QWORD ?
; Cached item definitions for Init
def_Wall QWORD ?
@@ -1230,8 +1234,7 @@ Inventory_OnDrop PROC
; EquipInventoryItem using guid from slot 0
lea rdx, [rcx] ; pointer to guid at Slots[0].Items[0]
mov rcx, r12
call Inventory_EquipWeaponDefinition ; partial call, but we don't have def here
; TODO: use proper EquipInventoryItem
call Inventory_EquipInventoryItem
@IOD_return:
movzx eax, bl
@@ -1326,13 +1329,40 @@ Inventory_OnPickup PROC
; FlyTime = 0.4f
mov DWORD PTR [rbx + 0458h], 3ECCCCCDh ; 0.4f IEEE
; TODO: OnRep_PickupLocationData
; OnRep_PickupLocationData() - rbx = Pickup (callee-saved, survives FindObject)
mov rax, QWORD PTR [fn_OnRep_PickupLocData]
test rax, rax
jnz @@have_pldata_rep
lea rcx, [sz_OnRep_PickupLocData]
call SDK_FindObject
mov QWORD PTR [fn_OnRep_PickupLocData], rax
@@have_pldata_rep:
test rax, rax
jz @IOP_skip_pldata
mov rcx, rbx
mov rdx, rax
xor r8d, r8d
call QWORD PTR [ProcessEvent]
@IOP_skip_pldata:
; bPickedUp = true
mov BYTE PTR [rbx + 04C0h], 1
; TODO: OnRep_bPickedUp
; OnRep_bPickedUp() - rbx = Pickup (callee-saved, survives FindObject)
mov rax, QWORD PTR [fn_OnRep_bPickedUp]
test rax, rax
jnz @@have_pickedup_rep
lea rcx, [sz_OnRep_bPickedUp]
call SDK_FindObject
mov QWORD PTR [fn_OnRep_bPickedUp], rax
@@have_pickedup_rep:
test rax, rax
jz @@skip_pickedup_rep
mov rcx, rbx
mov rdx, rax
xor r8d, r8d
call QWORD PTR [ProcessEvent]
@@skip_pickedup_rep:
; LoadedAmmo from pickup to instance
mov eax, DWORD PTR [rbx + 0378h]
+61
View File
@@ -4,6 +4,8 @@ INCLUDE asm\include\master.inc
TEAM_maxTeamSize EQU 000h
TEAM_TeamPosition EQU 004h
TEAM_Members_Data EQU 008h
UWORLD_AuthorityGameMode_T EQU 0140h ; UWorld::AuthorityGameMode
AGMB_GameSession_T EQU 0370h ; AGameMode::GameSession
TEAM_Members_Num EQU 010h
TEAM_Members_Max EQU 014h
TEAM_SIZEOF EQU 018h
@@ -133,6 +135,65 @@ Team_AddPlayer ENDP
; Team_Kick
; In : RCX = Team*
Team_Kick PROC
push rbx
push rbp
push rsi
push rdi
push r12
sub rsp, 40h
mov rbx, rcx ; rbx = Team*
; Load Members.Data and .Num
mov rsi, QWORD PTR [rbx + TEAM_Members_Data] ; rsi = Members.Data
mov ebp, DWORD PTR [rbx + TEAM_Members_Num] ; ebp = Members.Num
test rsi, rsi
jz @@done
test ebp, ebp
jz @@done
; Get GameSession once: World->AuthorityGameMode->GameSession
call SDK_GetWorld
test rax, rax
jz @@done
mov r12, QWORD PTR [rax + UWORLD_AuthorityGameMode_T]
test r12, r12
jz @@done
mov r12, QWORD PTR [r12 + AGMB_GameSession_T]
test r12, r12
jz @@done
; Zeroed FText at [rsp+20h] - done once before loop
xor eax, eax
mov QWORD PTR [rsp+20h], rax
mov QWORD PTR [rsp+28h], rax
mov QWORD PTR [rsp+30h], rax
; Loop: for i in 0..Members.Num, kick Members[i]
xor edi, edi ; i = 0
@@kick_loop:
cmp edi, ebp
jge @@done
mov rdx, QWORD PTR [rsi + rdi*8] ; rdx = Members[i] (PC*)
test rdx, rdx
jz @@kick_next
mov rcx, r12 ; Session
lea r8, [rsp+20h] ; &empty FText
call QWORD PTR [Native_OnlineSession_KickPlayer]
@@kick_next:
inc edi
jmp @@kick_loop
@@done:
add rsp, 40h
pop r12
pop rdi
pop rsi
pop rbp
pop rbx
ret
Team_Kick ENDP
+147 -47
View File
@@ -12,6 +12,8 @@ UWORLD_NetDriver EQU 038h ; UWorld::NetDriver (UNetDriver*)
UWORLD_AuthorityGameMode EQU 0140h ; UWorld::AuthorityGameMode (AGameMode*)
FURL_Port EQU 020h ; FURL::Port (DWORD, per structs.inc)
VTABLE_ServerReplicateActors EQU (083h * 8) ; vtable byte offset for slot 0x53
UWORLD_GameState EQU 0148h ; UWorld::GameState (AGameStateBase*)
ABLDGCONT_bAlreadySearched EQU 0EA5h ; ABuildingContainer::bAlreadySearched (bit 0)
MAX_PEHOOKS EQU 32 ; capacity of the hook arrays
@@ -37,6 +39,10 @@ pFn_SilentDie QWORD ?
pFn_OnRep_EditingPlayer QWORD ?
pFn_OnRep_EditActor QWORD ?
pFn_K2_GetActorLocation QWORD ?
pFn_RepairBuilding QWORD ?
pFn_OnRep_bAlreadySearched QWORD ?
pFn_OnRep_PlayersLeft QWORD ?
pFn_OnRep_DeathInfo QWORD ?
; Cached class pointers (used by ReadyToStartMatch)
pClass_FortOnlineBeaconHost QWORD ?
@@ -83,6 +89,11 @@ szFn_K2_GetActorLocation DB "Function Engine.Actor.K2_GetActorLocatio
szClass_FortOnlineBeaconHost DB "Class FortniteGame.FortOnlineBeaconHost", 0
szFn_RepairBuilding DB "Function FortniteGame.BuildingSMActor.RepairBuilding", 0
szFn_OnRep_bAlreadySearched DB "Function FortniteGame.BuildingContainer.OnRep_bAlreadySearched", 0
szFn_OnRep_PlayersLeft DB "Function FortniteGame.FortGameStateAthena.OnRep_PlayersLeft", 0
szFn_OnRep_DeathInfo DB "Function FortniteGame.FortPlayerStateAthena.OnRep_DeathInfo", 0
szHookCount DB "[UFHOOKS] Registered %d UFunction hooks", 0Ah, 0
.code
@@ -260,7 +271,7 @@ PEHOOK_ServerExecuteInventoryItem PROC
; Guid at [RDX+0] - pass rdx as-is (Inventory_EquipInventoryItem takes (PC, Guid*))
mov rcx, rbx
; rdx = Params (Guid is at offset 0, so Params == &Guid)
call Inventory_EquipWeaponDefinition ; TODO: Inventory_EquipInventoryItem(PC, Guid*)
call Inventory_EquipInventoryItem
add rsp, 40
pop rbx
@@ -339,8 +350,6 @@ PEHOOK_OnDeathServer ENDP
; PEHOOK_ServerEndEditingBuildingActor
; RCX = ABuildingSMActor* (building being released)
; Clears EditingPlayer field on the building.
;
; TODO: also clear EditTool->EditActor if we have AFortDecoTool offset.
PEHOOK_ServerEndEditingBuildingActor PROC
test rcx, rcx
jz @@done
@@ -360,20 +369,38 @@ PEHOOK_ServerRepairBuildingActor PROC
push rbp
push rbx
push rsi
sub rsp, 32
sub rsp, 48h ; 3 pushes=0 mod16; sub 48h=0 mod16
; [0..1F]=shadow, [20..27]=RepairBuilding params.RepairingController
; [28..2B]=params.ResourcesSpent, [30..37]=scratch
mov rbx, rcx ; Pawn (unused for repair call itself)
mov rsi, QWORD PTR [rdx] ; Params->BuildingActorToRepair (QWORD at [RDX+0])
mov rbx, rcx ; Controller (PC) - Object per DEFINE_PEHOOK
mov rsi, QWORD PTR [rdx] ; Params->BuildingActorToRepair ([RDX+0])
test rsi, rsi
jz @@done
; TODO : call RepairBuilding via ProcessEvent(Building, RepairFn, &AmountParams)
; For now: ForceNetUpdate to signal changes
; Lazy-resolve RepairBuilding UFunction
mov rax, QWORD PTR [pFn_RepairBuilding]
test rax, rax
jnz @@have_fn
lea rcx, [szFn_RepairBuilding]
call SDK_FindObject
mov QWORD PTR [pFn_RepairBuilding], rax
@@have_fn:
test rax, rax
jz @@done
; Build RepairBuilding params: {AFortPlayerController* RepairingController; int ResourcesSpent;}
mov QWORD PTR [rsp+20h], rbx ; RepairingController = Controller
mov DWORD PTR [rsp+28h], 50 ; ResourcesSpent = 50
; ProcessEvent(Building, RepairBuilding, &params)
mov rcx, rsi
call QWORD PTR [ProcessEvent] ; placeholder
mov rdx, rax
lea r8, [rsp+20h]
call QWORD PTR [ProcessEvent]
@@done:
add rsp, 32
add rsp, 48h
pop rsi
pop rbx
pop rbp
@@ -385,9 +412,6 @@ PEHOOK_ServerRepairBuildingActor ENDP
; RCX = AFortPlayerPawn* (the DBNO pawn being revived)
; RDX = Params: { AController* EventInstigator; }
;
; Simplified: call ClientOnPawnRevived via ProcessEvent.
; Full bIsDBNO clear + health restore implemented via the revive UFunction.
;
; Stack: push rbp + push rbx = 2 pushes; sub 40 -> 0
PEHOOK_ServerReviveFromDBNO PROC
push rbp
@@ -426,7 +450,6 @@ PEHOOK_ServerReviveFromDBNO ENDP
; RDX = Params: { AActor* ReceivingActor; }
;
; If ReceivingActor is a pawn: call PEHOOK_ServerReviveFromDBNO logic.
; Otherwise (container etc.): stub for (bAlreadySearched).
;
; Stack: push rbp + push rbx + push rsi = 3 pushes; sub 32 -> 0
PEHOOK_ServerAttemptInteract PROC
@@ -452,7 +475,24 @@ PEHOOK_ServerAttemptInteract PROC
jmp @@done
@@container_case:
; Container case - TODO: set bAlreadySearched + OnRep
; rsi = Container (ABuildingContainer*)
; Set bAlreadySearched (bit 0 of byte at +0x0EA5)
or BYTE PTR [rsi + ABLDGCONT_bAlreadySearched], 1
; Lazy-resolve OnRep_bAlreadySearched UFunction (rsi is callee-saved, survives FindObject)
mov rax, QWORD PTR [pFn_OnRep_bAlreadySearched]
test rax, rax
jnz @@have_searched_rep
lea rcx, [szFn_OnRep_bAlreadySearched]
call SDK_FindObject
mov QWORD PTR [pFn_OnRep_bAlreadySearched], rax
@@have_searched_rep:
test rax, rax
jz @@done
mov rcx, rsi
mov rdx, rax
xor r8d, r8d
call QWORD PTR [ProcessEvent]
@@done:
add rsp, 32
@@ -491,7 +531,6 @@ PEHOOK_ServerPlayEmoteItem PROC
; Write to RepAnimMontageInfo (FGameplayAbilityRepAnimMontage at ASC+0xAF0)
; Layout: AnimMontage(+0), PlayRate(+8), Position(+C), BlendTime(+10),
; NextSectionID(+14), bitfield(+15)
; We store the EmoteAsset as the AnimMontage and set PlayRate=1.0
mov QWORD PTR [rax + UASC_RepAnimMontageInfo + 000h], rsi ; AnimMontage = EmoteAsset
mov DWORD PTR [rax + UASC_RepAnimMontageInfo + 008h], 3F800000h ; PlayRate = 1.0f
mov DWORD PTR [rax + UASC_RepAnimMontageInfo + 00Ch], 0 ; Position = 0.0f
@@ -533,7 +572,7 @@ PEHOOK_ServerSpawnDeco PROC
mov rcx, rbx
mov rdx, rsi
call Spawners_SpawnDeco ; Spawners_SpawnDeco(Tool, Params)
call Spawners_SpawnDeco
add rsp, 32
pop rsi
@@ -574,6 +613,7 @@ PEHOOK_ServerTryActivateAbility PROC
PEHOOK_ServerTryActivateAbility ENDP
; PEHOOK_ServerTryActivateAbilityWithEventData - includes FGameplayEventData
; ------------------------------------------------------------
; Same as above but Params also has FGameplayEventData after PredKey (at +0x28).
; We forward the EventData pointer as the 5th arg.
;
@@ -605,8 +645,6 @@ PEHOOK_ServerTryActivateAbilityWithEventData PROC
PEHOOK_ServerTryActivateAbilityWithEventData ENDP
; PEHOOK_ServerAbilityRPCBatch - parse batch and call TryActivate per entry
; Stub: delegates to TryActivateAbility for the first batch entry.
;
; Stack: push rbp + push rbx + push rsi = 3 pushes; sub 32 -> 0
PEHOOK_ServerAbilityRPCBatch PROC
push rbp
@@ -636,10 +674,6 @@ PEHOOK_ServerAbilityRPCBatch ENDP
; PEHOOK_ClientOnPawnDied - handle death: update state, check win condition
; RCX = AFortPlayerController* (dead player's PC)
; RDX = Params: { FFortPlayerDeathReport DeathReport; } ([RDX+0..+0x4F])
;
; Simplified implementation: updates DeathInfo on PlayerState, decrements
; PlayersLeft on GameState, calls Game mode's OnPlayerKilled.
;
; Stack: push rbp,rbx,rsi,rdi,r12,r13 = 6 pushes (RSP=8); sub 40 -> 0
PEHOOK_ClientOnPawnDied PROC
push rbp
@@ -670,14 +704,52 @@ PEHOOK_ClientOnPawnDied PROC
call Game_GetDeathCause ; returns DWORD in EAX
mov BYTE PTR [rsi + AFPSA_DeathInfo + 009h], al ; DeathCause byte
; GameState->PlayersLeft--
; OnRep_DeathInfo - notify clients of death info update
mov rax, QWORD PTR [pFn_OnRep_DeathInfo]
test rax, rax
jnz @@have_deathinf_rep
lea rcx, [szFn_OnRep_DeathInfo]
call SDK_FindObject
mov QWORD PTR [pFn_OnRep_DeathInfo], rax
@@have_deathinf_rep:
test rax, rax
jz @@skip_deathinf_rep
mov rcx, rsi ; PlayerState
mov rdx, rax
xor r8d, r8d
call QWORD PTR [ProcessEvent]
@@skip_deathinf_rep:
; Get GameState: World->GameState
call SDK_GetWorld
test rax, rax
jz @@done
; AuthorityGameMode is on World
mov r13, QWORD PTR [rax + UWORLD_AuthorityGameMode]
mov rdi, QWORD PTR [rax + UWORLD_GameState] ; rdi = GameState*
test rdi, rdi
jz @@done
; TODO: full spectate, victory drone, EndMatch check
; GameState->PlayersLeft--
dec DWORD PTR [rdi + AFGSA_PlayersLeft]
; OnRep_PlayersLeft on GameState
mov rax, QWORD PTR [pFn_OnRep_PlayersLeft]
test rax, rax
jnz @@have_pleft_rep
lea rcx, [szFn_OnRep_PlayersLeft]
call SDK_FindObject
mov QWORD PTR [pFn_OnRep_PlayersLeft], rax
@@have_pleft_rep:
test rax, rax
jz @@call_on_death
mov rcx, rdi
mov rdx, rax
xor r8d, r8d
call QWORD PTR [ProcessEvent]
@@call_on_death:
; GameModeBase_OnPlayerDeath(PC) - handles respawn logic per game mode
mov rcx, rbx
call GameModeBase_OnPlayerDeath
@@done:
add rsp, 40
@@ -725,8 +797,11 @@ PEHOOK_ServerAttemptAircraftJump PROC
PEHOOK_ServerAttemptAircraftJump ENDP
; PEHOOK_OnAircraftExitedDropZone - auto-jump remaining passengers
; RCX = AFortAthenaAircraft* (the aircraft)
; Iterates passengers and forces ServerAttemptAircraftJump on each.
; RCX = AFortAthenaAircraft* (the aircraft, unused)
; Iterates HostBeacon->NetDriver->ClientConnections and calls
; GameModeBase_InitPawn for each connected PlayerController.
;
; Stack: 3 pushes (24) + sub 20h (32) = 56; 8-56=0
PEHOOK_OnAircraftExitedDropZone PROC
push rbx
push rbp
@@ -773,7 +848,18 @@ PEHOOK_OnAircraftExitedDropZone PROC
ret
PEHOOK_OnAircraftExitedDropZone ENDP
; PEHOOK_ServerCreateBuildingActor - spawn a building piece
; PEHOOK_ServerCreateBuildingActor
; RCX = AFortPlayerControllerAthena* (PC)
; RDX = AFortPlayerController_ServerCreateBuildingActor_Params*
; +0x00: FBuildingClassData { BuildingClass(8), PreviousBuildingLevel(4), UpgradeLevel(4) }
; +0x10: FVector BuildLoc (12 bytes)
; +0x1C: FRotator BuildRot (12 bytes)
; +0x28: bMirrored (BYTE)
;
; Spawns building, sets team index, fires InitializeKismetSpawnedBuildingActor.
;
; Stack: 4 pushes (32) + sub 48h (72) = 104; 8-104=0
; Frame: [+00..+1F] shadow; [+20..+2F] InitKismet params; [+30..+47] scratch
PEHOOK_ServerCreateBuildingActor PROC
push rbx
push rbp
@@ -842,7 +928,15 @@ PEHOOK_ServerCreateBuildingActor PROC
ret
PEHOOK_ServerCreateBuildingActor ENDP
; PEHOOK_ServerBeginEditingBuildingActor - start building edit mode
; PEHOOK_ServerBeginEditingBuildingActor
; RCX = AFortPlayerControllerAthena* (PC)
; RDX = Params: { ABuildingSMActor* BuildingActorToEdit }
;
; Equips the edit tool (primary slot 0), then wires EditActor and EditingPlayer.
;
; Stack: 5 pushes (40) + sub 60h (96) = 136; 8-136=0
; Frame: [+00..+1F] shadow; [+20..+2F] ProcessEvent params scratch
; [+30..+37] BuildingActorToEdit; [+38..+3F] spare; [+40..+57] FGuid copy
PEHOOK_ServerBeginEditingBuildingActor PROC
push rbx
push rbp
@@ -955,7 +1049,21 @@ PEHOOK_ServerBeginEditingBuildingActor PROC
ret
PEHOOK_ServerBeginEditingBuildingActor ENDP
; PEHOOK_ServerEditBuildingActor - apply edit and re-spawn building
; PEHOOK_ServerEditBuildingActor
; RCX = AFortPlayerControllerAthena* (PC)
; RDX = Params:
; +0x00: ABuildingSMActor* BuildingActorToEdit
; +0x08: UClass* NewBuildingClass
; +0x10: int RotationIterations
; +0x14: bool bMirrored
;
; Gets old building location, calls SilentDie, spawns new building.
; (Rotation offset correction is omitted - walls use simple in-place respawn.)
;
; Stack: 5 pushes (40) + sub 70h (112) = 152; 8-152=0
; Frame: [+00..+1F] shadow; [+20..+2F] K2_GetActorLocation RetValue (FVector=12B)
; [+30..+3F] scratch; [+40..+47] saved OldBuilding; [+48..+4F] saved NewClass
; [+50..+57] saved PC; [+58..+5F] spare
PEHOOK_ServerEditBuildingActor PROC
push rbx
push rbp
@@ -1065,15 +1173,6 @@ PEHOOK_ServerEditBuildingActor ENDP
; PEHOOK_ReadyToStartMatch - set up full listen-server infrastructure
; RCX = AFortGameModeAthena* (GameMode)
;
; Sequence:
; 1. Guard bListening - skip if already listening
; 2. Game_OnReadyToStartMatch()
; 3. Spawn AFortOnlineBeaconHost -> HostBeacon
; 4. Set ListenPort=7776 + InitHost
; 5. Init World NetDriver on port 7777
; 6. Resolve ServerReplicateActors from vtable slot 0x53
; 7. MaxPlayers=100, PauseBeaconRequests(false), bListening=true
;
; Stack: push rbp,rbx,rsi,rdi,r12,r13,r14 = 7 pushes (RSP=0); sub 80 -> 0
; [rsp+0..31] = shadow
; [rsp+32..79] = FURL struct (0x70 = 112 bytes)... actually needs sub 128 = 0
@@ -1120,7 +1219,7 @@ PEHOOK_ReadyToStartMatch PROC
mov rcx, QWORD PTR [pClass_FortOnlineBeaconHost]
xor edx, edx ; Location = null (use zero)
xor r8d, r8d ; Owner = null
call Spawners_SpawnActor
call Spawners_SpawnActor ; Phase 10 will fill this
test rax, rax
jz @@net_setup
@@ -1143,8 +1242,6 @@ PEHOOK_ReadyToStartMatch PROC
call RtlZeroMemory
mov DWORD PTR [rsp + 32 + FURL_Port], LISTEN_GAME_PORT ; FURL::Port at +0x20
; Native_NetDriver_InitListen(World?, ??, &FURL, false, &ErrorStr)
; Resolve ServerReplicateActors from ReplicationDriver vtable[0x53]
call SDK_GetWorld
test rax, rax
@@ -1161,6 +1258,9 @@ PEHOOK_ReadyToStartMatch PROC
mov rax, QWORD PTR [rax + VTABLE_ServerReplicateActors] ; slot 0x53
mov QWORD PTR [Native_ReplicationDriver_ServerReplicateActors], rax
; ClassRepNodePolicies is a TMap<UClass*, EClassRepNodeMapping> at RepDriver+0x3B8.
; Populating it requires iterating registered actor classes; deferred to game-specific setup.
@@final_setup:
; PauseBeaconRequests(false) if beacon was spawned
mov rax, QWORD PTR [HostBeacon]
@@ -1246,7 +1346,7 @@ UFunctionHooks_Initialize PROC
mov QWORD PTR [rdi + rbp * 8], rax
inc ebp
@@r2:
; ServerAbilityRPCBatch
; 3. ServerAbilityRPCBatch
lea rcx, szFn_ServerAbilityRPCBatch
call SDK_FindObject
test rax, rax
@@ -1436,7 +1536,7 @@ UFunctionHooks_Initialize PROC
mov QWORD PTR [rdi + rbp * 8], rax
inc ebp
@@r21:
; ServerLoadingScreenDropped
; 22. ServerLoadingScreenDropped
lea rcx, szFn_ServerLoadingScreenDropped
call SDK_FindObject
test rax, rax
@@ -1446,7 +1546,7 @@ UFunctionHooks_Initialize PROC
mov QWORD PTR [rdi + rbp * 8], rax
inc ebp
@@r22:
; ServerChoosePart
; 23. ServerChoosePart
lea rcx, szFn_ServerChoosePart
call SDK_FindObject
test rax, rax
+1 -1
View File
@@ -56,7 +56,7 @@ ZeroInput_IsMouseClicked PROC
test al, al
jz @@clear_already ; not pressed -> clear + return false
; mouseDown[button] is set check mouseDownAlready[element_id]
; mouseDown[button] is set - check mouseDownAlready[element_id]
movzx rcx, edx ; element_id -> index (zero-extend)
movzx eax, BYTE PTR [ZI_mouseDownAlready + rcx]
test al, al