1
0
Dieser Commit ist enthalten in:
Chaoscaot 2023-03-06 18:29:03 +01:00
Ursprung d352bfaded
Commit 0df001602e
9 geänderte Dateien mit 380 neuen und 133 gelöschten Zeilen

Datei anzeigen

@ -2,7 +2,15 @@
members = [ members = [
"schemsearch-cli", "schemsearch-cli",
"schemsearch-lib", "schemsearch-lib",
"schemsearch_faster",
"schemsearch-files", "schemsearch-files",
"schemsearch-sql", "schemsearch-sql",
"schemsearch-java" "schemsearch-java"
] ]
[profile.test]
inherits = "release"
lto = true
[profile.release]
lto = true

Datei anzeigen

@ -7,4 +7,5 @@ edition = "2021"
[dependencies] [dependencies]
schemsearch-lib = { path = "../schemsearch-lib" } schemsearch-lib = { path = "../schemsearch-lib" }
schemsearch-files = { path = "../schemsearch-files" } schemsearch-files = { path = "../schemsearch-files" }
clap = { version = "4.1.8", features = ["cargo"] }

Datei anzeigen

@ -1,13 +1,203 @@
use std::path::Path; use std::fmt::format;
use std::fs::File;
use std::io::{BufWriter, Stdout, StdoutLock, Write};
use clap::{command, Arg, ArgAction, ColorChoice, value_parser, Command};
use schemsearch_files::Schematic; use schemsearch_files::Schematic;
use schemsearch_lib::pattern_mapper::match_palette; use schemsearch_lib::pattern_mapper::match_palette;
use std::path::Path;
use clap::ArgAction::Help;
use clap::error::ErrorKind;
use schemsearch_lib::{search, SearchBehavior};
fn main() { fn main() {
let schematic = Schematic::load(Path::new("tests/simple.schem")); let mut cmd = command!("schemsearch")
let endstone = Schematic::load(Path::new("tests/endstone.schem")); .arg(
Arg::new("pattern")
.help("The pattern to search for")
.required(true)
.action(ArgAction::Set),
)
.arg(
Arg::new("schematic")
.help("The schematics to search in")
.required(true)
.action(ArgAction::Append),
)
.arg(
Arg::new("ignore-data")
.help("Ignores block data when searching")
.short('d')
.long("ignore-data")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("ignore-block-entities")
.help("Ignores block entities when searching")
.short('b')
.long("ignore-block-entities")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("ignore-entities")
.help("Ignores entities when searching")
.short('e')
.long("ignore-entities")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("ignore-air")
.help("Ignores air when searching")
.short('a')
.long("ignore-air")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("air-as-any")
.help("Treats air as any block when searching")
.short('A')
.long("air-as-any")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("output")
.help("The output format")
.short('o')
.long("output")
.action(ArgAction::Append)
.default_value("std")
.value_parser(["std_csv", "file_csv", "std"]),
)
.arg(
Arg::new("output-file")
.help("The output file")
.short('O')
.long("output-file")
.action(ArgAction::Append)
)
.arg(
Arg::new("threshold")
.help("The threshold for the search")
.short('t')
.long("threshold")
.action(ArgAction::Set)
.default_value("0.9")
.value_parser(|s: &str| s.parse::<f64>().map_err(|e| e.to_string())),
)
.about("Searches for a pattern in a schematic")
.bin_name("schemsearch");
let (matched_schematic, matched_endstone) = match_palette(&schematic, &endstone, true); let matches = cmd.get_matches_mut();
println!("{:?}", matched_schematic); if matches.contains_id("help") {
println!("{:?}", matched_endstone); return;
}
let search_behavior = SearchBehavior {
ignore_block_data: matches.get_flag("ignore-data"),
ignore_block_entities: matches.get_flag("ignore-block-entities"),
ignore_air: matches.get_flag("ignore-air"),
air_as_any: matches.get_flag("air-as-any"),
ignore_entities: matches.get_flag("ignore-entities"),
threshold: *matches.get_one::<f64>("threshold").expect("Couldn't get threshold"),
};
let pattern = match Schematic::load(Path::new(matches.get_one::<String>("pattern").unwrap())) {
Ok(x) => x,
Err(e) => {
cmd.error(ErrorKind::Io, format!("Error while loading Pattern: {}", e.to_string())).exit();
}
};
let schematics = matches.get_many::<String>("schematic").expect("Couldn't get schematics");
let mut output_std = false;
let mut output_std_csv = false;
let mut output_file_csv = false;
let mut output_file = false;
for x in matches.get_many::<String>("output").expect("Couldn't get output") {
match x.as_str() {
"std" => output_std = true,
"std_csv" => output_std_csv = true,
"file_csv" => output_file_csv = true,
"file" => output_file = true,
_ => {}
}
};
let mut stdout = std::io::stdout();
let mut lock = stdout.lock();
let mut file: Option<File> = None;
let mut file_out: Option<BufWriter<File>> = None;
if output_file || output_file_csv {
let output_file_path = match matches.get_one::<String>("output-file") {
None => {
cmd.error(ErrorKind::MissingRequiredArgument, "No output file specified").exit();
}
Some(x) => x
};
file = match std::fs::File::create(output_file_path) {
Ok(x) => Some(x),
Err(e) => {
cmd.error(ErrorKind::Io, format!("Error while creating output file: {}", e.to_string())).exit();
}
};
file_out = Some(BufWriter::new(file.unwrap()));
}
for schem_path in schematics {
let path = Path::new(schem_path);
if path.is_dir() {
match path.read_dir() {
Ok(x) => {
for path in x {
match path {
Ok(x) => {
if x.path().extension().unwrap_or_default() == "schem" {
search_schempath(&mut cmd, search_behavior, &pattern, &mut output_std, &mut output_std_csv, &mut output_file_csv, &mut output_file, &mut lock, &mut file_out, &x.path());
}
}
Err(e) => cmd.error(ErrorKind::Io, format!("Error while reading dir: {}", e.to_string())).exit()
}
}
}
Err(e) => cmd.error(ErrorKind::Io, "Expected to be a dir").exit()
}
} else {
search_schempath(&mut cmd, search_behavior, &pattern, &mut output_std, &mut output_std_csv, &mut output_file_csv, &mut output_file, &mut lock, &mut file_out, path)
}
}
}
fn search_schempath(cmd: &mut Command, search_behavior: SearchBehavior, pattern: &Schematic, output_std: &mut bool, output_std_csv: &mut bool, output_file_csv: &mut bool, output_file: &mut bool, stdout: &mut StdoutLock, file_out: &mut Option<BufWriter<File>>, schem_path: &Path) {
let schematic = match Schematic::load(schem_path) {
Ok(x) => x,
Err(e) => {
cmd.error(ErrorKind::Io, format!("Error while loading Schematic ({}): {}", schem_path.file_name().unwrap().to_str().unwrap(), e.to_string())).exit();
}
};
if *output_std {
writeln!(stdout, "Searching in schematic: {}", schem_path.file_name().unwrap().to_str().unwrap()).unwrap();
}
let matches = search(&schematic, &pattern, search_behavior);
for x in matches {
if *output_std {
writeln!(stdout, "Found match at x: {}, y: {}, z: {}", x.0, x.1, x.2).unwrap();
}
if *output_std_csv {
writeln!(stdout, "{},{},{},{}", schem_path.file_name().unwrap().to_str().unwrap(), x.0, x.1, x.2).unwrap();
}
if *output_file {
writeln!(file_out.as_mut().unwrap(), "Found match at x: {}, y: {}, z: {}", x.0, x.1, x.2).unwrap();
}
if *output_file_csv {
writeln!(file_out.as_mut().unwrap(), "{},{},{},{}", schem_path.file_name().unwrap().to_str().unwrap(), x.0, x.1, x.2).unwrap();
}
}
} }

