mirror of
https://github.com/ApfelTeeSaft/Perfectium.git
synced 2026-08-26 19:33:36 +00:00
add GUI/Input layer (zeroinput, zerogui, gui)
This commit is contained in:
@@ -0,0 +1,576 @@
|
||||
INCLUDE asm\include\master.inc
|
||||
|
||||
; SDK offsets - AFortGameStateAthena
|
||||
AGSA_WarmupCountdownEndTime EQU 14F4h
|
||||
AGSA_AircraftStartTime EQU 14F8h
|
||||
AGSA_GamePhase EQU 1B98h ; BYTE, EAthenaGamePhase
|
||||
AGSA_bWillSkipAircraft EQU 1BA8h ; BYTE
|
||||
AGSA_PlayerArray_Data EQU 0330h ; TArray<APlayerState*>.Data
|
||||
AGSA_PlayerArray_Num EQU 0338h ; TArray<APlayerState*>.Num
|
||||
|
||||
; UWorld offsets
|
||||
UWORLD_GameState EQU 0148h
|
||||
UWORLD_AuthorityGameMode EQU 0140h
|
||||
|
||||
; AGameModeBase offsets
|
||||
AGMB_GameSession EQU 0370h ; AGameSession*
|
||||
|
||||
; AActor offsets
|
||||
AACTOR_Owner EQU 0108h ; AActor* (PlayerController for PlayerState)
|
||||
|
||||
; EAthenaGamePhase::Aircraft = 3
|
||||
EGAMEPHASE_Aircraft EQU 3
|
||||
|
||||
; FText size
|
||||
FTEXT_SIZE EQU 18h ; 24 bytes
|
||||
|
||||
; Window parameters
|
||||
GUI_WINDOW_W_BITS EQU 43FA0000h ; 500.0f
|
||||
GUI_WINDOW_H_BITS EQU 444F0000h ; 828.0f
|
||||
GUI_WINDOW_H_BITS2 EQU 44AF0000h ; 700.0f (for header)
|
||||
|
||||
; Position of GUI window
|
||||
; Menu pos: FVector2D starting at 200, 250
|
||||
F_200_0 EQU 43480000h ; 200.0f
|
||||
F_250_0 EQU 437A0000h ; 250.0f
|
||||
|
||||
.const
|
||||
|
||||
; Wide string constants for GUI text
|
||||
szTitle_Raider DW 'R','a','i','d','e','r', 0
|
||||
szBtn_StartBus DW 'S','t','a','r','t',' ','B','u','s', 0
|
||||
szBtn_Back DW '<', 0
|
||||
szBtn_Kick DW 'K','i','c','k', 0
|
||||
szBtnTab_Game DW 'G','a','m','e', 0
|
||||
szBtnTab_Players DW 'P','l','a','y','e','r','s', 0
|
||||
szText_CurPlayer DW 'C','u','r','r','e','n','t',' ','P','l','a','y','e','r',':', 0
|
||||
szText_ConnPlayers DW 'C','o','n','n','e','c','t','e','d',' ','P','l','a','y','e','r','s', 0
|
||||
|
||||
; Console command: "startaircraft"
|
||||
szConsoleCmd_W DW 's','t','a','r','t','a','i','r','c','r','a','f','t', 0
|
||||
|
||||
; UFunction / UClass paths for static calls
|
||||
szFn_ExecConsoleCmd DB "Function Engine.KismetSystemLibrary.ExecuteConsoleCommand", 0
|
||||
szClass_KismetSys DB "Class Engine.KismetSystemLibrary", 0
|
||||
szFn_GetPlayerName DB "Function Engine.PlayerState.GetPlayerName", 0
|
||||
szFn_ConvStrToText DB "Function Engine.KismetTextLibrary.Conv_StringToText", 0
|
||||
szClass_KismetText DB "Class Engine.KismetTextLibrary", 0
|
||||
|
||||
; Kick reason wide string
|
||||
szKickReason DW 'Y','o','u',' ','h','a','v','e',' ','b','e','e','n',' ','k','i','c','k','e','d','.', 0
|
||||
|
||||
; Sizebit constants as REAL4
|
||||
f_25_0 REAL4 25.0
|
||||
f_100_0 REAL4 100.0
|
||||
f_110_0 REAL4 110.0
|
||||
f_60_0 REAL4 60.0
|
||||
f_90_0 REAL4 90.0
|
||||
f_130_0 REAL4 130.0
|
||||
f_500_0 REAL4 500.0
|
||||
f_700_0 REAL4 700.0
|
||||
f_0_5_gui REAL4 0.5
|
||||
|
||||
.data?
|
||||
|
||||
; Persistent menu state
|
||||
GUI_menu_opened BYTE ? ; bool: menu visible (toggled by F2)
|
||||
GUI_initialized BYTE ? ; one-time init done
|
||||
GUI_tab DWORD ? ; active tab (0=Game, 1=Players)
|
||||
GUI_currentPlayer QWORD ? ; APlayerState* selected for kick view (or 0)
|
||||
GUI_pos_X REAL4 ? ; window position X (drag-persistent)
|
||||
GUI_pos_Y REAL4 ? ; window position Y
|
||||
|
||||
; Cached UFunction* and UClass* pointers
|
||||
GUI_pFn_ExecConsole QWORD ?
|
||||
GUI_pClass_KismetSys QWORD ?
|
||||
GUI_pFn_GetPlyName QWORD ?
|
||||
GUI_pFn_ConvStr QWORD ?
|
||||
GUI_pClass_TextLib QWORD ?
|
||||
|
||||
; Scratch buffer for player name FString (single-frame, reused per player)
|
||||
GUI_nameFStr_Data QWORD ? ; FString.Data (wchar_t*)
|
||||
GUI_nameFStr_Num DWORD ? ; FString.Num
|
||||
GUI_nameFStr_Max DWORD ? ; FString.Max
|
||||
|
||||
; Scratch buffer for kick reason FString
|
||||
GUI_kickFStr_Data QWORD ?
|
||||
GUI_kickFStr_Num DWORD ?
|
||||
GUI_kickFStr_Max DWORD ?
|
||||
|
||||
.code
|
||||
|
||||
; GUI__GetPlayerName (internal helper)
|
||||
; Calls GetPlayerName UFunction on a PlayerState via ProcessEvent.
|
||||
; Fills GUI_nameFStr_Data/Num/Max.
|
||||
; In: RCX = APlayerState* (PlayerState object)
|
||||
; Out: RAX = wchar_t* (Data pointer, or 0 on failure)
|
||||
;
|
||||
; Frame: 2 pushes (RBX=PlayerState*) + sub 28h -> RSP = 0
|
||||
; GetPlayerName params at [rsp+20h..+2Fh]:
|
||||
; +0x00: FString ReturnValue (16 bytes)
|
||||
GUI__GetPlayerName PROC
|
||||
push rbx
|
||||
push rsi
|
||||
sub rsp, 28h
|
||||
|
||||
mov rbx, rcx ; PlayerState*
|
||||
|
||||
; Lazy-load GetPlayerName UFunction*
|
||||
mov rsi, QWORD PTR [GUI_pFn_GetPlyName]
|
||||
test rsi, rsi
|
||||
jnz @@fn_ready
|
||||
lea rcx, [szFn_GetPlayerName]
|
||||
call SDK_FindObject
|
||||
mov QWORD PTR [GUI_pFn_GetPlyName], rax
|
||||
mov rsi, rax
|
||||
test rsi, rsi
|
||||
jz @@fail
|
||||
@@fn_ready:
|
||||
|
||||
; Zero the ReturnValue FString at [rsp+20h]
|
||||
xor eax, eax
|
||||
mov QWORD PTR [rsp+20h], rax ; Data = nullptr
|
||||
mov QWORD PTR [rsp+28h], rax ; Num=0, Max=0 - wait this overwrites our saved RSI
|
||||
|
||||
mov QWORD PTR [rsp+20h], 0 ; Data = 0
|
||||
mov DWORD PTR [rsp+28h], 0 ; Num = 0 (this is fine - shadow can be written)
|
||||
mov DWORD PTR [rsp+2Ch], 0 ; Max = 0
|
||||
|
||||
; ProcessEvent(PlayerState, GetPlayerName, ¶ms)
|
||||
mov rcx, rbx
|
||||
mov rdx, rsi
|
||||
lea r8, [rsp+20h]
|
||||
call QWORD PTR [ProcessEvent]
|
||||
|
||||
; Return FString.Data (the wchar_t* pointer)
|
||||
mov rax, QWORD PTR [rsp+20h]
|
||||
jmp @@done
|
||||
@@fail:
|
||||
xor rax, rax
|
||||
@@done:
|
||||
add rsp, 28h
|
||||
pop rsi
|
||||
pop rbx
|
||||
ret
|
||||
GUI__GetPlayerName ENDP
|
||||
|
||||
|
||||
; GUI__KickController (internal helper)
|
||||
; Calls Native_OnlineSession_KickPlayer(Session, PC, &empty_FText).
|
||||
; In: RCX = APlayerController* (PC to kick)
|
||||
; Out: none
|
||||
;
|
||||
; Frame: 2 pushes (RBX=PC) + sub 38h -> RSP = 8-16-56 = -64 = 0
|
||||
; [rsp+20h..+37h] = zeroed FText (0x18 = 24 bytes)
|
||||
GUI__KickController PROC
|
||||
push rbx
|
||||
push rsi
|
||||
sub rsp, 38h
|
||||
|
||||
mov rbx, rcx ; PC to kick
|
||||
test rbx, rbx
|
||||
jz @@done
|
||||
|
||||
; Get GameSession: World->AuthorityGameMode->GameSession
|
||||
call SDK_GetWorld
|
||||
test rax, rax
|
||||
jz @@done
|
||||
mov rsi, QWORD PTR [rax + UWORLD_AuthorityGameMode]
|
||||
test rsi, rsi
|
||||
jz @@done
|
||||
mov rsi, QWORD PTR [rsi + AGMB_GameSession]
|
||||
test rsi, rsi
|
||||
jz @@done
|
||||
|
||||
; Zero FText at [rsp+20h] (24 bytes)
|
||||
xor eax, eax
|
||||
mov QWORD PTR [rsp+20h], rax
|
||||
mov QWORD PTR [rsp+28h], rax
|
||||
mov QWORD PTR [rsp+30h], rax
|
||||
|
||||
; Native_OnlineSession_KickPlayer(Session, PC, &FText)
|
||||
mov rcx, rsi ; Session
|
||||
mov rdx, rbx ; PC
|
||||
lea r8, [rsp+20h] ; &FText (empty)
|
||||
call QWORD PTR [Native_OnlineSession_KickPlayer]
|
||||
|
||||
@@done:
|
||||
add rsp, 38h
|
||||
pop rsi
|
||||
pop rbx
|
||||
ret
|
||||
GUI__KickController ENDP
|
||||
|
||||
|
||||
; GUI__StartBus (internal helper)
|
||||
; Sets GameState fields and fires "startaircraft" console command
|
||||
; then calls GameModeLateGame_InitializeGameplay.
|
||||
; In: none
|
||||
; Frame: 4 pushes (RBX=GameState*,RBP=World*,RSI=KismetClass,RDI=fn)
|
||||
; + sub 48h -> RSP = 8-32-72 = -96 = 0
|
||||
; Params for ExecuteConsoleCommand at [rsp+20h]:
|
||||
; +0x00: WorldContextObject QWORD
|
||||
; +0x08: FString.Data QWORD
|
||||
; +0x10: FString.Num DWORD
|
||||
; +0x14: FString.Max DWORD
|
||||
; +0x18: SpecificPlayer QWORD = 0
|
||||
; Total = 0x20 = 32 bytes (fits in shadow + [rsp+20h..+3Fh])
|
||||
GUI__StartBus PROC
|
||||
push rbx
|
||||
push rbp
|
||||
push rsi
|
||||
push rdi
|
||||
sub rsp, 48h
|
||||
|
||||
; Get World
|
||||
call SDK_GetWorld
|
||||
test rax, rax
|
||||
jz @@done
|
||||
mov rbp, rax ; World*
|
||||
|
||||
; Get GameState
|
||||
mov rbx, QWORD PTR [rbp + UWORLD_GameState]
|
||||
test rbx, rbx
|
||||
jz @@done
|
||||
|
||||
; GameState->bGameModeWillSkipAircraft = false
|
||||
mov BYTE PTR [rbx + AGSA_bWillSkipAircraft], 0
|
||||
|
||||
; GameState->AircraftStartTime = 0
|
||||
xor eax, eax
|
||||
mov DWORD PTR [rbx + AGSA_AircraftStartTime], eax
|
||||
|
||||
; GameState->WarmupCountdownEndTime = 0
|
||||
mov DWORD PTR [rbx + AGSA_WarmupCountdownEndTime], eax
|
||||
|
||||
; ExecuteConsoleCommand via KismetSystemLibrary
|
||||
; Lazy-load KismetSystemLibrary class
|
||||
mov rsi, QWORD PTR [GUI_pClass_KismetSys]
|
||||
test rsi, rsi
|
||||
jnz @@kls_ready
|
||||
lea rcx, [szClass_KismetSys]
|
||||
call SDK_FindObject
|
||||
mov QWORD PTR [GUI_pClass_KismetSys], rax
|
||||
mov rsi, rax
|
||||
test rsi, rsi
|
||||
jz @@done
|
||||
@@kls_ready:
|
||||
|
||||
; Lazy-load ExecuteConsoleCommand UFunction*
|
||||
mov rdi, QWORD PTR [GUI_pFn_ExecConsole]
|
||||
test rdi, rdi
|
||||
jnz @@fn_ready
|
||||
lea rcx, [szFn_ExecConsoleCmd]
|
||||
call SDK_FindObject
|
||||
mov QWORD PTR [GUI_pFn_ExecConsole], rax
|
||||
mov rdi, rax
|
||||
test rdi, rdi
|
||||
jz @@done
|
||||
@@fn_ready:
|
||||
|
||||
; Build FString for "startaircraft" command using FString_FromWideChar
|
||||
; Temporarily store the FString at [rsp+30h] (3 slots: Data*, Num, Max = 16 bytes)
|
||||
lea rcx, [rsp+30h]
|
||||
lea rdx, [szConsoleCmd_W]
|
||||
call FString_FromWideChar
|
||||
|
||||
; Build params block at [rsp+20h]:
|
||||
; [rsp+20h] = World* (WorldContextObject)
|
||||
; [rsp+28h] = FString.Data (wchar_t*)
|
||||
; [rsp+30h] = FString.Num (DWORD)
|
||||
; [rsp+34h] = FString.Max (DWORD)
|
||||
; [rsp+38h] = SpecificPlayer = 0
|
||||
mov QWORD PTR [rsp+20h], rbp ; World*
|
||||
mov rax, QWORD PTR [rsp+30h] ; FString.Data (was stored by FString_FromWideChar)
|
||||
mov QWORD PTR [rsp+28h], rax
|
||||
|
||||
mov QWORD PTR [rsp+20h], rbp ; WorldContextObject = World*
|
||||
lea rcx, [rsp+28h] ; out = &Command FString
|
||||
lea rdx, [szConsoleCmd_W]
|
||||
call FString_FromWideChar
|
||||
xor rax, rax
|
||||
mov QWORD PTR [rsp+38h], rax ; SpecificPlayer = nullptr
|
||||
|
||||
; ProcessEvent(KismetSysClass, fn, ¶ms)
|
||||
mov rcx, rsi ; KismetSystemLibrary class object
|
||||
mov rdx, rdi ; ExecuteConsoleCommand fn
|
||||
lea r8, [rsp+20h]
|
||||
call QWORD PTR [ProcessEvent]
|
||||
|
||||
; Free the command FString
|
||||
lea rcx, [rsp+28h]
|
||||
call FString_Free
|
||||
|
||||
; Call GameModeLateGame_InitializeGameplay
|
||||
call GameModeLateGame_InitializeGameplay
|
||||
|
||||
; Set bStartedBus = true
|
||||
mov BYTE PTR [bStartedBus], 1
|
||||
|
||||
@@done:
|
||||
add rsp, 48h
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbp
|
||||
pop rbx
|
||||
ret
|
||||
GUI__StartBus ENDP
|
||||
|
||||
|
||||
; GUI_Tick
|
||||
; Called each frame from Hooks_PostRender.
|
||||
; Frame: 4 pushes (RBX=World, RBP=GameState, RSI=playerState loop, RDI=spare)
|
||||
; + sub 68h (104) -> RSP = 8-32-104 = -128 = 0
|
||||
GUI_Tick PROC
|
||||
push rbx
|
||||
push rbp
|
||||
push rsi
|
||||
push rdi
|
||||
sub rsp, 68h
|
||||
|
||||
; One-time initialization
|
||||
movzx eax, BYTE PTR [GUI_initialized]
|
||||
test al, al
|
||||
jnz @@skip_init
|
||||
; Set initial window position
|
||||
mov DWORD PTR [GUI_pos_X], F_200_0
|
||||
mov DWORD PTR [GUI_pos_Y], F_250_0
|
||||
; menu_opened = true by default
|
||||
mov BYTE PTR [GUI_menu_opened], 1
|
||||
; tab = 0
|
||||
mov DWORD PTR [GUI_tab], 0
|
||||
; currentPlayer = nullptr
|
||||
xor rax, rax
|
||||
mov QWORD PTR [GUI_currentPlayer], rax
|
||||
mov BYTE PTR [GUI_initialized], 1
|
||||
@@skip_init:
|
||||
|
||||
; ZeroInput_Update (poll mouse state)
|
||||
call ZeroInput_Update
|
||||
|
||||
; F2 toggle
|
||||
mov ecx, 071h ; VK_F2 = 0x71
|
||||
call GetAsyncKeyState
|
||||
test ax, 1 ; check lowest bit (just-pressed flag)
|
||||
jz @@no_toggle
|
||||
movzx eax, BYTE PTR [GUI_menu_opened]
|
||||
xor al, 1
|
||||
mov BYTE PTR [GUI_menu_opened], al
|
||||
@@no_toggle:
|
||||
|
||||
; ZeroGUI_Begin (Window)
|
||||
lea rcx, [szTitle_Raider]
|
||||
lea rdx, [GUI_pos_X] ; pos (FVector2D*) - persistent in .data?
|
||||
movss xmm0, DWORD PTR [f_500_0]
|
||||
movd r8d, xmm0 ; sizeX bits
|
||||
movss xmm0, DWORD PTR [f_700_0]
|
||||
movd r9d, xmm0 ; sizeY bits
|
||||
movzx eax, BYTE PTR [GUI_menu_opened]
|
||||
mov DWORD PTR [rsp+20h], eax ; isOpen (5th arg)
|
||||
call ZeroGUI_Begin
|
||||
test al, al
|
||||
jz @@end_gui ; window closed
|
||||
|
||||
; Inside window: only if bListening && HostBeacon
|
||||
movzx eax, BYTE PTR [bListening]
|
||||
test al, al
|
||||
jz @@end_gui
|
||||
mov rax, QWORD PTR [HostBeacon]
|
||||
test rax, rax
|
||||
jz @@end_gui
|
||||
|
||||
; Get World and GameState (used by both tabs)
|
||||
call SDK_GetWorld
|
||||
test rax, rax
|
||||
jz @@end_gui
|
||||
mov rbx, rax ; rbx = World*
|
||||
mov rbp, QWORD PTR [rbx + UWORLD_GameState]
|
||||
test rbp, rbp
|
||||
jz @@end_gui
|
||||
; rbp = GameState*
|
||||
|
||||
; currentPlayer != nullptr branch
|
||||
mov rax, QWORD PTR [GUI_currentPlayer]
|
||||
test rax, rax
|
||||
jz @@show_tabs
|
||||
|
||||
; Back button
|
||||
lea rcx, [szBtn_Back]
|
||||
movss xmm0, DWORD PTR [f_25_0]
|
||||
movd edx, xmm0 ; sizeX = 25.0f
|
||||
movd r8d, xmm0 ; sizeY = 25.0f
|
||||
call ZeroGUI_Button
|
||||
test al, al
|
||||
jz @@no_back
|
||||
; Back pressed: clear currentPlayer
|
||||
xor rax, rax
|
||||
mov QWORD PTR [GUI_currentPlayer], rax
|
||||
jmp @@end_gui ; redraw next frame
|
||||
|
||||
@@no_back:
|
||||
; NextColumn(90.0f)
|
||||
movss xmm0, DWORD PTR [f_90_0]
|
||||
call ZeroGUI_NextColumn
|
||||
|
||||
; Text("Current Player:")
|
||||
lea rcx, [szText_CurPlayer]
|
||||
xor dl, dl ; center=false
|
||||
xor r8b, r8b ; outline=false
|
||||
call ZeroGUI_Text
|
||||
|
||||
; Kick button
|
||||
lea rcx, [szBtn_Kick]
|
||||
movss xmm0, DWORD PTR [f_60_0]
|
||||
movd edx, xmm0
|
||||
movss xmm0, DWORD PTR [f_25_0]
|
||||
movd r8d, xmm0
|
||||
call ZeroGUI_Button
|
||||
test al, al
|
||||
jz @@no_kick
|
||||
|
||||
; Kick pressed: KickController(currentPlayer->Owner, ...)
|
||||
mov rax, QWORD PTR [GUI_currentPlayer]
|
||||
mov rcx, QWORD PTR [rax + AACTOR_Owner] ; Owner = PlayerController
|
||||
call GUI__KickController
|
||||
; Clear currentPlayer
|
||||
xor rax, rax
|
||||
mov QWORD PTR [GUI_currentPlayer], rax
|
||||
jmp @@end_gui
|
||||
|
||||
@@no_kick:
|
||||
jmp @@end_gui
|
||||
|
||||
; Tab bar
|
||||
@@show_tabs:
|
||||
; ButtonTab "Game" (110×25, active when tab==0)
|
||||
lea rcx, [szBtnTab_Game]
|
||||
movss xmm0, DWORD PTR [f_110_0]
|
||||
movd edx, xmm0
|
||||
movss xmm0, DWORD PTR [f_25_0]
|
||||
movd r8d, xmm0
|
||||
xor r9d, r9d
|
||||
cmp DWORD PTR [GUI_tab], 0
|
||||
sete r9b ; active = (tab == 0)
|
||||
call ZeroGUI_ButtonTab
|
||||
test al, al
|
||||
jz @@no_tab0
|
||||
mov DWORD PTR [GUI_tab], 0
|
||||
@@no_tab0:
|
||||
|
||||
; ButtonTab "Players" (110×25, active when tab==1)
|
||||
lea rcx, [szBtnTab_Players]
|
||||
movss xmm0, DWORD PTR [f_110_0]
|
||||
movd edx, xmm0
|
||||
movss xmm0, DWORD PTR [f_25_0]
|
||||
movd r8d, xmm0
|
||||
xor r9d, r9d
|
||||
cmp DWORD PTR [GUI_tab], 1
|
||||
sete r9b
|
||||
call ZeroGUI_ButtonTab
|
||||
test al, al
|
||||
jz @@no_tab1
|
||||
mov DWORD PTR [GUI_tab], 1
|
||||
@@no_tab1:
|
||||
|
||||
; NextColumn(130.0f)
|
||||
movss xmm0, DWORD PTR [f_130_0]
|
||||
call ZeroGUI_NextColumn
|
||||
|
||||
; Tab content
|
||||
mov eax, DWORD PTR [GUI_tab]
|
||||
cmp eax, 0
|
||||
je @@tab_game
|
||||
cmp eax, 1
|
||||
je @@tab_players
|
||||
jmp @@end_gui
|
||||
|
||||
; Tab 0: Game
|
||||
@@tab_game:
|
||||
; Only show "Start Bus" if !bStartedBus
|
||||
movzx eax, BYTE PTR [bStartedBus]
|
||||
test al, al
|
||||
jnz @@end_gui
|
||||
|
||||
lea rcx, [szBtn_StartBus]
|
||||
movss xmm0, DWORD PTR [f_100_0]
|
||||
movd edx, xmm0
|
||||
movss xmm0, DWORD PTR [f_25_0]
|
||||
movd r8d, xmm0
|
||||
call ZeroGUI_Button
|
||||
test al, al
|
||||
jz @@end_gui
|
||||
|
||||
; Start Bus clicked
|
||||
call GUI__StartBus
|
||||
jmp @@end_gui
|
||||
|
||||
; Tab 1: Players
|
||||
@@tab_players:
|
||||
; Text("Connected Players")
|
||||
lea rcx, [szText_ConnPlayers]
|
||||
xor dl, dl
|
||||
xor r8b, r8b
|
||||
call ZeroGUI_Text
|
||||
|
||||
; Iterate GameState->PlayerArray
|
||||
mov esi, DWORD PTR [rbp + AGSA_PlayerArray_Num]
|
||||
test esi, esi
|
||||
jz @@end_gui
|
||||
mov rdi, QWORD PTR [rbp + AGSA_PlayerArray_Data]
|
||||
test rdi, rdi
|
||||
jz @@end_gui
|
||||
|
||||
xor DWORD PTR [rsp+2Ch], 0 ; loop index = 0
|
||||
mov DWORD PTR [rsp+2Ch], 0
|
||||
|
||||
@@player_loop:
|
||||
mov eax, DWORD PTR [rsp+2Ch]
|
||||
cmp eax, esi
|
||||
jae @@end_gui ; done iterating
|
||||
|
||||
; Get PlayerState pointer = PlayerArray.Data[i] (array of pointers)
|
||||
movzx rax, eax
|
||||
mov rax, QWORD PTR [rdi + rax*8]
|
||||
test rax, rax
|
||||
jz @@player_next
|
||||
|
||||
mov QWORD PTR [rsp+30h], rax ; save PlayerState*
|
||||
|
||||
; Get player name via ProcessEvent
|
||||
mov rcx, rax
|
||||
call GUI__GetPlayerName ; RAX = wchar_t* (or 0)
|
||||
test rax, rax
|
||||
jz @@player_next
|
||||
|
||||
; Button with player name (100×25)
|
||||
mov rcx, rax ; name = wchar_t*
|
||||
movss xmm0, DWORD PTR [f_100_0]
|
||||
movd edx, xmm0
|
||||
movss xmm0, DWORD PTR [f_25_0]
|
||||
movd r8d, xmm0
|
||||
call ZeroGUI_Button
|
||||
test al, al
|
||||
jz @@player_next
|
||||
|
||||
; Button clicked: set currentPlayer = PlayerState
|
||||
mov rax, QWORD PTR [rsp+30h]
|
||||
mov QWORD PTR [GUI_currentPlayer], rax
|
||||
jmp @@end_gui
|
||||
|
||||
@@player_next:
|
||||
inc DWORD PTR [rsp+2Ch]
|
||||
jmp @@player_loop
|
||||
|
||||
@@end_gui:
|
||||
; ZeroGUI_End (flush drawlist)
|
||||
call ZeroGUI_End
|
||||
|
||||
add rsp, 68h
|
||||
pop rdi
|
||||
pop rsi
|
||||
pop rbp
|
||||
pop rbx
|
||||
ret
|
||||
GUI_Tick ENDP
|
||||
|
||||
END
|
||||
+1240
File diff suppressed because it is too large
Load Diff
+122
@@ -0,0 +1,122 @@
|
||||
INCLUDE asm\include\master.inc
|
||||
|
||||
.data?
|
||||
|
||||
ZI_mouseDown BYTE 5 DUP(?) ; mouseDown[5]
|
||||
ZI_mouseDownAlready BYTE 256 DUP(?) ; mouseDownAlready[256]
|
||||
ZI_keysDown BYTE 256 DUP(?) ; keysDown[256]
|
||||
ZI_keysDownAlready BYTE 256 DUP(?) ; keysDownAlready[256]
|
||||
|
||||
.code
|
||||
|
||||
; ZeroInput_Update (= Input::Handle)
|
||||
; Polls GetAsyncKeyState(0x01) and updates mouseDown[0].
|
||||
;
|
||||
; In: none
|
||||
; Out: none
|
||||
; Frame: 0 pushes + sub 28h -> RSP = 8-40 = -32 = 0
|
||||
ZeroInput_Update PROC
|
||||
sub rsp, 28h
|
||||
|
||||
mov ecx, 1 ; VK_LBUTTON = 0x01
|
||||
call GetAsyncKeyState
|
||||
test ax, ax
|
||||
jz @@mouse_up
|
||||
mov BYTE PTR [ZI_mouseDown], 1
|
||||
jmp @@done
|
||||
@@mouse_up:
|
||||
mov BYTE PTR [ZI_mouseDown], 0
|
||||
@@done:
|
||||
add rsp, 28h
|
||||
ret
|
||||
ZeroInput_Update ENDP
|
||||
|
||||
|
||||
; ZeroInput_IsMouseClicked
|
||||
; In: ECX = button index (0-4)
|
||||
; EDX = element_id (0-255)
|
||||
; R8B = repeat (bool)
|
||||
; Out: AL = 1 if clicked, 0 otherwise
|
||||
;
|
||||
; Logic:
|
||||
; if mouseDown[button] is set:
|
||||
; if !mouseDownAlready[element_id]: set it, return true
|
||||
; if repeat: return true
|
||||
; else:
|
||||
; clear mouseDownAlready[element_id]
|
||||
; return false
|
||||
;
|
||||
; Frame: 0 pushes + sub 28h -> RSP = 0
|
||||
ZeroInput_IsMouseClicked PROC
|
||||
sub rsp, 28h
|
||||
|
||||
; Check mouseDown[button]
|
||||
movzx rax, ecx ; button index (zero-extend to 64-bit)
|
||||
movzx eax, BYTE PTR [ZI_mouseDown + rax]
|
||||
test al, al
|
||||
jz @@clear_already ; not pressed -> clear + return false
|
||||
|
||||
; 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
|
||||
jnz @@check_repeat ; already marked -> check repeat
|
||||
|
||||
; First press: set mouseDownAlready[element_id] = true, return true
|
||||
mov BYTE PTR [ZI_mouseDownAlready + rcx], 1
|
||||
mov al, 1
|
||||
jmp @@done
|
||||
|
||||
@@check_repeat:
|
||||
; Already pressed: return repeat flag
|
||||
movzx eax, r8b ; AL = repeat
|
||||
jmp @@done
|
||||
|
||||
@@clear_already:
|
||||
; Mouse is not down: clear mouseDownAlready[element_id]
|
||||
movzx rcx, edx
|
||||
mov BYTE PTR [ZI_mouseDownAlready + rcx], 0
|
||||
xor al, al
|
||||
@@done:
|
||||
add rsp, 28h
|
||||
ret
|
||||
ZeroInput_IsMouseClicked ENDP
|
||||
|
||||
|
||||
; ZeroInput_IsKeyPressed
|
||||
; In: ECX = key code (0-255)
|
||||
; DL = repeat (bool)
|
||||
; Out: AL = 1 if pressed, 0 otherwise
|
||||
;
|
||||
; Frame: 0 pushes + sub 28h -> RSP = 0
|
||||
ZeroInput_IsKeyPressed PROC
|
||||
sub rsp, 28h
|
||||
|
||||
movzx rax, ecx ; key index
|
||||
movzx eax, BYTE PTR [ZI_keysDown + rax]
|
||||
test al, al
|
||||
jz @@clear_already
|
||||
|
||||
movzx rcx, ecx
|
||||
movzx eax, BYTE PTR [ZI_keysDownAlready + rcx]
|
||||
test al, al
|
||||
jnz @@check_repeat
|
||||
|
||||
mov BYTE PTR [ZI_keysDownAlready + rcx], 1
|
||||
mov al, 1
|
||||
jmp @@done
|
||||
|
||||
@@check_repeat:
|
||||
movzx eax, dl ; AL = repeat
|
||||
jmp @@done
|
||||
|
||||
@@clear_already:
|
||||
movzx rcx, ecx
|
||||
mov BYTE PTR [ZI_keysDownAlready + rcx], 0
|
||||
xor al, al
|
||||
@@done:
|
||||
add rsp, 28h
|
||||
ret
|
||||
ZeroInput_IsKeyPressed ENDP
|
||||
|
||||
END
|
||||
Reference in New Issue
Block a user