organization and buidings db
This commit is contained in:
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -1321,6 +1321,14 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "buildings"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bevy",
|
||||||
|
"world_generation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.15.4"
|
version = "3.15.4"
|
||||||
@@ -3246,6 +3254,7 @@ dependencies = [
|
|||||||
"bevy",
|
"bevy",
|
||||||
"bevy-inspector-egui 0.23.4",
|
"bevy-inspector-egui 0.23.4",
|
||||||
"bevy_rapier3d",
|
"bevy_rapier3d",
|
||||||
|
"buildings",
|
||||||
"iyes_perf_ui",
|
"iyes_perf_ui",
|
||||||
"noise 0.8.2",
|
"noise 0.8.2",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"game/main",
|
"game/main",
|
||||||
|
"game/buildings",
|
||||||
"engine/world_generation",
|
"engine/world_generation",
|
||||||
"engine/asset_loader"]
|
"engine/asset_loader", "game/buildings"]
|
||||||
|
|
||||||
# Enable a small amount of optimization in debug mode
|
# Enable a small amount of optimization in debug mode
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
@@ -14,4 +15,4 @@ opt-level = 1
|
|||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|||||||
34
engine/world_generation/src/consts.rs
Normal file
34
engine/world_generation/src/consts.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use bevy::{
|
||||||
|
prelude::*,
|
||||||
|
render::{mesh::MeshVertexAttribute, render_resource::VertexFormat},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::hex_utils::{INNER_RADIUS, OUTER_RADIUS};
|
||||||
|
|
||||||
|
pub const TEX_MULTI: Vec2 = Vec2::new(1000., 1.);
|
||||||
|
|
||||||
|
pub const HEX_CORNERS: [Vec3; 6] = [
|
||||||
|
Vec3::new(0., 0., OUTER_RADIUS),
|
||||||
|
Vec3::new(INNER_RADIUS, 0., 0.5 * OUTER_RADIUS),
|
||||||
|
Vec3::new(INNER_RADIUS, 0., -0.5 * OUTER_RADIUS),
|
||||||
|
Vec3::new(0., 0., -OUTER_RADIUS),
|
||||||
|
Vec3::new(-INNER_RADIUS, 0., -0.5 * OUTER_RADIUS),
|
||||||
|
Vec3::new(-INNER_RADIUS, 0., 0.5 * OUTER_RADIUS),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const HEX_NORMALS: [Vec3; 6] = [
|
||||||
|
Vec3::new(INNER_RADIUS / 2., 0., (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / 2.),
|
||||||
|
Vec3::Z,
|
||||||
|
Vec3::new(INNER_RADIUS / -2., 0., (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / 2.),
|
||||||
|
Vec3::new(INNER_RADIUS / -2., 0., (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / -2.),
|
||||||
|
Vec3::NEG_Z,
|
||||||
|
Vec3::new(INNER_RADIUS / 2., 0., (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / -2.),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub const ATTRIBUTE_PACKED_VERTEX_DATA: MeshVertexAttribute =
|
||||||
|
MeshVertexAttribute::new("PackedVertexData", 988540817, VertexFormat::Uint32);
|
||||||
|
pub const ATTRIBUTE_VERTEX_HEIGHT: MeshVertexAttribute =
|
||||||
|
MeshVertexAttribute::new("VertexHeight", 988540717, VertexFormat::Float32);
|
||||||
|
|
||||||
|
pub const ATTRIBUTE_TEXTURE_INDEX: MeshVertexAttribute =
|
||||||
|
MeshVertexAttribute::new("TextureIndex", 988540917, VertexFormat::Uint32);
|
||||||
3
engine/world_generation/src/generators/mod.rs
Normal file
3
engine/world_generation/src/generators/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
pub mod chunk_colliders;
|
||||||
|
pub mod mesh_generator;
|
||||||
|
pub mod packed_mesh_generator;
|
||||||
@@ -1,333 +1,9 @@
|
|||||||
pub mod biome_painter;
|
pub mod biome_painter;
|
||||||
pub mod chunk_colliders;
|
pub mod consts;
|
||||||
|
pub mod generators;
|
||||||
pub mod heightmap;
|
pub mod heightmap;
|
||||||
pub mod hex_utils;
|
pub mod hex_utils;
|
||||||
pub mod mesh_generator;
|
pub mod map;
|
||||||
pub mod packed_mesh_generator;
|
pub mod prelude;
|
||||||
pub mod tile_manager;
|
pub mod tile_manager;
|
||||||
pub mod tile_mapper;
|
pub mod tile_mapper;
|
||||||
|
|
||||||
pub mod prelude {
|
|
||||||
use crate::hex_utils::{get_tile_count, HexCoord, INNER_RADIUS, OUTER_RADIUS, SHORT_DIAGONAL};
|
|
||||||
use bevy::math::{IVec2, UVec2, Vec2, Vec3};
|
|
||||||
use bevy::prelude::Resource;
|
|
||||||
use bevy::prelude::*;
|
|
||||||
use bevy::render::mesh::MeshVertexAttribute;
|
|
||||||
use bevy::render::render_resource::VertexFormat;
|
|
||||||
use bevy_inspector_egui::InspectorOptions;
|
|
||||||
use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
|
||||||
pub const TEX_MULTI: Vec2 = Vec2::new(1000., 1.);
|
|
||||||
|
|
||||||
pub const HEX_CORNERS: [Vec3; 6] = [
|
|
||||||
Vec3::new(0., 0., OUTER_RADIUS),
|
|
||||||
Vec3::new(INNER_RADIUS, 0., 0.5 * OUTER_RADIUS),
|
|
||||||
Vec3::new(INNER_RADIUS, 0., -0.5 * OUTER_RADIUS),
|
|
||||||
Vec3::new(0., 0., -OUTER_RADIUS),
|
|
||||||
Vec3::new(-INNER_RADIUS, 0., -0.5 * OUTER_RADIUS),
|
|
||||||
Vec3::new(-INNER_RADIUS, 0., 0.5 * OUTER_RADIUS),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const HEX_NORMALS: [Vec3; 6] = [
|
|
||||||
Vec3::new(INNER_RADIUS / 2., 0., (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / 2.),
|
|
||||||
Vec3::Z,
|
|
||||||
Vec3::new(INNER_RADIUS / -2., 0., (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / 2.),
|
|
||||||
Vec3::new(INNER_RADIUS / -2., 0., (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / -2.),
|
|
||||||
Vec3::NEG_Z,
|
|
||||||
Vec3::new(INNER_RADIUS / 2., 0., (OUTER_RADIUS + 0.5 * OUTER_RADIUS) / -2.),
|
|
||||||
];
|
|
||||||
|
|
||||||
#[derive(Resource, Reflect, Default)]
|
|
||||||
#[reflect(Resource)]
|
|
||||||
pub struct GenerationConfig {
|
|
||||||
pub noise_scale: f64,
|
|
||||||
pub sea_level: f64,
|
|
||||||
pub border_size: f32,
|
|
||||||
pub size: UVec2,
|
|
||||||
pub layers: Vec<GeneratorLayer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GenerationConfig {
|
|
||||||
pub fn get_total_width(&self) -> usize {
|
|
||||||
return self.size.x as usize * Chunk::SIZE;
|
|
||||||
}
|
|
||||||
pub fn get_total_height(&self) -> usize {
|
|
||||||
return self.size.y as usize * Chunk::SIZE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Reflect, InspectorOptions)]
|
|
||||||
pub struct GeneratorLayer {
|
|
||||||
pub strength: f64,
|
|
||||||
pub min_value: f64,
|
|
||||||
pub base_roughness: f64,
|
|
||||||
pub roughness: f64,
|
|
||||||
pub persistence: f64,
|
|
||||||
pub is_rigid: bool,
|
|
||||||
pub weight: f64,
|
|
||||||
pub weight_multi: f64,
|
|
||||||
pub layers: usize,
|
|
||||||
pub first_layer_mask: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Chunk {
|
|
||||||
pub heights: [f32; Chunk::AREA],
|
|
||||||
pub textures: [[u32; 2]; Chunk::AREA],
|
|
||||||
pub moisture: [f32; Chunk::AREA],
|
|
||||||
pub temperature: [f32; Chunk::AREA],
|
|
||||||
pub chunk_offset: IVec2,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Chunk {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
heights: [0.; Chunk::AREA],
|
|
||||||
textures: [[0; 2]; Chunk::AREA],
|
|
||||||
moisture: [0.; Chunk::AREA],
|
|
||||||
temperature: [0.; Chunk::AREA],
|
|
||||||
chunk_offset: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Chunk {
|
|
||||||
pub const SIZE: usize = 64;
|
|
||||||
pub const AREA: usize = Chunk::SIZE * Chunk::SIZE;
|
|
||||||
pub const WORLD_WIDTH: f32 = Chunk::SIZE as f32 * SHORT_DIAGONAL;
|
|
||||||
pub const WORLD_HEIGHT: f32 = Chunk::SIZE as f32 * 1.5;
|
|
||||||
pub const WORLD_SIZE: Vec2 = Vec2::new(Chunk::WORLD_WIDTH, Chunk::WORLD_HEIGHT);
|
|
||||||
|
|
||||||
pub fn get_pos_z_edge(&self) -> [f32; Chunk::SIZE] {
|
|
||||||
let mut data = [0.; Chunk::SIZE];
|
|
||||||
|
|
||||||
for x in 0..Chunk::SIZE {
|
|
||||||
let idx = x + (Chunk::SIZE - 1) * Chunk::SIZE;
|
|
||||||
data[x] = self.heights[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_neg_z_edge(&self) -> [f32; Chunk::SIZE] {
|
|
||||||
let mut data = [0.; Chunk::SIZE];
|
|
||||||
|
|
||||||
for x in 0..Chunk::SIZE {
|
|
||||||
data[x] = self.heights[x];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_pos_x_edge(&self) -> [f32; Chunk::SIZE] {
|
|
||||||
let mut data = [0.; Chunk::SIZE];
|
|
||||||
|
|
||||||
for z in 0..Chunk::SIZE {
|
|
||||||
let idx = (Chunk::SIZE - 1) + z * Chunk::SIZE;
|
|
||||||
data[z] = self.heights[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_neg_x_edge(&self) -> [f32; Chunk::SIZE] {
|
|
||||||
let mut data = [0.; Chunk::SIZE];
|
|
||||||
|
|
||||||
for z in 0..Chunk::SIZE {
|
|
||||||
let idx = z * Chunk::SIZE;
|
|
||||||
data[z] = self.heights[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MeshChunkData {
|
|
||||||
pub heights: [f32; Chunk::AREA],
|
|
||||||
pub textures: [[u32; 2]; Chunk::AREA],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MeshChunkData {
|
|
||||||
pub fn get_neighbors(&self, coord: &HexCoord) -> [f32; 6] {
|
|
||||||
let mut data = [0.; 6];
|
|
||||||
let n_tiles = coord.get_neighbors();
|
|
||||||
for i in 0..6 {
|
|
||||||
let n = n_tiles[i];
|
|
||||||
if !n.is_in_bounds(Chunk::SIZE, Chunk::SIZE) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
data[i] = self.heights[n.to_index(Chunk::SIZE)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Resource, Clone)]
|
|
||||||
pub struct Map {
|
|
||||||
pub chunks: Vec<Chunk>,
|
|
||||||
pub height: usize,
|
|
||||||
pub width: usize,
|
|
||||||
pub sea_level: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Map {
|
|
||||||
pub fn get_chunk_mesh_data(&self, chunk_index: usize) -> MeshChunkData {
|
|
||||||
#[cfg(feature = "tracing")]
|
|
||||||
let _spawn_span = info_span!("Chunk Mesh Data").entered();
|
|
||||||
let chunk = &self.chunks[chunk_index];
|
|
||||||
|
|
||||||
return MeshChunkData {
|
|
||||||
heights: chunk.heights.clone(),
|
|
||||||
textures: chunk.textures.clone(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_neighbors(&self, pos: &HexCoord) -> [Option<f32>; 6] {
|
|
||||||
let mut results: [Option<f32>; 6] = [None; 6];
|
|
||||||
let w = self.width * Chunk::SIZE;
|
|
||||||
let h = self.height * Chunk::SIZE;
|
|
||||||
let n_tiles = pos.get_neighbors();
|
|
||||||
for i in 0..6 {
|
|
||||||
let n_tile = n_tiles[i];
|
|
||||||
if !n_tile.is_in_bounds(h, w) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let c_idx = n_tile.to_chunk_index(self.width);
|
|
||||||
let chunk = &self.chunks[c_idx];
|
|
||||||
let local = n_tile.to_chunk_local_index();
|
|
||||||
results[i] = Some(chunk.heights[local]);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sample_height(&self, pos: &HexCoord) -> f32 {
|
|
||||||
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
|
||||||
return chunk.heights[pos.to_chunk_local_index()];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sample_height_mut(&mut self, pos: &HexCoord) -> &mut f32 {
|
|
||||||
let chunk = &mut self.chunks[pos.to_chunk_index(self.width)];
|
|
||||||
return &mut chunk.heights[pos.to_chunk_local_index()];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_in_bounds(&self, pos: &HexCoord) -> bool {
|
|
||||||
return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_moisture(&self, pos: &HexCoord) -> f32 {
|
|
||||||
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
|
||||||
return chunk.moisture[pos.to_chunk_local_index()];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_tempurature(&self, pos: &HexCoord) -> f32 {
|
|
||||||
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
|
||||||
return chunk.temperature[pos.to_chunk_local_index()];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_center(&self) -> Vec3 {
|
|
||||||
let w = self.get_world_width();
|
|
||||||
let h = self.get_world_height();
|
|
||||||
return Vec3::new(w / 2., self.sea_level, h / 2.);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_world_width(&self) -> f32 {
|
|
||||||
return (self.width * Chunk::SIZE) as f32 * SHORT_DIAGONAL;
|
|
||||||
}
|
|
||||||
pub fn get_world_height(&self) -> f32 {
|
|
||||||
return (self.height * Chunk::SIZE) as f32 * 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_world_size(&self) -> Vec2 {
|
|
||||||
return Vec2::new(self.get_world_width(), self.get_world_height());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_height(&mut self, pos: &HexCoord, height: f32) {
|
|
||||||
self.chunks[pos.to_chunk_index(self.width)].heights[pos.to_chunk_local_index()] = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_crater(&mut self, pos: &HexCoord, radius: usize, depth: f32) -> Vec<usize> {
|
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
|
||||||
let width = self.width;
|
|
||||||
|
|
||||||
let mut chunks = self.hex_select_mut(pos, radius, true, |p, h, r| {
|
|
||||||
let d = (r as f32) / (radius as f32);
|
|
||||||
let cur = *h;
|
|
||||||
let h2 = cur - depth;
|
|
||||||
*h = h2.lerp(cur, d * d);
|
|
||||||
|
|
||||||
return p.to_chunk_index(width);
|
|
||||||
});
|
|
||||||
|
|
||||||
chunks.dedup();
|
|
||||||
|
|
||||||
return chunks;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hex_select<OP, Ret>(&self, center: &HexCoord, radius: usize, include_center: bool, op: OP) -> Vec<Ret>
|
|
||||||
where
|
|
||||||
OP: Fn(&HexCoord, f32, usize) -> Ret + Sync + Send,
|
|
||||||
{
|
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
|
||||||
|
|
||||||
if include_center {
|
|
||||||
let h = self.sample_height(¢er);
|
|
||||||
(op)(¢er, h, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = Vec::with_capacity(get_tile_count(radius));
|
|
||||||
|
|
||||||
for k in 0..(radius + 1) {
|
|
||||||
let mut p = center.scale(4, k);
|
|
||||||
for i in 0..6 {
|
|
||||||
for _j in 0..k {
|
|
||||||
p = p.get_neighbor(i);
|
|
||||||
let h = self.sample_height(&p);
|
|
||||||
result.push((op)(&p, h, k));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hex_select_mut<OP, Ret>(
|
|
||||||
&mut self,
|
|
||||||
center: &HexCoord,
|
|
||||||
radius: usize,
|
|
||||||
include_center: bool,
|
|
||||||
op: OP,
|
|
||||||
) -> Vec<Ret>
|
|
||||||
where
|
|
||||||
OP: Fn(&HexCoord, &mut f32, usize) -> Ret + Sync + Send,
|
|
||||||
{
|
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
|
||||||
|
|
||||||
if include_center {
|
|
||||||
let h = self.sample_height_mut(¢er);
|
|
||||||
(op)(¢er, h, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut result = Vec::with_capacity(get_tile_count(radius));
|
|
||||||
|
|
||||||
for k in 0..(radius + 1) {
|
|
||||||
let mut p = center.scale(4, k);
|
|
||||||
for i in 0..6 {
|
|
||||||
for _j in 0..k {
|
|
||||||
p = p.get_neighbor(i);
|
|
||||||
let h = self.sample_height_mut(&p);
|
|
||||||
result.push((op)(&p, h, k));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const ATTRIBUTE_PACKED_VERTEX_DATA: MeshVertexAttribute =
|
|
||||||
MeshVertexAttribute::new("PackedVertexData", 988540817, VertexFormat::Uint32);
|
|
||||||
pub const ATTRIBUTE_VERTEX_HEIGHT: MeshVertexAttribute =
|
|
||||||
MeshVertexAttribute::new("VertexHeight", 988540717, VertexFormat::Float32);
|
|
||||||
|
|
||||||
pub const ATTRIBUTE_TEXTURE_INDEX: MeshVertexAttribute =
|
|
||||||
MeshVertexAttribute::new("TextureIndex", 988540917, VertexFormat::Uint32);
|
|
||||||
}
|
|
||||||
|
|||||||
74
engine/world_generation/src/map/chunk.rs
Normal file
74
engine/world_generation/src/map/chunk.rs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
use crate::hex_utils::SHORT_DIAGONAL;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Chunk {
|
||||||
|
pub heights: [f32; Chunk::AREA],
|
||||||
|
pub textures: [[u32; 2]; Chunk::AREA],
|
||||||
|
pub moisture: [f32; Chunk::AREA],
|
||||||
|
pub temperature: [f32; Chunk::AREA],
|
||||||
|
pub chunk_offset: IVec2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Chunk {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
heights: [0.; Chunk::AREA],
|
||||||
|
textures: [[0; 2]; Chunk::AREA],
|
||||||
|
moisture: [0.; Chunk::AREA],
|
||||||
|
temperature: [0.; Chunk::AREA],
|
||||||
|
chunk_offset: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Chunk {
|
||||||
|
pub const SIZE: usize = 64;
|
||||||
|
pub const AREA: usize = Chunk::SIZE * Chunk::SIZE;
|
||||||
|
pub const WORLD_WIDTH: f32 = Chunk::SIZE as f32 * SHORT_DIAGONAL;
|
||||||
|
pub const WORLD_HEIGHT: f32 = Chunk::SIZE as f32 * 1.5;
|
||||||
|
pub const WORLD_SIZE: Vec2 = Vec2::new(Chunk::WORLD_WIDTH, Chunk::WORLD_HEIGHT);
|
||||||
|
|
||||||
|
pub fn get_pos_z_edge(&self) -> [f32; Chunk::SIZE] {
|
||||||
|
let mut data = [0.; Chunk::SIZE];
|
||||||
|
|
||||||
|
for x in 0..Chunk::SIZE {
|
||||||
|
let idx = x + (Chunk::SIZE - 1) * Chunk::SIZE;
|
||||||
|
data[x] = self.heights[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_neg_z_edge(&self) -> [f32; Chunk::SIZE] {
|
||||||
|
let mut data = [0.; Chunk::SIZE];
|
||||||
|
|
||||||
|
for x in 0..Chunk::SIZE {
|
||||||
|
data[x] = self.heights[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pos_x_edge(&self) -> [f32; Chunk::SIZE] {
|
||||||
|
let mut data = [0.; Chunk::SIZE];
|
||||||
|
|
||||||
|
for z in 0..Chunk::SIZE {
|
||||||
|
let idx = (Chunk::SIZE - 1) + z * Chunk::SIZE;
|
||||||
|
data[z] = self.heights[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_neg_x_edge(&self) -> [f32; Chunk::SIZE] {
|
||||||
|
let mut data = [0.; Chunk::SIZE];
|
||||||
|
|
||||||
|
for z in 0..Chunk::SIZE {
|
||||||
|
let idx = z * Chunk::SIZE;
|
||||||
|
data[z] = self.heights[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
engine/world_generation/src/map/config.rs
Normal file
37
engine/world_generation/src/map/config.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_inspector_egui::InspectorOptions;
|
||||||
|
|
||||||
|
use super::chunk::Chunk;
|
||||||
|
|
||||||
|
#[derive(Resource, Reflect, Default)]
|
||||||
|
#[reflect(Resource)]
|
||||||
|
pub struct GenerationConfig {
|
||||||
|
pub noise_scale: f64,
|
||||||
|
pub sea_level: f64,
|
||||||
|
pub border_size: f32,
|
||||||
|
pub size: UVec2,
|
||||||
|
pub layers: Vec<GeneratorLayer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GenerationConfig {
|
||||||
|
pub fn get_total_width(&self) -> usize {
|
||||||
|
return self.size.x as usize * Chunk::SIZE;
|
||||||
|
}
|
||||||
|
pub fn get_total_height(&self) -> usize {
|
||||||
|
return self.size.y as usize * Chunk::SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Reflect, InspectorOptions)]
|
||||||
|
pub struct GeneratorLayer {
|
||||||
|
pub strength: f64,
|
||||||
|
pub min_value: f64,
|
||||||
|
pub base_roughness: f64,
|
||||||
|
pub roughness: f64,
|
||||||
|
pub persistence: f64,
|
||||||
|
pub is_rigid: bool,
|
||||||
|
pub weight: f64,
|
||||||
|
pub weight_multi: f64,
|
||||||
|
pub layers: usize,
|
||||||
|
pub first_layer_mask: bool,
|
||||||
|
}
|
||||||
167
engine/world_generation/src/map/map.rs
Normal file
167
engine/world_generation/src/map/map.rs
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
use crate::hex_utils::*;
|
||||||
|
|
||||||
|
use super::{chunk::Chunk, mesh_chunk::MeshChunkData};
|
||||||
|
|
||||||
|
#[derive(Resource, Clone)]
|
||||||
|
pub struct Map {
|
||||||
|
pub chunks: Vec<Chunk>,
|
||||||
|
pub height: usize,
|
||||||
|
pub width: usize,
|
||||||
|
pub sea_level: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Map {
|
||||||
|
pub fn get_chunk_mesh_data(&self, chunk_index: usize) -> MeshChunkData {
|
||||||
|
#[cfg(feature = "tracing")]
|
||||||
|
let _spawn_span = info_span!("Chunk Mesh Data").entered();
|
||||||
|
let chunk = &self.chunks[chunk_index];
|
||||||
|
|
||||||
|
return MeshChunkData {
|
||||||
|
heights: chunk.heights.clone(),
|
||||||
|
textures: chunk.textures.clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_neighbors(&self, pos: &HexCoord) -> [Option<f32>; 6] {
|
||||||
|
let mut results: [Option<f32>; 6] = [None; 6];
|
||||||
|
let w = self.width * Chunk::SIZE;
|
||||||
|
let h = self.height * Chunk::SIZE;
|
||||||
|
let n_tiles = pos.get_neighbors();
|
||||||
|
for i in 0..6 {
|
||||||
|
let n_tile = n_tiles[i];
|
||||||
|
if !n_tile.is_in_bounds(h, w) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let c_idx = n_tile.to_chunk_index(self.width);
|
||||||
|
let chunk = &self.chunks[c_idx];
|
||||||
|
let local = n_tile.to_chunk_local_index();
|
||||||
|
results[i] = Some(chunk.heights[local]);
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample_height(&self, pos: &HexCoord) -> f32 {
|
||||||
|
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
||||||
|
return chunk.heights[pos.to_chunk_local_index()];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sample_height_mut(&mut self, pos: &HexCoord) -> &mut f32 {
|
||||||
|
let chunk = &mut self.chunks[pos.to_chunk_index(self.width)];
|
||||||
|
return &mut chunk.heights[pos.to_chunk_local_index()];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_in_bounds(&self, pos: &HexCoord) -> bool {
|
||||||
|
return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_moisture(&self, pos: &HexCoord) -> f32 {
|
||||||
|
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
||||||
|
return chunk.moisture[pos.to_chunk_local_index()];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_tempurature(&self, pos: &HexCoord) -> f32 {
|
||||||
|
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
||||||
|
return chunk.temperature[pos.to_chunk_local_index()];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_center(&self) -> Vec3 {
|
||||||
|
let w = self.get_world_width();
|
||||||
|
let h = self.get_world_height();
|
||||||
|
return Vec3::new(w / 2., self.sea_level, h / 2.);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_world_width(&self) -> f32 {
|
||||||
|
return (self.width * Chunk::SIZE) as f32 * SHORT_DIAGONAL;
|
||||||
|
}
|
||||||
|
pub fn get_world_height(&self) -> f32 {
|
||||||
|
return (self.height * Chunk::SIZE) as f32 * 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_world_size(&self) -> Vec2 {
|
||||||
|
return Vec2::new(self.get_world_width(), self.get_world_height());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_height(&mut self, pos: &HexCoord, height: f32) {
|
||||||
|
self.chunks[pos.to_chunk_index(self.width)].heights[pos.to_chunk_local_index()] = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_crater(&mut self, pos: &HexCoord, radius: usize, depth: f32) -> Vec<usize> {
|
||||||
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
let width = self.width;
|
||||||
|
|
||||||
|
let mut chunks = self.hex_select_mut(pos, radius, true, |p, h, r| {
|
||||||
|
let d = (r as f32) / (radius as f32);
|
||||||
|
let cur = *h;
|
||||||
|
let h2 = cur - depth;
|
||||||
|
*h = h2.lerp(cur, d * d);
|
||||||
|
|
||||||
|
return p.to_chunk_index(width);
|
||||||
|
});
|
||||||
|
|
||||||
|
chunks.dedup();
|
||||||
|
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hex_select<OP, Ret>(&self, center: &HexCoord, radius: usize, include_center: bool, op: OP) -> Vec<Ret>
|
||||||
|
where
|
||||||
|
OP: Fn(&HexCoord, f32, usize) -> Ret + Sync + Send,
|
||||||
|
{
|
||||||
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
|
||||||
|
if include_center {
|
||||||
|
let h = self.sample_height(¢er);
|
||||||
|
(op)(¢er, h, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = Vec::with_capacity(get_tile_count(radius));
|
||||||
|
|
||||||
|
for k in 0..(radius + 1) {
|
||||||
|
let mut p = center.scale(4, k);
|
||||||
|
for i in 0..6 {
|
||||||
|
for _j in 0..k {
|
||||||
|
p = p.get_neighbor(i);
|
||||||
|
let h = self.sample_height(&p);
|
||||||
|
result.push((op)(&p, h, k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hex_select_mut<OP, Ret>(
|
||||||
|
&mut self,
|
||||||
|
center: &HexCoord,
|
||||||
|
radius: usize,
|
||||||
|
include_center: bool,
|
||||||
|
op: OP,
|
||||||
|
) -> Vec<Ret>
|
||||||
|
where
|
||||||
|
OP: Fn(&HexCoord, &mut f32, usize) -> Ret + Sync + Send,
|
||||||
|
{
|
||||||
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
|
||||||
|
if include_center {
|
||||||
|
let h = self.sample_height_mut(¢er);
|
||||||
|
(op)(¢er, h, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut result = Vec::with_capacity(get_tile_count(radius));
|
||||||
|
|
||||||
|
for k in 0..(radius + 1) {
|
||||||
|
let mut p = center.scale(4, k);
|
||||||
|
for i in 0..6 {
|
||||||
|
for _j in 0..k {
|
||||||
|
p = p.get_neighbor(i);
|
||||||
|
let h = self.sample_height_mut(&p);
|
||||||
|
result.push((op)(&p, h, k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
engine/world_generation/src/map/mesh_chunk.rs
Normal file
24
engine/world_generation/src/map/mesh_chunk.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
use crate::hex_utils::HexCoord;
|
||||||
|
|
||||||
|
use super::chunk::Chunk;
|
||||||
|
|
||||||
|
pub struct MeshChunkData {
|
||||||
|
pub heights: [f32; Chunk::AREA],
|
||||||
|
pub textures: [[u32; 2]; Chunk::AREA],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MeshChunkData {
|
||||||
|
pub fn get_neighbors(&self, coord: &HexCoord) -> [f32; 6] {
|
||||||
|
let mut data = [0.; 6];
|
||||||
|
let n_tiles = coord.get_neighbors();
|
||||||
|
for i in 0..6 {
|
||||||
|
let n = n_tiles[i];
|
||||||
|
if !n.is_in_bounds(Chunk::SIZE, Chunk::SIZE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
data[i] = self.heights[n.to_index(Chunk::SIZE)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
engine/world_generation/src/map/mod.rs
Normal file
4
engine/world_generation/src/map/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub mod chunk;
|
||||||
|
pub mod mesh_chunk;
|
||||||
|
pub mod config;
|
||||||
|
pub mod map;
|
||||||
5
engine/world_generation/src/prelude.rs
Normal file
5
engine/world_generation/src/prelude.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub use crate::consts::*;
|
||||||
|
pub use crate::map::chunk::*;
|
||||||
|
pub use crate::map::config::*;
|
||||||
|
pub use crate::map::map::*;
|
||||||
|
pub use crate::map::mesh_chunk::*;
|
||||||
13
game/buildings/Cargo.toml
Normal file
13
game/buildings/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[package]
|
||||||
|
name = "buildings"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bevy = "0.13.2"
|
||||||
|
world_generation = {path = "../../engine/world_generation"}
|
||||||
|
|
||||||
|
[features]
|
||||||
|
tracing = []
|
||||||
65
game/buildings/src/buildings_database.rs
Normal file
65
game/buildings/src/buildings_database.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use world_generation::hex_utils::HexCoord;
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
pub struct BuildingDatabase {
|
||||||
|
pub chunks: Vec<BuildingChunk>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildingDatabase {
|
||||||
|
pub fn new(size: UVec2) -> Self {
|
||||||
|
let mut db = BuildingDatabase {
|
||||||
|
chunks: Vec::with_capacity(size.length_squared() as usize),
|
||||||
|
};
|
||||||
|
|
||||||
|
for y in 0..size.y as i32 {
|
||||||
|
for x in 0..size.x as i32 {
|
||||||
|
let offset = IVec2::new(x, y);
|
||||||
|
let index = (x + y * size.x as i32) as usize;
|
||||||
|
db.chunks.push(BuildingChunk::new(offset, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_buildings_in_range(&self, coord: &HexCoord, radius: usize) -> Option<Vec<&BuildingEntry>> {
|
||||||
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_building(&self, coord: &HexCoord) -> Option<&BuildingEntry> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BuildingChunk {
|
||||||
|
pub entries: Vec<BuildingChunk>,
|
||||||
|
pub index: usize,
|
||||||
|
pub offset: IVec2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildingChunk {
|
||||||
|
pub fn new(offset: IVec2, index: usize) -> Self {
|
||||||
|
return BuildingChunk {
|
||||||
|
entries: Vec::new(),
|
||||||
|
index,
|
||||||
|
offset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_building(&self, coord: &HexCoord) -> Option<&BuildingEntry> {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BuildingEntry {
|
||||||
|
pub coord: HexCoord,
|
||||||
|
pub entity: Entity,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuildingEntry {
|
||||||
|
pub fn new(coord: HexCoord, entity: Entity) -> Self {
|
||||||
|
return BuildingEntry { coord, entity };
|
||||||
|
}
|
||||||
|
}
|
||||||
1
game/buildings/src/lib.rs
Normal file
1
game/buildings/src/lib.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod buildings_database;
|
||||||
@@ -14,7 +14,7 @@ noise = "0.8.2"
|
|||||||
world_generation ={path="../../engine/world_generation"}
|
world_generation ={path="../../engine/world_generation"}
|
||||||
bevy_rapier3d = { version = "0.25.0", features = [ "simd-stable","parallel" ] }
|
bevy_rapier3d = { version = "0.25.0", features = [ "simd-stable","parallel" ] }
|
||||||
rayon = "1.10.0"
|
rayon = "1.10.0"
|
||||||
|
buildings = {path="../buildings"}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
tracing = ["bevy/trace_tracy", "world_generation/tracing"]
|
tracing = ["bevy/trace_tracy", "world_generation/tracing", "buildings/tracing"]
|
||||||
@@ -10,9 +10,8 @@ use bevy_rapier3d::geometry::{Collider, TriMeshFlags};
|
|||||||
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
||||||
use world_generation::{
|
use world_generation::{
|
||||||
biome_painter::BiomePainterAsset,
|
biome_painter::BiomePainterAsset,
|
||||||
chunk_colliders::generate_chunk_collider,
|
generators::{chunk_colliders::generate_chunk_collider, mesh_generator::generate_chunk_mesh},
|
||||||
hex_utils::{offset_to_index, offset_to_world},
|
hex_utils::offset_to_world,
|
||||||
mesh_generator::generate_chunk_mesh,
|
|
||||||
prelude::{Chunk, Map, MeshChunkData},
|
prelude::{Chunk, Map, MeshChunkData},
|
||||||
tile_manager::TileAsset,
|
tile_manager::TileAsset,
|
||||||
tile_mapper::TileMapperAsset,
|
tile_mapper::TileMapperAsset,
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ impl Default for RenderDistanceSettings {
|
|||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct RenderDistanceVisibility {
|
pub struct RenderDistanceVisibility {
|
||||||
pub distance_multiplier: f32,
|
|
||||||
pub offset: Vec3,
|
pub offset: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,19 +42,11 @@ impl RenderDistanceVisibility {
|
|||||||
self.offset = offset;
|
self.offset = offset;
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_multiplier(mut self, distance_multiplier: f32) -> Self {
|
|
||||||
self.distance_multiplier = distance_multiplier;
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RenderDistanceVisibility {
|
impl Default for RenderDistanceVisibility {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self { offset: Vec3::ZERO }
|
||||||
distance_multiplier: 1.,
|
|
||||||
offset: Vec3::ZERO,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +57,7 @@ fn render_distance_system(
|
|||||||
) {
|
) {
|
||||||
let camera = camera_query.single();
|
let camera = camera_query.single();
|
||||||
for (t, mut vis, r) in objects.iter_mut() {
|
for (t, mut vis, r) in objects.iter_mut() {
|
||||||
let dist = (camera.translation - (t.translation + r.offset)).length() * r.distance_multiplier;
|
let dist = (camera.translation - (t.translation + r.offset)).length();
|
||||||
if settings.render_distance < dist {
|
if settings.render_distance < dist {
|
||||||
*vis = Visibility::Hidden;
|
*vis = Visibility::Hidden;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,2 +1,4 @@
|
|||||||
hard_tabs=true
|
hard_tabs = true
|
||||||
max_width=120
|
max_width = 120
|
||||||
|
brace_style = "AlwaysNextLine"
|
||||||
|
control_brace_style = "AlwaysNextLine"
|
||||||
Reference in New Issue
Block a user