Add launcher engine (scopenet-core) and admin panel server

- scopenet-shared: wire types for branding, auth, instances, manifests
- scopenet-core: Mojang versions/libraries/assets, automatic Java runtimes,
  Fabric/Quilt/Forge/NeoForge installation, file sync, launch command
  builder, Microsoft auth, servers.dat injection, server list ping
- scopenet-panel: Axum + SQLite admin API with JWT auth, users/groups,
  branding, settings, instances, Modrinth/CurseForge/zip import, file
  hosting and launch stats

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011ARcGWxLx21FwXJ3yfGriS
This commit is contained in:
Claude committed 2026-09-28 04:22:17 +00:00
1 parent 915f40a4c4
commit 8cdf616a94
43 files changed
+9317

No files matched your search

+54
View File
@@ -0,0 +1,54 @@
//! Writes player keybinds / preferences into Minecraft's `options.txt`.
use anyhow::Result;
use std::collections::BTreeMap;
use std::path::Path;
/// 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<()> {
let mut values: BTreeMap<String, String> = binds.iter().map(|(k, v)| (format!("key_{k}"), v.clone())).collect();
apply(game_dir, &mut values)
}
/// Merge arbitrary `name:value` options.
pub fn apply(game_dir: &Path, values: &mut BTreeMap<String, String>) -> Result<()> {
if values.is_empty() {
return Ok(());
}
let path = game_dir.join("options.txt");
let existing = std::fs::read_to_string(&path).unwrap_or_default();
let mut lines: Vec<String> = Vec::new();
for line in existing.lines() {
match line.split_once(':') {
Some((k, _)) if values.contains_key(k) => {
let v = values.remove(k).unwrap();
lines.push(format!("{k}:{v}"));
}
_ => lines.push(line.to_string()),
}
}
for (k, v) in values.iter() {
lines.push(format!("{k}:{v}"));
}
std::fs::create_dir_all(game_dir)?;
std::fs::write(path, lines.join("\n") + "\n")?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn merges_keybinds() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(dir.path().join("options.txt"), "version:3465\nkey_key.forward:key.keyboard.w\nfov:0.0\n").unwrap();
let mut binds = BTreeMap::new();
binds.insert("key.forward".to_string(), "key.keyboard.up".to_string());
binds.insert("key.sprint".to_string(), "key.keyboard.left.control".to_string());
apply_keybinds(dir.path(), &binds).unwrap();
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");
}
}