Homebrew  Updated

FPSLocker - set custom FPS target in retail games

An overlay that with SaltyNX 1.2.0+ allows to set custom refresh rate in both handheld and docked mode + FPS in Nintendo Switch retail games.

Disclaimer: Tool is utilizing detection of graphics API to manipulate FPS. It supports special patches that are helping with going above 30 FPS in games using proprietary FPS locks.

You can see here how it works (I was utilizing Witcher 3 dynamic resolution config mod to make anything above 30 FPS available):


More in README (I recommend to read it + also SaltyNX readme if you don't know how it works)
Repo: https://github.com/masagrator/FPSLocker
Releases: https://github.com/masagrator/FPSLocker/releases
Patches: https://github.com/masagrator/FPSLocker-Warehouse
 
Last edited by masagrator,
Tested with NEO: TWEWY and Tormented Souls, games I used to modify FPS with cheats and they work perfectly with FPSLocker, no more suffering from updating cheats :lol:
 
  • Love
Reactions: mathew77
You're going put 60fps cheats out of a job haha. But seriously this is amazing. Modifying the nvnwindowsetpresentinterval or the other one is such a genius idea.
I was wondering as well if you could hook into unreal 4 settings addition as well because for graphics settings like they show up in a consistent way in memory as in this video of as the many cheats in the database
 
I was wondering as well if you could hook into unreal 4 settings addition as well because for graphics settings like they show up in a consistent way in memory as in this video of as the many cheats in the database
I would need 100% sure way to do it on first try. Anything below won't cut. I know a way how to reliably detect if it's UE4 game and which version, but nothing more. That's why I want to implement support for patching RAM through cheat style codes for anything that cannot be reliably searched.

If you have 100% sure way to find DR/frametime values for any version of some game, I can implement it directly to plugin.
 
Last edited by masagrator,
NX-FPS not running at fw 15.0.1 AMS 1.4.1. NX-FPS already installed inside saltynx>plugins. SaltyNX 5.0, Status Ovl 0.8.1, NX-FPS 1.0.

Edited : Nevermind, fix archive bit fixed everything. Something corrupted when i use card reader to my pc.
 
Last edited by Gumistret,
Designed a binary file format that will be created by using yaml files and loaded by plugin.
My final goal is to implement option in overlay itself to convert yaml to bin so repository would store only yaml files.

I was thinking about implementing yaml parser into plugin, but all existing solutions are bloating plugin too much.
JSON parsers are 3x lighter, but they weren't fitting my needs.

This is for example working yaml file for Xenoblade Chronicles 3 1.3.0 based on this cheat file
YAML:
15FPS:
  -
    type: write
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
20FPS:
  -
    type: write
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
25FPS:
  -
    type: write
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
30FPS:
  -
    type: write
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
35FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
40FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
45FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
50FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
55FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]
60FPS:
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 1
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [1, 1]
  -
    type: compare
    compare_address: [MAIN, 0x1A65958]
    compare_type: "!="
    compare_value_type: int8
    compare_value: 0
    address: [MAIN, 0x1A08F98]
    value_type: int32
    value: [2, 2]

and this is bin file after conversion
1678537804177.png

Plugin supports for now two things as I don't see for now other valid cases to implement something else.

