mirror of
https://github.com/ApfelTeeSaft/Perfectium.git
synced 2026-08-26 19:33:36 +00:00
implement stuff that was stubbed before
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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]
|
||||
|
||||
@@ -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
@@ -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, ¶ms)
|
||||
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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user