Datei anzeigen

@ -1,6 +1,7 @@
use std::path::Path; use std::path::Path;
use nbt::{Map, Value}; use nbt::{Map, Value};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Deserializer, Serialize};
use serde::de::Error;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct Schematic { pub struct Schematic {
@ -22,14 +23,22 @@ pub struct Schematic {
pub palette_max: i32, pub palette_max: i32,
#[serde(rename = "Palette")] #[serde(rename = "Palette")]
pub palette: Map<String, i32>, pub palette: Map<String, i32>,
#[serde(rename = "BlockData")] #[serde(rename = "BlockData", deserialize_with = "read_blockdata")]
pub block_data: Vec<u8>, pub block_data: Vec<i32>,
#[serde(rename = "BlockEntities")] #[serde(rename = "BlockEntities")]
pub block_entities: Vec<BlockEntity>, pub block_entities: Vec<BlockEntity>,
#[serde(rename = "Entities")] #[serde(rename = "Entities")]
pub entities: Option<Vec<Entity>>, pub entities: Option<Vec<Entity>>,
} }
fn read_blockdata<'de, D>(deserializer: D) -> Result<Vec<i32>, D::Error>
where
D: Deserializer<'de>,
{
let s: Vec<u8> = Deserialize::deserialize(deserializer)?;
Ok(read_varint_array(&s))
}
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct BlockEntity { pub struct BlockEntity {
#[serde(rename = "Id")] #[serde(rename = "Id")]
@ -47,17 +56,16 @@ pub struct Entity {
} }
impl Schematic { impl Schematic {
pub fn load(path: &Path) -> Schematic { pub fn load(path: &Path) -> Result<Schematic, String> {
let file = std::fs::File::open(path).expect("Failed to open file"); let file = match std::fs::File::open(path) {
Ok(x) => x,
Err(_) => return Err(format!("Failed to open file: {}", path.display()))
};
let schematic: Schematic = match nbt::from_gzip_reader(file) { let schematic: Schematic = match nbt::from_gzip_reader(file) {
Ok(schem) => schem, Ok(schem) => schem,
Err(e) => panic!("Failed to parse schematic: {}", e), Err(e) => return Err(format!("Failed to parse schematic: {}", e))
}; };
schematic Ok(schematic)
}
pub fn read_blockdata(&self) -> Vec<i32> {
read_varint_array(&self.block_data)
} }
} }
@ -89,20 +97,3 @@ pub fn read_varint_array(read: &Vec<u8>) -> Vec<i32> {
} }
data data
} }
pub fn to_varint_array(data: &Vec<i32>) -> Vec<u8> {
let mut bytes: Vec<u8> = Vec::new();
for value in data {
let mut value = *value as u32;
'inner: loop {
if (value & 0x80) == 0 {
bytes.push(value as u8);
break 'inner;
}
bytes.push((value & 0x7F) as u8 | 0x80);
value >>= 7;
}
}
bytes
}

