feat: 支持自定义 Minecraft 窗口标题
Sync source to CNB / Sync Git ref (push) Skipped

全局开关 + 默认标题,实例可覆盖;Win32 重命名窗口。前端设置页同步。
This commit is contained in:
AxTps committed 2026-10-10 21:02:34 +08:00
1 parent 544611738d
commit c718d75774
15 files changed
+274 -3

No files matched your search

+12
View File
@@ -250,6 +250,17 @@ async fn run_credentials(
.launch_overrides
.maximize_window
.unwrap_or(settings.maximize_window);
let window_title = settings
.custom_window_title_enabled
.then(|| {
context
.launch_overrides
.window_title
.clone()
.filter(|value| !value.trim().is_empty())
.unwrap_or_else(|| settings.default_window_title.clone())
})
.filter(|value| !value.trim().is_empty());
let env_args = context
.launch_overrides
.custom_env_vars
@@ -319,6 +330,7 @@ async fn run_credentials(
&memory,
&resolution,
maximize_window,
window_title,
credentials,
post_exit_hook,
&context,
+2
View File
@@ -400,6 +400,7 @@ pub async fn emit_process(
uuid: Uuid,
pid: u32,
maximize_window: bool,
window_title: Option<String>,
event: ProcessPayloadType,
message: &str,
crashed: Option<bool>,
@@ -416,6 +417,7 @@ pub async fn emit_process(
uuid,
pid,
maximize_window,
window_title,
event,
message: message.to_string(),
crashed,
+2
View File
@@ -336,6 +336,8 @@ pub struct ProcessPayload {
pub uuid: Uuid,
pub pid: u32,
pub maximize_window: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub window_title: Option<String>,
pub event: ProcessPayloadType,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
+2
View File
@@ -1520,6 +1520,7 @@ pub async fn launch_minecraft(
memory: &MemorySettings,
resolution: &WindowSize,
maximize_window: bool,
window_title: Option<String>,
credentials: &Credentials,
post_exit_hook: Option<String>,
context: &InstanceLaunchContext,
@@ -2391,6 +2392,7 @@ pub async fn launch_minecraft(
command,
post_exit_hook,
maximize_window,
window_title,
instance_path.clone(),
logs_folder,
version_info.logging.is_some(),
@@ -103,6 +103,12 @@ pub struct InstanceLaunchOverridesPatch {
skip_serializing_if = "Option::is_none",
with = "serde_with::rust::double_option"
)]
pub window_title: Option<Option<String>>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
with = "serde_with::rust::double_option"
)]
pub launch_preparation_timeout: Option<Option<u64>>,
pub hooks: Option<Hooks>,
}
@@ -371,6 +377,9 @@ fn apply_launch_overrides_patch(
if let Some(game_resolution) = patch.game_resolution {
overrides.game_resolution = game_resolution;
}
if let Some(window_title) = patch.window_title {
overrides.window_title = window_title.filter(|value| !value.trim().is_empty());
}
if let Some(mode) = patch.instance_mode {
overrides.instance_mode = Some(mode);
}
@@ -38,6 +38,8 @@ pub struct InstanceLaunchOverrides {
pub maximize_window: Option<bool>,
pub game_resolution: Option<WindowSize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub window_title: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub launch_preparation_timeout: Option<u64>,
pub hooks: Hooks,
}
@@ -55,6 +57,7 @@ impl InstanceLaunchOverrides {
force_fullscreen: None,
maximize_window: None,
game_resolution: None,
window_title: None,
launch_preparation_timeout: None,
hooks: Hooks {
pre_launch: None,
@@ -86,6 +89,8 @@ pub(crate) struct InstanceLaunchOverridesData {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub game_resolution: Option<WindowSize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub window_title: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub launch_preparation_timeout: Option<u64>,
#[serde(default)]
pub hooks: Hooks,
@@ -107,6 +112,7 @@ impl InstanceLaunchOverridesData {
force_fullscreen: self.force_fullscreen,
maximize_window: self.maximize_window,
game_resolution: self.game_resolution,
window_title: self.window_title,
launch_preparation_timeout: self.launch_preparation_timeout,
hooks: self.hooks,
}
@@ -125,6 +131,7 @@ impl From<&InstanceLaunchOverrides> for InstanceLaunchOverridesData {
force_fullscreen: overrides.force_fullscreen,
maximize_window: overrides.maximize_window,
game_resolution: overrides.game_resolution,
window_title: overrides.window_title.clone(),
launch_preparation_timeout: overrides.launch_preparation_timeout,
hooks: overrides.hooks.clone(),
}
+5
View File
@@ -312,6 +312,7 @@ impl ProcessManager {
mut mc_command: Command,
post_exit_command: Option<String>,
maximize_window: bool,
window_title: Option<String>,
game_dir: PathBuf,
logs_folder: PathBuf,
xml_logging: bool,
@@ -336,6 +337,7 @@ impl ProcessManager {
uuid: Uuid::new_v4(),
pid: mc_proc.id().unwrap_or_default(),
maximize_window,
window_title: window_title.clone(),
start_time: Utc::now(),
instance_id: instance_id.to_string(),
instance_path: instance_path.to_string(),
@@ -509,6 +511,7 @@ impl ProcessManager {
metadata.uuid,
metadata.pid,
metadata.maximize_window,
metadata.window_title.clone(),
ProcessPayloadType::Launched,
"Launched Minecraft",
None,
@@ -586,6 +589,7 @@ pub struct ProcessMetadata {
pub uuid: Uuid,
pub pid: u32,
pub maximize_window: bool,
pub window_title: Option<String>,
pub instance_id: String,
pub instance_path: String,
pub instance_name: String,
@@ -1311,6 +1315,7 @@ impl Process {
uuid,
pid,
false,
None,
ProcessPayloadType::Finished,
"Exited process",
Some(!mc_exit_status.success() && !manually_killed),
+30
View File
@@ -176,6 +176,10 @@ pub struct Settings {
pub force_fullscreen: bool,
pub maximize_window: bool,
#[serde(default)]
pub custom_window_title_enabled: bool,
#[serde(default = "default_window_title")]
pub default_window_title: String,
#[serde(default)]
pub force_unicode_font: bool,
pub game_resolution: WindowSize,
pub hide_on_process_start: bool,
@@ -198,6 +202,10 @@ pub struct Settings {
pub version: usize,
}
fn default_window_title() -> String {
"Minecraft".to_string()
}
fn default_true() -> bool {
true
}
@@ -328,6 +336,16 @@ impl Settings {
)
.fetch_one(exec)
.await?;
let custom_window_title_enabled: bool = sqlx::query_scalar(
"SELECT custom_window_title_enabled FROM settings WHERE id = 0",
)
.fetch_one(exec)
.await?;
let default_window_title: String = sqlx::query_scalar(
"SELECT default_window_title FROM settings WHERE id = 0",
)
.fetch_one(exec)
.await?;
let settings = Self {
max_concurrent_downloads: res.max_concurrent_downloads as usize,
max_concurrent_writes: res.max_concurrent_writes as usize,
@@ -415,6 +433,8 @@ impl Settings {
},
force_fullscreen: res.mc_force_fullscreen == 1,
maximize_window: res.mc_maximize_window == 1,
custom_window_title_enabled,
default_window_title,
force_unicode_font: sqlx::query_scalar(
"SELECT mc_force_unicode_font FROM settings WHERE id = 0",
)
@@ -663,6 +683,16 @@ impl Settings {
.bind(self.ignore_ssl_errors)
.execute(exec)
.await?;
sqlx::query(
"UPDATE settings SET custom_window_title_enabled = ? WHERE id = 0",
)
.bind(self.custom_window_title_enabled)
.execute(exec)
.await?;
sqlx::query("UPDATE settings SET default_window_title = ? WHERE id = 0")
.bind(self.default_window_title.trim())
.execute(exec)
.await?;
sqlx::query("UPDATE settings SET mc_memory_optimize = ? WHERE id = 0")
.bind(self.memory.optimize_before_launch)
.execute(exec)