22 Commits

Author SHA1 Message Date
e7c1fd1ef7 Fixing Something? 2023-04-05 00:33:21 +02:00
80eeaad5d5 Add output for machines 2023-04-04 22:38:02 +02:00
64158cf45b Remove Timer from Progressbar 2023-04-04 21:44:43 +02:00
e4b26755ea Revert "Print Progressbar to stdout"
This reverts commit 5607dcc72c.
2023-04-04 17:34:12 +02:00
5607dcc72c Print Progressbar to stdout 2023-04-04 17:29:04 +02:00
5c9bcfc2ec Add SQL to Makefile 2023-04-04 16:31:48 +02:00
1df33249c4 Add Makefile for easier building 2023-04-04 00:36:40 +02:00
ef2755115c Fix tests 2023-04-01 11:14:44 +02:00
b32aac0aba Fix naming and Tests 2023-04-01 11:08:57 +02:00
a9a3e70aef Update Roadmap 2023-04-01 11:07:12 +02:00
c477a52f92 Slowdown ProgressBar and add Stderr as output 2023-04-01 11:02:49 +02:00
818de6be47 Abstractions 2023-04-01 10:30:25 +02:00
8f15b42146 Add Issue Templates 2023-03-21 18:31:50 +01:00
b8d912881d Fix SQL-Interface 2023-03-19 21:18:40 +01:00
02404792a5 Bump Version 2023-03-19 11:59:39 +01:00
59272ed3e7 Add Complex Output Patterns 2023-03-19 11:57:22 +01:00
322ba65656 Add Caches 2023-03-18 10:27:34 +01:00
b082d6cd8d Fix Imports 2023-03-16 21:33:23 +01:00
f4bcde73f9 Add Roadmap 2023-03-16 21:09:41 +01:00
0e31714582 Add Roadmap 2023-03-16 21:08:56 +01:00
229c858d9a Optimize Workflows 2023-03-16 20:40:37 +01:00
abf6953172 Optimize Workflows 2023-03-16 20:40:17 +01:00
22 changed files with 435 additions and 103 deletions

40
.github/ISSUE_TEMPLATE/bug.yml vendored Normal file
View File

@ -0,0 +1,40 @@
name: Bug Report
description: Create a report to fix a bug
labels: [bug]
title: "[BUG] <title>"
body:
- type: textarea
id: description
attributes:
label: Description
description: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: Steps to reproduce the behavior.
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual Behavior
description: A clear and concise description of what actually happened.
validations:
required: true
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context about the problem here.
validations:
required: false

35
.github/ISSUE_TEMPLATE/feature.yml vendored Normal file
View File

@ -0,0 +1,35 @@
name: Feature Request
description: Suggest an idea for this project
title: "[FEATURE] <title>"
labels: [enhancement]
body:
- type: textarea
id: description
attributes:
label: Description
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
validations:
required: true
- type: textarea
id: solution
attributes:
label: Proposed Solution
description: A clear and concise description of what you want to happen.
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: Alternatives
description: A clear and concise description of any alternative solutions or features you've considered.
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: Add any other context or screenshots about the feature request here.
validations:
required: false

View File

@ -16,18 +16,37 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Cache Cargo modules
id: cache-cargo
uses: actions/cache@v3
env:
cache-name: cache-cargo-target-debug
with:
path: target
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Build - name: Build
run: cargo build --verbose run: make debug
- name: Run tests - name: Run tests
run: cargo test --verbose run: cargo test --verbose -p schemsearch-lib
build-realease:
build-release:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Cache Cargo modules
id: cache-cargo
uses: actions/cache@v3
env:
cache-name: cache-cargo-target-release
with:
path: target
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Build - name: Build
run: cargo build --verbose --release run: make
- name: Upload a Build Artifact - name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.2 uses: actions/upload-artifact@v3.1.2
with: with:

View File

@ -19,8 +19,18 @@ jobs:
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Cache Cargo modules
id: cache-cargo
uses: actions/cache@v3
env:
cache-name: cache-cargo-target-release
with:
path: target
key: ${{ runner.os }}-${{ env.cache-name }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ env.cache-name }}-
- name: Build - name: Build
run: cargo build --verbose --release run: make
- name: Create Tarball - name: Create Tarball
if: ${{ matrix.os != 'windows-latest' }} if: ${{ matrix.os != 'windows-latest' }}
run: tar -czvf schemsearch-cli-${{ matrix.os }}.tar.gz -C target/release schemsearch-cli run: tar -czvf schemsearch-cli-${{ matrix.os }}.tar.gz -C target/release schemsearch-cli