Datei anzeigen

@ -1,27 +1,29 @@
#![no_mangle] use std::path::Path;
use jni::JNIEnv; use jni::JNIEnv;
use jni::objects::{JClass, JString}; use jni::objects::{JClass, JString};
use jni::sys::jstring; use jni::sys::jstring;
use schemsearch_files::Schematic;
use schemsearch_lib::{search, SearchBehavior}; use schemsearch_lib::{search, SearchBehavior};
#[no_mangle]
pub extern "system" fn Java_SchemSearch_search<'local>(mut env: JNIEnv<'local>, pub extern "system" fn Java_SchemSearch_search<'local>(mut env: JNIEnv<'local>,
class: JClass<'local>, class: JClass<'local>,
schematic_path: JString<'local>, schematic_path: JString<'local>,
pattern_path: JString<'local>) -> jstring { pattern_path: JString<'local>) -> jstring {
let schematic_path: String = env.get_string(&schematic_path).expect("Couldn't get java string!").into(); let schematic_path: String = env.get_string(&schematic_path).expect("Couldn't get java string!").into();
let pattern_path: String = env.get_string(&pattern_path).expect("Couldn't get java string!").into(); let pattern_path: String = env.get_string(&pattern_path).expect("Couldn't get java string!").into();
let file = std::fs::File::open(schematic_path).expect("Failed to open file"); let schematic = Schematic::load(Path::new(&schematic_path));
let schematic = &std::io::Read::bytes(file).map(|b| b.unwrap()).collect(); let pattern = Schematic::load(Path::new(&pattern_path));
let file = std::fs::File::open(pattern_path).expect("Failed to open file");
let pattern = &std::io::Read::bytes(file).map(|b| b.unwrap()).collect();
let matches = search(schematic, pattern, SearchBehavior { let matches = search(&schematic, &pattern, SearchBehavior {
ignore_block_data: true, ignore_block_data: true,
ignore_block_entities: true, ignore_block_entities: true,
ignore_entities: true, ignore_entities: true,
ignore_air: false,
air_as_any: false,
threshold: 0.0,
}); });
let mut result = String::new(); let mut result = String::new();

Datei anzeigen

@ -1,23 +1,23 @@
pub mod pattern_mapper;
use pattern_mapper::match_palette; use pattern_mapper::match_palette;
use schemsearch_files::Schematic; use schemsearch_files::Schematic;
pub mod pattern_mapper;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct SearchBehavior { pub struct SearchBehavior {
pub ignore_block_data: bool, pub ignore_block_data: bool,
pub ignore_block_entities: bool, pub ignore_block_entities: bool,
pub ignore_air: bool,
pub air_as_any: bool,
pub ignore_entities: bool, pub ignore_entities: bool,
pub threshold: f64,
} }
pub fn search( pub fn search(
data: &Vec<u8>, schem: &Schematic,
pattern: &Vec<u8>, pattern_schem: &Schematic,
search_behavior: SearchBehavior, search_behavior: SearchBehavior,
) -> Vec<(u16, u16, u16)> { ) -> Vec<(u16, u16, u16)> {
let schem: Schematic = parse_schematic(data);
let pattern_schem: Schematic = parse_schematic(pattern);
if schem.width < pattern_schem.width || schem.height < pattern_schem.height || schem.length < pattern_schem.length { if schem.width < pattern_schem.width || schem.height < pattern_schem.height || schem.length < pattern_schem.length {
return vec![]; return vec![];
} }
@ -26,52 +26,44 @@ pub fn search(
return vec![]; return vec![];
} }
let (schem, pattern_schem) = match_palette(&schem, &pattern_schem, search_behavior.ignore_block_data); let pattern_schem = match match_palette(&schem, &pattern_schem, search_behavior.ignore_block_data) {
Some(x) => x,
None => return vec![],
};
let mut matches: Vec<(u16, u16, u16)> = Vec::new(); let mut matches: Vec<(u16, u16, u16)> = Vec::new();
println!("{:?}", schem); let pattern_data = pattern_schem.block_data;
println!("{:?}", pattern_schem); let schem_data = &schem.block_data;
let air_id = if search_behavior.ignore_air || search_behavior.air_as_any { pattern_schem.palette.get("minecraft:air").unwrap_or(&-1) } else { &-1};
let pattern_data = pattern_schem.read_blockdata(); let pattern_blocks = (pattern_schem.width * pattern_schem.height * pattern_schem.length) as f64;
let schem_data = schem.read_blockdata();
for x in 0..=schem.width - pattern_schem.width { for x in 0..=schem.width as usize - pattern_schem.width as usize {
for y in 0..=schem.height - pattern_schem.height { for y in 0..=schem.height as usize - pattern_schem.height as usize {
for z in 0..=schem.length - pattern_schem.length { for z in 0..=schem.length as usize - pattern_schem.length as usize {
let mut match_found = true; let mut matching = 0;
'outer: for i in 0..pattern_schem.width { for i in 0..pattern_schem.width as usize {
for j in 0..pattern_schem.height { for j in 0..pattern_schem.height as usize {
for k in 0..pattern_schem.length { for k in 0..pattern_schem.length as usize {
let index = (x + i) + (y + j) * schem.width + (z + k) * schem.width * schem.height; let index = (x + i) + (y + j) * (schem.width as usize) + (z + k) * (schem.width as usize) * (schem.height as usize);
let pattern_index = i + j * pattern_schem.width + k * pattern_schem.width * pattern_schem.height; let pattern_index = i + j * pattern_schem.width as usize + k * pattern_schem.width as usize * pattern_schem.height as usize;
if schem_data.get(index as usize) != pattern_data.get(pattern_index as usize) { let data = schem_data.get(index as usize).expect("Index out of bounds");
match_found = false; let pattern_data = pattern_data.get(pattern_index as usize).expect("Index out of bounds");
break 'outer; if data == pattern_data || (search_behavior.ignore_air && *data == *air_id) || (search_behavior.air_as_any && *pattern_data == *air_id) {
matching += 1;
} }
} }
} }
} }
if match_found { if matching as f64 / pattern_blocks > search_behavior.threshold {
matches.push((x, y, z)); matches.push((x as u16, y as u16, z as u16));
} }
} }
} }
} }
/*
[
0, -1, 1, 1, 2,
0, -1, 2, 1, 0,
2, -1, -1, 2, -1,
2, 0, 0, 2, -1,
2, 1, 2, 2, 1
]
*/
return matches; return matches;
} }
pub fn normalize_data(data: &String, ignore_data: bool) -> String { pub fn normalize_data(data: &String, ignore_data: bool) -> String {
@ -104,7 +96,6 @@ mod tests {
let schematic = Schematic::load(Path::new("../tests/simple.schem")); let schematic = Schematic::load(Path::new("../tests/simple.schem"));
assert_eq!(schematic.width as usize * schematic.height as usize * schematic.length as usize, schematic.block_data.len()); assert_eq!(schematic.width as usize * schematic.height as usize * schematic.length as usize, schematic.block_data.len());
assert_eq!(schematic.palette_max, schematic.palette.len() as i32); assert_eq!(schematic.palette_max, schematic.palette.len() as i32);
println!("{:?}", schematic);
} }
#[test] #[test]
@ -113,7 +104,6 @@ mod tests {
let schematic: Schematic = parse_schematic(&std::io::Read::bytes(file).map(|b| b.unwrap()).collect()); let schematic: Schematic = parse_schematic(&std::io::Read::bytes(file).map(|b| b.unwrap()).collect());
assert_eq!(schematic.width as usize * schematic.height as usize * schematic.length as usize, schematic.block_data.len()); assert_eq!(schematic.width as usize * schematic.height as usize * schematic.length as usize, schematic.block_data.len());
assert_eq!(schematic.palette_max, schematic.palette.len() as i32); assert_eq!(schematic.palette_max, schematic.palette.len() as i32);
println!("{:?}", schematic);
} }
#[test] #[test]
@ -122,7 +112,6 @@ mod tests {
let stripped = strip_data(&schematic); let stripped = strip_data(&schematic);
assert_eq!(stripped.palette.keys().any(|k| k.contains('[')), false); assert_eq!(stripped.palette.keys().any(|k| k.contains('[')), false);
println!("{:?}", stripped);
} }
#[test] #[test]
@ -130,17 +119,38 @@ mod tests {
let schematic = Schematic::load(Path::new("../tests/simple.schem")); let schematic = Schematic::load(Path::new("../tests/simple.schem"));
let endstone = Schematic::load(Path::new("../tests/endstone.schem")); let endstone = Schematic::load(Path::new("../tests/endstone.schem"));
let (matched_schematic, matched_endstone) = match_palette(&schematic, &endstone, true); let matched_schematic = match_palette(&schematic, &endstone, true);
}
println!("{:?}", matched_schematic); #[test]
println!("{:?}", matched_endstone); fn test_match_palette_ignore_data() {
let schematic = Schematic::load(Path::new("../tests/simple.schem"));
let endstone = Schematic::load(Path::new("../tests/endstone.schem"));
let matched_schematic = match_palette(&schematic, &endstone, false);
}
#[test]
pub fn test_big_search() {
let file = std::fs::File::open("../tests/simple.schem").expect("Failed to open file");
let schematic = &std::io::Read::bytes(file).map(|b| b.unwrap()).collect();
let file = std::fs::File::open("../tests/endstone.schem").expect("Failed to open file");
let pattern = &std::io::Read::bytes(file).map(|b| b.unwrap()).collect();
let matches = search(schematic, pattern, SearchBehavior {
ignore_block_data: true,
ignore_block_entities: true,
ignore_entities: true,
ignore_air: false,
air_as_any: false,
threshold: 0.9
});
} }
#[test] #[test]
pub fn test_search() { pub fn test_search() {
let file = std::fs::File::open("../tests/Random.schem").expect("Failed to open file"); let file = std::fs::File::open("../tests/Random.schem").expect("Failed to open file");
let schematic = &std::io::Read::bytes(file).map(|b| b.unwrap()).collect(); let schematic = &std::io::Read::bytes(file).map(|b| b.unwrap()).collect();
println!("{:?}", schematic);
let file = std::fs::File::open("../tests/Pattern.schem").expect("Failed to open file"); let file = std::fs::File::open("../tests/Pattern.schem").expect("Failed to open file");
let pattern = &std::io::Read::bytes(file).map(|b| b.unwrap()).collect(); let pattern = &std::io::Read::bytes(file).map(|b| b.unwrap()).collect();
@ -148,6 +158,9 @@ mod tests {
ignore_block_data: true, ignore_block_data: true,
ignore_block_entities: true, ignore_block_entities: true,
ignore_entities: true, ignore_entities: true,
ignore_air: false,
air_as_any: false,
threshold: 0.9
}); });
println!("{:?}", matches); println!("{:?}", matches);

