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
@@ -19,6 +19,7 @@ use tokio::io::{AsyncBufReadExt, BufReader};
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct StatePayload {
|
||||
pub instance_id: String,
|
||||
pub run_id: Option<String>,
|
||||
/// "preparing" | "running" | "idle" | "error"
|
||||
pub state: String,
|
||||
pub message: Option<String>,
|
||||
@@ -27,6 +28,7 @@ pub struct StatePayload {
|
||||
#[derive(Serialize, Clone)]
|
||||
pub struct ExitPayload {
|
||||
pub instance_id: String,
|
||||
pub run_id: String,
|
||||
pub code: Option<i32>,
|
||||
pub crashed: bool,
|
||||
pub tail: Vec<String>,
|
||||
@@ -34,7 +36,7 @@ pub struct ExitPayload {
|
||||
}
|
||||
|
||||
pub fn emit_state(app: &AppHandle, id: &str, state: &str, message: Option<String>) {
|
||||
app.emit("launch://state", StatePayload { instance_id: id.into(), state: state.into(), message }).ok();
|
||||
app.emit("launch://state", StatePayload { instance_id: id.into(), run_id: None, state: state.into(), message }).ok();
|
||||
}
|
||||
|
||||
/// Fetch the instance definition, falling back to the last copy we saw so
|
||||
@@ -119,7 +121,19 @@ pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -
|
||||
deep_verify: deep,
|
||||
};
|
||||
let installed = install::install(&state.http, &state.layout, &spec, &report).await?;
|
||||
sync::sync(&state.http, &panel, &game_dir, inst.revision, &manifest.files, spec.concurrency, deep, &report).await?;
|
||||
let already_running = state.game.lock().unwrap().iter().any(|g| g.instance_id == instance_id);
|
||||
// The on-disk file may be newer when the launcher was closed before Minecraft.
|
||||
let current_options = options::read_vanilla_preferences(&game_dir).unwrap_or_default();
|
||||
let mut saved_options = if current_options.is_empty() {
|
||||
settings.instance_game_options.get(&instance_id).cloned().unwrap_or_default()
|
||||
} else {
|
||||
current_options
|
||||
};
|
||||
// Do not rewrite pack files or options while another copy is using this directory.
|
||||
if !already_running {
|
||||
sync::sync(&state.http, &panel, &game_dir, inst.revision, &manifest.files, spec.concurrency, deep, &report).await?;
|
||||
options::apply(&game_dir, &mut saved_options)?;
|
||||
}
|
||||
|
||||
if let Some(server) = &inst.server {
|
||||
if server.inject && !server.address.is_empty() {
|
||||
@@ -127,7 +141,13 @@ pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -
|
||||
servers_dat::upsert(&game_dir, &name, &servers_dat::format_address(&server.address, server.port)).ok();
|
||||
}
|
||||
}
|
||||
if settings.keybinds_enabled && installed.version.is_modern() && !settings.keybinds.is_empty() {
|
||||
if !already_running && settings.vanilla_controls_enabled {
|
||||
let mut controls = std::collections::BTreeMap::new();
|
||||
controls.insert("autoJump".to_string(), settings.auto_jump.to_string());
|
||||
controls.insert("mouseSensitivity".to_string(), settings.sensitivity.clamp(0.0, 1.0).to_string());
|
||||
options::apply(&game_dir, &mut controls)?;
|
||||
}
|
||||
if !already_running && settings.keybinds_enabled && installed.version.is_modern() && !settings.keybinds.is_empty() {
|
||||
options::apply_keybinds(&game_dir, &settings.keybinds).ok();
|
||||
}
|
||||
|
||||
@@ -203,8 +223,9 @@ pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -
|
||||
}
|
||||
|
||||
let (kill_tx, kill_rx) = tokio::sync::oneshot::channel();
|
||||
*state.game.lock().unwrap() = Some(RunningGame { instance_id: instance_id.clone(), kill: kill_tx });
|
||||
emit_state(&app, &instance_id, "running", None);
|
||||
let run_id = uuid::Uuid::new_v4().to_string();
|
||||
state.game.lock().unwrap().push(RunningGame { run_id: run_id.clone(), instance_id: instance_id.clone(), kill: Some(kill_tx) });
|
||||
app.emit("launch://state", StatePayload { instance_id: instance_id.clone(), run_id: Some(run_id.clone()), state: "running".into(), message: None }).ok();
|
||||
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
match settings.after_launch.as_str() {
|
||||
@@ -241,6 +262,7 @@ pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -
|
||||
|
||||
let app2 = app.clone();
|
||||
let id2 = instance_id.clone();
|
||||
let run_id2 = run_id.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut tail: VecDeque<String> = VecDeque::with_capacity(200);
|
||||
let mut batch: Vec<String> = Vec::new();
|
||||
@@ -297,15 +319,22 @@ pub async fn run(app: AppHandle, instance_id: String, start: bool, deep: bool) -
|
||||
},
|
||||
&id2,
|
||||
);
|
||||
*st.game.lock().unwrap() = None;
|
||||
if let Some(w) = app2.get_webview_window("main") {
|
||||
w.show().ok();
|
||||
w.unminimize().ok();
|
||||
if crashed {
|
||||
w.set_focus().ok();
|
||||
let preferences = options::read_vanilla_preferences(&st.layout.instance_dir(&id2)).unwrap_or_default();
|
||||
if !preferences.is_empty() {
|
||||
st.settings.write().unwrap().instance_game_options.insert(id2.clone(), preferences);
|
||||
st.save_settings().ok();
|
||||
}
|
||||
st.game.lock().unwrap().retain(|g| g.run_id != run_id2);
|
||||
if st.game.lock().unwrap().is_empty() {
|
||||
if let Some(w) = app2.get_webview_window("main") {
|
||||
w.show().ok();
|
||||
w.unminimize().ok();
|
||||
if crashed {
|
||||
w.set_focus().ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
app2.emit("game://exit", ExitPayload { instance_id: id2.clone(), code, crashed, tail: tail.into_iter().collect(), crash_report })
|
||||
app2.emit("game://exit", ExitPayload { instance_id: id2.clone(), run_id: run_id2, code, crashed, tail: tail.into_iter().collect(), crash_report })
|
||||
.ok();
|
||||
emit_state(&app2, &id2, "idle", None);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user