Add launcher preferences and modular landing studio [skip ci]
This commit is contained in:
1 parent
454620f21e
commit
6deff62a3a
25 files changed
+822
-682
No files matched your search
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in new issue
Block a user