View File

@ -2,7 +2,7 @@
members = [ members = [
"schemsearch-cli", "schemsearch-cli",
"schemsearch-lib", "schemsearch-lib",
"schemsearch_faster", "schemsearch-faster",
"schemsearch-files", "schemsearch-files",
"schemsearch-sql", "schemsearch-sql",
"schemsearch-java" "schemsearch-java"

28
Makefile Normal file
View File

@ -0,0 +1,28 @@
default:
@echo "Building (Release)...";
cargo rustc --release --color=always -p schemsearch-cli -- -C target-feature=+avx2
sql:
@echo "Building (Release)...";
cargo rustc --release --color=always -p schemsearch-cli --features sql -- -C target-feature=+avx2
debug:
@echo "Building (Debug)...";
cargo build -p schemsearch-cli
install: default
@echo "Installing...";
install -Dm755 target/release/schemsearch-cli /usr/bin/schemsearch
uninstall:
@echo "Uninstalling...";
rm -f /usr/bin/schemsearch
java:
@echo "Building Java...";
@echo "WARNING: This is WORK IN PROGRESS!";
javac SchemSearch.java
clean:
@echo "Cleaning...";
cargo clean

View File

@ -5,10 +5,10 @@
## WARNING: This is a work in progress and is really simple right now. It will be improved in the future. ## WARNING: This is a work in progress and is really simple right now. It will be improved in the future.
| Feature | Status | | Feature | Status |
|------------------------|--------| |---------------------------|--------|
| Block search | ✅ | | Block search | ✅ |
| Block data less search | ✅ | | Block data less search | ✅ |
| Tile entities search | ❌ | | Tile entities data search | ❌ |
| Entities search | ❌ | | Entities search | ❌ |
--- ---
@ -40,6 +40,17 @@ schemsearch-cli --help
--- ---
## Roadmap
A list of features that are planned to be implemented in the future. In order of priority.
- [ ] Full JSON output (Progressbar)
- [ ] Use AVX2 for faster search
- [ ] Tile entities data search
- [ ] Entities search
- [ ] McEdit Schematic support
---
## Building ## Building
This project is build using Rust for the CLI and library. It can be built using Cargo. This project is build using Rust for the CLI and library. It can be built using Cargo.
```bash ```bash

View File

@ -1,6 +1,6 @@
[package] [package]
name = "schemsearch-cli" name = "schemsearch-cli"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
@ -16,6 +16,8 @@ futures = { version = "0.3", optional = true }
sqlx = { version = "0.6", features = [ "runtime-async-std-native-tls" , "mysql" ], optional = true } sqlx = { version = "0.6", features = [ "runtime-async-std-native-tls" , "mysql" ], optional = true }
rayon = "1.7.0" rayon = "1.7.0"
indicatif = { version = "0.17.3", features = ["rayon"] } indicatif = { version = "0.17.3", features = ["rayon"] }
serde = "1.0.157"
serde_json = "1.0.94"
[features] [features]
sql = ["dep:schemsearch-sql", "dep:futures", "dep:sqlx"] sql = ["dep:schemsearch-sql", "dep:futures", "dep:sqlx"]

View File

@ -0,0 +1,29 @@
use serde::{Deserialize, Serialize};
use schemsearch_lib::{Match, SearchBehavior};
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "event")]
pub enum JsonEvent {
Found(FoundEvent),
Init(InitEvent),
End(EndEvent),
}
#[derive(Serialize, Deserialize, Debug)]
pub struct FoundEvent {
pub name: String,
#[serde(flatten, rename = "match")]
pub match_: Match,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct InitEvent {
pub total: u32,
pub search_behavior: SearchBehavior,
pub start_time: u128,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct EndEvent {
pub end_time: u128,
}

View File

@ -16,16 +16,17 @@
*/ */
mod types; mod types;
mod json_output;
mod sinks;
mod stderr;
use std::fmt::Debug; use std::fmt::Debug;
use std::fs::File; use std::io::Write;
use std::io;
use std::io::{BufWriter, Write};
use clap::{command, Arg, ArgAction, ValueHint}; use clap::{command, Arg, ArgAction, ValueHint};
use schemsearch_files::Schematic;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr;
use clap::error::ErrorKind; use clap::error::ErrorKind;
use schemsearch_lib::{search, SearchBehavior}; use schemsearch_lib::{Match, search, SearchBehavior};
use crate::types::{PathSchematicSupplier, SchematicSupplierType}; use crate::types::{PathSchematicSupplier, SchematicSupplierType};
#[cfg(feature = "sql")] #[cfg(feature = "sql")]
use futures::executor::block_on; use futures::executor::block_on;
@ -37,7 +38,10 @@ use schemsearch_sql::filter::SchematicFilter;
use schemsearch_sql::load_all_schematics; use schemsearch_sql::load_all_schematics;
#[cfg(feature = "sql")] #[cfg(feature = "sql")]
use crate::types::SqlSchematicSupplier; use crate::types::SqlSchematicSupplier;
use indicatif::{ProgressBar, ParallelProgressIterator, ProgressStyle}; use indicatif::*;
use schemsearch_files::Schematic;
use crate::sinks::{OutputFormat, OutputSink};
use crate::stderr::MaschineStdErr;
fn main() { fn main() {
#[allow(unused_mut)] #[allow(unused_mut)]
@ -92,20 +96,32 @@ fn main() {
) )
.arg( .arg(
Arg::new("output") Arg::new("output")
.help("The output format") .help("The output format and path [Format:Path] available formats: text, json, csv; available paths: std, err, (file path)")
.short('o') .short('o')
.long("output") .long("output")
.action(ArgAction::Append) .action(ArgAction::Append)
.default_value("std") .default_value("text:std")
.value_parser(["std_csv", "file_csv", "std", "file"]), .value_parser(|s: &str| {
) let mut split = s.splitn(2, ':');
.arg( let format = match split.next() {
Arg::new("output-file") None => return Err("No format specified".to_string()),
.help("The output file") Some(x) => x
.short('O') };
.long("output-file") let path = match split.next() {
.value_hint(ValueHint::FilePath) None => return Err("No path specified".to_string()),
.action(ArgAction::Append) Some(x) => x
};
let format = match OutputFormat::from_str(format) {
Ok(x) => x,
Err(e) => return Err(e.to_string()),
};
let path = match OutputSink::from_str(path) {
Ok(x) => x,
Err(e) => return Err(e.to_string()),
};
Ok((format, path))
}),
) )
.arg( .arg(
Arg::new("threshold") Arg::new("threshold")
@ -125,6 +141,15 @@ fn main() {
.default_value("0") .default_value("0")
.value_parser(|s: &str| s.parse::<usize>().map_err(|e| e.to_string())), .value_parser(|s: &str| s.parse::<usize>().map_err(|e| e.to_string())),
) )
.arg(
Arg::new("machine")
.help("Output for machines")
.short('m')
.long("machine")
.action(ArgAction::Set)
.default_value("0")
.value_parser(|s: &str| s.parse::<u16>().map_err(|e| e.to_string()))
)
.about("Searches for a pattern in a schematic") .about("Searches for a pattern in a schematic")
.bin_name("schemsearch"); .bin_name("schemsearch");
@ -223,52 +248,33 @@ fn main() {
cmd.error(ErrorKind::MissingRequiredArgument, "No schematics specified").exit(); cmd.error(ErrorKind::MissingRequiredArgument, "No schematics specified").exit();
} }
let mut output_std = false; let output: Vec<&(OutputFormat, OutputSink)> = matches.get_many::<(OutputFormat, OutputSink)>("output").expect("Error").collect();
let mut output_std_csv = false; let mut output: Vec<(OutputFormat, Box<dyn Write>)> = output.into_iter().map(|x| (x.0.clone(), x.1.output())).collect();
let mut output_file_csv = false;
let mut output_file = false;
for x in matches.get_many::<String>("output").expect("Couldn't get output") { for x in &mut output {
match x.as_str() { write!(x.1, "{}", x.0.start(schematics.len() as u32, &search_behavior, start.elapsed().as_millis())).unwrap();
"std" => output_std = true,
"std_csv" => output_std_csv = true,
"file_csv" => output_file_csv = true,
"file" => output_file = true,
_ => {}
} }
};
let file: Option<File>;
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 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()));
}
ThreadPoolBuilder::new().num_threads(*matches.get_one::<usize>("threads").expect("Could not get threads")).build_global().unwrap(); ThreadPoolBuilder::new().num_threads(*matches.get_one::<usize>("threads").expect("Could not get threads")).build_global().unwrap();
let matches: Vec<Result> = schematics.par_iter().progress_with_style(ProgressStyle::with_template("[{elapsed}, ETA: {eta}] {wide_bar} {pos}/{len} {per_sec}").unwrap()).map(|schem| { let bar = ProgressBar::new(schematics.len() as u64); // "maschine"
bar.set_style(ProgressStyle::with_template("[{elapsed}, ETA: {eta}] {wide_bar} {pos}/{len} {per_sec}").unwrap());
let term_size = *matches.get_one::<u16>("machine").expect("Could not get machine");
if term_size != 0 {
bar.set_draw_target(ProgressDrawTarget::term_like(Box::new(MaschineStdErr { size: term_size })))
}
let matches: Vec<SearchResult> = schematics.par_iter().progress_with(bar).map(|schem| {
match schem { match schem {
SchematicSupplierType::PATH(schem) => { SchematicSupplierType::PATH(schem) => {
let schematic = match load_schem(&schem.path) { let schematic = match load_schem(&schem.path) {
Some(x) => x, Some(x) => x,
None => return Result { None => return SearchResult {
name: schem.get_name(), name: schem.get_name(),
matches: vec![] matches: Vec::default()
} }
}; };
Result { SearchResult {
name: schem.get_name(), name: schem.get_name(),
matches: search(schematic, &pattern, search_behavior) matches: search(schematic, &pattern, search_behavior)
} }
@ -277,18 +283,16 @@ fn main() {
SchematicSupplierType::SQL(schem) => { SchematicSupplierType::SQL(schem) => {
match schem.get_schematic() { match schem.get_schematic() {
Ok(schematic) => { Ok(schematic) => {
Result { SearchResult {
name: schem.get_name(), name: schem.get_name(),
matches: search(schematic, &pattern, search_behavior) matches: search(schematic, &pattern, search_behavior)
} }
} }
Err(e) => { Err(e) => {
if !output_std && !output_std_csv { eprintln!("Error while loading schematic ({}): {}", schem.get_name(), e.to_string());
println!("Error while loading schematic ({}): {}", schem.get_name(), e.to_string()); SearchResult {
}
Result {
name: schem.get_name(), name: schem.get_name(),
matches: vec![] matches: Vec::default()
} }
} }
} }
@ -296,30 +300,21 @@ fn main() {
} }
}).collect(); }).collect();
let stdout = io::stdout();
let mut lock = stdout.lock();
for matching in matches { for matching in matches {
let schem_name = matching.name; let schem_name = matching.name;
let matching = matching.matches; let matching = matching.matches;
for x in matching { for x in matching {
if output_std { for out in &mut output {
writeln!(lock, "Found match in '{}' at x: {}, y: {}, z: {}, % = {}", schem_name, x.0, x.1, x.2, x.3).unwrap(); write!(out.1, "{}", out.0.found_match(&schem_name, x)).unwrap();
}
if output_std_csv {
writeln!(lock, "{},{},{},{},{}", schem_name, x.0, x.1, x.2, x.3).unwrap();
}
if output_file {
writeln!(file_out.as_mut().unwrap(), "Found match in '{}' at x: {}, y: {}, z: {}, % = {}", schem_name, x.0, x.1, x.2, x.3).unwrap();
}
if output_file_csv {
writeln!(file_out.as_mut().unwrap(), "{},{},{},{},{}", schem_name, x.0, x.1, x.2, x.3).unwrap();
} }
} }
} }
let end = std::time::Instant::now(); let end = std::time::Instant::now();
println!("Finished in {:.2}s! Searched in {} Schematics", end.duration_since(start).as_secs_f32(), schematics.len()); for x in &mut output {
write!(x.1, "{}", x.0.end(end.duration_since(start).as_millis())).unwrap();
x.1.flush().unwrap();
}
} }
fn load_schem(schem_path: &PathBuf) -> Option<Schematic> { fn load_schem(schem_path: &PathBuf) -> Option<Schematic> {
@ -333,8 +328,8 @@ fn load_schem(schem_path: &PathBuf) -> Option<Schematic> {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct Result { struct SearchResult {
name: String, name: String,
matches: Vec<(u16, u16, u16, f32)>, matches: Vec<Match>,
} }

View File

@ -0,0 +1,90 @@
use std::fs::File;
use std::io::BufWriter;
use std::str::FromStr;
use std::io::Write;
use std::time::Duration;
use indicatif::HumanDuration;
use schemsearch_lib::{Match, SearchBehavior};
use crate::json_output::{EndEvent, FoundEvent, InitEvent, JsonEvent};
#[derive(Debug, Clone)]
pub enum OutputSink {
Stdout,
Stderr,
File(String),
}
#[derive(Debug, Clone)]
pub enum OutputFormat {
Text,
CSV,
JSON
}
impl FromStr for OutputFormat {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"text" => Ok(OutputFormat::Text),
"csv" => Ok(OutputFormat::CSV),
"json" => Ok(OutputFormat::JSON),
_ => Err(format!("'{}' is not a valid output format", s))
}
}
}
impl FromStr for OutputSink {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"std" => Ok(OutputSink::Stdout),
"err" => Ok(OutputSink::Stderr),
_ => Ok(OutputSink::File(s.to_string()))
}
}
}
impl OutputSink {
pub fn output(&self) -> Box<dyn Write> {
match self {
OutputSink::Stdout => Box::new(std::io::stdout()),
OutputSink::Stderr => Box::new(std::io::stderr()),
OutputSink::File(path) => Box::new(BufWriter::new(File::create(path).unwrap()))
}
}
}
impl OutputFormat {
pub fn found_match(&self, name: &String, pos: Match) -> String {
match self {
OutputFormat::Text => format!("Found match in '{}' at x: {}, y: {}, z: {}, % = {}\n", name, pos.x, pos.y, pos.z, pos.percent),
OutputFormat::CSV => format!("{},{},{},{},{}\n", name, pos.x, pos.y, pos.z, pos.percent),
OutputFormat::JSON => format!("{}\n", serde_json::to_string(&JsonEvent::Found(FoundEvent {
name: name.clone(),
match_: pos,
})).unwrap())
}
}
pub fn start(&self, total: u32, search_behavior: &SearchBehavior, start_time: u128) -> String {
match self {
OutputFormat::Text => format!("Starting search in {} schematics\n", total),
OutputFormat::CSV => format!("Name,X,Y,Z,Percent\n"),
OutputFormat::JSON => format!("{}\n", serde_json::to_string(&JsonEvent::Init(InitEvent {
total,
search_behavior: search_behavior.clone(),
start_time,
})).unwrap())
}
}
pub fn end(&self, end_time: u128) -> String {
match self {
OutputFormat::Text => format!("Search complete in {}\n", HumanDuration(Duration::from_millis(end_time as u64))),
OutputFormat::CSV => format!("{}\n", end_time),
OutputFormat::JSON => format!("{}\n", serde_json::to_string(&JsonEvent::End(EndEvent{ end_time })).unwrap())
}
}
}

View File

@ -0,0 +1,44 @@
use std::fmt::Debug;
use std::io::Write;
use indicatif::TermLike;
#[derive(Debug)]
pub struct MaschineStdErr { pub(crate) size: u16}
impl TermLike for MaschineStdErr {
fn width(&self) -> u16 {
self.size
}
fn move_cursor_up(&self, _: usize) -> std::io::Result<()> {
Ok(())
}
fn move_cursor_down(&self, _: usize) -> std::io::Result<()> {
Ok(())
}
fn move_cursor_right(&self, _: usize) -> std::io::Result<()> {
Ok(())
}
fn move_cursor_left(&self, _: usize) -> std::io::Result<()> {
Ok(())
}
fn write_line(&self, s: &str) -> std::io::Result<()> {
writeln!(std::io::stderr(), "{}", s)
}
fn write_str(&self, s: &str) -> std::io::Result<()> {
write!(std::io::stderr(), "{}", s)
}
fn clear_line(&self) -> std::io::Result<()> {
Ok(())
}
fn flush(&self) -> std::io::Result<()> {
std::io::stderr().flush()
}
}

View File

@ -18,6 +18,7 @@
use std::path::PathBuf; use std::path::PathBuf;
#[cfg(feature = "sql")] #[cfg(feature = "sql")]
use futures::executor::block_on; use futures::executor::block_on;
#[allow(unused_imports)]
use schemsearch_files::Schematic; use schemsearch_files::Schematic;
#[cfg(feature = "sql")] #[cfg(feature = "sql")]
use schemsearch_sql::{load_schemdata, SchematicNode}; use schemsearch_sql::{load_schemdata, SchematicNode};

View File

@ -1,6 +1,6 @@
[package] [package]
name = "schemsearch_faster" name = "schemsearch_faster"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "schemsearch-files" name = "schemsearch-files"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,6 +1,6 @@
[package] [package]
name = "schemsearch-java" name = "schemsearch-java"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"

View File

@ -45,8 +45,8 @@ pub extern "system" fn Java_SchemSearch_search<'local>(mut env: JNIEnv<'local>,
}); });
let mut result = String::new(); let mut result = String::new();
for (x, y, z, p) in matches { for m in matches {
result.push_str(&format!("{}, {}, {}, {};", x, y, z, p)); result.push_str(&format!("{}, {}, {}, {};", m.x, m.y, m.z, m.percent));
} }
result.remove(result.len() - 1); result.remove(result.len() - 1);
let output = env.new_string(result).expect("Couldn't create java string!"); let output = env.new_string(result).expect("Couldn't create java string!");

