cobble_core/minecraft/models/
library.rs1use crate::consts;
2use crate::minecraft::models::{LibraryDownloads, LibraryExtract, LibraryNatives, Rule};
3use crate::utils::Architecture;
4use serde::{Deserialize, Serialize};
5use std::path::{Path, PathBuf};
6
7#[derive(Clone, Debug, Deserialize, Serialize)]
9pub struct Library {
10 pub downloads: LibraryDownloads,
12 pub name: String,
14 pub natives: Option<LibraryNatives>,
16 #[serde(default)]
18 pub rules: Vec<Rule>,
19 pub extract: Option<LibraryExtract>,
21}
22
23impl Library {
24 pub fn check_use(&self) -> bool {
26 for rule in &self.rules {
27 if !rule.allows() {
28 return false;
29 }
30 }
31
32 true
33 }
34
35 pub fn jar_name(&self) -> String {
37 let split = self.split_name();
38 let parts = split.iter().skip(1).take(2).cloned();
40 let suffixes = split.iter().skip(3).cloned();
42
43 let mut name = vec![];
44
45 name.extend(parts);
47
48 if let Some(native) = self.get_native() {
50 name.push(native);
51 }
52
53 name.extend(suffixes);
55
56 let mut name = name.join("-");
57 name.push_str(".jar");
58
59 name
60 }
61
62 pub fn library_path(&self, libraries_path: impl AsRef<Path>) -> PathBuf {
65 let mut library_path = PathBuf::from(libraries_path.as_ref());
66
67 library_path.push(self.relative_library_path());
68
69 library_path
70 }
71
72 pub fn relative_library_path(&self) -> PathBuf {
75 let path_parts = self.split_name().into_iter().take(3);
77
78 let mut library_path = PathBuf::new();
79 for (i, path_part) in path_parts.enumerate() {
80 let part = match i {
81 0 => path_part.replace('.', "/"),
82 _ => path_part,
83 };
84
85 library_path.push(part);
86 }
87
88 library_path
89 }
90
91 pub fn jar_path(&self, libraries_path: impl AsRef<Path>) -> PathBuf {
93 let mut jar_path = self.library_path(&libraries_path);
94 jar_path.push(self.jar_name());
95
96 jar_path
97 }
98
99 pub fn relative_jar_path(&self) -> PathBuf {
101 let mut jar_path = self.relative_library_path();
102 jar_path.push(self.jar_name());
103
104 jar_path
105 }
106
107 pub fn download_url(&self) -> (String, Option<String>, Option<usize>) {
110 let url: String;
111 let mut sha1 = None;
112 let mut size = None;
113
114 match &self.get_native() {
115 Some(native) => match self.downloads.classifiers.get(native) {
116 Some(file) => {
117 url = file.url.clone();
118 sha1 = Some(file.sha1.clone());
119 size = Some(file.size);
120 }
121 None => {
122 url = self.build_url_from_name();
123 }
124 },
125 None => match &self.downloads.artifact {
126 Some(file) => {
127 url = file.url.clone();
128 sha1 = Some(file.sha1.clone());
129 size = Some(file.size);
130 }
131 None => {
132 url = self.build_url_from_name();
133 }
134 },
135 }
136
137 (url, sha1, size)
138 }
139
140 pub fn needs_extract(&self) -> bool {
142 self.get_native().is_some() && self.extract.is_some()
143 }
144
145 fn build_url_from_name(&self) -> String {
146 let parts = self.split_name().into_iter().take(3);
148
149 let mut url = vec![consts::MC_LIBRARIES_BASE_URL.to_string()];
150
151 for (i, part) in parts.enumerate() {
152 if i == 0 {
153 url.push(part.replace('.', "/"));
154 } else {
155 url.push(part);
156 }
157 }
158
159 url.push(self.jar_name());
160
161 url.join("/")
162 }
163
164 pub fn get_native(&self) -> Option<String> {
166 let arch = Architecture::current();
167
168 self.natives.as_ref().and_then(|natives| {
169 natives
170 .get_for_current_platform()
171 .map(|n| n.replace("${arch}", &arch.get_bits().to_string()))
172 })
173 }
174
175 fn split_name(&self) -> Vec<String> {
176 self.name.split(':').map(String::from).collect()
177 }
178}