gizmo_engine/systems/
chunk_system.rs1use crate::core::World;
2use gizmo_math::Vec3;
3use std::collections::{HashMap, HashSet};
4
5pub const CHUNK_SIZE: f32 = 100.0;
6pub const CHUNK_LOAD_RADIUS: i32 = 2; pub type ChunkCoord = (i32, i32);
9
10pub struct ChunkEntity {
12 pub coord: ChunkCoord,
13}
14
15pub struct ChunkManager {
17 pub active_chunks: HashSet<ChunkCoord>,
19 pub chunk_entities: HashMap<ChunkCoord, Vec<u64>>,
21 pub last_player_chunk: ChunkCoord,
23}
24
25impl Default for ChunkManager {
26 fn default() -> Self {
27 Self {
28 active_chunks: HashSet::new(),
29 chunk_entities: HashMap::new(),
30 last_player_chunk: (i32::MAX, i32::MAX), }
32 }
33}
34
35impl ChunkManager {
36 pub fn world_pos_to_chunk(pos: Vec3) -> ChunkCoord {
37 (
38 (pos.x / CHUNK_SIZE).floor() as i32,
39 (pos.z / CHUNK_SIZE).floor() as i32,
40 )
41 }
42
43 pub fn chunk_to_world_pos(coord: ChunkCoord) -> Vec3 {
44 Vec3::new(
45 (coord.0 as f32) * CHUNK_SIZE + (CHUNK_SIZE / 2.0),
46 0.0,
47 (coord.1 as f32) * CHUNK_SIZE + (CHUNK_SIZE / 2.0),
48 )
49 }
50
51 pub fn register_entity(&mut self, coord: ChunkCoord, entity_id: u64) {
53 self.chunk_entities
54 .entry(coord)
55 .or_default()
56 .push(entity_id);
57 }
58}
59
60pub fn open_world_chunk_system<F, U>(
64 world: &mut World,
65 player_pos: Vec3,
66 mut load_callback: F,
67 mut unload_callback: U,
68) where
69 F: FnMut(&mut World, ChunkCoord),
70 U: FnMut(&mut World, ChunkCoord, Vec<u64>),
71{
72 if world.get_resource::<ChunkManager>().is_none() {
74 world.insert_resource(ChunkManager::default());
75 }
76
77 let current_chunk = ChunkManager::world_pos_to_chunk(player_pos);
78 let mut chunks_to_load = Vec::new();
79 let mut chunks_to_unload = Vec::new();
80
81 {
83 let mut manager = world.get_resource_mut::<ChunkManager>().unwrap();
84 if manager.last_player_chunk == current_chunk {
85 return; }
87 manager.last_player_chunk = current_chunk;
88
89 let mut expected_chunks = HashSet::new();
90
91 for x in -CHUNK_LOAD_RADIUS..=CHUNK_LOAD_RADIUS {
93 for z in -CHUNK_LOAD_RADIUS..=CHUNK_LOAD_RADIUS {
94 expected_chunks.insert((current_chunk.0 + x, current_chunk.1 + z));
95 }
96 }
97
98 for &chunk in &manager.active_chunks {
100 if !expected_chunks.contains(&chunk) {
101 chunks_to_unload.push(chunk);
102 }
103 }
104
105 for &chunk in &expected_chunks {
107 if !manager.active_chunks.contains(&chunk) {
108 chunks_to_load.push(chunk);
109 }
110 }
111 } for chunk in chunks_to_unload {
115 let mut manager = world.get_resource_mut::<ChunkManager>().unwrap();
116 manager.active_chunks.remove(&chunk);
117
118 if let Some(entities) = manager.chunk_entities.remove(&chunk) {
119 drop(manager);
121 unload_callback(world, chunk, entities);
122 }
123 tracing::info!("🗑️ Chunk Yüklemesi Kaldırıldı (Havuzlandı): {:?}", chunk);
124 }
125
126 for chunk in chunks_to_load {
128 {
129 let mut manager = world.get_resource_mut::<ChunkManager>().unwrap();
130 manager.active_chunks.insert(chunk);
131 }
132 tracing::info!("🌍 Yeni Chunk Yüklendi: {:?}", chunk);
133
134 load_callback(world, chunk);
136 }
137}