mirror of
https://github.com/Xevion/smart-rgb.git
synced 2025-12-06 01:16:24 -06:00
207 lines
7.7 KiB
Rust
207 lines
7.7 KiB
Rust
#![allow(dead_code)]
|
|
#![allow(unused_imports)]
|
|
|
|
/// Shared test utilities and helpers
|
|
///
|
|
/// This module provides infrastructure for testing the Bevy ECS-based game logic:
|
|
/// - `builders`: Fluent API for constructing test worlds and maps
|
|
/// - `assertions`: Fluent assertion API for ECS state verification
|
|
/// - `fixtures`: Pre-built test scenarios for integration tests
|
|
///
|
|
/// # Usage Example
|
|
/// ```
|
|
/// use common::builders::TestWorld;
|
|
///
|
|
/// let mut world = TestWorld::new()
|
|
/// .with_player(NationId::ZERO, 100.0)
|
|
/// .with_map_size(50, 50)
|
|
/// .build();
|
|
///
|
|
/// world.conquer_tile(U16Vec2::new(5, 5), NationId::ZERO);
|
|
/// world.assert().player_owns(U16Vec2::new(5, 5), NationId::ZERO);
|
|
/// ```
|
|
use borders_core::prelude::*;
|
|
use extension_traits::extension;
|
|
use std::collections::HashMap;
|
|
use std::collections::HashSet;
|
|
|
|
mod assertions;
|
|
mod builders;
|
|
mod fixtures;
|
|
|
|
// Re-export commonly used items
|
|
pub use assertions::*;
|
|
pub use builders::*;
|
|
pub use fixtures::*;
|
|
|
|
/// Extension trait providing convenient action methods for World in tests
|
|
#[extension(pub trait WorldTestExt)]
|
|
impl World {
|
|
/// Conquer a tile for a player
|
|
fn conquer_tile(&mut self, tile: U16Vec2, player: NationId) {
|
|
self.resource_mut::<TerritoryManager>().conquer(tile, player);
|
|
}
|
|
|
|
/// Conquer multiple tiles for a player
|
|
fn conquer_tiles(&mut self, tiles: &[U16Vec2], player: NationId) {
|
|
let mut territory_manager = self.resource_mut::<TerritoryManager>();
|
|
for &tile in tiles {
|
|
territory_manager.conquer(tile, player);
|
|
}
|
|
}
|
|
|
|
/// Conquer a square region of tiles centered at a position
|
|
///
|
|
/// Conquers all tiles within `radius` steps of `center` (using taxicab distance).
|
|
/// For radius=1, conquers a 3x3 square. For radius=2, conquers a 5x5 square, etc.
|
|
fn conquer_region(&mut self, center: U16Vec2, radius: i32, player: NationId) {
|
|
let mut territory_manager = self.resource_mut::<TerritoryManager>();
|
|
for dy in -radius..=radius {
|
|
for dx in -radius..=radius {
|
|
let tile = center.as_ivec2() + glam::IVec2::new(dx, dy);
|
|
if tile.x >= 0 && tile.y >= 0 {
|
|
let tile = tile.as_u16vec2();
|
|
if tile.x < territory_manager.width() && tile.y < territory_manager.height() {
|
|
territory_manager.conquer(tile, player);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Conquer all 4-directional neighbors of a tile
|
|
fn conquer_neighbors(&mut self, center: U16Vec2, player: NationId) {
|
|
let map_size = {
|
|
let mgr = self.resource::<TerritoryManager>();
|
|
U16Vec2::new(mgr.width(), mgr.height())
|
|
};
|
|
|
|
let mut territory_manager = self.resource_mut::<TerritoryManager>();
|
|
for neighbor in neighbors(center, map_size) {
|
|
territory_manager.conquer(neighbor, player);
|
|
}
|
|
}
|
|
|
|
/// Clear ownership of a tile, returning the previous owner
|
|
fn clear_tile(&mut self, tile: U16Vec2) -> Option<NationId> {
|
|
self.resource_mut::<TerritoryManager>().clear(tile)
|
|
}
|
|
|
|
fn est(&mut self) {}
|
|
|
|
/// Clear all territory changes from the change buffer
|
|
fn clear_territory_changes(&mut self) {
|
|
self.resource_mut::<TerritoryManager>().clear_changes();
|
|
}
|
|
|
|
/// Deactivate the spawn phase
|
|
fn deactivate_spawn_phase(&mut self) {
|
|
self.resource_mut::<SpawnPhase>().active = false;
|
|
}
|
|
|
|
/// Activate the spawn phase
|
|
fn activate_spawn_phase(&mut self) {
|
|
self.resource_mut::<SpawnPhase>().active = true;
|
|
}
|
|
|
|
/// Get the number of territory changes in the ChangeBuffer
|
|
fn get_change_count(&self) -> usize {
|
|
self.resource::<TerritoryManager>().iter_changes().count()
|
|
}
|
|
|
|
/// Get the entity associated with a player
|
|
fn get_player_entity(&self, player_id: NationId) -> Entity {
|
|
let entity_map = self.resource::<PlayerEntityMap>();
|
|
*entity_map.0.get(&player_id).unwrap_or_else(|| panic!("Player entity not found for player {}", player_id.get()))
|
|
}
|
|
|
|
/// Run the border update logic (inline implementation for testing)
|
|
fn update_borders(&mut self) {
|
|
// Check if there are changes
|
|
{
|
|
let territory_manager = self.resource::<TerritoryManager>();
|
|
if !territory_manager.has_changes() {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Collect all data we need from TerritoryManager before mutating
|
|
let (changed_tiles, map_size, tiles_by_owner) = {
|
|
let territory_manager = self.resource::<TerritoryManager>();
|
|
|
|
let changed_tiles: HashSet<U16Vec2> = territory_manager.iter_changes().collect();
|
|
let map_size = U16Vec2::new(territory_manager.width(), territory_manager.height());
|
|
|
|
let mut affected_tiles = HashSet::with_capacity(changed_tiles.len() * 5);
|
|
for &tile in &changed_tiles {
|
|
affected_tiles.insert(tile);
|
|
affected_tiles.extend(neighbors(tile, map_size));
|
|
}
|
|
|
|
// Group tiles by owner
|
|
let mut tiles_by_owner: HashMap<NationId, HashSet<U16Vec2>> = HashMap::new();
|
|
for &tile in &affected_tiles {
|
|
if let Some(nation_id) = territory_manager.get_nation_id(tile) {
|
|
tiles_by_owner.entry(nation_id).or_default().insert(tile);
|
|
}
|
|
}
|
|
|
|
(changed_tiles, map_size, tiles_by_owner)
|
|
};
|
|
|
|
// Build ownership snapshot for border checking
|
|
let ownership_snapshot: HashMap<U16Vec2, Option<NationId>> = {
|
|
let territory_manager = self.resource::<TerritoryManager>();
|
|
let mut snapshot = HashMap::new();
|
|
for &tile in changed_tiles.iter() {
|
|
for neighbor in neighbors(tile, map_size) {
|
|
snapshot.entry(neighbor).or_insert_with(|| territory_manager.get_nation_id(neighbor));
|
|
}
|
|
snapshot.insert(tile, territory_manager.get_nation_id(tile));
|
|
}
|
|
snapshot
|
|
};
|
|
|
|
// Update each player's borders
|
|
let mut players_query = self.query::<(&NationId, &mut BorderTiles)>();
|
|
for (nation_id, mut component_borders) in players_query.iter_mut(self) {
|
|
let empty_set = HashSet::new();
|
|
let player_tiles = tiles_by_owner.get(nation_id).unwrap_or(&empty_set);
|
|
|
|
// Process tiles owned by this player
|
|
for &tile in player_tiles {
|
|
let is_border = neighbors(tile, map_size).any(|neighbor| ownership_snapshot.get(&neighbor).and_then(|&owner| owner) != Some(*nation_id));
|
|
|
|
if is_border {
|
|
component_borders.0.insert(tile);
|
|
} else {
|
|
component_borders.0.remove(&tile);
|
|
}
|
|
}
|
|
|
|
// Remove tiles that changed ownership away from this player
|
|
for &tile in changed_tiles.iter() {
|
|
if ownership_snapshot.get(&tile).and_then(|&owner| owner) != Some(*nation_id) {
|
|
component_borders.0.remove(&tile);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Clear territory changes
|
|
fn clear_borders_changes(&mut self) {
|
|
self.resource_mut::<TerritoryManager>().clear_changes();
|
|
}
|
|
|
|
/// Get border tiles for a player from ECS component
|
|
fn get_player_borders(&self, player_id: NationId) -> HashSet<U16Vec2> {
|
|
let entity = self.get_player_entity(player_id);
|
|
self.get::<BorderTiles>(entity).expect("Player entity missing BorderTiles component").0.clone()
|
|
}
|
|
|
|
/// Get border tiles for a player from BorderCache
|
|
fn get_border_cache(&self, player_id: NationId) -> Option<HashSet<U16Vec2>> {
|
|
self.resource::<BorderCache>().get(player_id).cloned()
|
|
}
|
|
}
|