summaryrefslogtreecommitdiffstats
path: root/src/launcher/runner.rs
blob: 4d07f208e4ec7990a97fc6003ef00ab94ded34e0 (plain) (blame)
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
use std::borrow::Cow;
use std::ffi::OsString;
use std::iter;
use crate::version::{CompleteVersion, FeatureMatcher};
use super::rules::CompatCheck;
use super::strsub::{self, SubFunc};
use super::LaunchInfo;

#[derive(Clone, Copy)]
struct LaunchArgSub<'a: 'l, '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().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.to_string_lossy()),
            "game_directory" => Some(self.0.instance_home.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.to_string_lossy()),
            "natives_directory" => Some(self.0.natives_path.to_string_lossy()),
            "primary_jar" => self.0.client_jar.as_ref().map(|p| p.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).to_string_lossy().into_owned()))
                }

                None
            }
        }
    }
}

#[derive(Clone, Copy)]
pub enum ArgumentType {
    JVM,
    Game
}

struct OptionalIterator<I>
where
    I: Iterator
{
    opt: Option<I>
}

impl<I: Iterator> Iterator for OptionalIterator<I> {
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        match self.opt {
            Some(ref mut i) => i.next(),
            None => None
        }
    }
}

impl<II: IntoIterator> From<Option<II>> for OptionalIterator<II::IntoIter> {
    fn from(opt: Option<II>) -> Self {
        OptionalIterator {
            opt: opt.map(IntoIterator::into_iter)
        }
    }
}

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()
            .flat_map(|wa| OptionalIterator::from(wa.rules_apply(system_info, launch.feature_matcher).ok().map(|_| &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 => {
                todo!()
            }
            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()
    }
}