Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,35 @@ const messages = defineMessages({
defaultMessage:
'Hooks allow advanced users to run certain system commands before and after launching the game.',
},
hookVariablesDescription: {
id: 'instance.settings.tabs.hooks.variables.description',
defaultMessage:
'Hooks run in the working directory of the instance, with the following variables:',
},
instanceNameDescription: {
id: 'instance.settings.tabs.hooks.variables.inst-name.description',
defaultMessage: '$INST_NAME: The name of the instance',
},
instanceIdDescription: {
id: 'instance.settings.tabs.hooks.variables.inst-id.description',
defaultMessage: "$INST_ID: The name of the instance's folder",
},
instanceDirDescription: {
id: 'instance.settings.tabs.hooks.variables.inst-dir.description',
defaultMessage: "$INST_DIR: The absolute path to the instance's folder",
},
instanceMcDirDescription: {
id: 'instance.settings.tabs.hooks.variables.inst-mc-dir.description',
defaultMessage: '$INST_MC_DIR: An alias for $INST_DIR',
},
instanceJavaDescription: {
id: 'instance.settings.tabs.hooks.variables.inst-java.description',
defaultMessage: '$INST_JAVA: The absolute path to the java binary',
},
instanceJavaArgsDescription: {
id: 'instance.settings.tabs.hooks.variables.inst-java-args.description',
defaultMessage: '$INST_JAVA_ARGS: The JVM Arguments provided to the game',
},
customHooks: {
id: 'instance.settings.tabs.hooks.custom-hooks',
defaultMessage: 'Custom launch hooks',
Expand Down Expand Up @@ -153,5 +182,17 @@ const messages = defineMessages({
<p class="m-0">
{{ formatMessage(messages.postExitDescription) }}
</p>

<div class="m-0 mt-6">
{{ formatMessage(messages.hookVariablesDescription) }}
</div>
<ul class="m-0 mt-2">
<li>{{ formatMessage(messages.instanceNameDescription) }}</li>
<li>{{ formatMessage(messages.instanceIdDescription) }}</li>
<li>{{ formatMessage(messages.instanceDirDescription) }}</li>
<li>{{ formatMessage(messages.instanceMcDirDescription) }}</li>
<li>{{ formatMessage(messages.instanceJavaDescription) }}</li>
<li>{{ formatMessage(messages.instanceJavaArgsDescription) }}</li>
</ul>
</div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,18 @@ watch(
/>
<p class="m-0 leading-tight">Ran after the game closes.</p>
</div>

<div class="m-0 leading-tight">
Hooks run in the working directory of the instance, with the following variables:
<ul>
<li>$INST_NAME: The name of the instance</li>
<li>$INST_ID: The name of the instance's folder</li>
<li>$INST_DIR: The absolute path to the instance's folder</li>
<li>$INST_MC_DIR: An alias for $INST_DIR</li>
<li>$INST_JAVA: The absolute path to the java binary</li>
<li>$INST_JAVA_ARGS: The JVM Arguments provided to the game</li>
</ul>
</div>
</div>
</div>
</template>
21 changes: 21 additions & 0 deletions apps/app-frontend/src/locales/en-US/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,27 @@
"instance.settings.tabs.hooks.title": {
"message": "Game launch hooks"
},
"instance.settings.tabs.hooks.variables.description": {
"message": "Hooks run in the working directory of the instance, with the following variables:"
},
"instance.settings.tabs.hooks.variables.inst-dir.description": {
"message": "$INST_DIR: The absolute path to the instance's folder"
},
"instance.settings.tabs.hooks.variables.inst-id.description": {
"message": "$INST_ID: The name of the instance's folder"
},
"instance.settings.tabs.hooks.variables.inst-java-args.description": {
"message": "$INST_JAVA_ARGS: The JVM Arguments provided to the game"
},
"instance.settings.tabs.hooks.variables.inst-java.description": {
"message": "$INST_JAVA: The absolute path to the java binary"
},
"instance.settings.tabs.hooks.variables.inst-mc-dir.description": {
"message": "$INST_MC_DIR: An alias for $INST_DIR"
},
"instance.settings.tabs.hooks.variables.inst-name.description": {
"message": "$INST_NAME: The name of the instance"
},
"instance.settings.tabs.hooks.wrapper": {
"message": "Wrapper"
},
Expand Down
123 changes: 89 additions & 34 deletions packages/app-lib/src/api/profile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -785,15 +785,84 @@ async fn run_credentials(
))
})?;

let pre_launch_hooks = profile
let pre_launch_hook = profile
.hooks
.pre_launch
.as_ref()
.or(settings.hooks.pre_launch.as_ref())
.filter(|hook_command| !hook_command.is_empty());
if let Some(hook) = pre_launch_hooks {
// TODO: hook parameters
let mut cmd = shlex::split(hook)

let java_args = profile
.extra_launch_args
.clone()
.unwrap_or(settings.extra_launch_args);

let wrapper = profile
.hooks
.wrapper
.clone()
.or(settings.hooks.wrapper)
.filter(|hook_command| !hook_command.is_empty());

let env_args = profile
.custom_env_vars
.clone()
.unwrap_or(settings.custom_env_vars);

// Post post exit hooks
let post_exit_hook = profile
.hooks
.post_exit
.clone()
.or(settings.hooks.post_exit)
.filter(|hook_command| !hook_command.is_empty());

let memory = profile.memory.unwrap_or(settings.memory);
let resolution =
profile.game_resolution.unwrap_or(settings.game_resolution);
let has_hook_commands = pre_launch_hook.is_some()
|| wrapper.is_some()
|| post_exit_hook.is_some();
let full_path = if has_hook_commands {
Some(get_full_path(&profile.path).await?)
} else {
None
};
let hook_environment = if has_hook_commands {
let full_path = full_path
.as_ref()
.expect("hooked launches always resolve their instance path");
let java_version =
crate::launcher::resolve_java_for_launch(&profile).await?;

Some(crate::launcher::hooks::HookEnvironment::from_current_env(
&env_args,
crate::launcher::hooks::HookVariables {
instance_name: profile.name.clone(),
instance_id: profile.path.clone(),
instance_dir: full_path.to_string_lossy().to_string(),
java_path: java_version.path.clone(),
java_args: crate::launcher::hooks::build_hook_java_args(
&java_args,
memory,
&java_version,
),
},
))
} else {
None
};
let launch_env_args = hook_environment
.as_ref()
.map_or_else(|| env_args.clone(), |env| env.injected_envs());

if let (Some(hook), Some(hook_environment), Some(full_path)) = (
pre_launch_hook,
hook_environment.as_ref(),
full_path.as_ref(),
) {
let expanded_hook = hook_environment.expand(hook);
let mut cmd = shlex::split(&expanded_hook)
.ok_or_else(|| {
crate::ErrorKind::LauncherError(format!(
"Invalid pre-launch command: {hook}",
Expand All @@ -802,12 +871,12 @@ async fn run_credentials(
.into_iter();

if let Some(command) = cmd.next() {
let full_path = get_full_path(&profile.path).await?;
let result = Command::new(command)
.args(cmd)
.current_dir(&full_path)
.envs(launch_env_args.iter().cloned())
.current_dir(full_path)
.spawn()
.map_err(|e| IOError::with_path(e, &full_path))?
.map_err(|e| IOError::with_path(e, full_path))?
.wait()
.await
.map_err(IOError::from)?;
Expand All @@ -822,33 +891,19 @@ async fn run_credentials(
}
}

let java_args = profile
.extra_launch_args
.clone()
.unwrap_or(settings.extra_launch_args);

let wrapper = profile
.hooks
.wrapper
.clone()
.or(settings.hooks.wrapper)
let wrapper = wrapper
.map(|hook| {
hook_environment
.as_ref()
.map_or(hook.clone(), |env| env.expand(&hook))
})
.filter(|hook_command| !hook_command.is_empty());

let memory = profile.memory.unwrap_or(settings.memory);
let resolution =
profile.game_resolution.unwrap_or(settings.game_resolution);

let env_args = profile
.custom_env_vars
.clone()
.unwrap_or(settings.custom_env_vars);

// Post post exit hooks
let post_exit_hook = profile
.hooks
.post_exit
.clone()
.or(settings.hooks.post_exit)
let post_exit_hook = post_exit_hook
.map(|hook| {
hook_environment
.as_ref()
.map_or(hook.clone(), |env| env.expand(&hook))
})
.filter(|hook_command| !hook_command.is_empty());

// Any options.txt settings that we want set, add here
Expand Down Expand Up @@ -919,7 +974,7 @@ async fn run_credentials(

crate::launcher::launch_minecraft(
&java_args,
&env_args,
&launch_env_args,
&mc_set_options,
&wrapper,
&memory,
Expand Down
Loading