WASM plugins, scripting, i18n, GUI pan/zoom, cargo-dist CI/CD
- WASM plugin host (wasmtime 46, 17 host fns) + example noisemap plugin - Rhai scripting engine (12 API fns, `terrafier run` cmd) - i18n: en/ru translations, auto-detect, t! macro - GUI: pan (click-drag) + zoom (scroll wheel) with viewport transform - cargo-dist 0.31: MSI/pkg/shell installers, both binaries - CI: .github/workflows/ci.yml + release.yml - Security: wasmtime 30→46, bincode 1.3→2.0, quick-xml CVE docs - Code review: SAFETY comments, unwrap→match cleanup - Fixes: clippy approx_constant, needless_borrows, rustfmt
This commit is contained in:
parent
bdd4564240
commit
18613260a8
100 changed files with 4262 additions and 585 deletions
|
|
@ -73,7 +73,10 @@ fn terrafier_biome_name(id: u8) -> &'static str {
|
|||
arr
|
||||
});
|
||||
|
||||
names.get(id as usize).copied().unwrap_or("minecraft:plains")
|
||||
names
|
||||
.get(id as usize)
|
||||
.copied()
|
||||
.unwrap_or("minecraft:plains")
|
||||
}
|
||||
|
||||
pub struct BiomeLayerExport;
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@ pub fn biome_name(
|
|||
"minecraft:plains"
|
||||
}
|
||||
|
||||
mod biome_res;
|
||||
mod caves_frost;
|
||||
mod river_trees;
|
||||
mod biome_res;
|
||||
|
||||
pub use biome_res::{BiomeLayerExport, ResourcesLayerExport};
|
||||
pub use caves_frost::{CavesLayerExport, FrostLayerExport};
|
||||
pub use river_trees::{RiverLayerExport, TreesLayerExport};
|
||||
pub use biome_res::{BiomeLayerExport, ResourcesLayerExport};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::collections::{BTreeSet, HashMap};
|
||||
use crate::io::layer_export::{apply_layers, biome_name, LayerExport};
|
||||
use crate::io::minecraft::{data_version, Result};
|
||||
use crate::model::tile::Tile;
|
||||
use super::blocks::{bits_needed, pack_indices, BLOCK_SET, BLOCK_SET_EXTENDED};
|
||||
use super::block_name;
|
||||
use super::blocks::{BLOCK_SET, BLOCK_SET_EXTENDED, bits_needed, pack_indices};
|
||||
use crate::io::layer_export::{LayerExport, apply_layers, biome_name};
|
||||
use crate::io::minecraft::{Result, data_version};
|
||||
use crate::model::tile::Tile;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
|
||||
fn make_section(
|
||||
sec_y: i32,
|
||||
|
|
@ -12,7 +12,10 @@ fn make_section(
|
|||
) -> terrafier_nbt::Tag {
|
||||
let mut sec = HashMap::new();
|
||||
sec.insert("Y".into(), terrafier_nbt::Tag::Byte(sec_y as i8));
|
||||
sec.insert("block_states".into(), terrafier_nbt::Tag::Compound(block_states));
|
||||
sec.insert(
|
||||
"block_states".into(),
|
||||
terrafier_nbt::Tag::Compound(block_states),
|
||||
);
|
||||
sec.insert("biomes".into(), terrafier_nbt::Tag::Compound(biomes));
|
||||
terrafier_nbt::Tag::Compound(sec)
|
||||
}
|
||||
|
|
@ -38,7 +41,10 @@ pub(super) fn build_chunk_nbt(
|
|||
let mut compound = HashMap::new();
|
||||
compound.insert("xPos".into(), terrafier_nbt::Tag::Int(chunk_x));
|
||||
compound.insert("zPos".into(), terrafier_nbt::Tag::Int(chunk_z));
|
||||
compound.insert("DataVersion".into(), terrafier_nbt::Tag::Int(data_version()));
|
||||
compound.insert(
|
||||
"DataVersion".into(),
|
||||
terrafier_nbt::Tag::Int(data_version()),
|
||||
);
|
||||
compound.insert("Status".into(), terrafier_nbt::Tag::String("full".into()));
|
||||
let min_sec = (tile.min_height as i32 >> 4).max(-4);
|
||||
let max_sec = (tile.max_height as i32 >> 4).min(20);
|
||||
|
|
@ -104,7 +110,10 @@ pub(super) fn build_chunk_nbt_with_layers(
|
|||
let mut compound = HashMap::new();
|
||||
compound.insert("xPos".into(), terrafier_nbt::Tag::Int(chunk_x));
|
||||
compound.insert("zPos".into(), terrafier_nbt::Tag::Int(chunk_z));
|
||||
compound.insert("DataVersion".into(), terrafier_nbt::Tag::Int(data_version()));
|
||||
compound.insert(
|
||||
"DataVersion".into(),
|
||||
terrafier_nbt::Tag::Int(data_version()),
|
||||
);
|
||||
compound.insert("Status".into(), terrafier_nbt::Tag::String("full".into()));
|
||||
let min_sec = (tile.min_height as i32 >> 4).max(-4);
|
||||
let max_sec = (tile.max_height as i32 >> 4).min(20);
|
||||
|
|
@ -125,7 +134,12 @@ pub(super) fn build_chunk_nbt_with_layers(
|
|||
let terrain_id = tile.terrain[tile_lz * 128 + tile_lx];
|
||||
let base_name = block_name(terrain_id, global_y, surface_y);
|
||||
let name = apply_layers(
|
||||
tile, tile_lx, tile_lz, global_y, surface_y, base_name,
|
||||
tile,
|
||||
tile_lx,
|
||||
tile_lz,
|
||||
global_y,
|
||||
surface_y,
|
||||
base_name,
|
||||
layer_exporters,
|
||||
);
|
||||
BLOCK_SET_EXTENDED
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ mod blocks;
|
|||
mod chunk;
|
||||
mod writer;
|
||||
|
||||
pub(crate) use blocks::block_name;
|
||||
pub use writer::save_world;
|
||||
pub use writer::save_world_with_layers;
|
||||
pub(crate) use blocks::block_name;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::fs;
|
|||
use std::path::Path;
|
||||
|
||||
use crate::io::layer_export::LayerExport;
|
||||
use crate::io::minecraft::{data_version, Result};
|
||||
use crate::io::minecraft::{Result, data_version};
|
||||
use crate::model::tile::Tile;
|
||||
use crate::model::world::World;
|
||||
|
||||
|
|
@ -47,8 +47,7 @@ pub fn save_world(world: &World, output_path: &Path) -> Result<()> {
|
|||
let region_local_x = (chunk_x & 31) as u8;
|
||||
let region_local_z = (chunk_z & 31) as u8;
|
||||
|
||||
let chunk_data =
|
||||
build_chunk_nbt(chunk_x, chunk_z, tile, chunk_lx, chunk_lz)?;
|
||||
let chunk_data = build_chunk_nbt(chunk_x, chunk_z, tile, chunk_lx, chunk_lz)?;
|
||||
|
||||
if chunk_data.is_empty() {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ mod export;
|
|||
mod reader;
|
||||
mod version;
|
||||
|
||||
pub use reader::load_save;
|
||||
pub use reader::discover_region_files;
|
||||
pub use export::save_world;
|
||||
pub use export::save_world_with_layers;
|
||||
pub use version::version_from_data_version;
|
||||
pub use reader::discover_region_files;
|
||||
pub use reader::load_save;
|
||||
pub(crate) use version::data_version;
|
||||
pub use version::version_from_data_version;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
|
|||
|
|
@ -51,7 +51,19 @@ pub fn load_save(path: &Path) -> Result<World> {
|
|||
let region_bytes = fs::read(&path)?;
|
||||
let region = Region::from_bytes(rx, rz, ®ion_bytes)?;
|
||||
for (local_x, local_z) in region.chunk_coords() {
|
||||
let chunk_data = region.get_chunk_data(local_x, local_z).unwrap();
|
||||
let chunk_data = match region.get_chunk_data(local_x, local_z) {
|
||||
Some(data) => data,
|
||||
None => {
|
||||
log::warn!(
|
||||
"corrupted chunk data at ({}, {}) in region ({}, {})",
|
||||
local_x,
|
||||
local_z,
|
||||
rx,
|
||||
rz
|
||||
);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
if let Ok(chunk_tag) = read_gzip(chunk_data)
|
||||
&& let Some(chunk) =
|
||||
terrafier_fastanvil::io::chunk::Chunk::from_nbt(&chunk_tag)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ pub type Result<T> = std::result::Result<T, BinaryError>;
|
|||
|
||||
/// Save a `World` to a binary file.
|
||||
pub fn save_binary(world: &World, path: &Path) -> Result<()> {
|
||||
let bytes = bincode::serialize(world).map_err(|e| BinaryError::Serialize(e.to_string()))?;
|
||||
let config = bincode::config::standard();
|
||||
let bytes =
|
||||
bincode::serde::encode_to_vec(world, config).map_err(|e| BinaryError::Serialize(e.to_string()))?;
|
||||
|
||||
std::fs::write(path, &bytes)?;
|
||||
Ok(())
|
||||
|
|
@ -35,8 +37,10 @@ pub fn save_binary(world: &World, path: &Path) -> Result<()> {
|
|||
/// Load a `World` from a binary file.
|
||||
pub fn load_binary(path: &Path) -> Result<World> {
|
||||
let bytes = std::fs::read(path)?;
|
||||
let world: World =
|
||||
bincode::deserialize(&bytes).map_err(|e| BinaryError::Deserialize(e.to_string()))?;
|
||||
let config = bincode::config::standard();
|
||||
let (world, _): (World, usize) =
|
||||
bincode::serde::decode_from_slice(&bytes, config)
|
||||
.map_err(|e| BinaryError::Deserialize(e.to_string()))?;
|
||||
Ok(world)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use super::types::{
|
||||
ClassDesc, JvmValue, BASE_WIRE_HANDLE, TC_ARRAY, TC_BLOCKDATA, TC_BLOCKDATALONG, TC_CLASS,
|
||||
BASE_WIRE_HANDLE, ClassDesc, JvmValue, TC_ARRAY, TC_BLOCKDATA, TC_BLOCKDATALONG, TC_CLASS,
|
||||
TC_ENUM, TC_LONGSTRING, TC_NULL, TC_OBJECT, TC_REFERENCE, TC_RESET, TC_STRING,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ pub use extract::*;
|
|||
pub use types::WpImportError;
|
||||
|
||||
use crate::model::dimension::Dimension;
|
||||
use crate::model::types::Platform;
|
||||
use crate::model::tile::Tile;
|
||||
use crate::model::types::Platform;
|
||||
use crate::model::world::World;
|
||||
|
||||
use java_reader::JvmStream;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use super::super::java_reader::JvmStream;
|
||||
use super::java_types::{
|
||||
ClassDesc, FieldInfo, JvmValue, BASE_WIRE_HANDLE, TC_ARRAY, TC_BLOCKDATA, TC_BLOCKDATALONG,
|
||||
BASE_WIRE_HANDLE, ClassDesc, FieldInfo, JvmValue, TC_ARRAY, TC_BLOCKDATA, TC_BLOCKDATALONG,
|
||||
TC_CLASS, TC_CLASSDESC, TC_ENDBLOCKDATA, TC_ENUM, TC_LONGSTRING, TC_NULL, TC_OBJECT,
|
||||
TC_PROXYCLASSDESC, TC_REFERENCE, TC_RESET, TC_STRING,
|
||||
};
|
||||
use super::super::java_reader::JvmStream;
|
||||
|
||||
impl JvmStream {
|
||||
pub fn read_classdesc(&mut self) -> std::io::Result<JvmValue> {
|
||||
|
|
@ -124,10 +124,7 @@ impl JvmStream {
|
|||
other => {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
format!(
|
||||
"unexpected token in class annotations: 0x{:02x}",
|
||||
other
|
||||
),
|
||||
format!("unexpected token in class annotations: 0x{:02x}", other),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -182,5 +179,4 @@ impl JvmStream {
|
|||
self.handles[(handle - BASE_WIRE_HANDLE) as usize] = obj.clone();
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use super::super::java_reader::JvmStream;
|
||||
use super::java_types::{
|
||||
ClassDesc, FieldInfo, JvmValue, PRIM_BOOL, PRIM_BYTE, PRIM_CHAR, PRIM_DOUBLE, PRIM_FLOAT,
|
||||
PRIM_INT, PRIM_LONG, PRIM_SHORT, SC_WRITE_METHOD, TC_BLOCKDATA, TC_BLOCKDATALONG,
|
||||
};
|
||||
use super::super::java_reader::JvmStream;
|
||||
|
||||
impl JvmStream {
|
||||
pub fn read_object_fields(&mut self, cd: &ClassDesc) -> std::io::Result<JvmValue> {
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ pub use coords::{BlockCoords, ChunkCoords, RegionCoords, TileCoords};
|
|||
pub use io::export;
|
||||
pub use io::import;
|
||||
pub use model::dimension::Dimension;
|
||||
pub use model::types::{Platform, Terrain};
|
||||
pub use model::tile::Tile;
|
||||
pub use model::types::{Platform, Terrain};
|
||||
pub use model::world::World;
|
||||
|
||||
pub use terrafier_biome_db as biome_db;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ impl World {
|
|||
}
|
||||
|
||||
/// Create a new world using a custom height map source.
|
||||
pub fn with_heightmap(name: &str, seed: u64, heightmap: impl HeightMapSource + 'static) -> Self {
|
||||
pub fn with_heightmap(
|
||||
name: &str,
|
||||
seed: u64,
|
||||
heightmap: impl HeightMapSource + 'static,
|
||||
) -> Self {
|
||||
let platform = Platform::java_1_18();
|
||||
|
||||
let coords: Vec<(i32, i32)> = (-1..=1)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
//! Filter system — restrict which cells an operation affects based on terrain, height, or slope.
|
||||
use std::sync::OnceLock;
|
||||
use crate::model::dimension::Dimension;
|
||||
use crate::model::tile::{TILE_SIZE, Tile};
|
||||
use crate::model::types::Terrain;
|
||||
use crate::model::tile::{Tile, TILE_SIZE};
|
||||
use crate::ops::operations::{Operation, OperationError, RestoreHeightsOperation};
|
||||
use std::sync::OnceLock;
|
||||
/// Determines whether a cell should be modified by an operation.
|
||||
pub trait Filter: Send + Sync {
|
||||
fn name(&self) -> &'static str;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Height map sources — generate height maps from noise, flat, or combined sources.
|
||||
|
||||
use crate::model::types::Terrain;
|
||||
use crate::model::tile::Tile;
|
||||
use crate::model::types::Terrain;
|
||||
|
||||
/// A source that can generate a height map for a tile.
|
||||
pub trait HeightMapSource: Send + Sync {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ fn tile_hash(tile_x: i32, tile_z: i32, seed: u64) -> u64 {
|
|||
}
|
||||
|
||||
fn pseudo_rand(state: &mut u64) -> u64 {
|
||||
*state = state.wrapping_mul(6364136223846793005).wrapping_add(1442695040888963407);
|
||||
*state = state
|
||||
.wrapping_mul(6364136223846793005)
|
||||
.wrapping_add(1442695040888963407);
|
||||
*state >> 33
|
||||
}
|
||||
|
||||
|
|
@ -34,9 +36,7 @@ impl crate::ops::layers::LayerGenerator for TreesGenerator {
|
|||
for idx in 0..total {
|
||||
let terrain_type = terrain[idx] as usize;
|
||||
bytes[idx] = match terrain_type {
|
||||
t if t == Terrain::Forest as usize => {
|
||||
(pseudo_rand(&mut rng) % 60).max(20) as u8
|
||||
}
|
||||
t if t == Terrain::Forest as usize => (pseudo_rand(&mut rng) % 60).max(20) as u8,
|
||||
t if t == Terrain::Grass as usize && pseudo_rand(&mut rng) % 100 < 30 => {
|
||||
(pseudo_rand(&mut rng) % 20 + 5) as u8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::sync::{Arc, OnceLock};
|
||||
use crate::model::types::Brush;
|
||||
use crate::model::dimension::Dimension;
|
||||
use crate::model::types::Terrain;
|
||||
use crate::model::tile::TILE_SIZE;
|
||||
use crate::model::types::Brush;
|
||||
use crate::model::types::Terrain;
|
||||
use crate::ops::operations::{Operation, OperationError, RestoreTerrainOperation};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
|
||||
struct BrushApply<'a> {
|
||||
tile: &'a mut crate::model::tile::Tile,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ use std::collections::VecDeque;
|
|||
use std::sync::OnceLock;
|
||||
|
||||
use crate::model::dimension::Dimension;
|
||||
use crate::model::types::Terrain;
|
||||
use crate::model::tile::TILE_SIZE;
|
||||
use crate::model::types::Terrain;
|
||||
|
||||
use super::{Operation, OperationError, RestoreTerrainOperation};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@ pub enum OperationError {
|
|||
}
|
||||
|
||||
mod brush;
|
||||
mod shaping;
|
||||
mod fill;
|
||||
mod shaping;
|
||||
|
||||
pub use brush::{FloodOperation, PaintOperation, PencilOperation};
|
||||
pub use shaping::{ErodeOperation, FlattenOperation, HeightOperation, MultiTileOperation, SmoothOperation};
|
||||
pub use fill::FillOperation;
|
||||
pub use shaping::{
|
||||
ErodeOperation, FlattenOperation, HeightOperation, MultiTileOperation, SmoothOperation,
|
||||
};
|
||||
|
||||
/// Restores heights from a saved snapshot (used as inverse of FlattenOperation).
|
||||
pub struct RestoreHeightsOperation {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::model::types::Brush;
|
||||
use crate::model::dimension::Dimension;
|
||||
use crate::model::tile::TILE_SIZE;
|
||||
use crate::model::types::Brush;
|
||||
|
||||
use crate::ops::operations::{Operation, OperationError, RestoreHeightsOperation};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::model::types::Brush;
|
||||
use crate::model::dimension::Dimension;
|
||||
use crate::model::tile::TILE_SIZE;
|
||||
use crate::model::types::Brush;
|
||||
|
||||
use crate::ops::operations::{Operation, OperationError, RestoreHeightsOperation};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
mod erode;
|
||||
mod height;
|
||||
mod smooth;
|
||||
mod erode;
|
||||
pub use erode::*;
|
||||
pub use height::*;
|
||||
pub use smooth::*;
|
||||
pub use erode::*;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::sync::Arc;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::model::types::Brush;
|
||||
use crate::model::dimension::Dimension;
|
||||
use crate::model::tile::TILE_SIZE;
|
||||
use crate::model::types::Brush;
|
||||
|
||||
use crate::ops::operations::{Operation, OperationError, RestoreHeightsOperation};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Plugin host — trait-объекты для расширения функциональности.
|
||||
|
||||
mod traits;
|
||||
pub mod registry;
|
||||
mod traits;
|
||||
|
||||
pub use traits::{ExportPlugin, LayerPlugin, OperationPlugin, TileSourcePlugin};
|
||||
pub use registry::PluginRegistry;
|
||||
pub use traits::{ExportPlugin, LayerPlugin, OperationPlugin, TileSourcePlugin};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue