mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Round the physics solver's step count up above 60 fps and give Ocarina a steady step.
Above 60 fps players fell off moving platforms. The physics system takes its solver step count for a frame as trunc(frames per update * 4 + 0.001): 4 at 60 fps and 8 at 30, the rates the game ships with, but 3 from 61 to 80 fps, 2 to 120, 1 to 240 (144 solver steps a second at 144 fps against 240 at 60), and 0 in a frame shorter than a quarter of a 60 Hz frame. The solver skips its whole solve and sub-integration loop at 0, so such a frame resolves no contact or friction and moves no rigid body. At a 240 fps limit, which "unlimited" paces at too, that was the frame after every late one: the pacer keeps its phase, so the next display interval is shorter than the period. The new patch set osolver rounds the count up, ceil(frames per update * 4 - 0.25): 4 and 8 as before, never fewer steps a second than at 60 fps, at least 1. physics_steps = 0 gives the game's own count. The step itself was the mean of the last five display intervals and changed with every frame: intervals of 5 and 30 ms in turn gave steps of 15 and 20 ms in turn, and one 60 ms frame at 200 fps took the step from 5 to 16 ms for five frames. The game never saw a changing step on the console. The step is now the mean of the last 12 intervals without the longest and the shortest, is the pacer's period when within 3% of it (at a 60 fps limit exactly one frame, every frame), and repays the time the game was not given at up to a tenth of the step, so game time still follows the clock. It is at least 1/480 s. step_steady = 0 gives the mean of five again. With trace = perf the fps lines show the shortest and longest step and the time owed. tests/frame_step_check.py drives frame_rate.c with made-up display times and the rest of the runtime stubbed. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ set wide_movie NX2NAVI_PATCH_WIDE_MOVIE 0
|
||||
set res_fixed NX2NAVI_PATCH_RES_FIXED 0
|
||||
set ostep NX2NAVI_OCARINA_REALTIME 1
|
||||
set zstd NX2NAVI_ZSTD_NATIVE 1
|
||||
set osolver NX2NAVI_PHYSICS_STEPS 1
|
||||
|
||||
# Real-time step: the framework's per-frame update (main+0x6e6be0) gives the time manager **[main+0x4c7e890] its
|
||||
# nominal frame through main+0x3b4e300 (+0x10 frames per update, +0x14 the inverse, +0x18 seconds, +0x1c the rate),
|
||||
@@ -28,6 +29,25 @@ set zstd NX2NAVI_ZSTD_NATIVE 1
|
||||
site ostep main 6e6cc0 1e220c21 @page:x10 # fcsel s1, s1, s2, eq -> adrp x10, page
|
||||
site ostep main 6e6cc4 1e201828 bd410148 # fdiv s8, s1, s0 -> ldr s8, [x10, #256]
|
||||
|
||||
# Physics solver steps: the physics system's step setup (main+0x38aeb80, and the same code in main+0x38afc10) gives the
|
||||
# rigid body world its solver step count for the frame, trunc(frames per update * count + 0.001) with the count at
|
||||
# system +0x244 (4, set by the constructor main+0x38ae800), and the world keeps the result's inverse beside it (world
|
||||
# vtable +0x88, main+0x3a24c20: world +0xc48 and +0xcb8). That is 4 at 60 fps and 8 at 30, the two rates the game ships
|
||||
# with: 240 solver steps a second. Below one frame per update it truncates to fewer a second (3 a frame from 61 to 80
|
||||
# fps, 2 to 120, 1 to 240: 144 a second at 144 fps), and to 0 under a quarter frame, with an infinite inverse. The
|
||||
# solver (main+0x180b0a0) runs its solve and sub-integration loop that many times and skips it at 0 (main+0x180b380):
|
||||
# such a frame solves no contact or friction and moves no rigid body, so whatever stands on a moving body is left
|
||||
# behind in it. At a 240 fps limit that was the frame after a late one, whose display interval is shorter than the
|
||||
# period (runtime/frame_rate.c ocarina_step). The count rounds up instead, ceil(frames per update * count - 0.25): 4 and 8 as before at 60 and 30
|
||||
# fps, also with a step a few percent off them, never fewer steps a second than at 60 fps, and at least 1 down to a
|
||||
# 16th of a frame. s2 is loaded only for this sum, and none of the words reads or writes the flags.
|
||||
site osolver main 38aebe4 bd440d02 1e2a1002 # ldr s2, [x8, #0x40c] (0.001) -> fmov s2, #0.25
|
||||
site osolver main 38aebf0 1f010800 1f218800 # fmadd s0, s0, s1, s2 -> fnmsub s0, s0, s1, s2 (s0 * s1 - s2)
|
||||
site osolver main 38aebf4 1e380001 1e280001 # fcvtzs w1, s0 -> fcvtps w1, s0 (round up)
|
||||
site osolver main 38afd10 bd440d02 1e2a1002 # the same three words in the second copy
|
||||
site osolver main 38afd1c 1f010800 1f218800
|
||||
site osolver main 38afd20 1e380001 1e280001
|
||||
|
||||
# Game image: the graphics setup (main+0x1202ce0) fills the renderer's configuration with the size of the picture the
|
||||
# game presents, 2560x1440 at every console mode (config +0x14, copied to renderer +0x9c, which main+0x346be50 reads
|
||||
# for the main render target set, main+0xf49040), and the display settings object (main+0x31f3890) stores the same size
|
||||
|
||||
Reference in New Issue
Block a user