[XCX] Port FPS++ to 60FPS mod, dynamic FPS limits and fixed cutscenes

Fixes https://github.com/ActualMandM/cemu_graphic_packs/issues/475.

Thanks to @MetrosexualGarbodor for the generous bounty!
This commit is contained in:
Crementif 2022-07-26 01:13:50 +02:00
parent 468d165cf2
commit e1ac320f89
8 changed files with 629 additions and 215 deletions

View File

@ -1,153 +0,0 @@
[XCX60fpsV16J] ; ########################################################
moduleMatches = 0x785CA8A9
;Default as of 0.51 - Limit logic/2d animation to 30 fps Less timing issues, more jitter
;0x100D0604 = .float 0.5 ; .float 1.0 ; GUI animations
0x100CFAE8 = .float 0.5 ; .float 1.0 ; GUI animations *
0x10059514 = .float 0.5 ; .float 1.0 ;Title screen cutscene -
0x100144F0 = .float 0.1 ; controller acceleration
0x10171070 = .float 2.0 ; arbitrary 2.0 float
0x1017117C = .float 0.5 ; .5 float
0x10171070 = _halfRate:
0x1017117C = _fullRate:
0x027370B8 = lis r11, _halfRate@ha ; Double updateEventParam cutscene
0x027370C4 = lfs f1, _halfRate@l(r11) ; -
0x027A0180 = lis r10, _fullRate@ha ; half SyncFrame cinematic cutscene, fixes timing issues with cinematic cutscenes -
0x027A0184 = lfs f1, _fullRate@l(r10) ; but introduces Shake and stutter issue. CODE XREF: ev::CEvtManager::startPage((float,bool))+6C j -
0x025F149C = lis r12, _fullRate@h ;;; Move__11CfSceneTaskFv ;Filter CPU, 30 fps logic
0x025F14A4 = lfs f31, _fullRate@l(r12) ;;; Move__11CfSceneTaskFv ;
0x02768064 = lis r8, _fullRate@ha ; sync in game cut scene
0x02768068 = lfs f31, _fullRate@l(r8) ;
0x0273BBD0 = lis r7, _fullRate@ha ; sync elevator, vehicles etc
0x0273BBD4 = lfs f31, _fullRate@l(r7) ; Ç
; swapInterval 60
0x02FCEB9C = li r3, 1
[XCX60fpsV48J] ; ########################################################
moduleMatches = 0x7672271D
;Default as of 0.51 - Limit logic/2d animation to 30 fps Less timing issues, more jitter
;0x100D0604 = .float 0.5 ; .float 1.0 ; GUI animations *
;0x1005989C = .float 0.5 ; .float 1.0 ;Title screen cutscene -
;0x10014528 = .float 0.1 ; controller acceleration -
;0x10171980 = .float 2.0 ; arbitrary 2.0 float
0x100D0070 = .float 0.5
0x1005989C = .float 0.5
0x10014528 = .float 0.1
0x10171570 = .float 2.0
0x10171570 = _halfRate:
0x100D0070 = _fullRate:
0x0273802C = lis r11, _halfRate@ha ; Double updateEventParam cutscene, ver
0x02738038 = lfs f1, _halfRate@l(r11) ; -
0x027A1120 = lis r10, _fullRate@ha ; half SyncFrame cinematic cutscene, fixes timing issues with cinematic cutscenes -
0x027A1124 = lfs f1, _fullRate@l(r10) ; but introduces Shake and stutter issue. CODE XREF: ev::CEvtManager::startPage((float,bool))+6C j -
0x025F1F78 = lis r12, _fullRate@h ;;; Move__11CfSceneTaskFv ;Filter CPU, 30 fps logic
0x025F1F80 = lfs f31, _fullRate@l(r12) ;;; Move__11CfSceneTaskFv ;
0x02768FD4 = lis r8, _fullRate@ha ; sync in game cut scene
0x02768FD8 = lfs f31, _fullRate@l(r8) ;
0x0273CB44 = lis r7, _fullRate@ha ; sync elevator, vehicles etc
0x0273CB48 = lfs f31, _fullRate@l(r7) ; Ç
; swapInterval 60
0x02FD3F5C= li r3, 1
[XCX60fpsV100E_V101E] ; ########################################################
moduleMatches = 0x218F6E07, 0xF882D5CF
;Default as of 0.51 - Limit logic/2d animation to 30 fps Less timing issues
0x100D03E8 = .float 0.5 ; .float 1.0 ; GUI animations *
0x100598E4 = .float 0.5 ; .float 1.0 ;Title screen cutscene -
0x10014528 = .float 0.05 ; controller acceleration -
0x10171980 = .float 2.0 ; arbitrary 2.0 float
0x10171980 = _halfRate:
0x100D03E8 = _fullRate:
0x027398B4 = lis r11, _halfRate@ha ; Double updateEventParam cutscene -
0x027398C0 = lfs f1, _halfRate@l(r11) ; -
0x027A33D8 = lis r10, _fullRate@ha ; half SyncFrame cinematic cutscene, fixes timing issues with cinematic cutscenes -
0x027A33DC = lfs f1, _fullRate@l(r10) ; but introduces Shake and stutter issue. CODE XREF: ev::CEvtManager::startPage((float,bool))+6Cj -
;0x02707478 = lis r7, _tmp@ha ; ALT calcAdxSkip__Q2_2ev13CFrameManagerFv
;0x0270747C = lfs f1, _tmp@l(r7) ; calcAdxSkip__Q2_2ev13CFrameManagerFv
;0x02707660 = lis r9, _tmp@ha ; calcCpuSkip__Q2_2ev13CFrameManagerFv ; SLOW down scene
;0x02707668 = lfs f31, _tmp@l(r9) ; calcCpuSkip__Q2_2ev13CFrameManagerFv
0x025F299C = lis r12, _fullRate@h ;;; Move__11CfSceneTaskFv ;Filter CPU, 30 fps logic
0x025F29A4 = lfs f31, _fullRate@l(r12) ;;; Move__11CfSceneTaskFv ;
0x0276A85C = lis r8, _fullRate@ha ; sync in game cut scene
0x0276A860 = lfs f31, _fullRate@l(r8) ;
0x0273E3CC = lis r7, _fullRate@ha ; sync elevator, vehicles etc
0x0273E3D0 = lfs f31, _fullRate@l(r7) ; Ç
; swapInterval 60
0x02FD8A94 = li r3, 1
0x10012644 = .float 15.0 ; fix for soulvoices (not sure it's safe)
[XCX60fpsV102U] ; ########################################################
moduleMatches = 0x30B6E091
;Default as of 0.51 - Limit logic/2d animation to 30 fps Less timing issues
0x100D03D0 = .float 0.5 ; .float 1.0 ; GUI animations
0x100598E4 = .float 0.5 ; .float 1.0 ;Title screen cutscene
0x10014528 = .float 0.05 ; controller acceleration
0x10171980 = .float 2.0 ; arbitrary 2.0 float
0x10171980 = _halfRate:
0x100D03D0 = _fullRate:
0x027398B4 = lis r11, _halfRate@ha ; Double updateEventParam cutscene
0x027398C0 = lfs f1, _halfRate@l(r11) ;
0x027A33D8 = lis r10, _fullRate@ha ; half SyncFrame cinematic cutscene, fixes timing issues with cinematic cutscenes
0x027A33DC = lfs f1, _fullRate@l(r10) ; but introduces Shake and stutter issue.
0x025F299C = lis r12, _fullRate@h ;;; Move__11CfSceneTaskFv ;Filter CPU, 30 fps logic
0x025F29A4 = lfs f31, _fullRate@l(r12) ;;; Move__11CfSceneTaskFv ;
0x0276A85C = lis r8, _fullRate@ha ; sync in game cut scene
0x0276A860 = lfs f31, _fullRate@l(r8) ;
0x0273E3CC = lis r7, _fullRate@ha ; sync elevator, vehicles etc
0x0273E3D0 = lfs f31, _fullRate@l(r7) ; Ç
;Disabled, original per feature approach, severe timing issues
;0x101231F0 = .float 0.5 ; .float 1.0 ; ingame animation timing
;0x100D03D0 = .float 0.5 ; .float 1.0 ; GUI animations
;0x100598E4 = .float 0.5 ; .float 1.0 ;Title screen cutscene
;0x1003C3A0 = .float 15.0 ; .float 30.0 fight 3d animations
;0x1000F7A8 = .float 0.1 ; RegistDamage_ButtonChallenge
;0x10014528 = .float 0.05 ; controller acceleration
;0x100211D8 = .float 15.0 ; .float 30.0 fade in
;0x10034804 = .float 15.0 ; .float 30.0 bullets
;0x10035D84 = .float 15.0 ; walk acceleration
;0x1003C3A0 = .float 15.0 ; arts frame to sec
;0x10012368 = .float 45.0 ; respawn
;0x10012644 = .float 15.0 ; soulvoice
;0x1000C448 = .float 15.0 ; init battle
;0x1000CB90 = .float 15.0 ; init battle
;0x1003E538 = .float 0.33333335 ;birds, falling leaves
;0x10171980 = .float 2.0 ; arbitrary 2.0 float
;0x100955F0 = .float 60.0 ; 30.0 Create avatar cam rotation
; JFF
;0x101123B4 = .float 0.03333335 ; .float 0.016666668 superfast (vsync)
;0x10035D7C = .float 0.25 ; .float 1.0 fast run
;0x10035E00 = .float 2.0 ; jump high.float 0.5
;0x10190C7C = .float 0.75 ; master FOV
;0x10012368 = .float 45.0 ; seconds before respawn "cheat"
; swapInterval 60
0x02FD8A34 = li r3, 1
0x10012644 = .float 15.0 ; fix for soulvoices (not sure it's safe)
;SNESticleNGCVERIONPP71Copyright - Sardu you magnificent bastard, we salute you!

View File

@ -1,18 +0,0 @@
[XCX_60FPS_OVERDRIVE] ; ########################################################
moduleMatches = 0xF882D5CF, 0x30B6E091, 0xAB97DE6B ; 1.0.1E, 1.0.2U, 1.0.1U
.origin = codecave
_timePassed:
.float 0.5
_over:
fmr f31, f1
lis r31, _timePassed@ha
lfs f1, _timePassed@l(r31)
fmuls f1, f31, f1
blr
0x021BC904 = bla _over
0x021E2020 = bla _over ; Skell Overdrive

View File

@ -1,40 +0,0 @@
[XCX_60FPS_QTE] ; ########################################################
moduleMatches = 0xF882D5CF, 0x30B6E091 ; 1.0.1E, 1.0.2U
.origin = codecave
_setup:
.float 15.0 ; reduces speed of animation
_justFrame1:
lwz r12, 0x47C(r29)
mulli r12, r12, 2
blr
_justFrame2:
lwz r0, 0x478(r29)
mulli r0, r0, 2
blr
[XCX_60FPS_QTE_1E] ; ########################################################
moduleMatches = 0xF882D5CF ; 1.0.1E
; menu::MenuButtonChallenge::setup
0x02ACE40C = lis r7, _setup@ha
0x02ACE414 = lfs f0, _setup@l(r7)
; menu::MenuButtonChallenge::move
0x02ACE6E4 = bla _justFrame1
0x02ACE700 = bla _justFrame2
[XCX_60FPS_QTE_2U] ; ########################################################
moduleMatches = 0x30B6E091 ; 1.0.2U
; menu::MenuButtonChallenge::setup
0x02ACE3FC = lis r7, _setup@ha
0x02ACE404 = lfs f0, _setup@l(r7)
; menu::MenuButtonChallenge::move
0x02ACE6D4 = bla _justFrame1
0x02ACE6F0 = bla _justFrame2

View File

@ -0,0 +1,98 @@
[XCX_FPS++_Cutscene]
moduleMatches = 0x218F6E07, 0xF882D5CF, 0x30B6E091, 0x7672271D ; 1.0.0E, 1.0.1E, 1.0.2U, 1.0.2J
.origin = codecave
forceCutsceneLimit:
.int 0
_useCutsceneLimit:
li r10, 1
lis r9, forceCutsceneLimit@ha
stw r10, forceCutsceneLimit@l(r9)
lfs f11, -0x303C(r8)
blr
_resetCutsceneLimit:
li r10, 0
lis r9, forceCutsceneLimit@ha
stw r10, forceCutsceneLimit@l(r9)
b _restoreRegisters
cutsceneFloatConv:
cutsceneFloatConvHa:
.uint 0
cutsceneFloatConvL:
.uint 0
; Check if a cutscene is ongoing with a set FPS limit
_waitTillCutsceneLimit:
li r10, $cutsceneFPSLimit
cmpwi r10, 1
bne _calculateFPS
lis r10, forceCutsceneLimit@ha
lwz r10, forceCutsceneLimit@l(r10)
cmpwi r10, 1
bne _calculateFPS
; If a cutscene FPS limit is set, lower FPS
_lowerCutsceneFPS:
lis r10, const_30@ha
lfs f12, const_30@l(r10)
; Calculate how many ticks a frame has to take to render at the given FPS limit
lis r10, const_1@ha
lfs f7, const_1@l(r10)
fdivs f12, f7, f12
lis r10, timerTickSpeed@ha
lfs f7, timerTickSpeed@l(r10)
fmuls f12, f7, f12
; Subtract the time that it took for the actual frame to render and make sure that it's not negative (which means a frame already took longer to render then the FPS limit)
fsubs f12, f12, f10
lis r10, const_0.0@ha
lfs f7, const_0.0@l(r10)
fcmpu cr0, f7, f12
ble .+0x8
fmr f12, f7
; Convert the remaining ticks that should be spend idling to an integer (but it requires storing it in memory)
fctiwz f12, f12
lis r10, cutsceneFloatConvHa@ha
stfd f12, cutsceneFloatConvHa@l(r10)
# ; Load the converted integer ticks and sleep for the given amount of time
mr r10, r4
lis r9, cutsceneFloatConvL@ha
lwz r4, cutsceneFloatConvL@l(r9)
mr r11, r3
# li r3, 0
lis r9, cutsceneFloatConvHa@ha
lwz r3, cutsceneFloatConvHa@l(r9)
mflr r9
bl import.coreinit.OSSleepTicks
mtlr r9
mr r3, r11
mr r4, r10
_reacquireTime:
mr r11, r3
mr r10, r4
mflr r9
bl import.coreinit.OSGetSystemTime
mtlr r9
lis r9, prevFrameTime_Up32Bit@ha
stw r3, prevFrameTime_Up32Bit@l(r9)
lis r9, prevFrameTime_Low32Bit@ha
stw r4, prevFrameTime_Low32Bit@l(r9)
mr r3, r11
mr r4, r10
; Directly set the game speed to 30FPS when cutscenes are active
lis r10, const_30@ha
lfs f10, const_30@l(r10)
b _setGameSpeed

View File

@ -0,0 +1,369 @@
[XCX_FPS++_GameSpeed]
moduleMatches = 0x218F6E07, 0xF882D5CF, 0x30B6E091, 0x7672271D ; 1.0.0E, 1.0.1E, 1.0.2U, 1.0.2J
.origin = codecave
# Constants
timerTickSpeed:
busSpeed:
.float 62156250
convSub:
.uint 0x43300000
.uint 0x80000000
floatConv:
floatConvHa:
.uint 0
floatConvL:
.uint 0
prevFrameTime:
prevFrameTime_Up32Bit:
.uint 0
prevFrameTime_Low32Bit:
.uint 0
const_0.0:
.float 0.0
const_0.1:
.float 0.1
const_0.25:
.float 0.25
const_0.5:
.float 0.5
const_1:
.float 1.0
const_1.5:
.float 1.5
const_2.0:
.float 2.0
const_15:
.float 15.0
const_30:
.float 30.0
const_60:
.float 60.0
const_roundUpModifier:
.float $roundUpModifier
# Variables
fpsLimit:
.float $fpsLimit
lowFPSLimit:
.float $lowFPSLimit
bufferSizeDivider:
.float $frameAverageAmount
averageFPS30:
.float $fpsLimit
averageFPS30Inv:
.float (900/$fpsLimit)
averageFPS1:
.float ($fpsLimit/30.0)
averageFPS1Inv:
.float (30.0/$fpsLimit)
averageFPS0.1:
.float ($fpsLimit/300.0)
averageFPS1IntInv:
averageFPS1IntInvHa:
.uint 0
averageFPS1IntInvL:
.uint 1
buffer:
.float 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30 ; buffer can only store a max length of 32 frames
bufferIndex:
.int 0
bufferIndexEnd:
.int (4*$frameAverageAmount)
; free registers: r10, r8, r9, r0
; backed-up registers: r3, r4
_calculateGamespeed:
; TODO: Maybe filter out 0
_loadPreviousTicks:
; Load current previous tick before overwriting it
lis r9, prevFrameTime_Up32Bit@ha
lwz r8, prevFrameTime_Up32Bit@l(r9)
lis r9, prevFrameTime_Low32Bit@ha
lwz r10, prevFrameTime_Low32Bit@l(r9)
_storeCurrentTicks:
; Store current ticks
lis r9, prevFrameTime_Up32Bit@ha
stw r3, prevFrameTime_Up32Bit@l(r9)
lis r9, prevFrameTime_Low32Bit@ha
stw r4, prevFrameTime_Low32Bit@l(r9)
_getGameTicks:
.uint 0x7D2A2010 ; subfc r9, r10, r4
.uint 0x7C081910 ; subfe r0, r8, r3
_convertTicksToFrametime:
xoris r9, r9, 0x8000
lis r10, floatConv@ha
stw r9, floatConv@l+0x4(r10)
lis r9, 0x4330
stw r9, floatConv@l+0x0(r10)
lfd f10, floatConv@l+0x0(r10)
lis r10, convSub@ha
lfd f12, convSub@l(r10)
fsub f10, f10, f12
frsp f10, f10
; Call externalized cutscene FPS function
_callWaitTillCutsceneLimit:
b _waitTillCutsceneLimit
_calculateFPS:
lis r10, const_1@ha
lfs f12, const_1@l(r10)
fdivs f10, f12, f10
lis r10, timerTickSpeed@ha
lfs f12, timerTickSpeed@l(r10)
fmuls f10, f12, f10
; Calculate the rolling average FPS over the last N amount of frames which are stored in the circular buffer
_calcAverageFPS:
; Store FPS value from this frame into the buffer first
lis r10, buffer@ha
addi r10, r10, buffer@l
lis r9, bufferIndex@ha
lwz r9, bufferIndex@l(r9)
.int 0x7D4A4D2E
;stfsx f10, r10, r9
; Then store the offset to the next buffer entry
lis r8, bufferIndexEnd@ha
lwz r8, bufferIndexEnd@l(r8)
addi r9, r9, 0x04
cmpw r8, r9
bgt .+0x08
li r9, 0
lis r10, bufferIndex@ha
stw r9, bufferIndex@l(r10)
; Finally, loop over the whole buffer and create an average sum of FPS values
_calculateBuffer:
lis r9, const_0.0@ha
lfs f10, const_0.0@l(r9)
lis r9, buffer@ha
addi r9, r9, buffer@l
lis r8, bufferIndexEnd@ha ; technically unncessary
lwz r8, bufferIndexEnd@l(r8)
li r10, 0
startCalculateBufferLoop:
.int 0x7D89542E
; lfsx f12, r9, r10
fadds f10, f10, f12
addi r10, r10, 0x04
cmpw r10, r8
blt startCalculateBufferLoop
lis r10, bufferSizeDivider@ha
lfs f7, bufferSizeDivider@l(r10)
fdivs f10, f10, f7
_setGameSpeed:
; Set game speed (30 range)
lis r10, averageFPS30@ha
stfs f10, averageFPS30@l(r10)
; Set game speed (inverted 30 range)
lis r10, const_30@ha
lfs f12, const_30@l(r10)
fmuls f12, f12, f12
fdivs f7, f12, f10
lis r10, averageFPS30Inv@ha
stfs f7, averageFPS30Inv@l(r10)
; Set game speed (1.0 range)
lis r10, const_30@ha
lfs f12, const_30@l(r10)
fdivs f7, f10, f12
lis r10, averageFPS1@ha
stfs f7, averageFPS1@l(r10)
; Set game speed (inverted 1.0 range)
fdivs f7, f12, f10
lis r10, averageFPS1Inv@ha
stfs f7, averageFPS1Inv@l(r10)
; Set game speed (inverted 0.1 range)
lis r10, averageFPS1@ha
lfs f7, averageFPS1@l(r10)
fdivs f7, f12, f10
lis r10, const_0.1@ha
lfs f12, const_0.1@l(r10)
fmuls f7, f12, f7
lis r10, averageFPS0.1@ha
stfs f7, averageFPS0.1@l(r10)
; Set title FPS manually instead of editing 10 places that read this
lis r10, averageFPS1Inv@ha
lfs f7, averageFPS1Inv@l(r10)
lis r10, titleScreenSpeed@ha
stfs f7, titleScreenSpeed@l(r10)
; Set soul voice FPS manually
lis r10, averageFPS30Inv@ha
lfs f7, averageFPS30Inv@l(r10)
lis r10, soulVoiceSpeed@ha
stfs f7, soulVoiceSpeed@l(r10)
; Set havok half-speed
lis r10, averageFPS30@ha
lfs f7, averageFPS30@l(r10)
lis r10, havokHalfSpeed@ha
stfs f7, havokHalfSpeed@l(r10)
; Calculate the FPS speed
_calculateAverageFPSInt:
lis r10, averageFPS1@ha
lfs f7, averageFPS1@l(r10)
lis r10, const_roundUpModifier@ha
lfs f12, const_roundUpModifier@l(r10)
fadds f7, f7, f12
fctiwz f7, f7
lis r10, averageFPS1IntInv@ha
stfd f7, averageFPS1IntInv@l(r10)
; Reset the cutscene FPS limit each frame
_callResetCutsceneLimit:
b _resetCutsceneLimit
; Restore register state
_restoreRegisters:
lis r9, prevFrameTime_Up32Bit@ha
lwz r3, prevFrameTime_Up32Bit@l(r9)
lis r9, prevFrameTime_Low32Bit@ha
lwz r4, prevFrameTime_Low32Bit@l(r9)
lwz r10, 0x14(r1)
blr
[XCX_FPS++_GameSpeed_V100E_V101E]
moduleMatches = 0x218F6E07, 0xF882D5CF
; Global data patch
0x10171980 = havokHalfSpeed:
0x100598E4 = titleScreenSpeed:
0x10012644 = soulVoiceSpeed:
; Instruction-specific patches
0x02228274 = lis r5, averageFPS0.1@ha ; Controller acceleration
0x0222827C = lfs f30, averageFPS0.1@l(r5) ; Controller acceleration
0x0273E3CC = lis r7, averageFPS1Inv@ha ; Sync elevator, vehicles etc
0x0273E3D0 = lfs f31, averageFPS1Inv@l(r7) ; Sync elevator, vehicles etc
0x0276A85C = lis r8, averageFPS1Inv@ha ; Sync in-game cutscenes
0x0276A860 = lfs f31, averageFPS1Inv@l(r8) ; Sync in-game cutscenes
0x025F299C = lis r12, averageFPS1Inv@ha ; Move__11CfSceneTaskFv ; Filter CPU, 30FPS logic
0x025F29A4 = lfs f31, averageFPS1Inv@l(r12) ; Move__11CfSceneTaskFv
0x02D20328 = lis r12, averageFPS1Inv@ha ; MenuObject::playEvent
0x02D2032C = lfs f31, averageFPS1Inv@l(r12) ; MenuObject::playEvent
0x02D203F4 = lis r12, averageFPS1Inv@ha ; MenuObject::playEventFrame
0x02D203F8 = lfs f31, averageFPS1Inv@l(r12) ; MenuObject::playEventFrame
; Call GX2SetSwapInterval with 0 which removes any vsync
0x02FD8A94 = li r3, 0
; Use FPS waiting logic even with swap interval being 0
0x02FD5A14 = li r3, 1
0x02FD5AB4 = bla _calculateGamespeed
0x027685B0 = bla _useCutsceneLimit
# These patches are replaced by lowering the framerate to prevent side-effects
# 0x027398B4 = lis r11, averageFPS1@ha ; Double updateEventParam cutscenes
# 0x027398C0 = lfs f1, averageFPS1@l(r11) ; Double updateEventParam cutscenes
# 0x027A33D8 = lis r10, averageFPS1Inv@ha ; Half SyncFrame cinematic cutscene, fixes timing issues with cinematic cutscenes
# 0x027A33DC = lfs f1, averageFPS1Inv@l(r10) ; But introduces shake and stutter issue. CODE XREF: ev::CEvtManager::startPage((float,bool))+6Cj
[XCX_FPS++_GameSpeed_V102J]
moduleMatches = 0x7672271D
; Global data patch
0x10171570 = havokHalfSpeed:
0x1005989C = titleScreenSpeed:
0x10012644 = soulVoiceSpeed:
; Instruction-specific patches
0x02227D40 = lis r5, averageFPS0.1@ha ; Controller acceleration
0x02227D48 = lfs f30, averageFPS0.1@l(r5) ; Controller acceleration
0x0273CB44 = lis r7, averageFPS1Inv@ha ; Sync elevator, vehicles etc
0x0273CB48 = lfs f31, averageFPS1Inv@l(r7) ; Sync elevator, vehicles etc
0x02768FD4 = lis r8, averageFPS1Inv@ha ; Sync in-game cutscenes
0x02768FD8 = lfs f31, averageFPS1Inv@l(r8) ; Sync in-game cutscenes
0x025F1F78 = lis r12, averageFPS1Inv@ha ; Move__11CfSceneTaskFv ; Filter CPU, 30FPS logic
0x025F1F80 = lfs f31, averageFPS1Inv@l(r12) ; Move__11CfSceneTaskFv
0x02D1B818 = lis r12, averageFPS1Inv@ha ; MenuObject::playEvent
0x02D1B81C = lfs f31, averageFPS1Inv@l(r12) ; MenuObject::playEvent
0x02D1B8E4 = lis r12, averageFPS1Inv@ha ; MenuObject::playEventFrame
0x02D1B8E8 = lfs f31, averageFPS1Inv@l(r12) ; MenuObject::playEventFrame
; Call GX2SetSwapInterval with 0 which removes any vsync
0x02FD3F5C = li r3, 0
; Use FPS waiting logic even with swap interval being 0
0x02FD0EDC = li r3, 1
0x02FD0F7C = bla _calculateGamespeed
0x02766D28 = bla _useCutsceneLimit
# These patches are replaced by lowering the framerate to prevent side-effects
# 0x0273802C = lis r11, averageFPS1@ha ; Double updateEventParam cutscenes
# 0x02738038 = lfs f1, averageFPS1@l(r11) ; Double updateEventParam cutscenes
# 0x027A1120 = lis r10, averageFPS1Inv@ha ; Half SyncFrame cinematic cutscene, fixes timing issues with cinematic cutscenes
# 0x027A1124 = lfs f1, averageFPS1Inv@l(r10) ; But introduces shake and stutter issue. CODE XREF: ev::CEvtManager::startPage((float,bool))+6Cj
[XCX_FPS++_GameSpeed_V102U]
moduleMatches = 0x30B6E091
; Global data patch
0x10171980 = havokHalfSpeed:
0x100598E4 = titleScreenSpeed:
0x10012644 = soulVoiceSpeed:
; Instruction-specific patches
0x02228274 = lis r5, averageFPS0.1@ha ; Controller acceleration
0x0222827C = lfs f30, averageFPS0.1@l(r5) ; Controller acceleration
0x0273E3CC = lis r7, averageFPS1Inv@ha ; Sync elevator, vehicles etc
0x0273E3D0 = lfs f31, averageFPS1Inv@l(r7) ; Sync elevator, vehicles etc
0x0276A85C = lis r8, averageFPS1Inv@ha ; Sync in-game cutscenes
0x0276A860 = lfs f31, averageFPS1Inv@l(r8) ; Sync in-game cutscenes
0x025F299C = lis r12, averageFPS1Inv@ha ; Move__11CfSceneTaskFv ; Filter CPU, 30FPS logic
0x025F29A4 = lfs f31, averageFPS1Inv@l(r12) ; Move__11CfSceneTaskFv
0x02D202C8 = lis r12, averageFPS1Inv@ha ; MenuObject::playEvent
0x02D202CC = lfs f31, averageFPS1Inv@l(r12) ; MenuObject::playEvent
0x02D20394 = lis r12, averageFPS1Inv@ha ; MenuObject::playEventFrame
0x02D20398 = lfs f31, averageFPS1Inv@l(r12) ; MenuObject::playEventFrame
; Call GX2SetSwapInterval with 0 which removes any vsync
0x02FD8A34 = li r3, 0
; Use FPS waiting logic even with swap interval being 0
0x02FD59B4 = li r3, 1
0x02FD5A54 = bla _calculateGamespeed
0x027685B0 = bla _useCutsceneLimit
# These patches are replaced by lowering the framerate to prevent side-effects
# 0x027398B4 = lis r11, averageFPS1@ha ; Double updateEventParam cutscenes
# 0x027398C0 = lfs f1, averageFPS1@l(r11) ; Double updateEventParam cutscenes
# 0x027A33D8 = lis r10, averageFPS1Inv@ha ; Half SyncFrame cinematic cutscene, fixes timing issues with cinematic cutscenes
# 0x027A33DC = lfs f1, averageFPS1Inv@l(r10) ; But introduces shake and stutter issue. CODE XREF: ev::CEvtManager::startPage((float,bool))+6Cj

View File

@ -0,0 +1,24 @@
[XCX_FPS++_Overdrive_General] ; ########################################################
moduleMatches = 0xF882D5CF, 0x30B6E091, 0xAB97DE6B, 0x7672271D ; 1.0.1E, 1.0.2U, 1.0.1U, 1.0.2J
.origin = codecave
_over:
fmr f31, f1
lis r31, averageFPS1@ha
lfs f1, averageFPS1@l(r31)
fmuls f1, f31, f1
blr
[XCX_FPS++_Overdrive_NonJ] ; ########################################################
moduleMatches = 0xF882D5CF, 0x30B6E091, 0xAB97DE6B ; 1.0.1E, 1.0.2U, 1.0.1U
0x021BC904 = bla _over
0x021E2020 = bla _over ; Skell Overdrive
[XCX_FPS++_Overdrive_2J] ; ########################################################
moduleMatches = 0x7672271D ; 1.0.2J
0x021BC3D0 = bla _over
0x021E1AEC = bla _over ; Skell Overdrive

View File

@ -0,0 +1,51 @@
[XCX_FPS++_QTE_General] ; ########################################################
moduleMatches = 0x218F6E07, 0xF882D5CF, 0x30B6E091, 0x7672271D ; 1.0.1E, 1.0.2U, 1.0.1U, 1.0.2J
.origin = codecave
_justFrame1:
lwz r12, 0x47C(r29)
lis r10, averageFPS1IntInv@ha
lbz r10, averageFPS1IntInv@l(r10)
mullw r12, r12, r10
blr
_justFrame2:
lwz r0, 0x478(r29)
lis r8, averageFPS1IntInv@ha
lbz r8, averageFPS1IntInv@l(r8)
mullw r0, r0, r8
blr
[XCX_FPS++_QTE_1E] ; ########################################################
moduleMatches = 0xF882D5CF ; 1.0.1E
; menu::MenuButtonChallenge::setup
0x02ACE40C = lis r7, averageFPS1Inv@ha
0x02ACE414 = lfs f0, averageFPS1Inv@l(r7)
; menu::MenuButtonChallenge::move
0x02ACE6E4 = bla _justFrame1
0x02ACE700 = bla _justFrame2
[XCX_FPS++_QTE_2U] ; ########################################################
moduleMatches = 0x30B6E091 ; 1.0.2U
; menu::MenuButtonChallenge::setup
0x02ACE3FC = lis r7, averageFPS1Inv@ha
0x02ACE404 = lfs f0, averageFPS1Inv@l(r7)
; menu::MenuButtonChallenge::move
0x02ACE6D4 = bla _justFrame1
0x02ACE6F0 = bla _justFrame2
[XCX_FPS++_QTE_2J]
moduleMatches = 0x7672271D ; 1.0.2J
; menu::MenuButtonChallenge::setup
0x02ACAA38 = lis r7, averageFPS1Inv@ha
0x02ACAA40 = lfs f0, averageFPS1Inv@l(r7)
; menu::MenuButtonChallenge::move
0x02ACAD10 = bla _justFrame1
0x02ACAD2C = bla _justFrame2

View File

@ -1,6 +1,89 @@
[Definition]
titleIds = 0005000010116100,00050000101C4C00,00050000101C4D00
name = 60FPS
path = "Xenoblade Chronicles X/Mods/60FPS"
description = Important: This patches the gameplay to be in 60FPS. Getting under 60FPS will slow down the game's speed.
version = 5
name = FPS++ For Xenoblade Chronicles X
path = "Xenoblade Chronicles X/Mods/FPS++ For XCX"
description = Allows you to change the FPS and the speed that most things run at.|Some bugs might still occur if you run games at 60FPS.
version = 6
[Default]
$fpsLimit = 60
$cutsceneFPSLimit:int = 1
$lowFPSLimit = 20
$frameAverageAmount = 8
$roundUpModifier = 0.8
[Preset]
name = 240FPS Limit
category = FPS Limit
$fpsLimit = 240
[Preset]
name = 165FPS Limit
category = FPS Limit
$fpsLimit = 165
[Preset]
name = 144FPS Limit
category = FPS Limit
$fpsLimit = 144
[Preset]
name = 120FPS Limit
category = FPS Limit
$fpsLimit = 120
[Preset]
name = 90FPS Limit
category = FPS Limit
$fpsLimit = 90
[Preset]
name = 75FPS Limit
category = FPS Limit
$fpsLimit = 75
[Preset]
name = 72FPS Limit
category = FPS Limit
$fpsLimit = 72
[Preset]
name = 60FPS Limit (Default)
category = FPS Limit
default = 1
$fpsLimit = 60
[Preset]
name = 55FPS Limit
category = FPS Limit
$fpsLimit = 55
[Preset]
name = 45FPS Limit
category = FPS Limit
$fpsLimit = 45
[Preset]
name = 30FPS Limit
category = FPS Limit
$fpsLimit = 30
[Preset]
name = 20FPS Limit
category = FPS Limit
$fpsLimit = 20
# [Preset]
# name = Enabled (Limit Stuttery Cutscenes To 30FPS)
# category = Cutscene FPS Limit
# default = 1
# $cutsceneFPSLimit:int = 1
#
# [Preset]
# name = Disabled (Allow Jittery Cutscenes)
# category = Cutscene FPS Limit
# $cutsceneFPSLimit:int = 0
[Control]
vsyncFrequency = $fpsLimit