One is "write fixed value directly to RAM" and second is "if comparison with fixed compare value is true, write fixed value directly to RAM".
It supports writing types in signed and unsigned integers from 8 to 64-bit + float and double. It also supports writing few values one after another (it's used in example)). For now it works with writing to and comparing values from [MAIN + address], but I know we must support heaps and aliases, thus why testing will take a little longer.
 
Last edited by masagrator,
One is "write fixed value directly to RAM" and second is "if comparison with fixed value is true, write fixed value directly to RAM".
It supports writing types in signed and unsigned integers from 8 to 64-bit + float and double. It also supports writing few values one after another (it's used in example)). For now it works with writing to and comparing values from [MAIN + address], but I know we must support heaps and aliases, thus why testing will take a little longer.

Brilliant job!
 
  • Like
Reactions: binkinator
1.1.0
Released 1.1.0 version of FPSLocker.
To work properly it requires updating NX-FPS to 1.1 version and SaltyNX to 0.5.1 version.

Overall plugin now supports loading special LOCK patches to adjust games FPS if plugin is not enough to do the job.
FPSLocker has option to convert yaml configs to LOCK patches when game is running (to retrieve BID of game) that will be applied on next game boot.

if for some reason you would like to convert yaml to LOCK patch on PC, you can use this script:
https://github.com/masagrator/NX-FPS/blob/master/scripts/yamlToBin.py
And for reversing patch to yaml (though it will use different layout, sort keys in alphabetical order and store numbers only in decimal system - because I don't see an option to fix that somehow)
https://github.com/masagrator/NX-FPS/blob/master/scripts/binToYaml.py

Created new repo which whole purpose is to store those yaml files and info about 30 FPS games + how to update each patch yourself if you know how to use required tools:
https://github.com/masagrator/FPSLocker-Warehouse

As I suck at writing documentation I hope you will forgive my Methodology folder that it's not written with perfect English. :D


For starters I have added patches for 3 games that I have currently on my Switch and didn't work as expected without those patches:
- Xenoblade Chronicles 3 1.3.0 (to disable double buffer turn off Sync Wait)
- The Witcher 3 - Complete Edition 3.7 (with dynamic resolution tweaks for each FPS)
- Monster Hunter Rise 14.0.0 (added warning to DETAILS that if game will be running without patch and you will save settings with some custom FPS target, game will crash at boot. If you don't have a patch for your version of game, you can delete settings by opening FPSLocker when no game is running).

I will do more yaml configs from next month since I am not in home for next 2 weeks.
 
Last edited by masagrator,
I'm really glad one of my ideas came to reality (obviously it's not my idea, I'm sure there are several more people who thought of a general switch fps unlocker). Good job!

I remember asking somewhere if a general fps unlocker could become a reality and the results were a unfortunate no. I bet those people are pretty flabbergasted right now.
 
  • Wow
Reactions: Cooler3D
the results were a unfortunate no
I was in this camp too. But did it anyway to see the results and it was from the beginning very stable, needed only to find a correction value by trial and error that will cause PFPS value to behave the same across whole FPS range (When setting 45 FPS I have found that status monitor shows 45.2 FPS, but PFPS behavior remains the same as for other FPS, so I guess there is some flaw in calculations at this vicinity. Using Monster Hunter Rise internal FPS lock was a good comparison since setting it to 45 FPS provided exactly the same results). In few hours I have made a completely working project, send to two people for some quick tests, got very positive feedback and released it.
 
Saltynx seems very inconsistent half the time it says it is not running for some reason. hence revernx or fpslocker wont work. Sometimes a reboot fix its.
 
Saltynx seems very inconsistent
Well, that's true since the beginning. It was never a clean solution. Issue is nobody made something better to this date. I guess with GDB I can try to figure out where is the issue because causing SaltyNX to not respond is pretty simple.
 
Last edited by masagrator,
  • Like
Reactions: Chrisssj2
Well, that's true since the beginning. It was never a clean solution. Issue is nobody made something better to this date. I guess with GDB I can try to figure out where is the issue because causing SaltyNX to not respond is pretty simple.
Atleast i know its not something on my end then. cuz with 1 game it seems to trigger and i boot other game and it gone xD
 
1.1.1 / 1.1.2
NX-FPS was updated to 1.2 to solve issue with some old games being unable to get more than 30 FPS with FPSLocker because they were using nvnQueueAcquireTexture instead of nvnWindowAcquireTexture (for example Outlast), so I recommend to update it.
Post automatically merged:

Updated to version 1.1.1 to implement fix for random crashes in docked mode related to freeing framebuffer.
Post automatically merged:

Well, well. How fast new edge cases I am finding.

Released 1.1.2 version fixing RTLD detection in older games such as L.A. Noire.
It is required to update SaltyNX to 0.5.2+ version and NX-FPS to 1.2.1+ version to completely fix the issue.
 
Last edited by masagrator,

Site & Scene News

Popular threads in this forum