# Xenoblade Chronicles 2 2.1.0 # BID: F77F1559371C0EC6 DECLARATIONS: - type: variable name: last_tick value_type: uint64 default_value: 0 - type: variable name: game_speed value_type: float default_value: 0.03333333333 - type: variable name: min_delta value_type: float default_value: 0.03333333333 evaluate: "1 / FPS_TARGET" - type: variable name: max_delta value_type: float default_value: 30 evaluate: "FPS_TARGET / 2" - type: variable name: dr_target value_type: float default_value: 0.0166666666 evaluate: "(1 / FPS_TARGET) / VSYNC_TARGET" - type: const name: microseconds_in_sec value: 1000000 - type: const name: nano_in_micro value: 1000 - type: code name: dynamicSpeed instructions: [ [stp, x29, x30, [sp, -16], "!"], [mov, x29, sp], [mrs, x0, cntpct_el0], [adrp, x2, $last_tick], [ldr, x1, [x2, $last_tick]], [str, x0, [x2, $last_tick]], [cbz, x1, :goto3], [sub, x0, x0, x1], [bl, _convertTickToTimeSpan()], [adrp, x1, $max_delta], [ldr, s2, [x1, $max_delta]], [mov, w1, $nano_in_micro], [udiv, x0, x0, x1], [ucvtf, s0, x0], [mov, w1, $microseconds_in_sec], [movk, w1, $microseconds_in_sec, 16], [ucvtf, s1, w1], [b, :goto2], :goto4, [adrp, x0, 0xb8f000], [ldr, x0, [x0, 0xd0]], [cbz, x0, :goto3], [str, s0, [x0, 0x78]], [str, s0, [x0, 0x7c]], [adrp, x0, 0xc22000], [ldr, x0, [x0, 0x2c8]], [str, s0, [x0, 0x80]], [adrp, x0, $game_speed], [str, s0, [x0, $game_speed]], [b, :goto3], :goto5, [fmov, s1, 1.0], [fdiv, s2, s1, s2], [fcmp, s0, s2], [b.lt, :goto6], [fmov, s0, s2], [b, :goto4], :goto6, [adrp, x0, $min_delta], [ldr, s2, [x0, $min_delta]], [fcmp, s0, s2], [b.hi, :goto4], [fmov, s0, s2], [b, :goto4], :goto2, [fdiv, s0, s0, s1], [b, :goto5], :goto3, [mov, w8, 0x21a0], [ldp, x29, x30, [sp], 16], [ret], ] MASTER_WRITE: # Dynamic speed # Jump before pushing frame - type: asm_a64 main_offset: 0x700164 instructions: [ [bl, _dynamicSpeed()] ] # Patch wind speed to take game speed - type: asm_a64 main_offset: 0x747DD8 instructions: [ [adrp, x8, $game_speed], [ldr, s6, [x8, $game_speed]] ] # Redirect DR timing - type: asm_a64 main_offset: 0x6AA14C instructions: [ [adrp, x8, $dr_target], [ldr, s0, [x8, $dr_target]] ] ALL_FPS: - type: evaluate_write address: [MAIN, 0xB74BF0] value_type: uint32 value: ["VSYNC_TARGET", "VSYNC_TARGET"] # Cutscenes in 30 FPS - type: compare compare_type: "==" compare_value_type: uint8 compare_value: 1 compare_address: [MAIN, 0xBD7F40] value_type: refresh_rate value: 60 - type: compare compare_type: "==" compare_value_type: uint8 compare_value: 1 compare_address: [MAIN, 0xBD7F40] address: [VARIABLE, min_delta] value: 0.0333333333 - type: compare compare_type: "==" compare_value_type: uint8 compare_value: 1 compare_address: [MAIN, 0xBD7F40] address: [VARIABLE, max_delta] value: 30 - type: compare compare_type: "==" compare_value_type: uint8 compare_value: 1 compare_address: [MAIN, 0xBD7F40] address: [MAIN, 0xB74BF0] value_type: uint32 value: [2, 2] - type: compare compare_type: "==" compare_value_type: uint8 compare_value: 1 compare_address: [MAIN, 0xBD7F40] address: [VARIABLE, dr_target] value: 0.0166666666