Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
fd3863c0d4 | |||
8740c41a63 | |||
f057283998 | |||
52359bfeeb | |||
8c19ed0208 | |||
dd2d5a58b1 |
32
.gitea/workflows/rust.yml
Normal file
32
.gitea/workflows/rust.yml
Normal file
@ -0,0 +1,32 @@
|
||||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["master"]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install rust
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: "x86_64-pc-windows-gnu"
|
||||
|
||||
- name: Install cross compilation tools
|
||||
run: sudo apt-get update && sudo apt-get install mingw-w64 -y
|
||||
|
||||
- name: Setup Cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Build release
|
||||
run: cargo build --verbose --locked --release --target x86_64-pc-windows-gnu
|
||||
|
||||
- name: Archive build
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: alt_enter_fix
|
||||
path: target/x86_64-pc-windows-gnu/release/alt_enter_fix.exe
|
22
.github/workflows/rust.yml
vendored
22
.github/workflows/rust.yml
vendored
@ -1,22 +0,0 @@
|
||||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
90
Cargo.lock
generated
90
Cargo.lock
generated
@ -1,7 +1,95 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "alt_enter_fix"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
@ -5,4 +5,8 @@ edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[target.x86_64-pc-windows-gnu]
|
||||
linker = "x86_64-w64-mingw32-gcc"
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0.140"
|
||||
|
@ -1,5 +1,5 @@
|
||||
# alt_enter_fix
|
||||
|
||||
[](https://github.com/dowoge/alt_enter_fix/actions/workflows/rust.yml)
|
||||
[](https://git.tommyy.dev/tommy/alt_enter_fix/actions/workflows/rust.yml)
|
||||
|
||||
fire program
|
||||
|
181
src/main.rs
181
src/main.rs
@ -1,47 +1,150 @@
|
||||
use std::{io, fs, env, path::Path};
|
||||
use io::Read;
|
||||
fn main() {
|
||||
let mut rblxpath = String::new();
|
||||
if let Some(lad) = env::var("LOCALAPPDATA").ok() {
|
||||
let temprbx_lad = format!("{}\\Roblox",lad);
|
||||
if Path::new(&temprbx_lad).is_dir() {
|
||||
rblxpath = temprbx_lad;
|
||||
}
|
||||
} else if let Some(pfx86) = env::var("ProgramFiles(x86)").ok() {
|
||||
let temprbx_pfx86 = format!("{}\\Roblox",pfx86);
|
||||
if Path::new(&temprbx_pfx86).is_dir() {
|
||||
rblxpath = temprbx_pfx86;
|
||||
}
|
||||
}
|
||||
if rblxpath != "" {
|
||||
println!("Found path: {}",rblxpath);
|
||||
} else {
|
||||
use serde_json::{json, Value};
|
||||
use std::{env, fs, io::{self, stdin, Read, Write}, path::{Path, PathBuf}};
|
||||
|
||||
const UNLIMITED_FPS_CAP_NUM: i32 = i32::max_value();
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let roblox_path = find_roblox_path().ok_or_else(|| {
|
||||
println!("Roblox not found (Die)");
|
||||
return;
|
||||
io::Error::new(io::ErrorKind::NotFound, "Roblox installation not found")
|
||||
})?;
|
||||
|
||||
println!("Found path: {}", roblox_path.display());
|
||||
|
||||
println!("What FPS would you like to cap the fps to? (0 for no cap at all)");
|
||||
io::stdout().flush()?;
|
||||
|
||||
let fps = read_fps_input()?;
|
||||
let desired_fps = if fps == 0 { UNLIMITED_FPS_CAP_NUM } else { fps };
|
||||
|
||||
println!("FPS cap will be set to {desired_fps}");
|
||||
|
||||
let required_settings = json!({
|
||||
// Restore original 'alt-enter' behaviour
|
||||
"FFlagHandleAltEnterFullscreenManually": "False",
|
||||
|
||||
// Disable Roblox's built-in 240 fps hard-coded cap and replace with custom cap
|
||||
"DFIntTaskSchedulerTargetFps": desired_fps,
|
||||
"FFlagGameBasicSettingsFramerateCap5": "False",
|
||||
"FFlagTaskSchedulerLimitTargetFpsTo2402": "False",
|
||||
|
||||
// Ensure Direct3D11 is the rendering API for optimal performance
|
||||
"FFlagDebugGraphicsDisableDirect3D11": "False",
|
||||
"FFlagDebugGraphicsPreferD3D11": "True",
|
||||
|
||||
// Disable telemetry related FFlags
|
||||
"FFlagDebugDisableTelemetryEphemeralCounter": "True",
|
||||
"FFlagDebugDisableTelemetryEphemeralStat": "True",
|
||||
"FFlagDebugDisableTelemetryEventIngest": "True",
|
||||
"FFlagDebugDisableTelemetryPoint": "True",
|
||||
"FFlagDebugDisableTelemetryV2Counter": "True",
|
||||
"FFlagDebugDisableTelemetryV2Event": "True",
|
||||
"FFlagDebugDisableTelemetryV2Stat": "True"
|
||||
});
|
||||
|
||||
update_client_settings(&roblox_path, required_settings)?;
|
||||
|
||||
println!("Press enter to exit");
|
||||
let _ = io::stdin().read(&mut [0u8])?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn find_roblox_path() -> Option<PathBuf> {
|
||||
if let Some(local_app_data) = env::var("LOCALAPPDATA").ok() {
|
||||
let path = PathBuf::from(local_app_data).join("Roblox");
|
||||
if path.is_dir() {
|
||||
return Some(path);
|
||||
}
|
||||
}
|
||||
let versions = format!("{}\\Versions\\",rblxpath);
|
||||
for folder in fs::read_dir(versions).unwrap() {
|
||||
let cur_folder = folder.unwrap().path().display().to_string();
|
||||
if cur_folder.to_lowercase().contains("version") {
|
||||
let executable = format!("{}\\RobloxPlayerBeta.exe",cur_folder);
|
||||
if Path::new(&executable).is_file() {
|
||||
let cs_folder = format!("{}\\ClientSettings",cur_folder);
|
||||
if !Path::new(&cs_folder).is_dir() {
|
||||
fs::create_dir(&cs_folder).ok();
|
||||
println!("Created ClientSettings folder in {}",cur_folder);
|
||||
|
||||
// This is here because Roblox installs into Program Files (x86) if you run the installer as administrator (??? lol)
|
||||
if let Some(program_files) = env::var("ProgramFiles(x86)").ok() {
|
||||
let path = PathBuf::from(program_files).join("Roblox");
|
||||
if path.is_dir() {
|
||||
return Some(path);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn read_fps_input() -> io::Result<i32> {
|
||||
let mut input = String::new();
|
||||
stdin().read_line(&mut input)?;
|
||||
|
||||
let input = input.trim();
|
||||
|
||||
input.parse::<i32>().map_err(|_| {
|
||||
io::Error::new(io::ErrorKind::InvalidInput, "Invalid FPS value")
|
||||
})
|
||||
}
|
||||
|
||||
fn update_client_settings(roblox_path: &Path, required_settings: Value) -> io::Result<()> {
|
||||
let versions_path = roblox_path.join("Versions");
|
||||
|
||||
for entry in fs::read_dir(versions_path)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
let path_str = path.to_string_lossy().to_lowercase();
|
||||
|
||||
if path_str.contains("version") {
|
||||
let executable = path.join("RobloxPlayerBeta.exe");
|
||||
|
||||
if executable.is_file() {
|
||||
let client_settings_dir = path.join("ClientSettings");
|
||||
|
||||
if !client_settings_dir.exists() {
|
||||
fs::create_dir(&client_settings_dir)?;
|
||||
println!("Created ClientSettings folder in {}", path.display());
|
||||
} else {
|
||||
println!("ClientSettings folder already exists in {}",cur_folder);
|
||||
}
|
||||
let cas_json = format!("{}\\ClientAppSettings.json",cs_folder);
|
||||
if !Path::new(&cas_json).is_file() {
|
||||
fs::write(cas_json, "{\"FFlagHandleAltEnterFullscreenManually\":\"False\",\"DFIntTaskSchedulerTargetFps\":5588562,\"FFlagEnableInGameMenuChromeABTest3\":\"False\",\"FFlagGameBasicSettingsFramerateCap5\":\"False\",\"FFlagTaskSchedulerLimitTargetFpsTo2402\":\"False\"}").ok();
|
||||
println!("Wrote ClientAppSettings.json to {}",cur_folder)
|
||||
} else {
|
||||
println!("ClientAppSettings.json already exists in {}",cur_folder)
|
||||
println!("ClientSettings folder already exists in {}", path.display());
|
||||
}
|
||||
|
||||
let settings_file = client_settings_dir.join("ClientAppSettings.json");
|
||||
update_settings_file(&settings_file, &required_settings)?;
|
||||
println!("Updated ClientAppSettings.json in {}", path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("Press enter to exit");
|
||||
let _ = io::stdin().read(&mut [0u8]).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_settings_file(file_path: &Path, required_settings: &Value) -> io::Result<()> {
|
||||
// Funky code to edit or create the ClientAppSettings.json file (shoutout claude for the help with the object stuff (json sucks))
|
||||
let mut settings = if file_path.exists() {
|
||||
match fs::read_to_string(file_path) {
|
||||
Ok(content) if !content.trim().is_empty() => {
|
||||
match serde_json::from_str::<Value>(&content) {
|
||||
Ok(existing) => existing,
|
||||
Err(e) => {
|
||||
println!("Warning: Could not parse existing settings ({}), creating new file", e);
|
||||
json!({})
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => json!({})
|
||||
}
|
||||
} else {
|
||||
json!({})
|
||||
};
|
||||
|
||||
if let Some(required_obj) = required_settings.as_object() {
|
||||
if !settings.is_object() {
|
||||
settings = json!({});
|
||||
}
|
||||
|
||||
if let Some(settings_obj) = settings.as_object_mut() {
|
||||
for (key, value) in required_obj {
|
||||
println!("Adding {}: {}", key, value);
|
||||
settings_obj.insert(key.clone(), value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let formatted = serde_json::to_string_pretty(&settings)?;
|
||||
fs::write(file_path, formatted)?;
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue
Block a user