Wrap TileMap HashMaps in Arc for async pathfinding access
- Add Arc<AHashMap> wrapper around floor_tiles, fixture_tiles, item_tiles - Copy-on-write semantics: Arc::make_mut clones only if other Arcs exist - Add insert_floor, insert_fixture, insert_item, remove_item methods - Add get_floor_mut, get_fixture_mut for visibility updates - Update all mutation sites to use new TileMap methods - Enables cheap Arc::clone for async pathfinding workers - Single-threaded pathfinding: no clone, direct access - Multi-threaded pathfinding: clone Arc, read without locks
This commit is contained in:
@@ -41,15 +41,7 @@ pub fn spawn_prefab(
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.id();
|
.id();
|
||||||
let mut items = tilemap
|
tilemap.insert_item(position.as_ivec3(), meat.index_u32());
|
||||||
.item_tiles
|
|
||||||
.get(&position.as_ivec3())
|
|
||||||
.unwrap_or(&Vec::new())
|
|
||||||
.clone();
|
|
||||||
items.push(meat.index_u32());
|
|
||||||
tilemap
|
|
||||||
.item_tiles
|
|
||||||
.insert(position.as_ivec3(), items.clone());
|
|
||||||
return commands
|
return commands
|
||||||
.entity(meat)
|
.entity(meat)
|
||||||
.insert(VisibleGameEntity)
|
.insert(VisibleGameEntity)
|
||||||
@@ -76,15 +68,7 @@ pub fn spawn_prefab(
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
.id();
|
.id();
|
||||||
let mut items = tilemap
|
tilemap.insert_item(position.as_ivec3(), coin.index_u32());
|
||||||
.item_tiles
|
|
||||||
.get(&position.as_ivec3())
|
|
||||||
.unwrap_or(&Vec::new())
|
|
||||||
.clone();
|
|
||||||
items.push(coin.index_u32());
|
|
||||||
tilemap
|
|
||||||
.item_tiles
|
|
||||||
.insert(position.as_ivec3(), items.clone());
|
|
||||||
commands
|
commands
|
||||||
.entity(coin)
|
.entity(coin)
|
||||||
.insert(VisibleGameEntity)
|
.insert(VisibleGameEntity)
|
||||||
|
|||||||
@@ -116,13 +116,13 @@ pub fn item_tile_management_system(
|
|||||||
|
|
||||||
for position in positions {
|
for position in positions {
|
||||||
let items = match tilemap.item_tiles.get(&position) {
|
let items = match tilemap.item_tiles.get(&position) {
|
||||||
Some(i) => i,
|
Some(i) => i.clone(),
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Clean up empty tiles
|
// Clean up empty tiles
|
||||||
if items.is_empty() {
|
if items.is_empty() {
|
||||||
tilemap.item_tiles.remove(&position);
|
tilemap.remove_item(&position);
|
||||||
rotation_timer.current_indices.remove(&position);
|
rotation_timer.current_indices.remove(&position);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -146,8 +146,8 @@ pub fn item_tile_management_system(
|
|||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
for &entity_id in items {
|
for entity_id in &items {
|
||||||
if let Some(entity) = Entity::from_raw_u32(entity_id) {
|
if let Some(entity) = Entity::from_raw_u32(*entity_id) {
|
||||||
if let Ok(mut rotation_state) = item_query.get_mut(entity) {
|
if let Ok(mut rotation_state) = item_query.get_mut(entity) {
|
||||||
rotation_state.should_be_visible = false;
|
rotation_state.should_be_visible = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ pub fn generate_chunk_forrestry(
|
|||||||
|
|
||||||
let collected_updates = collected_tilemap_updates.into_inner().unwrap();
|
let collected_updates = collected_tilemap_updates.into_inner().unwrap();
|
||||||
for (ivec, data) in collected_updates {
|
for (ivec, data) in collected_updates {
|
||||||
tilemap.fixture_tiles.insert(ivec, data);
|
tilemap.insert_fixture(ivec, data);
|
||||||
}
|
}
|
||||||
if count > 0 {
|
if count > 0 {
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ pub fn generate_chunk_terrain(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(pos, data)| {
|
.map(|(pos, data)| {
|
||||||
tilemap.floor_tiles.insert(pos, data);
|
tilemap.insert_floor(pos, data);
|
||||||
pos
|
pos
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use ahash::AHashMap;
|
use ahash::AHashMap;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// Packed floor tile data for efficient storage. ~35 bytes vs 76 bytes tuple.
|
/// Packed floor tile data for efficient storage. ~35 bytes vs 76 bytes tuple.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@@ -170,12 +171,13 @@ impl FixtureTileData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tile map with fast AHashMap for pathfinding lookups.
|
/// Tile map with Arc-wrapped HashMaps for async pathfinding access.
|
||||||
#[derive(Resource, Default)]
|
/// Uses copy-on-write: Arc::make_mut clones only if other Arcs exist.
|
||||||
|
#[derive(Resource, Clone, Default)]
|
||||||
pub struct TileMap {
|
pub struct TileMap {
|
||||||
pub floor_tiles: AHashMap<IVec3, FloorTileData>,
|
pub floor_tiles: Arc<AHashMap<IVec3, FloorTileData>>,
|
||||||
pub fixture_tiles: AHashMap<IVec3, FixtureTileData>,
|
pub fixture_tiles: Arc<AHashMap<IVec3, FixtureTileData>>,
|
||||||
pub item_tiles: AHashMap<IVec3, Vec<u32>>,
|
pub item_tiles: Arc<AHashMap<IVec3, Vec<u32>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileMap {
|
impl TileMap {
|
||||||
@@ -202,4 +204,37 @@ impl TileMap {
|
|||||||
pub fn has_fixture(&self, pos: &IVec3) -> bool {
|
pub fn has_fixture(&self, pos: &IVec3) -> bool {
|
||||||
self.fixture_tiles.contains_key(pos)
|
self.fixture_tiles.contains_key(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn insert_floor(&mut self, pos: IVec3, tile: FloorTileData) {
|
||||||
|
Arc::make_mut(&mut self.floor_tiles).insert(pos, tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn insert_fixture(&mut self, pos: IVec3, tile: FixtureTileData) {
|
||||||
|
Arc::make_mut(&mut self.fixture_tiles).insert(pos, tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn insert_item(&mut self, pos: IVec3, entity_id: u32) {
|
||||||
|
Arc::make_mut(&mut self.item_tiles)
|
||||||
|
.entry(pos)
|
||||||
|
.or_default()
|
||||||
|
.push(entity_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn remove_item(&mut self, pos: &IVec3) -> Option<Vec<u32>> {
|
||||||
|
Arc::make_mut(&mut self.item_tiles).remove(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_floor_mut(&mut self, pos: &IVec3) -> Option<&mut FloorTileData> {
|
||||||
|
Arc::make_mut(&mut self.floor_tiles).get_mut(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_fixture_mut(&mut self, pos: &IVec3) -> Option<&mut FixtureTileData> {
|
||||||
|
Arc::make_mut(&mut self.fixture_tiles).get_mut(pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ pub fn handle_tile_occlusion_updates(
|
|||||||
for (_, mut tile, pos) in floor_tiles.iter_mut() {
|
for (_, mut tile, pos) in floor_tiles.iter_mut() {
|
||||||
if let Some(visibility) = update_map.get(&pos.translation.as_ivec3()) {
|
if let Some(visibility) = update_map.get(&pos.translation.as_ivec3()) {
|
||||||
tile.visible_range = *visibility;
|
tile.visible_range = *visibility;
|
||||||
if let Some(tile_data) = tilemap.floor_tiles.get_mut(&pos.translation.as_ivec3()) {
|
if let Some(tile_data) = tilemap.get_floor_mut(&pos.translation.as_ivec3()) {
|
||||||
tile_data.visible_range = *visibility;
|
tile_data.visible_range = *visibility;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user