Datei anzeigen

@ -1,5 +1,5 @@
use nbt::Map; use nbt::Map;
use schemsearch_files::{Schematic, to_varint_array}; use schemsearch_files::Schematic;
use crate::normalize_data; use crate::normalize_data;
fn create_reverse_palette(schem: &Schematic) -> Vec<String> { fn create_reverse_palette(schem: &Schematic) -> Vec<String> {
@ -17,7 +17,7 @@ pub fn strip_data(schem: &Schematic) -> Schematic {
let mut palette: Map<String, i32> = Map::new(); let mut palette: Map<String, i32> = Map::new();
let mut palette_max: i32 = 0; let mut palette_max: i32 = 0;
let reverse_palette = create_reverse_palette(schem); let reverse_palette = create_reverse_palette(schem);
let dat = schem.read_blockdata(); let dat = &schem.block_data;
for block in dat.iter() { for block in dat.iter() {
let block_name = reverse_palette[*block as usize].clone(); let block_name = reverse_palette[*block as usize].clone();
@ -36,7 +36,7 @@ pub fn strip_data(schem: &Schematic) -> Schematic {
data_version: schem.data_version, data_version: schem.data_version,
palette, palette,
palette_max, palette_max,
block_data: to_varint_array(&data), block_data: data,
block_entities: schem.block_entities.clone(), block_entities: schem.block_entities.clone(),
height: schem.height, height: schem.height,
length: schem.length, length: schem.length,
@ -47,24 +47,27 @@ pub fn strip_data(schem: &Schematic) -> Schematic {
} }
} }
fn match_palette_adapt(schem: &Schematic, matching_palette: Map<String, i32>, ignore_data: bool) -> Vec<i32> { fn match_palette_adapt(schem: &Schematic, matching_palette: &Map<String, i32>, ignore_data: bool) -> Option<Vec<i32>> {
let mut data: Vec<i32> = Vec::new(); let mut data: Vec<i32> = Vec::new();
for x in schem.read_blockdata().iter() { for x in schem.block_data.iter() {
let blockname = schem.palette.iter().find(|(_, &v)| v == *x).expect("Invalid Schematic").0; let blockname = schem.palette.iter().find(|(_, &v)| v == *x).expect("Invalid Schematic").0;
let blockname = if ignore_data { normalize_data(&blockname, ignore_data) } else { blockname.clone() }; let blockname = if ignore_data { normalize_data(&blockname, ignore_data) } else { blockname.clone() };
let block_id = matching_palette.get(&blockname).unwrap_or(&-1); let block_id = match matching_palette.get(&blockname) {
None => return None,
Some(x) => x
};
data.push(*block_id); data.push(*block_id);
} }
data Some(data)
} }
pub fn match_palette( pub fn match_palette(
schem: &Schematic, schem: &Schematic,
pattern: &Schematic, pattern: &Schematic,
ignore_data: bool, ignore_data: bool,
) -> (Schematic, Schematic) { ) -> Option<Schematic> {
if ignore_data { if ignore_data {
match_palette_internal(&strip_data(schem), &strip_data(pattern), ignore_data) match_palette_internal(&strip_data(schem), &strip_data(pattern), ignore_data)
} else { } else {
@ -76,46 +79,21 @@ fn match_palette_internal(
schem: &Schematic, schem: &Schematic,
pattern: &Schematic, pattern: &Schematic,
ignore_data: bool, ignore_data: bool,
) -> (Schematic, Schematic) { ) -> Option<Schematic> {
if pattern.palette.iter().any(|(k, _)| schem.palette.get(k).is_none()) {
if schem.palette.len() < pattern.palette.len() { return None;
panic!("Schematic palette is larger than pattern palette");
} }
let mut matching_palette: Map<String, i32> = Map::new(); let data_pattern: Vec<i32> = match match_palette_adapt(&pattern, &schem.palette, ignore_data) {
let mut matching_palette_max: i32 = 0; None => return None,
Some(x) => x
for (block_name, _) in pattern.palette.iter() {
let block_name = normalize_data(block_name, true);
let schem_block_id = pattern.palette.get(&block_name).expect("Pattern block not found in schematic palette");
matching_palette.insert(block_name, *schem_block_id);
matching_palette_max += 1;
}
let data_schem: Vec<i32> = match_palette_adapt(&schem, matching_palette.clone(), true);
let data_pattern: Vec<i32> = match_palette_adapt(&pattern, matching_palette.clone(), true);
let schem = Schematic {
version: schem.version.clone(),
data_version: schem.data_version.clone(),
palette: matching_palette.clone(),
palette_max: matching_palette_max.clone(),
block_data: to_varint_array(&data_schem),
block_entities: schem.block_entities.clone(),
height: schem.height.clone(),
length: schem.length.clone(),
width: schem.width.clone(),
metadata: schem.metadata.clone(),
offset: schem.offset.clone(),
entities: None,
}; };
let pattern = Schematic { Some(Schematic {
version: pattern.version.clone(), version: pattern.version.clone(),
data_version: pattern.data_version.clone(), data_version: pattern.data_version.clone(),
palette: matching_palette.clone(), palette: schem.palette.clone(),
palette_max: matching_palette_max.clone(), palette_max: schem.palette_max,
block_data: to_varint_array(&data_pattern), block_data: data_pattern,
block_entities: pattern.block_entities.clone(), block_entities: pattern.block_entities.clone(),
height: pattern.height.clone(), height: pattern.height.clone(),
length: pattern.length.clone(), length: pattern.length.clone(),
@ -123,7 +101,5 @@ fn match_palette_internal(
metadata: pattern.metadata.clone(), metadata: pattern.metadata.clone(),
offset: pattern.offset.clone(), offset: pattern.offset.clone(),
entities: None, entities: None,
}; })
(schem, pattern)
} }

Datei anzeigen

@ -0,0 +1,11 @@
[package]
name = "schemsearch_faster"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
schemsearch-lib = { path = "../schemsearch-lib" }
schemsearch-files = { path = "../schemsearch-files" }
hematite-nbt = "0.5.2"

Datei anzeigen

@ -0,0 +1,55 @@
use nbt::Map;
use schemsearch_files::Schematic;
pub fn convert_to_search_space(schem: &Schematic, palette: &Vec<String>) -> Vec<Vec<u8>> {
let mut data: Vec<Vec<u8>> = Vec::with_capacity(palette.len());
let block_data = &schem.block_data;
for name in palette {
let mut output: Vec<u8> = Vec::with_capacity(block_data.len());
for block in block_data.iter() {
if schem.palette.get(name).unwrap_or(&-1) == block {
output.push(1);
} else {
output.push(0);
}
}
data.push(output);
}
data
}
pub fn unwrap_palette(palette: &Map<String, i32>) -> Vec<String> {
let mut output: Vec<String> = Vec::with_capacity(palette.len());
(0..palette.len()).for_each(|_| output.push(String::new()));
for (key, id) in palette.iter() {
output[*id as usize] = key.clone();
}
output
}
#[allow(unused_imports)]
mod tests {
use std::path::Path;
use schemsearch_files::Schematic;
use crate::{convert_to_search_space, unwrap_palette};
#[test]
pub fn test() {
let schematic = Schematic::load(Path::new("../tests/Pattern.schem"));
dbg!(convert_to_search_space(&schematic, &unwrap_palette(&schematic.palette)));
}
#[test]
pub fn test_2() {
let schematic = Schematic::load(Path::new("../tests/Pattern.schem"));
let schematic2 = Schematic::load(Path::new("../tests/Random.schem"));
println!("{:?}", convert_to_search_space(&schematic2, &unwrap_palette(&schematic.palette)));
}
#[test]
pub fn test_big() {
let schematic = Schematic::load(Path::new("../tests/endstone.schem"));
let schematic2 = Schematic::load(Path::new("../tests/simple.schem"));
let _ = convert_to_search_space(&schematic2, &unwrap_palette(&schematic.palette));
}
}