View File

@ -1,6 +1,6 @@
[package] [package]
name = "schemsearch-lib" name = "schemsearch-lib"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"

View File

@ -17,11 +17,12 @@
pub mod pattern_mapper; pub mod pattern_mapper;
use serde::{Deserialize, Serialize};
use pattern_mapper::match_palette; use pattern_mapper::match_palette;
use schemsearch_files::Schematic; use schemsearch_files::Schematic;
use crate::pattern_mapper::match_palette_adapt; use crate::pattern_mapper::match_palette_adapt;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, Deserialize, Serialize)]
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,
@ -35,7 +36,7 @@ pub fn search(
schem: Schematic, schem: Schematic,
pattern_schem: &Schematic, pattern_schem: &Schematic,
search_behavior: SearchBehavior, search_behavior: SearchBehavior,
) -> Vec<(u16, u16, u16, f32)> { ) -> Vec<Match> {
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![];
} }
@ -46,7 +47,7 @@ pub fn search(
let pattern_schem = match_palette(&schem, &pattern_schem, search_behavior.ignore_block_data); let pattern_schem = match_palette(&schem, &pattern_schem, search_behavior.ignore_block_data);
let mut matches: Vec<(u16, u16, u16, f32)> = Vec::new(); let mut matches: Vec<Match> = Vec::new();
let pattern_data = pattern_schem.block_data.as_slice(); let pattern_data = pattern_schem.block_data.as_slice();
@ -60,7 +61,7 @@ pub fn search(
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 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_blocks = (pattern_schem.width * pattern_schem.height * pattern_schem.length) as f32; let pattern_blocks = pattern_data.len() as f32;
let pattern_width = pattern_schem.width as usize; let pattern_width = pattern_schem.width as usize;
let pattern_height = pattern_schem.height as usize; let pattern_height = pattern_schem.height as usize;
@ -89,7 +90,12 @@ pub fn search(
} }
let matching_percent = matching as f32 / pattern_blocks; let matching_percent = matching as f32 / pattern_blocks;
if matching_percent >= search_behavior.threshold { if matching_percent >= search_behavior.threshold {
matches.push((x as u16, y as u16, z as u16, matching_percent)); matches.push(Match {
x: x as u16,
y: y as u16,
z: z as u16,
percent: matching_percent,
});
} }
} }
} }
@ -98,6 +104,25 @@ pub fn search(
return matches; return matches;
} }
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub struct Match {
pub x: u16,
pub y: u16,
pub z: u16,
pub percent: f32,
}
impl Default for Match {
fn default() -> Self {
Self {
x: 0,
y: 0,
z: 0,
percent: 0.0,
}
}
}
#[inline] #[inline]
pub fn normalize_data(data: &str, ignore_data: bool) -> &str { pub fn normalize_data(data: &str, ignore_data: bool) -> &str {
if ignore_data { if ignore_data {
@ -195,7 +220,10 @@ mod tests {
println!("{:?}", matches); println!("{:?}", matches);
assert_eq!(matches.len(), 1); assert_eq!(matches.len(), 1);
assert_eq!(matches[0], (1, 0, 3, 1.0)); assert_eq!(matches[0].x, 1);
assert_eq!(matches[0].y, 0);
assert_eq!(matches[0].z, 3);
assert_eq!(matches[0].percent, 1.0);
} }
#[test] #[test]

View File

@ -1,6 +1,6 @@
[package] [package]
name = "schemsearch-sql" name = "schemsearch-sql"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"

View File

@ -16,7 +16,7 @@
*/ */
use std::sync::Mutex; use std::sync::Mutex;
use sqlx::{ConnectOptions, Executor, MySql, MySqlPool, Pool, Row}; use sqlx::{Executor, MySql, Pool, Row};
use sqlx::mysql::{MySqlConnectOptions, MySqlPoolOptions}; use sqlx::mysql::{MySqlConnectOptions, MySqlPoolOptions};
use crate::filter::SchematicFilter; use crate::filter::SchematicFilter;