use bevy::prelude::*;
use bevy::reflect::Reflect;
use rand::{seq::SliceRandom, SeedableRng};
use std::hash::Hash;
use crate::{
enums::biome::{Altitude, Biome, Humidity, Latitude},
noise::OBJECT_POOL,
};
#[derive(Debug, Clone, Resource, Reflect, Default, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
#[allow(clippy::module_name_repetitions)]
pub struct BiomeData {
pub biome: Biome,
pub altitude: Altitude,
pub humidity: Humidity,
pub latitude: Latitude,
pub ground_tilesets: Vec<TilesetDetail>,
pub simple_objects: Vec<SimpleObjectDetail>,
}
impl BiomeData {
#[must_use]
pub const fn barren() -> Self {
Self {
biome: Biome::Barren,
altitude: Altitude::Montane,
humidity: Humidity::Arid,
latitude: Latitude::WarmTemperate,
ground_tilesets: Vec::new(),
simple_objects: Vec::new(),
}
}
pub fn random_ground_tile(&self) -> Option<(&str, usize)> {
let mut rng = rand::thread_rng();
if self.ground_tilesets.is_empty() {
tracing::error!("random_ground_tile: no ground tilesets!");
return None;
}
let Some(tileset) = self.ground_tilesets.choose(&mut rng) else {
tracing::error!("random_ground_tile: unable to get random tilset!");
return None;
};
let Ok(tile) = tileset
.weights
.choose_weighted(&mut rng, |item| item.weight)
else {
tracing::error!("random_ground_tile: unable to get random tile!");
return None;
};
Some((tileset.id.as_str(), tile.tile))
}
#[must_use]
pub fn object_pool(&self, seed: u64) -> Vec<Option<&str>> {
let mut pool = Vec::with_capacity(OBJECT_POOL);
for object in &self.simple_objects {
for _ in 0..object.weight {
pool.push(Some(object.id.as_str()));
}
}
while pool.len() < OBJECT_POOL {
pool.push(None);
}
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed);
pool.shuffle(&mut rng);
pool
}
}
#[derive(Debug, Clone, Resource, Reflect, Default, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TilesetDetail {
pub id: String,
pub weights: Vec<TilesetWeight>,
}
#[derive(Debug, Clone, Resource, Reflect, Default, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TilesetWeight {
pub tile: usize,
pub weight: f32,
}
impl Hash for BiomeData {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.biome.hash(state);
self.altitude.hash(state);
self.humidity.hash(state);
self.latitude.hash(state);
}
}
#[derive(Debug, Clone, Resource, Reflect, Default, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SimpleObjectDetail {
pub id: String,
pub weight: usize,
}