EBLAN_ENGINE/include/engine_simulation.inc
Игорь Федосеев aa64510def feat: stabilize fixed-tick simulation
Decouple gameplay from presentation and preserve signed movement fractions. Separate cinematic camera ownership with safe body handoff and transactional current-room restarts.

Resample input latches on focus regain, discard modal timing debt, and attach cinematic lighting to the view to match editor preview.

Verify editor 137/137 and ASM 288/288, cinematic traces, RGB bake and IPC framebuffer parity without changing project assets.
2026-10-31 22:31:20 +03:00

253 lines
5.7 KiB
PHP

; Fixed 60 Hz simulation and QPC scheduler. No presentation or keyboard APIs in
; Engine_Tick. AdvanceSimulation accepts elapsed QPC counts for deterministic tests.
.code
QueryPerformanceCounter PROTO :DWORD
QueryPerformanceFrequency PROTO :DWORD
GetSimulationState PROC
mov eax, SIM_UNFOCUSED
cmp inputFocused, 0
je state_ready
mov eax, SIM_PAUSED
cmp isGamePaused, 0
jne state_ready
mov eax, SIM_DIALOG
cmp gameDialogActive, 0
jne state_ready
mov eax, SIM_TRANSITION
cmp fadeState, 0
jne state_ready
mov eax, SIM_DEAD
cmp isPlayerDead, 0
jne state_ready
mov eax, SIM_CUTSCENE
cmp isCutsceneActive, 0
jne state_ready
cmp cutscenePending, 0
jne state_ready
mov eax, SIM_PLAYING
state_ready:
ret
GetSimulationState ENDP
; UI edges execute on ticks, never during polling or drawing.
ApplyInputCommands PROC
cmp keyPause, 0
je command_menu
xor isGamePaused, 1
mov clockReset, 1
command_menu:
cmp isGamePaused, 0
je command_hud
cmp keyMenu1, 0
je @F
mov isGamePaused, 0
mov clockReset, 1
@@:
cmp keyMenu2, 0
je @F
xor enableWeapons, 1
mov eax, enableWeapons
mov gameMode, eax
mov showCrosshair, eax
mov playerWeapon, WEAPON_NONE
test eax, eax
jz @F
mov playerWeapon, WEAPON_PISTOL
@@:
cmp keyMenu3, 0
je @F
xor hudStyle, 1
@@:
cmp keyMenu4, 0
je @F
call RestartCurrentRoom
; A failed reload stays paused with all room/gameplay state intact.
@@:
cmp keyMenu5, 0
je command_done
mov isRunning, 0
ret
command_hud:
cmp keyMap, 0
je @F
xor keyShowMap, 1
@@:
cmp keyHud, 0
je @F
xor hudStyle, 1
@@:
call GetSimulationState
cmp eax, SIM_PLAYING
jne command_done
cmp keyFlashlight, 0
je @F
xor isFlashlightOn, 1
@@:
cmp keyLightMode, 0
je @F
inc lightingMode
cmp lightingMode, 3
jb @F
mov lightingMode, 0
@@:
cmp enableWeapons, 0
je command_done
cmp gameMode, GAME_MODE_ACTION
jne command_done
cmp keyWeapon1, 0
je @F
mov playerWeapon, WEAPON_KNIFE
@@:
cmp keyWeapon2, 0
je @F
mov playerWeapon, WEAPON_PISTOL
@@:
cmp keyWeapon3, 0
je command_done
mov playerWeapon, WEAPON_SHOTGUN
command_done:
ret
ApplyInputCommands ENDP
Engine_Tick PROC
inc simulationTicks
mov gameplayTickBlocked, 1
call GetSimulationState
mov simulationState, eax
cmp eax, SIM_UNFOCUSED
je tick_done
call ApplyInputCommands
cmp clockReset, 0
jne tick_done
call GetSimulationState
mov simulationState, eax
cmp eax, SIM_PAUSED
je tick_done
cmp eax, SIM_DIALOG
je tick_dialog
cmp eax, SIM_TRANSITION
je tick_transition
cmp eax, SIM_DEAD
je tick_dead
cmp mapErrorFrames, 0
je @F
dec mapErrorFrames
@@:
call UpdatePlayer
call IsGameplayBlocked
test eax, eax
jnz tick_cinematic
call UpdateEntities
call IsGameplayBlocked
test eax, eax
jnz tick_done
call UpdateCombat
call IsGameplayBlocked
test eax, eax
jnz tick_done
call Game_OnTick
call IsGameplayBlocked
test eax, eax
jnz tick_done
call UpdateDynamicLights
cmp gameToastTimer, 0
jle tick_done
dec gameToastTimer
jmp tick_done
tick_cinematic:
cmp isCutsceneActive, 0
je tick_done
call UpdateDynamicLights
jmp tick_done
tick_dialog:
mov al, keyAction
or al, keyDismiss
or al, keyAttack
jz tick_done
call CloseGameDialog
mov clockReset, 1
jmp tick_done
tick_transition:
call UpdateScreenFade
jmp tick_done
tick_dead:
cmp keyRestart, 0
je tick_done
call RestartCurrentRoom
tick_done:
call ConsumeInputEdges
ret
Engine_Tick ENDP
InitSimulationClock PROC
invoke QueryPerformanceFrequency, OFFSET qpcFrequency
invoke QueryPerformanceCounter, OFFSET qpcPrevious
mov DWORD PTR tickAccumulator, 0
mov DWORD PTR tickAccumulator+4, 0
mov clockReset, 0
ret
InitSimulationClock ENDP
AdvanceSimulation PROC uses ebx esi edi, deltaLow:DWORD, deltaHigh:DWORD
; Drop elapsed stalls over 250ms, backwards time, and explicit pause/focus
; debt. Bound catch-up to 8 ticks even on an overloaded machine.
cmp clockReset, 0
jne clock_discard
mov eax, DWORD PTR qpcFrequency
mov edx, DWORD PTR qpcFrequency+4
shrd eax, edx, 2
shr edx, 2
cmp deltaHigh, edx
ja clock_discard
jb clock_add
cmp deltaLow, eax
ja clock_discard
clock_add:
mov eax, deltaLow
mov ebx, 60
mul ebx
imul ebx, deltaHigh
add edx, ebx
add DWORD PTR tickAccumulator, eax
adc DWORD PTR tickAccumulator+4, edx
mov esi, 8
clock_tick:
mov edx, DWORD PTR tickAccumulator+4
cmp edx, DWORD PTR qpcFrequency+4
jb clock_done
ja clock_step
mov eax, DWORD PTR tickAccumulator
cmp eax, DWORD PTR qpcFrequency
jb clock_done
clock_step:
mov eax, DWORD PTR qpcFrequency
mov edx, DWORD PTR qpcFrequency+4
sub DWORD PTR tickAccumulator, eax
sbb DWORD PTR tickAccumulator+4, edx
call Engine_Tick
cmp clockReset, 0
jne clock_discard
dec esi
jnz clock_tick
clock_discard:
mov DWORD PTR tickAccumulator, 0
mov DWORD PTR tickAccumulator+4, 0
mov clockReset, 0
clock_done:
ret
AdvanceSimulation ENDP
PumpSimulationClock PROC uses ebx
invoke QueryPerformanceCounter, OFFSET qpcNow
mov eax, DWORD PTR qpcNow
mov edx, DWORD PTR qpcNow+4
sub eax, DWORD PTR qpcPrevious
sbb edx, DWORD PTR qpcPrevious+4
mov ebx, DWORD PTR qpcNow
mov DWORD PTR qpcPrevious, ebx
mov ebx, DWORD PTR qpcNow+4
mov DWORD PTR qpcPrevious+4, ebx
invoke AdvanceSimulation, eax, edx
ret
PumpSimulationClock ENDP