Add launcher preferences and modular landing studio [skip ci]

This commit is contained in:
SCOPEDD committed 2026-09-30 06:48:03 -04:00
1 parent 454620f21e
commit 6deff62a3a
25 files changed
+822 -682

No files matched your search

+42
View File
@@ -4,6 +4,36 @@ use anyhow::Result;
use std::collections::BTreeMap;
use std::path::Path;
/// Player-owned vanilla preferences. Pack-managed options.txt may be replaced
/// during sync, so these are captured separately and merged back afterward.
const VANILLA_KEYS: &[&str] = &[
"fov", "gamma", "graphicsMode", "fancyGraphics", "renderDistance", "simulationDistance",
"maxFps", "enableVsync", "fullscreen", "fullscreenResolution", "guiScale", "particles",
"clouds", "renderClouds", "entityShadows", "entityDistanceScaling", "biomeBlendRadius",
"mipmapLevels", "ao", "ambientOcclusion", "bobView", "attackIndicator", "autoJump",
"mouseSensitivity", "invertYMouse", "discrete_mouse_scroll", "mouseWheelSensitivity",
"rawMouseInput", "toggleCrouch", "toggleSprint", "sneakToggled", "sprintToggled",
"screenEffectScale", "fovEffectScale", "darknessEffectScale", "narrator", "subtitles",
"chatVisibility", "chatColors", "chatLinks", "chatLinksPrompt", "chatOpacity", "textBackgroundOpacity",
"backgroundForChatOnly", "chatScale", "chatWidth", "chatHeightFocused", "chatHeightUnfocused",
"mainHand", "lang", "forceUnicodeFont", "tutorialStep", "hideBundleTutorial",
"soundDevice", "directionalAudio", "musicFrequency", "notificationDisplayTime",
"joinedFirstServer", "pauseOnLostFocus", "reducedDebugInfo", "showSubtitles",
];
pub fn read_vanilla_preferences(game_dir: &Path) -> Result<BTreeMap<String, String>> {
let path = game_dir.join("options.txt");
let contents = match std::fs::read_to_string(path) {
Ok(contents) => contents,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(BTreeMap::new()),
Err(e) => return Err(e.into()),
};
Ok(contents.lines().filter_map(|line| {
let (key, value) = line.split_once(':')?;
(VANILLA_KEYS.contains(&key) || key.starts_with("soundCategory_")).then(|| (key.to_owned(), value.to_owned()))
}).collect())
}
/// Merge `key_<binding>:<key>` lines into options.txt, keeping everything
/// else the game has written. Only for 1.13+ (named key codes).
pub fn apply_keybinds(game_dir: &Path, binds: &BTreeMap<String, String>) -> Result<()> {
@@ -51,4 +81,16 @@ mod tests {
let out = std::fs::read_to_string(dir.path().join("options.txt")).unwrap();
assert_eq!(out, "version:3465\nkey_key.forward:key.keyboard.up\nfov:0.0\nkey_key.sprint:key.keyboard.left.control\n");
}
#[test]
fn captures_only_vanilla_preferences() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("options.txt"), "fov:0.8\ngamma:1.0\nautoJump:false\nsoundCategory_music:0.25\nkey_key.forward:key.keyboard.w\nmodded:yes\n").unwrap();
let prefs = read_vanilla_preferences(dir.path()).unwrap();
assert_eq!(prefs.get("fov").map(String::as_str), Some("0.8"));
assert_eq!(prefs.get("autoJump").map(String::as_str), Some("false"));
assert_eq!(prefs.get("soundCategory_music").map(String::as_str), Some("0.25"));
assert!(!prefs.contains_key("modded"));
assert!(!prefs.contains_key("key_key.forward"));
}
}
+17
View File
@@ -31,6 +31,7 @@ pub struct Branding {
pub version_label: String,
pub news: Vec<NewsItem>,
pub links: Vec<SocialLink>,
pub about: AboutContent,
pub features: Features,
/// Raw CSS appended to the launcher stylesheet (power users).
pub custom_css: String,
@@ -60,12 +61,28 @@ impl Default for Branding {
tag: Some("News".into()),
}],
links: vec![],
about: AboutContent::default(),
features: Features::default(),
custom_css: String::new(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(default)]
pub struct AboutContent {
pub title: String,
pub icon_url: Option<String>,
pub body: String,
pub links: Vec<SocialLink>,
}
impl Default for AboutContent {
fn default() -> Self {
Self { title: String::new(), icon_url: None, body: String::new(), links: Vec::new() }
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(default)]
pub struct Background {