feat(debug): 支持网易 Minecraft 调试启动
新增 debug 子命令,自动准备开发世界、注册内置调试 MOD,并将项目行为包和资源包链接到网易运行目录,方便启动游戏后直接进入调试世界。 调试 MOD 资源随仓库一起嵌入,避免依赖本机绝对路径;Windows junction 写入剥离 verbatim 前缀后的 DOS 路径,保证 Minecraft 能正确读取链接包。
This commit is contained in:
51
build.rs
51
build.rs
@@ -6,10 +6,21 @@ use std::{
|
||||
|
||||
const EMPTY_DIRS_FILE: &str = ".empty-dirs";
|
||||
|
||||
const DEBUG_MOD_ROOT: &str = "debug_mod";
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=examples");
|
||||
println!("cargo:rerun-if-changed={}", DEBUG_MOD_ROOT);
|
||||
|
||||
let examples_root = PathBuf::from("examples");
|
||||
let debug_mod_root = PathBuf::from(DEBUG_MOD_ROOT);
|
||||
if !debug_mod_root.is_dir() {
|
||||
panic!(
|
||||
"required debug MOD resource directory was not found: {}",
|
||||
DEBUG_MOD_ROOT
|
||||
);
|
||||
}
|
||||
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR is not set"));
|
||||
let out_file = out_dir.join("embedded_examples.rs");
|
||||
|
||||
@@ -17,6 +28,8 @@ fn main() {
|
||||
let mut files = Vec::new();
|
||||
let mut empty_dirs_by_example = BTreeMap::new();
|
||||
|
||||
let mut debug_mod_files = Vec::new();
|
||||
|
||||
if examples_root.is_dir() {
|
||||
collect_examples(
|
||||
&examples_root,
|
||||
@@ -27,6 +40,8 @@ fn main() {
|
||||
)
|
||||
.expect("failed to collect example templates");
|
||||
}
|
||||
collect_files(&debug_mod_root, &debug_mod_root, &mut debug_mod_files)
|
||||
.expect("failed to collect debug MOD resources");
|
||||
|
||||
dirs.sort();
|
||||
dirs.dedup();
|
||||
@@ -35,6 +50,7 @@ fn main() {
|
||||
empty_dirs.sort();
|
||||
empty_dirs.dedup();
|
||||
}
|
||||
debug_mod_files.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
|
||||
let mut generated = String::new();
|
||||
generated.push_str(
|
||||
@@ -45,7 +61,8 @@ fn main() {
|
||||
generated.push_str(&format!(" {:?},\n", dir));
|
||||
}
|
||||
generated.push_str("];\n\n");
|
||||
generated.push_str("#[allow(dead_code)]\nstatic EMBEDDED_EXAMPLE_FILES: &[EmbeddedFile] = &[\n");
|
||||
generated
|
||||
.push_str("#[allow(dead_code)]\nstatic EMBEDDED_EXAMPLE_FILES: &[EmbeddedFile] = &[\n");
|
||||
for (relative_path, absolute_path) in &files {
|
||||
generated.push_str(&format!(
|
||||
" EmbeddedFile {{ path: {:?}, contents: include_bytes!(r#\"{}\"#) }},\n",
|
||||
@@ -70,9 +87,39 @@ fn main() {
|
||||
}
|
||||
generated.push_str(" ] },\n");
|
||||
}
|
||||
generated.push_str("];\n\n");
|
||||
|
||||
generated
|
||||
.push_str("#[allow(dead_code)]\nstatic EMBEDDED_DEBUG_MOD_FILES: &[EmbeddedFile] = &[\n");
|
||||
for (relative_path, absolute_path) in &debug_mod_files {
|
||||
generated.push_str(&format!(
|
||||
" EmbeddedFile {{ path: {:?}, contents: include_bytes!(r#\"{}\"#) }},\n",
|
||||
relative_path,
|
||||
absolute_path.display()
|
||||
));
|
||||
}
|
||||
generated.push_str("];\n");
|
||||
|
||||
fs::write(out_file, generated).expect("failed to write embedded example list");
|
||||
fs::write(out_file, generated).expect("failed to write embedded resource list");
|
||||
}
|
||||
|
||||
fn collect_files(root: &Path, dir: &Path, files: &mut Vec<(String, PathBuf)>) -> io::Result<()> {
|
||||
for entry in fs::read_dir(dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
collect_files(root, &path, files)?;
|
||||
} else if path.is_file() {
|
||||
let relative_path = path
|
||||
.strip_prefix(root)
|
||||
.expect("embedded resource path is outside root")
|
||||
.to_string_lossy()
|
||||
.replace('\\', "/");
|
||||
files.push((relative_path, path.canonicalize()?));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn collect_examples(
|
||||
|
||||
Reference in New Issue
Block a user