1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
use std::borrow::Cow;
use std::ffi::{OsStr, OsString};
use std::iter;
use std::process::Command;
use crate::util::AsJavaPath;
use crate::version::{CompleteVersion, FeatureMatcher, OperatingSystem};
use super::rules::CompatCheck;
use super::strsub::{self, SubFunc};
use super::{Launch, LaunchInfo};
#[derive(Clone, Copy)]
struct LaunchArgSub<'a, 'l, F: FeatureMatcher>(&'a LaunchInfo<'l, F>);
impl<'rep, 'l, F: FeatureMatcher> SubFunc<'rep> for LaunchArgSub<'rep, 'l, F> {
fn substitute(&self, key: &str) -> Option<Cow<'rep, str>> {
match key {
"assets_index_name" => self.0.asset_index_name.as_ref().map(|s| Cow::Borrowed(s.as_str())),
"assets_root" => Some(self.0.launcher.assets.get_home().as_java_path().to_string_lossy()),
"auth_access_token" => Some(Cow::Borrowed("-")), // TODO
"auth_player_name" => Some(Cow::Borrowed("Player")), // TODO
"auth_session" => Some(Cow::Borrowed("-")), // TODO
"auth_uuid" => Some(Cow::Borrowed("00000000-0000-0000-0000-000000000000")), // TODO
"auth_xuid" => Some(Cow::Borrowed("00000000-0000-0000-0000-000000000000")), // TODO
"classpath" => Some(Cow::Borrowed(self.0.classpath.as_str())), // TODO
"classpath_separator" => None, // FIXME
"game_assets" => self.0.virtual_assets_path.as_ref()
.map(|s| s.as_path().as_java_path().to_string_lossy()),
"game_directory" => Some(self.0.instance_home.as_java_path().to_string_lossy()),
"language" => Some(Cow::Borrowed("en-us")), // ???
"launcher_name" => Some(Cow::Borrowed("ozone (olauncher 3)")), // TODO
"launcher_version" => Some(Cow::Borrowed("yeah")), // TODO
"library_directory" => Some(self.0.launcher.libraries.home.as_java_path().to_string_lossy()),
"natives_directory" => Some(self.0.natives_path.as_java_path().to_string_lossy()),
"primary_jar" => self.0.client_jar.as_ref().map(|p| p.as_path().as_java_path().to_string_lossy()),
"quickPlayMultiplayer" => None, // TODO
"quickPlayPath" => None, // TODO
"quickPlayRealms" => None, // TODO
"quickPlaySingleplayer" => None, // TODO
"resolution_height" => None, // TODO
"resolution_width" => None, // TODO
"user_properties" => Some(Cow::Borrowed("{}")), // TODO
"user_property_map" => Some(Cow::Borrowed("[]")), // TODO
"user_type" => Some(Cow::Borrowed("legacy")), // TODO
"version_name" => Some(Cow::Borrowed(&self.0.version_id.as_ref())),
"version_type" => self.0.version_type.as_ref().map(|s| Cow::Borrowed(s.to_str())),
_ => {
if let Some(asset_key) = key.strip_prefix("asset=") {
return self.0.asset_index.as_ref()
.map_or(None, |idx| idx.objects.get(asset_key))
.map(|obj| Cow::Owned(self.0.launcher.assets.get_object_path(obj).as_java_path().to_string_lossy().into_owned()))
}
None
}
}
}
}
#[derive(Clone, Copy)]
pub enum ArgumentType {
JVM,
Game
}
pub fn build_arguments<'l, F: FeatureMatcher>(launch: &LaunchInfo<'l, F>, version: &CompleteVersion, arg_type: ArgumentType) -> Vec<OsString> {
let sub = LaunchArgSub(launch);
let system_info = &launch.launcher.system_info;
if let Some(arguments) = version.arguments.as_ref().map_or(None, |args| match arg_type {
ArgumentType::JVM => args.jvm.as_ref(),
ArgumentType::Game => args.game.as_ref()
}) {
arguments.iter()
.filter(|wa| wa.rules_apply(system_info, launch.feature_matcher).is_ok())
.flat_map(|wa| &wa.value)
.map(|s| OsString::from(strsub::replace_string(s, &sub).into_owned())).collect()
} else if let Some(arguments) = version.minecraft_arguments.as_ref() {
match arg_type {
ArgumentType::JVM => {
[
"-Djava.library.path=${natives_directory}",
"-Dminecraft.launcher.brand=${launcher_name}",
"-Dminecraft.launcher.version=${launcher_version}",
"-Dminecraft.client.jar=${primary_jar}",
"-cp",
"${classpath}"
].into_iter()
.chain(iter::once("-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump")
.take_while(|_| system_info.os == OperatingSystem::Windows))
.chain(iter::once(["-Dos.name=Windows 10", "-Dos.version=10.0"])
.take_while(|_| launch.feature_matcher.matches("__ozone_win10_hack"))
.flatten())
.chain(iter::once(["-Xdock:icon=${asset=icons/minecraft.icns}", "-Xdock:name=Minecraft"])
.take_while(|_| system_info.os == OperatingSystem::MacOS)
.flatten())
.map(|s| OsString::from(strsub::replace_string(s, &sub).into_owned()))
.collect()
},
ArgumentType::Game => {
arguments.split(' ')
.chain(iter::once("--demo")
.take_while(|_| launch.feature_matcher.matches("is_demo_user")))
.chain(iter::once(["--width", "${resolution_width}", "--height", "${resolution_height}"])
.take_while(|_| launch.feature_matcher.matches("has_custom_resolution"))
.flatten())
.map(|s| OsString::from(strsub::replace_string(s, &sub).into_owned()))
.collect()
}
}
} else {
Vec::default()
}
}
pub fn run_the_game(launch: &Launch) -> Result<(), Box<dyn std::error::Error>> {
Command::new("java")
.args(launch.jvm_args.iter()
.map(|o| o.as_os_str())
.chain(iter::once(OsStr::new(launch.main_class.as_str())))
.chain(launch.game_args.iter().map(|o| o.as_os_str())))
.current_dir(launch.instance_path.as_path().as_java_path()).spawn()?.wait()?;
Ok(())
}
|