chunk_saving_super/
chunk_saving_super.rs1use bevy::prelude::*;
6use chunky_bevy::prelude::*;
7use serde::{Deserialize, Serialize};
8
9fn main() {
10 App::new()
11 .add_plugins(DefaultPlugins)
12 .add_plugins(ChunkyPlugin::default())
13 .add_plugins(ChunkSavingPlugin::new("saves/super_world").with_style(
14 SaveStyle::SuperChunk {
15 size: UVec3::splat(4),
16 },
17 ))
18 .register_chunk_data::<SimpleData>()
19 .add_systems(Startup, setup)
20 .add_systems(Update, (handle_input, visualize_chunks))
21 .run();
22}
23
24#[derive(Component, Serialize, Deserialize, Clone, Debug)]
25struct SimpleData {
26 id: i32,
27}
28
29fn setup(mut commands: Commands) {
30 for x in -4..=4 {
32 for z in -4..=4 {
33 let pos = IVec3::new(x, 0, z);
34 commands.spawn((Chunk, ChunkPos(pos), SimpleData { id: x * 100 + z }));
35 }
36 }
37
38 commands.spawn((
39 Camera3d::default(),
40 Transform::from_xyz(0.0, 120.0, 0.0).looking_at(Vec3::ZERO, Vec3::Z),
41 ));
42
43 info!("SuperChunk mode: 4x4x4 chunks per file");
44 info!("Press S for batch save, L for batch load, C to clear, I to inspect files");
45}
46
47fn handle_input(
48 keys: Res<ButtonInput<KeyCode>>,
49 world: &World,
50 mut commands: Commands,
51 chunks: Query<Entity, With<Chunk>>,
52 registry: Res<ChunkDataRegistry>,
53 config: Res<ChunkSaveConfig>,
54) {
55 if keys.just_pressed(KeyCode::KeyS) {
57 let entities: Vec<_> = chunks.iter().collect();
58 match registry.save_batch(world, &entities, &config) {
59 Ok(_) => info!("Batch saved {} chunks", entities.len()),
60 Err(e) => error!("Batch save failed: {:?}", e),
61 }
62 }
63
64 if keys.just_pressed(KeyCode::KeyL) {
66 for sx in -1..=1 {
68 for sz in -1..=1 {
69 let pos = IVec3::new(sx * 4, 0, sz * 4);
71 match registry.load_batch(&mut commands, &config, pos) {
72 Ok(loaded) => {
73 info!(
74 "Loaded {} chunks from super-chunk ({}, {})",
75 loaded.len(),
76 sx,
77 sz
78 );
79 }
80 Err(e) => warn!("No super-chunk at ({}, {}): {:?}", sx, sz, e),
81 }
82 }
83 }
84 }
85
86 if keys.just_pressed(KeyCode::KeyC) {
88 for entity in chunks.iter() {
89 commands.entity(entity).despawn();
90 }
91 info!("Cleared all chunks");
92 }
93
94 if keys.just_pressed(KeyCode::KeyI) {
96 match std::fs::read_dir(&config.base_path) {
97 Ok(entries) => {
98 info!("Save files:");
99 for entry in entries.flatten() {
100 let path = entry.path();
101 let size = std::fs::metadata(&path).map(|m| m.len()).unwrap_or(0);
102 info!(" {:?} ({} bytes)", path.file_name().unwrap(), size);
103 }
104 }
105 Err(_) => info!("No save directory yet"),
106 }
107 }
108}
109
110fn visualize_chunks(
111 chunks: Query<(&ChunkPos, Option<&SimpleData>), With<Chunk>>,
112 config: Res<ChunkSaveConfig>,
113 mut gizmos: Gizmos,
114) {
115 let chunk_size = 10.0;
116
117 for (pos, data) in chunks.iter() {
119 let world_pos = pos.0.as_vec3() * chunk_size + Vec3::new(5.0, 0.0, 5.0);
120
121 let color = if data.is_some() {
123 Color::srgb(0.2, 0.8, 0.2)
124 } else {
125 Color::srgb(0.8, 0.2, 0.2)
126 };
127
128 gizmos.rect(
129 Isometry3d::new(
130 world_pos,
131 Quat::from_rotation_x(std::f32::consts::FRAC_PI_2),
132 ),
133 Vec2::splat(chunk_size - 0.5),
134 color,
135 );
136 }
137
138 if let SaveStyle::SuperChunk { size } = &config.style {
140 let super_size = size.as_vec3() * chunk_size;
141
142 for sx in -1..=1 {
143 for sz in -1..=1 {
144 let super_pos = Vec3::new(
145 sx as f32 * super_size.x + super_size.x / 2.0,
146 0.5,
147 sz as f32 * super_size.z + super_size.z / 2.0,
148 );
149
150 gizmos.rect(
152 Isometry3d::new(
153 super_pos,
154 Quat::from_rotation_x(std::f32::consts::FRAC_PI_2),
155 ),
156 Vec2::new(super_size.x - 0.2, super_size.z - 0.2),
157 Color::srgb(1.0, 1.0, 0.0),
158 );
159 }
160 }
161 }
162}