Initial commit: Terrafier v0.1.0
- Core world model (World, Dimension, Tile, Terrain, Platform) - NBT reader/writer with full tag support - Anvil region (.mca) format reader with chunk parsing - Block palette compression and export - Biome database with Minecraft 1.21 biomes - CLI commands: new, import, export, info, render - GUI application with egui (viewport, tools, undo/redo) - Noise-based heightmap generation and editing operations License: GPL-3.0-or-later
This commit is contained in:
commit
91835402b3
94 changed files with 12372 additions and 0 deletions
123
bench/benches/nbt.rs
Executable file
123
bench/benches/nbt.rs
Executable file
|
|
@ -0,0 +1,123 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
use terrafier_nbt::tag::Tag;
|
||||
use terrafier_nbt::{reader, writer};
|
||||
|
||||
fn make_small_compound() -> Tag {
|
||||
let mut map = HashMap::new();
|
||||
map.insert("byte".into(), Tag::Byte(42));
|
||||
map.insert("short".into(), Tag::Short(1000));
|
||||
map.insert("int".into(), Tag::Int(1_000_000));
|
||||
map.insert("long".into(), Tag::Long(1_000_000_000));
|
||||
map.insert("float".into(), Tag::Float(3.14));
|
||||
map.insert("double".into(), Tag::Double(2.718));
|
||||
map.insert("string".into(), Tag::String("Hello, Benchmark!".into()));
|
||||
map.insert(
|
||||
"inner".into(),
|
||||
Tag::Compound(HashMap::from([
|
||||
("x".into(), Tag::Int(10)),
|
||||
("y".into(), Tag::Int(20)),
|
||||
])),
|
||||
);
|
||||
map.insert("arr".into(), Tag::IntArray(vec![1, 2, 3, 4, 5]));
|
||||
map.insert("flag".into(), Tag::Byte(1));
|
||||
Tag::Compound(map)
|
||||
}
|
||||
|
||||
fn make_large_long_array() -> Tag {
|
||||
let vals: Vec<i64> = (0..4096).map(|i| i as i64 * 31 + 7).collect();
|
||||
Tag::Compound(HashMap::from([("data".into(), Tag::LongArray(vals))]))
|
||||
}
|
||||
|
||||
fn make_gzip_roundtrip_tag() -> Tag {
|
||||
Tag::Compound(HashMap::from([
|
||||
("version".into(), Tag::Int(3)),
|
||||
(
|
||||
"data".into(),
|
||||
Tag::ByteArray((0..512).map(|i| i as i8).collect()),
|
||||
),
|
||||
]))
|
||||
}
|
||||
|
||||
fn bench_nbt_parse_small(c: &mut Criterion) {
|
||||
let tag = make_small_compound();
|
||||
let bytes = writer::to_bytes(&tag).unwrap();
|
||||
|
||||
c.bench_function("nbt/parse_small_compound", |b| {
|
||||
b.iter(|| {
|
||||
let result = reader::read_bytes(black_box(&bytes)).unwrap();
|
||||
black_box(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_nbt_parse_large_array(c: &mut Criterion) {
|
||||
let tag = make_large_long_array();
|
||||
let bytes = writer::to_bytes(&tag).unwrap();
|
||||
|
||||
c.bench_function("nbt/parse_large_longarray_4096", |b| {
|
||||
b.iter(|| {
|
||||
let result = reader::read_bytes(black_box(&bytes)).unwrap();
|
||||
black_box(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_nbt_serialize_compound(c: &mut Criterion) {
|
||||
let tag = make_small_compound();
|
||||
|
||||
c.bench_function("nbt/serialize_compound", |b| {
|
||||
b.iter(|| {
|
||||
let result = writer::to_bytes(black_box(&tag)).unwrap();
|
||||
black_box(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_nbt_serialize_large_array(c: &mut Criterion) {
|
||||
let tag = make_large_long_array();
|
||||
|
||||
c.bench_function("nbt/serialize_large_longarray", |b| {
|
||||
b.iter(|| {
|
||||
let result = writer::to_bytes(black_box(&tag)).unwrap();
|
||||
black_box(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_nbt_gzip_roundtrip(c: &mut Criterion) {
|
||||
let tag = make_gzip_roundtrip_tag();
|
||||
|
||||
c.bench_function("nbt/gzip_roundtrip", |b| {
|
||||
b.iter(|| {
|
||||
let compressed = writer::to_gzip_bytes(black_box(&tag)).unwrap();
|
||||
let _parsed = reader::read_gzip(&compressed).unwrap();
|
||||
black_box(compressed);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_nbt_roundtrip_small(c: &mut Criterion) {
|
||||
let tag = make_small_compound();
|
||||
|
||||
c.bench_function("nbt/roundtrip_small", |b| {
|
||||
b.iter(|| {
|
||||
let bytes = writer::to_bytes(black_box(&tag)).unwrap();
|
||||
let _parsed = reader::read_bytes(&bytes).unwrap();
|
||||
black_box(bytes);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
nbt,
|
||||
bench_nbt_parse_small,
|
||||
bench_nbt_parse_large_array,
|
||||
bench_nbt_serialize_compound,
|
||||
bench_nbt_serialize_large_array,
|
||||
bench_nbt_gzip_roundtrip,
|
||||
bench_nbt_roundtrip_small
|
||||
);
|
||||
criterion_main!(nbt);
|
||||
108
bench/benches/render.rs
Executable file
108
bench/benches/render.rs
Executable file
|
|
@ -0,0 +1,108 @@
|
|||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
use terrafier_core::io::export::render_to_image;
|
||||
use terrafier_core::model::tile::Tile;
|
||||
use terrafier_core::model::world::World;
|
||||
|
||||
fn make_world_with_tiles(tile_count: i32) -> World {
|
||||
let mut world = World::new("bench", 42);
|
||||
|
||||
// World::new already creates 9 tiles (-1..=1, -1..=1).
|
||||
// If we need exactly 1 tile, rebuild.
|
||||
if tile_count == 1 {
|
||||
let dim = &mut world.dimensions[0];
|
||||
dim.tiles.clear();
|
||||
dim.tiles.insert(
|
||||
(0, 0),
|
||||
Tile::new(0, 0, world.platform.min_height, world.platform.max_height),
|
||||
);
|
||||
}
|
||||
world
|
||||
}
|
||||
|
||||
fn make_full_world() -> World {
|
||||
make_world_with_tiles(9)
|
||||
}
|
||||
|
||||
fn bench_render_one_tile_scale1(c: &mut Criterion) {
|
||||
let world = make_world_with_tiles(1);
|
||||
let path = std::env::temp_dir().join("terrafier_bench_1.png");
|
||||
|
||||
c.bench_function("render/one_tile_scale1", |b| {
|
||||
b.iter(|| {
|
||||
render_to_image(black_box(&world), &path, 1).unwrap();
|
||||
});
|
||||
});
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
fn bench_render_one_tile_scale2(c: &mut Criterion) {
|
||||
let world = make_world_with_tiles(1);
|
||||
let path = std::env::temp_dir().join("terrafier_bench_s2.png");
|
||||
|
||||
c.bench_function("render/one_tile_scale2", |b| {
|
||||
b.iter(|| {
|
||||
render_to_image(black_box(&world), &path, 2).unwrap();
|
||||
});
|
||||
});
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
fn bench_render_one_tile_scale4(c: &mut Criterion) {
|
||||
let world = make_world_with_tiles(1);
|
||||
let path = std::env::temp_dir().join("terrafier_bench_s4.png");
|
||||
|
||||
c.bench_function("render/one_tile_scale4", |b| {
|
||||
b.iter(|| {
|
||||
render_to_image(black_box(&world), &path, 4).unwrap();
|
||||
});
|
||||
});
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
fn bench_render_3x3_tiles_scale1(c: &mut Criterion) {
|
||||
let world = make_full_world();
|
||||
let path = std::env::temp_dir().join("terrafier_bench_9.png");
|
||||
|
||||
c.bench_function("render/3x3_tiles_scale1", |b| {
|
||||
b.iter(|| {
|
||||
render_to_image(black_box(&world), &path, 1).unwrap();
|
||||
});
|
||||
});
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
fn bench_render_3x3_tiles_scale2(c: &mut Criterion) {
|
||||
let world = make_full_world();
|
||||
let path = std::env::temp_dir().join("terrafier_bench_9s2.png");
|
||||
|
||||
c.bench_function("render/3x3_tiles_scale2", |b| {
|
||||
b.iter(|| {
|
||||
render_to_image(black_box(&world), &path, 2).unwrap();
|
||||
});
|
||||
});
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
fn bench_render_3x3_tiles_scale4(c: &mut Criterion) {
|
||||
let world = make_full_world();
|
||||
let path = std::env::temp_dir().join("terrafier_bench_9s4.png");
|
||||
|
||||
c.bench_function("render/3x3_tiles_scale4", |b| {
|
||||
b.iter(|| {
|
||||
render_to_image(black_box(&world), &path, 4).unwrap();
|
||||
});
|
||||
});
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
render,
|
||||
bench_render_one_tile_scale1,
|
||||
bench_render_one_tile_scale2,
|
||||
bench_render_one_tile_scale4,
|
||||
bench_render_3x3_tiles_scale1,
|
||||
bench_render_3x3_tiles_scale2,
|
||||
bench_render_3x3_tiles_scale4
|
||||
);
|
||||
criterion_main!(render);
|
||||
110
bench/benches/world.rs
Executable file
110
bench/benches/world.rs
Executable file
|
|
@ -0,0 +1,110 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
use terrafier_core::io::export::render_to_image;
|
||||
use terrafier_core::model::brush::SymmetricBrush;
|
||||
use terrafier_core::model::terrain::Terrain;
|
||||
use terrafier_core::model::world::World;
|
||||
use terrafier_core::ops::operations::{
|
||||
HeightOperation, Operation, PaintOperation,
|
||||
};
|
||||
|
||||
fn bench_world_new(c: &mut Criterion) {
|
||||
c.bench_function("world/new_default", |b| {
|
||||
b.iter(|| {
|
||||
let world = World::new(black_box("bench_world"), black_box(42));
|
||||
black_box(world);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_height_operation(c: &mut Criterion) {
|
||||
let mut world = World::new("bench", 42);
|
||||
let brush = Arc::new(SymmetricBrush::new(10.0));
|
||||
let op = HeightOperation {
|
||||
tile_x: 0,
|
||||
tile_z: 0,
|
||||
center_x: 64,
|
||||
center_z: 64,
|
||||
radius: 10,
|
||||
delta: 5,
|
||||
brush,
|
||||
before_snapshot: Default::default(),
|
||||
};
|
||||
|
||||
c.bench_function("world/height_operation", |b| {
|
||||
b.iter(|| {
|
||||
let dim = world.overworld_mut().unwrap();
|
||||
op.apply(black_box(dim)).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_paint_operation(c: &mut Criterion) {
|
||||
let mut world = World::new("bench", 42);
|
||||
let brush = Arc::new(SymmetricBrush::new(10.0));
|
||||
let op = PaintOperation {
|
||||
tile_x: 0,
|
||||
tile_z: 0,
|
||||
center_x: 64,
|
||||
center_z: 64,
|
||||
radius: 10,
|
||||
terrain: Terrain::Forest,
|
||||
brush,
|
||||
before_snapshot: Default::default(),
|
||||
};
|
||||
|
||||
c.bench_function("world/paint_operation", |b| {
|
||||
b.iter(|| {
|
||||
let dim = world.overworld_mut().unwrap();
|
||||
op.apply(black_box(dim)).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_world_serialize_json(c: &mut Criterion) {
|
||||
let world = World::new("bench_ser", 42);
|
||||
|
||||
c.bench_function("world/serialize_json", |b| {
|
||||
b.iter(|| {
|
||||
let json = serde_json::to_string(black_box(&world)).unwrap();
|
||||
black_box(json);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_world_deserialize_json(c: &mut Criterion) {
|
||||
let world = World::new("bench_ser", 42);
|
||||
let json = serde_json::to_string(&world).unwrap();
|
||||
|
||||
c.bench_function("world/deserialize_json", |b| {
|
||||
b.iter(|| {
|
||||
let w: World = serde_json::from_str(black_box(&json)).unwrap();
|
||||
black_box(w);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn bench_world_render_image(c: &mut Criterion) {
|
||||
let world = World::new("bench_render", 42);
|
||||
let path = std::env::temp_dir().join("terrafier_bench_world.png");
|
||||
|
||||
c.bench_function("world/render_image_scale4", |b| {
|
||||
b.iter(|| {
|
||||
render_to_image(black_box(&world), &path, 4).unwrap();
|
||||
});
|
||||
});
|
||||
let _ = std::fs::remove_file(&path);
|
||||
}
|
||||
|
||||
criterion_group!(
|
||||
world,
|
||||
bench_world_new,
|
||||
bench_height_operation,
|
||||
bench_paint_operation,
|
||||
bench_world_serialize_json,
|
||||
bench_world_deserialize_json,
|
||||
bench_world_render_image
|
||||
);
|
||||
criterion_main!(world);
|
||||
Loading…
Add table
Add a link
Reference in a new issue