Skip to content

Commit 8644531

Browse files
committed
mcpelauncher support
1 parent 763bc4d commit 8644531

4 files changed

Lines changed: 194 additions & 249 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,10 @@ ctor = "0.4"
99
log = "0.4"
1010
serde = { version = "1.0", features = ["derive"] }
1111
serde_json = "1.0"
12+
libc = "0.2"
1213

1314
[target.'cfg(target_os = "android")'.dependencies]
1415
jni = "0.21"
15-
elf = "0.8"
16-
17-
[target.'cfg(target_os = "linux")'.dependencies]
18-
elf = "0.8"
1916

2017
[target.'cfg(target_os = "windows")'.dependencies]
2118
windows-sys = { version = "0.52", features = [

src/config.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,38 @@ static CONFIG_DIR: OnceLock<String> = OnceLock::new();
1111
const CONFIG_FILE: &str = "dimensions.json";
1212
const LOG_FILE: &str = "log.txt";
1313

14-
pub fn config_path() -> Option<PathBuf> { CONFIG_DIR.get().map(|d| Path::new(d).join(CONFIG_FILE)) }
15-
pub fn log_path() -> Option<PathBuf> { CONFIG_DIR.get().map(|d| Path::new(d).join(LOG_FILE)) }
14+
pub fn config_path() -> Option<PathBuf> {
15+
CONFIG_DIR.get().map(|d| Path::new(d).join(CONFIG_FILE))
16+
}
17+
pub fn log_path() -> Option<PathBuf> {
18+
CONFIG_DIR.get().map(|d| Path::new(d).join(LOG_FILE))
19+
}
1620

17-
fn set_config_dir(path: String) { if CONFIG_DIR.set(path).is_err() { log::error!("CONFIG_DIR can only be set once"); } }
21+
fn set_config_dir(path: String) {
22+
if CONFIG_DIR.set(path).is_err() { log::error!("CONFIG_DIR can only be set once"); }
23+
}
1824

1925
pub fn save() -> Result<(), ()> {
2026
let defaults: BuildLimitMap = [
2127
("Overworld", BuildLimit { min: -64, max: 320 }),
2228
("Nether", BuildLimit { min: 0, max: 128 }),
2329
("TheEnd", BuildLimit { min: 0, max: 256 })
2430
].into_iter().map(|(k,v)| (k.to_string(), v)).collect();
25-
fs::write(config_path().ok_or_else(|| { log::error!("CONFIG_DIR is not set"); () })?,serde_json::to_string_pretty(&defaults).map_err(|e| log::error!("Serialize failed: {e}"))?)
31+
fs::write(config_path().ok_or_else(
32+
|| { log::error!("CONFIG_DIR is not set"); () })?,
33+
serde_json::to_string_pretty(&defaults)
34+
.map_err(|e| log::error!("Serialize failed: {e}"))?)
2635
.map_err(|e| log::error!("Write failed: {e}"))?;
2736
Ok(())
2837
}
2938

3039
pub fn load() -> BuildLimitMap {
3140
let path = match config_path() {
3241
Some(p) => p,
33-
None => { log::error!("CONFIG_DIR not set"); return BuildLimitMap::new(); }
42+
None => {
43+
log::error!("CONFIG_DIR not set");
44+
return BuildLimitMap::new();
45+
}
3446
};
3547
let content = fs::read_to_string(&path).unwrap_or_else(|_| {
3648
save().ok();
@@ -42,17 +54,11 @@ pub fn load() -> BuildLimitMap {
4254
})
4355
}
4456

45-
#[cfg_attr(target_os = "android", no_mangle)]
46-
pub fn init_config(#[cfg(target_os = "android")] env: &mut jni::JNIEnv) {
47-
let mut path = (|| { crate::utils::get_config_directory(#[cfg(target_os = "android")] env) })().unwrap_or_else(|| {
48-
log::error!("Failed to get a valid config directory");
49-
String::new()
50-
});
51-
57+
pub fn init_config(path: &mut String) {
5258
path.push_str("/BuildLimitChanger/");
53-
if !is_dir_writable(&path) { log::error!("Config directory not writable: {}", path); return; }
54-
set_config_dir(path.clone());
55-
if !config_path().map_or(false, |p| p.exists()) {
56-
save().ok();
59+
if !is_dir_writable(&path) {
60+
return log::error!("Config directory not writable: {}", path);
5761
}
62+
set_config_dir(path.clone());
63+
if !config_path().map_or(false, |p| p.exists()) { save().ok(); }
5864
}

src/lib.rs

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1+
#![allow(non_snake_case)]
12
mod config;
23
mod hook;
34
mod logger;
45
mod utils;
56

6-
use std::time::Instant;
7-
87
fn find_water_mob_cap_and_fn_starts(data: &[u8]) -> (Option<usize>, Vec<usize>) {
98
let mut seen_ret = false;
109
let mut possible_fn_starts = Vec::new();
@@ -15,7 +14,6 @@ fn find_water_mob_cap_and_fn_starts(data: &[u8]) -> (Option<usize>, Vec<usize>)
1514
#[cfg(target_arch = "aarch64")] {
1615
const MASKS: [u32; 3] = [0xFFFF_FC1F, 0xFFFF_FFE0, 0xFF00_0000];
1716
const PATTERNS: [u32; 3] = [0xD65F_0000, 0x52A8_4200, 0xD100_0000];
18-
1917
for inst in data.chunks_exact(4) {
2018
let addr = inst.as_ptr() as usize;
2119
let instr = u32::from_le_bytes(inst.try_into().unwrap());
@@ -45,7 +43,6 @@ fn find_water_mob_cap_and_fn_starts(data: &[u8]) -> (Option<usize>, Vec<usize>)
4543
let mut instruction = Instruction::default();
4644

4745
const TARGET_IMMEDIATE: u64 = 0x42100000;
48-
4946
while decoder.can_decode() {
5047
decoder.decode_out(&mut instruction);
5148

@@ -83,43 +80,49 @@ fn find_water_mob_cap_and_fn_starts(data: &[u8]) -> (Option<usize>, Vec<usize>)
8380
(water_mob_cap, possible_fn_starts)
8481
}
8582

86-
#[ctor::ctor]
83+
#[cfg_attr(target_os = "android", no_mangle)]
8784
fn init() {
88-
println!("Starting BuildLimitChanger");
89-
let time_start = Instant::now();
90-
log::set_logger(&logger::LOGGER).expect("Logger already set");
91-
log::set_max_level(log::LevelFilter::Debug);
92-
93-
#[cfg(any(target_os = "windows", target_os = "linux"))] {
94-
crate::config::init_config();
95-
crate::logger::init_log_file(false);
96-
}
97-
let mcmap = utils::find_minecraft_text_section().expect("Cannot find Minecraft .text section");
85+
let time_start = std::time::Instant::now();
86+
let mcmap = utils::find_minecraft_text_section().unwrap_or_else(|e| { panic!("Cannot find Minecraft .text section: {}", e.to_string()) });
9887
let data = unsafe { std::slice::from_raw_parts(mcmap.start as *const u8, mcmap.size) };
99-
10088
let (water_mob_cap, possible_fn_starts) = find_water_mob_cap_and_fn_starts(data);
101-
102-
if water_mob_cap.is_none() {
103-
log::error!("Cannot find the water mob cap");
104-
return;
105-
}
89+
if water_mob_cap.is_none() { return log::error!("Cannot find the water mob cap"); }
10690
let Some(function_addr) = utils::find_max_less_than(&possible_fn_starts, water_mob_cap.unwrap()) else {
107-
log::error!("Cannot get the function where water mob cap is located");
108-
return;
91+
return log::error!("Cannot get the function where water mob cap is located");
10992
};
11093
log::debug!("Function Offset: 0x{:X}", function_addr);
11194
log::debug!("{:02X?}", &data[function_addr - mcmap.start..(function_addr - mcmap.start + 10).min(data.len())]);
112-
11395
hook::setup_hook(function_addr);
11496
log::debug!("{:02X?}", &data[function_addr - mcmap.start..(function_addr - mcmap.start + 10).min(data.len())]);
11597
log::info!("Took: {:?}", time_start.elapsed());
11698
}
11799

100+
#[ctor::ctor]
101+
fn main() {
102+
println!("Starting BuildLimitChanger");
103+
log::set_logger(&logger::LOGGER).expect("Logger already set");
104+
log::set_max_level(log::LevelFilter::Debug);
105+
#[cfg(any(target_os = "linux", target_os = "windows"))] {
106+
config::init_config(&mut utils::get_config_directory().expect("Failed to get a valid config directory"));
107+
logger::init_log_file(false);
108+
init();
109+
}
110+
}
111+
112+
#[cfg(target_os = "android")]
113+
#[no_mangle]
114+
pub extern "C" fn mod_init() {
115+
config::init_config(&mut String::from("/data/data/com.mojang.minecraftpe"));
116+
logger::init_log_file(false);
117+
init();
118+
}
119+
118120
#[cfg(target_os = "android")]
119121
#[no_mangle]
120122
pub extern "system" fn JNI_OnLoad(vm: jni::JavaVM, _: *mut core::ffi::c_void) -> i32 {
121123
let mut env = vm.get_env().expect("Cannot get reference to the JNIEnv");
122-
config::init_config(&mut env);
123-
logger::init_log_file(crate::utils::is_levi_launcher(&mut env));
124+
config::init_config(&mut utils::get_config_directory(&mut env).expect("Failed to get a valid config directory"));
125+
logger::init_log_file(utils::is_levi_launcher(&mut env));
126+
init();
124127
return jni::sys::JNI_VERSION_1_6;
125128
}

0 commit comments

Comments
 (0)