From 38da6af3c60026faac0ce988066609fac5aceb2c Mon Sep 17 00:00:00 2001 From: sxv20_ Date: Fri, 10 May 2019 19:20:14 +0100 Subject: [PATCH 01/14] change remeshing queue from LinkedList to HashMap, add remesh weightings Former-commit-id: 28f0826501539848ca97721aff5057ccb4599736 --- voxygen/src/scene/terrain.rs | 62 +++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index e34251a06c..47edd65b99 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -1,9 +1,5 @@ // Standard -use std::{ - collections::{HashMap, LinkedList}, - sync::mpsc, - time::Duration, -}; +use std::{collections::HashMap, sync::mpsc, time::Duration}; // Library use vek::*; @@ -57,7 +53,7 @@ pub struct Terrain { // We keep the sender component for no reason othe than to clone it and send it to new workers. mesh_send_tmp: mpsc::Sender, mesh_recv: mpsc::Receiver, - mesh_todo: LinkedList, + mesh_todo: HashMap, ChunkMeshState>, } impl Terrain { @@ -71,7 +67,7 @@ impl Terrain { mesh_send_tmp: send, mesh_recv: recv, - mesh_todo: LinkedList::new(), + mesh_todo: HashMap::new(), } } @@ -79,6 +75,8 @@ impl Terrain { pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { let current_tick = client.get_tick(); + let mut remesh_weights = HashMap::new(); + // Add any recently created or changed chunks to the list of chunks to be meshed for pos in client .state() @@ -97,15 +95,21 @@ impl Terrain { let pos = pos + Vec3::new(i, j, k); if client.state().terrain().get_key(pos).is_some() { - match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) { - //Some(todo) => todo.started_tick = current_tick, - // The chunk it's queued yet, add it to the queue - _ /* None */ => self.mesh_todo.push_back(ChunkMeshState { - pos, - started_tick: current_tick, - active_worker: false, - }), - } + // match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) { + // //Some(todo) => todo.started_tick = current_tick, + // // The chunk it's queued yet, add it to the queue + // _ /* None */ => self.mesh_todo.push_back(ChunkMeshState { + // pos, + // started_tick: current_tick, + // active_worker: false, + // }), + // } + let weight = if (i, j, k) == (0, 0, 0) { 10 } else { 1 }; + + remesh_weights + .entry(pos) + .and_modify(|e| *e += weight) + .or_insert(weight); } } } @@ -115,15 +119,35 @@ impl Terrain { // Remove any models for chunks that have been recently removed for pos in &client.state().changes().removed_chunks { self.chunks.remove(pos); - self.mesh_todo.drain_filter(|todo| todo.pos == *pos); + remesh_weights.remove(pos); } + for (pos, _weight) in remesh_weights.iter().filter(|(_pos, weight)| **weight > 1) { + // match self.mesh_todo.get_mut(pos) { + // Some(mesh_state) => mesh_state.started_tick = current_tick, + // None => { + // self.mesh_todo.insert( + // *pos, + // ChunkMeshState { + // pos: *pos, + // started_tick: current_tick, + // active_worker: false, + // }, + // ); + // } + // } + self.mesh_todo.entry(*pos).or_insert(ChunkMeshState { + pos: *pos, + started_tick: current_tick, + active_worker: false, + }); + } // Clone the sender to the thread can send us the chunk data back // TODO: It's a bit hacky cloning it here and then cloning it again below. Fix this. let send = self.mesh_send_tmp.clone(); self.mesh_todo - .iter_mut() + .values_mut() // Only spawn workers for meshing jobs without an active worker already .filter(|todo| !todo.active_worker) .for_each(|todo| { @@ -165,7 +189,7 @@ impl Terrain { // Only pull out one chunk per frame to avoid an unacceptable amount of blocking lag due // to the GPU upload. That still gives us a 60 chunks / second budget to play with. if let Ok(response) = self.mesh_recv.recv_timeout(Duration::new(0, 0)) { - match self.mesh_todo.iter().find(|todo| todo.pos == response.pos) { + match self.mesh_todo.get(&response.pos) { // It's the mesh we want, insert the newly finished model into the terrain model // data structure (convert the mesh to a model first of course) Some(todo) if response.started_tick == todo.started_tick => { From c2a806910b64708f2cc71b66ee9d5ea447fb0710 Mon Sep 17 00:00:00 2001 From: sxv20_ Date: Fri, 10 May 2019 20:32:42 +0100 Subject: [PATCH 02/14] fix chunks not getting rendered once unloaded and reloaded, remove weightings Former-commit-id: d98d1e9bb767d80173c531e8914163c1cc23d7fc --- voxygen/src/scene/terrain.rs | 47 +++++++----------------------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 47edd65b99..b00b0c5db1 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -75,8 +75,6 @@ impl Terrain { pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { let current_tick = client.get_tick(); - let mut remesh_weights = HashMap::new(); - // Add any recently created or changed chunks to the list of chunks to be meshed for pos in client .state() @@ -95,53 +93,26 @@ impl Terrain { let pos = pos + Vec3::new(i, j, k); if client.state().terrain().get_key(pos).is_some() { - // match self.mesh_todo.iter_mut().find(|todo| todo.pos == pos) { - // //Some(todo) => todo.started_tick = current_tick, - // // The chunk it's queued yet, add it to the queue - // _ /* None */ => self.mesh_todo.push_back(ChunkMeshState { - // pos, - // started_tick: current_tick, - // active_worker: false, - // }), - // } - let weight = if (i, j, k) == (0, 0, 0) { 10 } else { 1 }; - remesh_weights - .entry(pos) - .and_modify(|e| *e += weight) - .or_insert(weight); + // re-mesh loaded chunks that border new/changed chunks + if self.chunks.contains_key(&pos) || (i, j, k) == (0, 0, 0) { + self.mesh_todo.entry(pos).or_insert(ChunkMeshState { + pos, + started_tick: current_tick, + active_worker: false, + }); + } } } } } } - // Remove any models for chunks that have been recently removed for pos in &client.state().changes().removed_chunks { self.chunks.remove(pos); - remesh_weights.remove(pos); + self.mesh_todo.remove(pos); } - for (pos, _weight) in remesh_weights.iter().filter(|(_pos, weight)| **weight > 1) { - // match self.mesh_todo.get_mut(pos) { - // Some(mesh_state) => mesh_state.started_tick = current_tick, - // None => { - // self.mesh_todo.insert( - // *pos, - // ChunkMeshState { - // pos: *pos, - // started_tick: current_tick, - // active_worker: false, - // }, - // ); - // } - // } - self.mesh_todo.entry(*pos).or_insert(ChunkMeshState { - pos: *pos, - started_tick: current_tick, - active_worker: false, - }); - } // Clone the sender to the thread can send us the chunk data back // TODO: It's a bit hacky cloning it here and then cloning it again below. Fix this. let send = self.mesh_send_tmp.clone(); From a5db1fd0a65fdbd7c251d901747c4f06c336c0a2 Mon Sep 17 00:00:00 2001 From: sxv20_ Date: Fri, 10 May 2019 21:17:46 +0100 Subject: [PATCH 03/14] fix TODO (unnecessary mpsc clone) Former-commit-id: 6f6319fa6bf86ee4eec4778c6795f71beab21e89 --- voxygen/src/scene/terrain.rs | 68 +++++++++++++++++------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index b00b0c5db1..40f943ad6c 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -93,7 +93,6 @@ impl Terrain { let pos = pos + Vec3::new(i, j, k); if client.state().terrain().get_key(pos).is_some() { - // re-mesh loaded chunks that border new/changed chunks if self.chunks.contains_key(&pos) || (i, j, k) == (0, 0, 0) { self.mesh_todo.entry(pos).or_insert(ChunkMeshState { @@ -113,48 +112,45 @@ impl Terrain { self.mesh_todo.remove(pos); } - // Clone the sender to the thread can send us the chunk data back - // TODO: It's a bit hacky cloning it here and then cloning it again below. Fix this. - let send = self.mesh_send_tmp.clone(); - - self.mesh_todo + for todo in self + .mesh_todo .values_mut() // Only spawn workers for meshing jobs without an active worker already .filter(|todo| !todo.active_worker) - .for_each(|todo| { - // Find the area of the terrain we want. Because meshing needs to compute things like - // ambient occlusion and edge elision, we also need to borders of the chunk's - // neighbours too (hence the `- 1` and `+ 1`). - let aabb = Aabb { - min: todo - .pos - .map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1), - max: todo - .pos - .map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1), - }; + { + // Find the area of the terrain we want. Because meshing needs to compute things like + // ambient occlusion and edge elision, we also need to borders of the chunk's + // neighbours too (hence the `- 1` and `+ 1`). + let aabb = Aabb { + min: todo + .pos + .map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1), + max: todo + .pos + .map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1), + }; - // Copy out the chunk data we need to perform the meshing. We do this by taking a - // sample of the terrain that includes both the chunk we want and - let volume = match client.state().terrain().sample(aabb) { - Ok(sample) => sample, - // If either this chunk or its neighbours doesn't yet exist, so we keep it in the - // todo queue to be processed at a later date when we have its neighbours. - Err(VolMapErr::NoSuchChunk) => return, - _ => panic!("Unhandled edge case"), - }; + // Copy out the chunk data we need to perform the meshing. We do this by taking a + // sample of the terrain that includes both the chunk we want and + let volume = match client.state().terrain().sample(aabb) { + Ok(sample) => sample, + // If either this chunk or its neighbours doesn't yet exist, so we keep it in the + // todo queue to be processed at a later date when we have its neighbours. + Err(VolMapErr::NoSuchChunk) => return, + _ => panic!("Unhandled edge case"), + }; - // Clone various things to that they can be moved into the thread - let send = send.clone(); - let pos = todo.pos; + // Clone various things to that they can be moved into the thread + let send = self.mesh_send_tmp.clone(); + let pos = todo.pos; - // Queue the worker thread - client.thread_pool().execute(move || { - send.send(mesh_worker(pos, current_tick, volume)) - .expect("Failed to send chunk mesh to main thread"); - }); - todo.active_worker = true; + // Queue the worker thread + client.thread_pool().execute(move || { + send.send(mesh_worker(pos, current_tick, volume)) + .expect("Failed to send chunk mesh to main thread"); }); + todo.active_worker = true; + } // Receive a chunk mesh from a worker thread, upload it to the GPU and then store it // Only pull out one chunk per frame to avoid an unacceptable amount of blocking lag due From a23f9d90ea319f5509d0033ab4f76e0c1e0d84b1 Mon Sep 17 00:00:00 2001 From: sxv20_ Date: Sat, 11 May 2019 20:32:41 +0100 Subject: [PATCH 04/14] cache a chunk while cloning to increase performance (?) Former-commit-id: 69c1fa67b13a8de49f2c73e9526f548779e988c1 --- common/src/volumes/vol_map.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs index e78e5f9ac7..453c0b2254 100644 --- a/common/src/volumes/vol_map.rs +++ b/common/src/volumes/vol_map.rs @@ -82,13 +82,29 @@ impl SampleVol for VolMap { let mut sample = Dyna::filled(range.size().map(|e| e as u32).into(), V::empty(), ()); + let mut last_chunk_pos = self.pos_key(range.min); + let mut last_chunk = self.get_key(last_chunk_pos); + for pos in sample.iter_positions() { + let new_chunk_pos = self.pos_key(range.min + pos); + if last_chunk_pos != new_chunk_pos { + last_chunk = self.get_key(new_chunk_pos); + last_chunk_pos = new_chunk_pos; + } sample .set( pos, - self.get(range.min + pos) - .map(|v| v.clone()) - .unwrap_or(V::empty()), + if let Some(chunk) = last_chunk { + chunk + .get(Self::chunk_offs(range.min + pos)) + .map(|v| v.clone()) + .unwrap_or(V::empty()) + // Fallback in case the chunk doesn't exist + } else { + self.get(range.min + pos) + .map(|v| v.clone()) + .unwrap_or(V::empty()) + }, ) .map_err(|err| VolMapErr::DynaErr(err))?; } From e20c2a1e001a92b0ff6be775be8560dd180cb861 Mon Sep 17 00:00:00 2001 From: sxv20_ Date: Sun, 12 May 2019 19:32:57 +0100 Subject: [PATCH 05/14] Move VolMap to HashMap<_, Arc> Former-commit-id: e209891596acbb1705876a1cb7ccce3ac2fe2d45 --- common/src/state.rs | 2 +- common/src/volumes/vol_map.rs | 115 +++++++++++++++++++++------------- 2 files changed, 74 insertions(+), 43 deletions(-) diff --git a/common/src/state.rs b/common/src/state.rs index 34eb33df50..8c47b233db 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -177,7 +177,7 @@ impl State { if self .ecs .write_resource::() - .insert(key, chunk) + .insert(key, Arc::new(chunk)) .is_some() { self.changes.changed_chunks.insert(key); diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs index 453c0b2254..f1d908a6c0 100644 --- a/common/src/volumes/vol_map.rs +++ b/common/src/volumes/vol_map.rs @@ -1,11 +1,12 @@ // Standard -use std::collections::HashMap; +use std::{collections::HashMap, sync::Arc}; // Library use vek::*; // Crate use crate::{ + terrain::TerrainChunkMeta, vol::{BaseVol, ReadVol, SampleVol, SizedVol, VolSize, Vox, WriteVol}, volumes::{ chunk::{Chunk, ChunkErr}, @@ -23,11 +24,12 @@ pub enum VolMapErr { // V = Voxel // S = Size (replace with a const when const generics is a thing) // M = Chunk metadata -pub struct VolMap { - chunks: HashMap, Chunk>, +#[derive(Clone)] +pub struct VolMap { + chunks: HashMap, Arc>>, } -impl VolMap { +impl VolMap { #[inline(always)] fn chunk_key(pos: Vec3) -> Vec3 { pos.map2(S::SIZE, |e, sz| e.div_euclid(sz as i32)) @@ -39,12 +41,12 @@ impl VolMap { } } -impl BaseVol for VolMap { +impl BaseVol for VolMap { type Vox = V; type Err = VolMapErr; } -impl ReadVol for VolMap { +impl ReadVol for VolMap { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V, VolMapErr> { let ck = Self::chunk_key(pos); @@ -58,8 +60,8 @@ impl ReadVol for VolMap { } } -impl SampleVol for VolMap { - type Sample = Dyna; +impl SampleVol for VolMap { + type Sample = VolMap; /// Take a sample of the terrain by cloning the voxels within the provided range. /// @@ -80,40 +82,60 @@ impl SampleVol for VolMap { } */ - let mut sample = Dyna::filled(range.size().map(|e| e as u32).into(), V::empty(), ()); + // let mut sample = Dyna::filled(range.size().map(|e| e as u32).into(), V::empty(), ()); - let mut last_chunk_pos = self.pos_key(range.min); - let mut last_chunk = self.get_key(last_chunk_pos); + // let mut last_chunk_pos = self.pos_key(range.min); + // let mut last_chunk = self.get_key(last_chunk_pos); - for pos in sample.iter_positions() { - let new_chunk_pos = self.pos_key(range.min + pos); - if last_chunk_pos != new_chunk_pos { - last_chunk = self.get_key(new_chunk_pos); - last_chunk_pos = new_chunk_pos; + // for pos in sample.iter_positions() { + // let new_chunk_pos = self.pos_key(range.min + pos); + // if last_chunk_pos != new_chunk_pos { + // last_chunk = self.get_key(new_chunk_pos); + // last_chunk_pos = new_chunk_pos; + // } + // sample + // .set( + // pos, + // if let Some(chunk) = last_chunk { + // chunk + // .get(Self::chunk_offs(range.min + pos)) + // .map(|v| v.clone()) + // .unwrap_or(V::empty()) + // // Fallback in case the chunk doesn't exist + // } else { + // self.get(range.min + pos) + // .map(|v| v.clone()) + // .unwrap_or(V::empty()) + // }, + // ) + // .map_err(|err| VolMapErr::DynaErr(err))?; + // } + + // Ok(sample) + + let mut sample = VolMap::new(); + let chunk_min = Self::chunk_key(range.min); + let chunk_max = Self::chunk_key(range.max); + for x in chunk_min.x..=chunk_max.x { + for y in chunk_min.y..=chunk_max.y { + for z in chunk_min.z..=chunk_max.z { + let chunk_key = Vec3::new(x, y, z); + + let chunk = self + .get_key(chunk_key) + .map(|v| v.clone()) + .ok_or(VolMapErr::NoSuchChunk)?; + + sample.insert(chunk_key, Arc::new(chunk)); + } } - sample - .set( - pos, - if let Some(chunk) = last_chunk { - chunk - .get(Self::chunk_offs(range.min + pos)) - .map(|v| v.clone()) - .unwrap_or(V::empty()) - // Fallback in case the chunk doesn't exist - } else { - self.get(range.min + pos) - .map(|v| v.clone()) - .unwrap_or(V::empty()) - }, - ) - .map_err(|err| VolMapErr::DynaErr(err))?; } Ok(sample) } } -impl WriteVol for VolMap { +impl WriteVol for VolMap { #[inline(always)] fn set(&mut self, pos: Vec3, vox: V) -> Result<(), VolMapErr> { let ck = Self::chunk_key(pos); @@ -122,12 +144,14 @@ impl WriteVol for VolMap { .ok_or(VolMapErr::NoSuchChunk) .and_then(|chunk| { let co = Self::chunk_offs(pos); - chunk.set(co, vox).map_err(|err| VolMapErr::ChunkErr(err)) + Arc::make_mut(chunk) + .set(co, vox) + .map_err(|err| VolMapErr::ChunkErr(err)) }) } } -impl VolMap { +impl VolMap { pub fn new() -> Self { Self { chunks: HashMap::new(), @@ -138,15 +162,22 @@ impl VolMap { S::SIZE } - pub fn insert(&mut self, key: Vec3, chunk: Chunk) -> Option> { + pub fn insert( + &mut self, + key: Vec3, + chunk: Arc>, + ) -> Option>> { self.chunks.insert(key, chunk) } pub fn get_key(&self, key: Vec3) -> Option<&Chunk> { - self.chunks.get(&key) + match self.chunks.get(&key) { + Some(arc_chunk) => Some(arc_chunk.as_ref()), + None => None, + } } - pub fn remove(&mut self, key: Vec3) -> Option> { + pub fn remove(&mut self, key: Vec3) -> Option>> { self.chunks.remove(&key) } @@ -165,12 +196,12 @@ impl VolMap { } } -pub struct ChunkIter<'a, V: Vox, S: VolSize, M> { - iter: std::collections::hash_map::Iter<'a, Vec3, Chunk>, +pub struct ChunkIter<'a, V: Vox + Clone, S: VolSize + Clone, M: Clone> { + iter: std::collections::hash_map::Iter<'a, Vec3, Arc>>, } -impl<'a, V: Vox, S: VolSize, M> Iterator for ChunkIter<'a, V, S, M> { - type Item = (Vec3, &'a Chunk); +impl<'a, V: Vox + Clone, S: VolSize + Clone, M: Clone> Iterator for ChunkIter<'a, V, S, M> { + type Item = (Vec3, &'a Arc>); fn next(&mut self) -> Option { self.iter.next().map(|(k, c)| (*k, c)) From 592477752eddcc0ef32ff1b896682fbca86b47ca Mon Sep 17 00:00:00 2001 From: sxv20_ Date: Sun, 12 May 2019 19:33:39 +0100 Subject: [PATCH 06/14] move sample() to returning VolMap, incomplete VolMap meshing code Former-commit-id: 77d3db6c3bf28364089647802f83d2d00f3a152d --- voxygen/src/mesh/terrain.rs | 39 ++++++++++++++++++++++++++++++++++-- voxygen/src/scene/terrain.rs | 5 +++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index a9157419e7..50c4ea7667 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -4,8 +4,8 @@ use vek::*; // Project use common::{ terrain::Block, - vol::{ReadVol, SizedVol, Vox}, - volumes::dyna::Dyna, + vol::{ReadVol, SizedVol, VolSize, Vox}, + volumes::{dyna::Dyna, vol_map::VolMap}, }; // Crate @@ -43,3 +43,38 @@ impl Meshable for Dyna { mesh } } + +impl Meshable for VolMap { + type Pipeline = TerrainPipeline; + type Supplement = Aabb; + + fn generate_mesh(&self, range: Self::Supplement) -> Mesh { + let mut mesh = Mesh::new(); + + let mut last_chunk_pos = self.pos_key(range.min); + let mut last_chunk = self.get_key(last_chunk_pos); + + let size = range.max - range.min; + for x in 1..(size.x - 1) { + for y in 1..(size.y - 1) { + for z in 1..(size.z - 1) { + let pos = Vec3::new(x, y, z); + + let new_chunk_pos = self.pos_key(range.min + pos); + if last_chunk_pos != new_chunk_pos { + last_chunk = self.get_key(new_chunk_pos); + last_chunk_pos = new_chunk_pos; + } + let offs = pos.map(|e| e as f32 - 1.0); + if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { + let col = col.map(|e| e as f32 / 255.0); + + vol::push_vox_verts(&mut mesh, self, pos, offs, col, TerrainVertex::new); + } + } + } + } + + mesh + } +} diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 40f943ad6c..f15d730d72 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -38,10 +38,11 @@ fn mesh_worker( pos: Vec3, started_tick: u64, volume: ::Sample, + supplement: Aabb, ) -> MeshWorkerResponse { MeshWorkerResponse { pos, - mesh: volume.generate_mesh(()), + mesh: volume.generate_mesh(supplement), started_tick, } } @@ -146,7 +147,7 @@ impl Terrain { // Queue the worker thread client.thread_pool().execute(move || { - send.send(mesh_worker(pos, current_tick, volume)) + send.send(mesh_worker(pos, current_tick, volume, aabb)) .expect("Failed to send chunk mesh to main thread"); }); todo.active_worker = true; From f600eca0724cf8a6830ec4110ab6757a5612769d Mon Sep 17 00:00:00 2001 From: sxv20_ Date: Sun, 12 May 2019 21:58:37 +0100 Subject: [PATCH 07/14] start fixing chunk rendering, noticed stack overflow crash Former-commit-id: 334904276580cd78f5d5e3bf010a86fcd822cfdf --- common/src/volumes/vol_map.rs | 15 ++++++++----- voxygen/src/mesh/terrain.rs | 41 +++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs index f1d908a6c0..d73ede7ee1 100644 --- a/common/src/volumes/vol_map.rs +++ b/common/src/volumes/vol_map.rs @@ -36,7 +36,7 @@ impl VolMap { } #[inline(always)] - fn chunk_offs(pos: Vec3) -> Vec3 { + pub fn chunk_offs(pos: Vec3) -> Vec3 { pos.map2(S::SIZE, |e, sz| e.rem_euclid(sz as i32)) } } @@ -121,12 +121,11 @@ impl SampleVol for VolMap for z in chunk_min.z..=chunk_max.z { let chunk_key = Vec3::new(x, y, z); - let chunk = self - .get_key(chunk_key) - .map(|v| v.clone()) - .ok_or(VolMapErr::NoSuchChunk)?; + let chunk = self.get_key_arc(chunk_key).map(|v| v.clone()); - sample.insert(chunk_key, Arc::new(chunk)); + if let Some(chunk) = chunk { + sample.insert(chunk_key, chunk); + } } } } @@ -177,6 +176,10 @@ impl VolMap { } } + pub fn get_key_arc(&self, key: Vec3) -> Option<&Arc>> { + self.chunks.get(&key) + } + pub fn remove(&mut self, key: Vec3) -> Option>> { self.chunks.remove(&key) } diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index 50c4ea7667..5e670d513a 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -55,9 +55,9 @@ impl Meshable for VolMap { let mut last_chunk = self.get_key(last_chunk_pos); let size = range.max - range.min; - for x in 1..(size.x - 1) { - for y in 1..(size.y - 1) { - for z in 1..(size.z - 1) { + for x in 0..size.x { + for y in 0..size.y { + for z in 0..size.z { let pos = Vec3::new(x, y, z); let new_chunk_pos = self.pos_key(range.min + pos); @@ -66,15 +66,42 @@ impl Meshable for VolMap { last_chunk_pos = new_chunk_pos; } let offs = pos.map(|e| e as f32 - 1.0); - if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) { - let col = col.map(|e| e as f32 / 255.0); + if let Some(chunk) = last_chunk { + let chunk_pos = Self::chunk_offs(range.min + pos); + if let Some(col) = chunk.get(chunk_pos).ok().and_then(|vox| vox.get_color()) + { + let col = col.map(|e| e as f32 / 255.0); - vol::push_vox_verts(&mut mesh, self, pos, offs, col, TerrainVertex::new); + vol::push_vox_verts( + &mut mesh, + self, + pos, + offs, + col, + TerrainVertex::new, + ); + } + } else { + if let Some(col) = self + .get(range.min + pos) + .ok() + .and_then(|vox| vox.get_color()) + { + let col = col.map(|e| e as f32 / 255.0); + + vol::push_vox_verts( + &mut mesh, + self, + pos, + offs, + col, + TerrainVertex::new, + ); + } } } } } - mesh } } From ba10ca38ba1b9aab7f278ad148b33ab51aca6261 Mon Sep 17 00:00:00 2001 From: robojumper Date: Mon, 13 May 2019 00:46:36 +0200 Subject: [PATCH 08/14] Fix chunk meshing Former-commit-id: d3a53602e4b480ab9db0a2a98e25cbba5081b624 --- voxygen/src/mesh/terrain.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index 5e670d513a..ff6272e856 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -75,7 +75,7 @@ impl Meshable for VolMap { vol::push_vox_verts( &mut mesh, self, - pos, + range.min + pos, offs, col, TerrainVertex::new, @@ -92,7 +92,7 @@ impl Meshable for VolMap { vol::push_vox_verts( &mut mesh, self, - pos, + range.min + pos, offs, col, TerrainVertex::new, From 761c6e9cf88fdf82daf8c50fc00c608bf2db1383 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 12 May 2019 22:21:18 +0100 Subject: [PATCH 09/14] Switched to actor system Former-commit-id: d2a482f6209aff7aaa4e747e35ce4a7c8a79cdfc --- common/src/comp/{character.rs => actor.rs} | 96 +++++++++------- common/src/comp/mod.rs | 10 +- common/src/msg/client.rs | 7 +- common/src/msg/ecs_packet.rs | 4 +- common/src/state.rs | 2 +- server/src/cmd.rs | 28 ++--- server/src/lib.rs | 29 +++-- voxygen/src/menu/char_selection/mod.rs | 5 +- voxygen/src/menu/char_selection/scene.rs | 11 +- voxygen/src/menu/char_selection/ui.rs | 107 ++++++++--------- voxygen/src/scene/figure.rs | 127 ++++++++++++--------- 11 files changed, 233 insertions(+), 193 deletions(-) rename common/src/comp/{character.rs => actor.rs} (68%) diff --git a/common/src/comp/character.rs b/common/src/comp/actor.rs similarity index 68% rename from common/src/comp/character.rs rename to common/src/comp/actor.rs index c56dddde3e..8bc0f4507a 100644 --- a/common/src/comp/character.rs +++ b/common/src/comp/actor.rs @@ -13,7 +13,7 @@ pub enum Race { } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum Gender { +pub enum BodyType { Female, Male, Unspecified, @@ -21,32 +21,32 @@ pub enum Gender { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Head { - DefaultHead, + Default, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Chest { - DefaultChest, + Default, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Belt { - DefaultBelt, + Default, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Pants { - DefaultPants, + Default, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Hand { - DefaultHand, + Default, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Foot { - DefaultFoot, + Default, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -62,42 +62,45 @@ pub enum Weapon { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Shoulder { - DefaultShoulder, + Default, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Draw { - DefaultDraw, + Default, } -use Belt::*; -use Chest::*; -use Draw::*; -use Foot::*; -use Gender::*; -use Hand::*; -use Head::*; -use Pants::*; -use Race::*; -use Shoulder::*; -use Weapon::*; - -const ALL_RACES: [Race; 6] = [Danari, Dwarf, Elf, Human, Orc, Undead]; -const ALL_GENDERS: [Gender; 3] = [Female, Male, Unspecified]; -const ALL_HEADS: [Head; 1] = [DefaultHead]; -const ALL_CHESTS: [Chest; 1] = [DefaultChest]; -const ALL_BELTS: [Belt; 1] = [DefaultBelt]; -const ALL_PANTS: [Pants; 1] = [DefaultPants]; -const ALL_HANDS: [Hand; 1] = [DefaultHand]; -const ALL_FEET: [Foot; 1] = [DefaultFoot]; -const ALL_WEAPONS: [Weapon; 7] = [Daggers, SwordShield, Sword, Axe, Hammer, Bow, Staff]; -const ALL_SHOULDERS: [Shoulder; 1] = [DefaultShoulder]; -const ALL_DRAW: [Draw; 1] = [DefaultDraw]; +const ALL_RACES: [Race; 6] = [ + Race::Danari, + Race::Dwarf, + Race::Elf, + Race::Human, + Race::Orc, + Race::Undead, +]; +const ALL_BODY_TYPES: [BodyType; 3] = [BodyType::Female, BodyType::Male, BodyType::Unspecified]; +const ALL_HEADS: [Head; 1] = [Head::Default]; +const ALL_CHESTS: [Chest; 1] = [Chest::Default]; +const ALL_BELTS: [Belt; 1] = [Belt::Default]; +const ALL_PANTS: [Pants; 1] = [Pants::Default]; +const ALL_HANDS: [Hand; 1] = [Hand::Default]; +const ALL_FEET: [Foot; 1] = [Foot::Default]; +const ALL_WEAPONS: [Weapon; 7] = [ + Weapon::Daggers, + Weapon::SwordShield, + Weapon::Sword, + Weapon::Axe, + Weapon::Hammer, + Weapon::Bow, + Weapon::Staff, +]; +const ALL_SHOULDERS: [Shoulder; 1] = [Shoulder::Default]; +const ALL_DRAW: [Draw; 1] = [Draw::Default]; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct Character { +pub struct HumanoidBody { pub race: Race, - pub gender: Gender, + pub body_type: BodyType, pub head: Head, pub chest: Chest, pub belt: Belt, @@ -109,11 +112,11 @@ pub struct Character { pub draw: Draw, } -impl Character { +impl HumanoidBody { pub fn random() -> Self { Self { race: *thread_rng().choose(&ALL_RACES).unwrap(), - gender: *thread_rng().choose(&ALL_GENDERS).unwrap(), + body_type: *thread_rng().choose(&ALL_BODY_TYPES).unwrap(), head: *thread_rng().choose(&ALL_HEADS).unwrap(), chest: *thread_rng().choose(&ALL_CHESTS).unwrap(), belt: *thread_rng().choose(&ALL_BELTS).unwrap(), @@ -127,6 +130,23 @@ impl Character { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Body { + Humanoid(HumanoidBody), +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Actor { + Character { + name: String, + body: Body, + }, +} + +impl Component for Actor { + type Storage = FlaggedStorage>; +} + #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub struct AnimationHistory { pub last: Option, @@ -151,10 +171,6 @@ pub enum Animation { Jump, } -impl Component for Character { - type Storage = FlaggedStorage>; -} - impl Component for AnimationHistory { type Storage = FlaggedStorage>; } diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index ca84c34dd9..20290a8283 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -1,11 +1,13 @@ pub mod agent; -pub mod character; +pub mod actor; pub mod phys; pub mod player; // Reexports pub use agent::{Agent, Control}; -pub use character::Animation; -pub use character::AnimationHistory; -pub use character::Character; +pub use actor::Animation; +pub use actor::AnimationHistory; +pub use actor::HumanoidBody; +pub use actor::Body; +pub use actor::Actor; pub use player::Player; diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs index ce70302ad6..f90315edd9 100644 --- a/common/src/msg/client.rs +++ b/common/src/msg/client.rs @@ -7,12 +7,15 @@ pub enum ClientMsg { Register { player: comp::Player, }, - Character(comp::Character), + Character { + name: String, + body: comp::HumanoidBody, + }, RequestState(ClientState), Ping, Pong, Chat(String), - PlayerAnimation(comp::character::AnimationHistory), + PlayerAnimation(comp::AnimationHistory), PlayerPhysics { pos: comp::phys::Pos, vel: comp::phys::Vel, diff --git a/common/src/msg/ecs_packet.rs b/common/src/msg/ecs_packet.rs index 9dd876a39f..b7da55f0a8 100644 --- a/common/src/msg/ecs_packet.rs +++ b/common/src/msg/ecs_packet.rs @@ -9,7 +9,7 @@ sphynx::sum_type! { Pos(comp::phys::Pos), Vel(comp::phys::Vel), Dir(comp::phys::Dir), - Character(comp::Character), + Actor(comp::Actor), Player(comp::Player), } } @@ -20,7 +20,7 @@ sphynx::sum_type! { Pos(PhantomData), Vel(PhantomData), Dir(PhantomData), - Character(PhantomData), + Actor(PhantomData), Player(PhantomData), } } diff --git a/common/src/state.rs b/common/src/state.rs index 8c47b233db..29cdb59f4a 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -95,7 +95,7 @@ impl State { // Create a new Sphynx ECS world fn setup_sphynx_world(ecs: &mut sphynx::World) { // Register synced components - ecs.register_synced::(); + ecs.register_synced::(); ecs.register_synced::(); // Register unsynched (or synced by other means) components diff --git a/server/src/cmd.rs b/server/src/cmd.rs index e585165d9b..b3bc12357a 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -191,26 +191,14 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha .read_component_cloned::(entity) { Some(pos) => { - let mut current = entity; - - for _ in 0..1 { - current = server - .create_npc(comp::Character::random()) - .with(comp::Control::default()) - .with(comp::Agent::Pet { - target: current, - offset: Vec2::zero(), - }) - .with(pos) - .build(); - } - server - .clients - .notify(entity, ServerMsg::Chat("Pet spawned!".to_owned())); - } - None => server - .clients - .notify(entity, ServerMsg::Chat("You have no position!".to_owned())), + server.create_npc("Bungo".to_owned(), comp::Body::Humanoid(comp::HumanoidBody::random())) + .with(comp::Control::default()) + .with(comp::Agent::Pet{ target: entity, offset: Vec2::zero() }) + .with(pos) + .build(); + server.clients.notify(entity, ServerMsg::Chat("Spawned pet!".to_owned())); + }, + None => server.clients.notify(entity, ServerMsg::Chat("You have no position!".to_owned())), } } diff --git a/server/src/lib.rs b/server/src/lib.rs index 55c755c26f..a358fdca9b 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -14,7 +14,6 @@ use crate::{ }; use common::{ comp, - comp::character::Animation, msg::{ClientMsg, ClientState, RequestStateError, ServerMsg}, net::PostOffice, state::{State, Uid}, @@ -81,7 +80,7 @@ impl Server { }; for i in 0..4 { - this.create_npc(comp::Character::random()) + this.create_npc("Tobermory".to_owned(), comp::Body::Humanoid(comp::HumanoidBody::random())) .with(comp::Control::default()) .with(comp::Agent::Wanderer(Vec2::zero())) .build(); @@ -114,24 +113,31 @@ impl Server { /// Build a non-player character #[allow(dead_code)] - pub fn create_npc(&mut self, character: comp::Character) -> EcsEntityBuilder { + pub fn create_npc(&mut self, name: String, body: comp::Body) -> EcsEntityBuilder { self.state .ecs_mut() .create_entity_synced() .with(comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0))) .with(comp::phys::Vel(Vec3::zero())) .with(comp::phys::Dir(Vec3::unit_y())) - .with(comp::AnimationHistory::new(Animation::Idle)) - .with(character) + .with(comp::AnimationHistory::new(comp::Animation::Idle)) + .with(comp::Actor::Character { + name, + body, + }) } pub fn create_player_character( state: &mut State, entity: EcsEntity, client: &mut Client, - character: comp::Character, + name: String, + body: comp::HumanoidBody, ) { - state.write_component(entity, character); + state.write_component(entity, comp::Actor::Character { + name, + body: comp::Body::Humanoid(body), + }); state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0))); state.write_component(entity, comp::phys::Vel(Vec3::zero())); state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); @@ -139,7 +145,10 @@ impl Server { state.write_component(entity, comp::phys::ForceUpdate); // Set initial animation - state.write_component(entity, comp::AnimationHistory::new(Animation::Idle)); + state.write_component( + entity, + comp::AnimationHistory::new(comp::Animation::Idle), + ); // Tell the client his request was successful client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character))); @@ -337,13 +346,13 @@ impl Server { // Use RequestState instead (No need to send `player` again) _ => client.error_state(RequestStateError::Impossible), }, - ClientMsg::Character(character) => match client.client_state { + ClientMsg::Character { name, body } => match client.client_state { // Become Registered first ClientState::Connected => { client.error_state(RequestStateError::Impossible) } ClientState::Registered | ClientState::Spectator => { - Self::create_player_character(state, entity, client, character) + Self::create_player_character(state, entity, client, name, body) } ClientState::Character => { client.error_state(RequestStateError::Already) diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 13f430d082..9316ca3682 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -76,7 +76,10 @@ impl PlayState for CharSelectionState { self.client .borrow_mut() .postbox - .send_message(ClientMsg::Character(self.char_selection_ui.character)); + .send_message(ClientMsg::Character { + name: self.char_selection_ui.character_name.clone(), + body: self.char_selection_ui.character_body, + }); return PlayStateResult::Switch(Box::new(SessionState::new( &mut global_state.window, self.client.clone(), diff --git a/voxygen/src/menu/char_selection/scene.rs b/voxygen/src/menu/char_selection/scene.rs index 6c999afa4b..fbf7595dce 100644 --- a/voxygen/src/menu/char_selection/scene.rs +++ b/voxygen/src/menu/char_selection/scene.rs @@ -1,3 +1,9 @@ +use vek::*; +use client::Client; +use common::{ + comp::HumanoidBody, + figure::Segment, +}; use crate::{ anim::{ character::{CharacterSkeleton, IdleAnimation}, @@ -12,9 +18,6 @@ use crate::{ figure::{FigureModelCache, FigureState}, }, }; -use client::Client; -use common::{comp::Character, figure::Segment}; -use vek::*; struct Skybox { model: Model, @@ -108,7 +111,7 @@ impl Scene { let model = self.figure_model_cache.get_or_create_model( renderer, - Character::random(), + HumanoidBody::random(), client.get_tick(), ); renderer.render_figure( diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index d53f9f0ffa..2977f684b9 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -7,8 +7,11 @@ use crate::{ }, window::Window, }; -use common::comp::character::{ - Belt, Character, Chest, Foot, Gender, Hand, Head, Pants, Race, Weapon, +use common::comp::{ + HumanoidBody, + actor::{ + Belt, Chest, Foot, BodyType, Hand, Head, Pants, Race, Weapon, + }, }; use conrod_core::{ color, @@ -37,7 +40,7 @@ widget_ids! { weapon_heading, weapon_description, races_bg, - gender_bg, + body_type_bg, desc_bg, skin_eyes_window, hair_window, @@ -71,8 +74,8 @@ widget_ids! { race_4, race_5, race_6, - gender_1, - gender_2, + body_type_1, + body_type_2, weapon_1, weapon_2, weapon_3, @@ -267,8 +270,8 @@ pub struct CharSelectionUi { fonts: Fonts, character_creation: bool, selected_char_no: Option, - character_name: String, - pub character: Character, + pub character_name: String, + pub character_body: HumanoidBody, creation_state: CreationState, } @@ -293,7 +296,7 @@ impl CharSelectionUi { character_creation: false, selected_char_no: None, character_name: "Character Name".to_string(), - character: Character::random(), + character_body: HumanoidBody::random(), creation_state: CreationState::Race, } } @@ -597,14 +600,14 @@ impl CharSelectionUi { // for alignment Rectangle::fill_with([151.0, 68.0], color::TRANSPARENT) .mid_top_with_margin_on(self.ids.creation_window, 210.0) - .set(self.ids.gender_bg, ui_widgets); + .set(self.ids.body_type_bg, ui_widgets); // Male Image::new(self.imgs.male) .w_h(68.0, 68.0) - .mid_left_of(self.ids.gender_bg) + .mid_left_of(self.ids.body_type_bg) .set(self.ids.male, ui_widgets); - if Button::image(if let Gender::Male = self.character.gender { + if Button::image(if let BodyType::Male = self.character_body.body_type { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -612,17 +615,17 @@ impl CharSelectionUi { .middle_of(self.ids.male) .hover_image(self.imgs.icon_border_mo) .press_image(self.imgs.icon_border_press) - .set(self.ids.gender_1, ui_widgets) + .set(self.ids.body_type_1, ui_widgets) .was_clicked() { - self.character.gender = Gender::Male; + self.character_body.body_type = BodyType::Male; } // Female Image::new(self.imgs.female) .w_h(68.0, 68.0) .right_from(self.ids.male, 16.0) .set(self.ids.female, ui_widgets); - if Button::image(if let Gender::Female = self.character.gender { + if Button::image(if let BodyType::Female = self.character_body.body_type { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -630,10 +633,10 @@ impl CharSelectionUi { .middle_of(self.ids.female) .hover_image(self.imgs.icon_border_mo) .press_image(self.imgs.icon_border_press) - .set(self.ids.gender_2, ui_widgets) + .set(self.ids.body_type_2, ui_widgets) .was_clicked() { - self.character.gender = Gender::Female; + self.character_body.body_type = BodyType::Female; } // for alignment Rectangle::fill_with([458.0, 68.0], color::TRANSPARENT) @@ -641,7 +644,7 @@ impl CharSelectionUi { .set(self.ids.races_bg, ui_widgets); // TODO: If races where in some sort of array format we could do this in a loop // Human - Image::new(if let Gender::Male = self.character.gender { + Image::new(if let BodyType::Male = self.character_body.body_type { self.imgs.human_m } else { self.imgs.human_f @@ -649,7 +652,7 @@ impl CharSelectionUi { .w_h(68.0, 68.0) .mid_left_of(self.ids.races_bg) .set(self.ids.human, ui_widgets); - if Button::image(if let Race::Human = self.character.race { + if Button::image(if let Race::Human = self.character_body.race { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -660,11 +663,11 @@ impl CharSelectionUi { .set(self.ids.race_1, ui_widgets) .was_clicked() { - self.character.race = Race::Human; + self.character_body.race = Race::Human; } // Orc - Image::new(if let Gender::Male = self.character.gender { + Image::new(if let BodyType::Male = self.character_body.body_type { self.imgs.orc_m } else { self.imgs.orc_f @@ -672,7 +675,7 @@ impl CharSelectionUi { .w_h(68.0, 68.0) .right_from(self.ids.human, 10.0) .set(self.ids.orc, ui_widgets); - if Button::image(if let Race::Orc = self.character.race { + if Button::image(if let Race::Orc = self.character_body.race { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -683,10 +686,10 @@ impl CharSelectionUi { .set(self.ids.race_2, ui_widgets) .was_clicked() { - self.character.race = Race::Orc; + self.character_body.race = Race::Orc; } // Dwarf - Image::new(if let Gender::Male = self.character.gender { + Image::new(if let BodyType::Male = self.character_body.body_type { self.imgs.dwarf_m } else { self.imgs.dwarf_f @@ -694,7 +697,7 @@ impl CharSelectionUi { .w_h(68.0, 68.0) .right_from(self.ids.human, 10.0 * 2.0 + 68.0) .set(self.ids.dwarf, ui_widgets); - if Button::image(if let Race::Dwarf = self.character.race { + if Button::image(if let Race::Dwarf = self.character_body.race { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -705,10 +708,10 @@ impl CharSelectionUi { .set(self.ids.race_3, ui_widgets) .was_clicked() { - self.character.race = Race::Dwarf; + self.character_body.race = Race::Dwarf; } // Elf - Image::new(if let Gender::Male = self.character.gender { + Image::new(if let BodyType::Male = self.character_body.body_type { self.imgs.elf_m } else { self.imgs.elf_f @@ -716,7 +719,7 @@ impl CharSelectionUi { .w_h(68.0, 68.0) .right_from(self.ids.human, 10.0 * 3.0 + 68.0 * 2.0) .set(self.ids.elf, ui_widgets); - if Button::image(if let Race::Elf = self.character.race { + if Button::image(if let Race::Elf = self.character_body.race { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -727,10 +730,10 @@ impl CharSelectionUi { .set(self.ids.race_4, ui_widgets) .was_clicked() { - self.character.race = Race::Elf; + self.character_body.race = Race::Elf; } // Undead - Image::new(if let Gender::Male = self.character.gender { + Image::new(if let BodyType::Male = self.character_body.body_type { self.imgs.undead_m } else { self.imgs.undead_f @@ -738,7 +741,7 @@ impl CharSelectionUi { .w_h(68.0, 68.0) .right_from(self.ids.human, 10.0 * 4.0 + 68.0 * 3.0) .set(self.ids.undead, ui_widgets); - if Button::image(if let Race::Undead = self.character.race { + if Button::image(if let Race::Undead = self.character_body.race { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -749,17 +752,17 @@ impl CharSelectionUi { .set(self.ids.race_5, ui_widgets) .was_clicked() { - self.character.race = Race::Undead; + self.character_body.race = Race::Undead; } // Danari - Image::new(if let Gender::Male = self.character.gender { + Image::new(if let BodyType::Male = self.character_body.body_type { self.imgs.danari_m } else { self.imgs.danari_f }) .right_from(self.ids.human, 10.0 * 5.0 + 68.0 * 4.0) .set(self.ids.danari, ui_widgets); - if Button::image(if let Race::Danari = self.character.race { + if Button::image(if let Race::Danari = self.character_body.race { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -771,7 +774,7 @@ impl CharSelectionUi { .set(self.ids.race_6, ui_widgets) .was_clicked() { - self.character.race = Race::Danari; + self.character_body.race = Race::Danari; } // Description Headline and Text @@ -832,7 +835,7 @@ impl CharSelectionUi { \n\ Outcast communities consisting of these Blessed Danari have formed all over the land."; - let (race_str, race_desc) = match self.character.race { + let (race_str, race_desc) = match self.character_body.race { Race::Human => ("Humans", HUMAN_DESC), Race::Orc => ("Orcs", ORC_DESC), Race::Dwarf => ("Dwarves", DWARF_DESC), @@ -872,7 +875,7 @@ impl CharSelectionUi { .w_h(60.0, 60.0) .mid_left_of(self.ids.weapon_bg) .set(self.ids.sword_shield, ui_widgets); - if Button::image(if let Weapon::SwordShield = self.character.weapon { + if Button::image(if let Weapon::SwordShield = self.character_body.weapon { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -883,7 +886,7 @@ impl CharSelectionUi { .set(self.ids.weapon_1, ui_widgets) .was_clicked() { - self.character.weapon = Weapon::SwordShield; + self.character_body.weapon = Weapon::SwordShield; } // Daggers @@ -891,7 +894,7 @@ impl CharSelectionUi { .w_h(60.0, 60.0) .right_from(self.ids.sword_shield, 8.0) .set(self.ids.daggers, ui_widgets); - if Button::image(if let Weapon::Daggers = self.character.weapon { + if Button::image(if let Weapon::Daggers = self.character_body.weapon { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -902,7 +905,7 @@ impl CharSelectionUi { .set(self.ids.weapon_2, ui_widgets) .was_clicked() { - self.character.weapon = Weapon::Daggers; + self.character_body.weapon = Weapon::Daggers; } // Sword @@ -910,7 +913,7 @@ impl CharSelectionUi { .w_h(60.0, 60.0) .right_from(self.ids.sword_shield, 8.0 * 2.0 + 60.0 * 1.0) .set(self.ids.sword, ui_widgets); - if Button::image(if let Weapon::Sword = self.character.weapon { + if Button::image(if let Weapon::Sword = self.character_body.weapon { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -921,14 +924,14 @@ impl CharSelectionUi { .set(self.ids.weapon_3, ui_widgets) .was_clicked() { - self.character.weapon = Weapon::Sword; + self.character_body.weapon = Weapon::Sword; } // Axe Image::new(self.imgs.axe) .w_h(60.0, 60.0) .right_from(self.ids.sword_shield, 8.0 * 3.0 + 60.0 * 2.0) .set(self.ids.axe, ui_widgets); - if Button::image(if let Weapon::Axe = self.character.weapon { + if Button::image(if let Weapon::Axe = self.character_body.weapon { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -939,14 +942,14 @@ impl CharSelectionUi { .set(self.ids.weapon_4, ui_widgets) .was_clicked() { - self.character.weapon = Weapon::Axe; + self.character_body.weapon = Weapon::Axe; } // Hammer Image::new(self.imgs.hammer) .w_h(60.0, 60.0) .right_from(self.ids.sword_shield, 8.0 * 4.0 + 60.0 * 3.0) .set(self.ids.hammer, ui_widgets); - if Button::image(if let Weapon::Hammer = self.character.weapon { + if Button::image(if let Weapon::Hammer = self.character_body.weapon { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -957,14 +960,14 @@ impl CharSelectionUi { .set(self.ids.weapon_5, ui_widgets) .was_clicked() { - self.character.weapon = Weapon::Hammer; + self.character_body.weapon = Weapon::Hammer; } // Bow Image::new(self.imgs.bow) .w_h(60.0, 60.0) .right_from(self.ids.sword_shield, 8.0 * 5.0 + 60.0 * 4.0) .set(self.ids.bow, ui_widgets); - if Button::image(if let Weapon::Bow = self.character.weapon { + if Button::image(if let Weapon::Bow = self.character_body.weapon { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -975,14 +978,14 @@ impl CharSelectionUi { .set(self.ids.weapon_6, ui_widgets) .was_clicked() { - self.character.weapon = Weapon::Bow; + self.character_body.weapon = Weapon::Bow; } // Staff Image::new(self.imgs.staff) .w_h(60.0, 60.0) .right_from(self.ids.sword_shield, 8.0 * 6.0 + 60.0 * 5.0) .set(self.ids.staff, ui_widgets); - if Button::image(if let Weapon::Staff = self.character.weapon { + if Button::image(if let Weapon::Staff = self.character_body.weapon { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -993,7 +996,7 @@ impl CharSelectionUi { .set(self.ids.weapon_7, ui_widgets) .was_clicked() { - self.character.weapon = Weapon::Staff; + self.character_body.weapon = Weapon::Staff; } // TODO: Load these from files (or from the server???) @@ -1005,7 +1008,7 @@ impl CharSelectionUi { const BOW_DESC: &str = " MISSING "; const STAFF_DESC: &str = " MISSING "; - let (weapon_str, weapon_desc) = match self.character.weapon { + let (weapon_str, weapon_desc) = match self.character_body.weapon { Weapon::SwordShield => ("Sword and Shield", SWORDSHIELD_DESC), Weapon::Daggers => ("Daggers", DAGGERS_DESC), Weapon::Sword => ("Sword", SWORD_DESC), @@ -1352,7 +1355,7 @@ impl CharSelectionUi { .was_clicked() {}; // Beard -> Only active when "male" was chosen - if let Gender::Male = self.character.gender { + if let BodyType::Male = self.character_body.body_type { Text::new("Beard Style") .mid_top_with_margin_on(self.ids.hair_window, 340.0) .color(TEXT_COLOR) @@ -1383,7 +1386,7 @@ impl CharSelectionUi { // Color -> Picker // Brightness -> Slider BodyPart::Accessories => { - match self.character.race { + match self.character_body.race { Race::Human => { Text::new("Head Band") .mid_top_with_margin_on(self.ids.accessories_window, 60.0) diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index ee363764dc..8192c12bee 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -14,7 +14,9 @@ use common::{ assets, comp::{ self, - character::{Belt, Character, Chest, Draw, Foot, Hand, Head, Pants, Shoulder, Weapon}, + Body, + HumanoidBody, + actor::{Belt, Chest, Foot, Hand, Head, Pants, Weapon}, }, figure::Segment, msg, @@ -25,7 +27,7 @@ use std::{collections::HashMap, f32}; use vek::*; pub struct FigureModelCache { - models: HashMap, u64)>, + models: HashMap, u64)>, } impl FigureModelCache { @@ -38,31 +40,30 @@ impl FigureModelCache { pub fn get_or_create_model( &mut self, renderer: &mut Renderer, - character: Character, + body: HumanoidBody, tick: u64, ) -> &Model { - match self.models.get_mut(&character) { + match self.models.get_mut(&body) { Some((model, last_used)) => { *last_used = tick; } None => { self.models.insert( - character, + body, ( { let bone_meshes = [ - Some(Self::load_head(character.head)), - Some(Self::load_chest(character.chest)), - Some(Self::load_belt(character.belt)), - Some(Self::load_pants(character.pants)), - Some(Self::load_left_hand(character.hand)), - Some(Self::load_right_hand(character.hand)), - Some(Self::load_left_foot(character.foot)), - Some(Self::load_right_foot(character.foot)), - Some(Self::load_weapon(character.weapon)), - Some(Self::load_left_shoulder(character.shoulder)), - Some(Self::load_right_shoulder(character.shoulder)), - //Some(Self::load_draw(character.draw)), + Some(Self::load_head(body.head)), + Some(Self::load_chest(body.chest)), + Some(Self::load_belt(body.belt)), + Some(Self::load_pants(body.pants)), + Some(Self::load_left_hand(body.hand)), + Some(Self::load_right_hand(body.hand)), + Some(Self::load_left_foot(body.foot)), + Some(Self::load_right_foot(body.foot)), + Some(Self::load_weapon(body.weapon)), + Some(Self::load_left_shoulder(body.shoulder)), + Some(Self::load_right_shoulder(body.shoulder)), None, None, None, @@ -89,7 +90,7 @@ impl FigureModelCache { } } - &self.models[&character].0 + &self.models[&body].0 } pub fn clean(&mut self, tick: u64) { @@ -108,7 +109,7 @@ impl FigureModelCache { fn load_head(head: Head) -> Mesh { Self::load_mesh( match head { - Head::DefaultHead => "head.vox", + Head::Default => "head.vox", }, Vec3::new(-7.0, -5.5, -6.0), ) @@ -117,7 +118,7 @@ impl FigureModelCache { fn load_chest(chest: Chest) -> Mesh { Self::load_mesh( match chest { - Chest::DefaultChest => "chest.vox", + Chest::Default => "chest.vox", }, Vec3::new(-6.0, -3.5, 0.0), ) @@ -126,7 +127,7 @@ impl FigureModelCache { fn load_belt(belt: Belt) -> Mesh { Self::load_mesh( match belt { - Belt::DefaultBelt => "belt.vox", + Belt::Default => "belt.vox", }, Vec3::new(-5.0, -3.5, 0.0), ) @@ -135,7 +136,7 @@ impl FigureModelCache { fn load_pants(pants: Pants) -> Mesh { Self::load_mesh( match pants { - Pants::DefaultPants => "pants.vox", + Pants::Default => "pants.vox", }, Vec3::new(-5.0, -3.5, 0.0), ) @@ -144,7 +145,7 @@ impl FigureModelCache { fn load_left_hand(hand: Hand) -> Mesh { Self::load_mesh( match hand { - Hand::DefaultHand => "hand.vox", + Hand::Default => "hand.vox", }, Vec3::new(2.0, 0.0, -7.0), ) @@ -153,7 +154,7 @@ impl FigureModelCache { fn load_right_hand(hand: Hand) -> Mesh { Self::load_mesh( match hand { - Hand::DefaultHand => "hand.vox", + Hand::Default => "hand.vox", }, Vec3::new(2.0, 0.0, -7.0), ) @@ -162,7 +163,7 @@ impl FigureModelCache { fn load_left_foot(foot: Foot) -> Mesh { Self::load_mesh( match foot { - Foot::DefaultFoot => "foot.vox", + Foot::Default => "foot.vox", }, Vec3::new(2.5, -3.5, -9.0), ) @@ -171,7 +172,7 @@ impl FigureModelCache { fn load_right_foot(foot: Foot) -> Mesh { Self::load_mesh( match foot { - Foot::DefaultFoot => "foot.vox", + Foot::Default => "foot.vox", }, Vec3::new(2.5, -3.5, -9.0), ) @@ -238,42 +239,50 @@ impl FigureMgr { pub fn maintain(&mut self, renderer: &mut Renderer, client: &Client) { let time = client.state().get_time(); let ecs = client.state().ecs(); - for (entity, pos, vel, dir, character, animation_history) in ( + for (entity, pos, vel, dir, actor, animation_history) in ( &ecs.entities(), &ecs.read_storage::(), &ecs.read_storage::(), &ecs.read_storage::(), - &ecs.read_storage::(), + &ecs.read_storage::(), &ecs.read_storage::(), ) .join() { - let state = self - .states - .entry(entity) - .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); + match actor { + comp::Actor::Character { body, .. } => match body { + Body::Humanoid(body) => { + let state = self + .states + .entry(entity) + .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); - let target_skeleton = match animation_history.current { - comp::character::Animation::Idle => IdleAnimation::update_skeleton( - state.skeleton_mut(), - time, - animation_history.time, - ), - comp::character::Animation::Run => RunAnimation::update_skeleton( - state.skeleton_mut(), - (vel.0.magnitude(), time), - animation_history.time, - ), - comp::character::Animation::Jump => JumpAnimation::update_skeleton( - state.skeleton_mut(), - time, - animation_history.time, - ), - }; + let target_skeleton = match animation_history.current { + comp::Animation::Idle => IdleAnimation::update_skeleton( + state.skeleton_mut(), + time, + animation_history.time, + ), + comp::Animation::Run => RunAnimation::update_skeleton( + state.skeleton_mut(), + (vel.0.magnitude(), time), + animation_history.time, + ), + comp::Animation::Jump => JumpAnimation::update_skeleton( + state.skeleton_mut(), + time, + animation_history.time, + ), + }; - state.skeleton.interpolate(&target_skeleton); + state.skeleton.interpolate(&target_skeleton); - state.update(renderer, pos.0, dir.0); + state.update(renderer, pos.0, dir.0); + }, + // TODO: Non-humanoid bodies + }, + // TODO: Non-character actors + } } self.states @@ -289,13 +298,17 @@ impl FigureMgr { let tick = client.get_tick(); let ecs = client.state().ecs(); - for (entity, &character) in (&ecs.entities(), &ecs.read_storage::()).join() + for (entity, actor) in (&ecs.entities(), &ecs.read_storage::()).join() { - if let Some(state) = self.states.get(&entity) { - let model = self - .model_cache - .get_or_create_model(renderer, character, tick); - renderer.render_figure(model, globals, &state.locals(), state.bone_consts()); + match actor { + comp::Actor::Character { body, .. } => match body { + Body::Humanoid(body) => if let Some(state) = self.states.get(&entity) { + let model = self.model_cache.get_or_create_model(renderer, *body, tick); + renderer.render_figure(model, globals, &state.locals(), state.bone_consts()); + }, + // TODO: Non-humanoid bodies + }, + // TODO: Non-character actors } } } From 216819ca92d785c585a315ffd4f2afb57860ce79 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 12 May 2019 22:34:20 +0100 Subject: [PATCH 10/14] fmt Former-commit-id: 4fd53e02969d9d044367d81640a2975043c6953a --- common/src/comp/actor.rs | 5 +--- common/src/comp/mod.rs | 8 +++--- server/src/cmd.rs | 21 ++++++++++++---- server/src/lib.rs | 32 ++++++++++++------------ voxygen/src/menu/char_selection/scene.rs | 9 +++---- voxygen/src/menu/char_selection/ui.rs | 4 +-- voxygen/src/scene/figure.rs | 30 ++++++++++++---------- 7 files changed, 58 insertions(+), 51 deletions(-) diff --git a/common/src/comp/actor.rs b/common/src/comp/actor.rs index 8bc0f4507a..4302749f12 100644 --- a/common/src/comp/actor.rs +++ b/common/src/comp/actor.rs @@ -137,10 +137,7 @@ pub enum Body { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Actor { - Character { - name: String, - body: Body, - }, + Character { name: String, body: Body }, } impl Component for Actor { diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 20290a8283..1d14704377 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -1,13 +1,13 @@ -pub mod agent; pub mod actor; +pub mod agent; pub mod phys; pub mod player; // Reexports -pub use agent::{Agent, Control}; +pub use actor::Actor; pub use actor::Animation; pub use actor::AnimationHistory; -pub use actor::HumanoidBody; pub use actor::Body; -pub use actor::Actor; +pub use actor::HumanoidBody; +pub use agent::{Agent, Control}; pub use player::Player; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index b3bc12357a..b12ecafe17 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -191,14 +191,25 @@ fn handle_pet(server: &mut Server, entity: EcsEntity, args: String, action: &Cha .read_component_cloned::(entity) { Some(pos) => { - server.create_npc("Bungo".to_owned(), comp::Body::Humanoid(comp::HumanoidBody::random())) + server + .create_npc( + "Bungo".to_owned(), + comp::Body::Humanoid(comp::HumanoidBody::random()), + ) .with(comp::Control::default()) - .with(comp::Agent::Pet{ target: entity, offset: Vec2::zero() }) + .with(comp::Agent::Pet { + target: entity, + offset: Vec2::zero(), + }) .with(pos) .build(); - server.clients.notify(entity, ServerMsg::Chat("Spawned pet!".to_owned())); - }, - None => server.clients.notify(entity, ServerMsg::Chat("You have no position!".to_owned())), + server + .clients + .notify(entity, ServerMsg::Chat("Spawned pet!".to_owned())); + } + None => server + .clients + .notify(entity, ServerMsg::Chat("You have no position!".to_owned())), } } diff --git a/server/src/lib.rs b/server/src/lib.rs index a358fdca9b..f25962deb5 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -80,10 +80,13 @@ impl Server { }; for i in 0..4 { - this.create_npc("Tobermory".to_owned(), comp::Body::Humanoid(comp::HumanoidBody::random())) - .with(comp::Control::default()) - .with(comp::Agent::Wanderer(Vec2::zero())) - .build(); + this.create_npc( + "Tobermory".to_owned(), + comp::Body::Humanoid(comp::HumanoidBody::random()), + ) + .with(comp::Control::default()) + .with(comp::Agent::Wanderer(Vec2::zero())) + .build(); } Ok(this) @@ -121,10 +124,7 @@ impl Server { .with(comp::phys::Vel(Vec3::zero())) .with(comp::phys::Dir(Vec3::unit_y())) .with(comp::AnimationHistory::new(comp::Animation::Idle)) - .with(comp::Actor::Character { - name, - body, - }) + .with(comp::Actor::Character { name, body }) } pub fn create_player_character( @@ -134,10 +134,13 @@ impl Server { name: String, body: comp::HumanoidBody, ) { - state.write_component(entity, comp::Actor::Character { - name, - body: comp::Body::Humanoid(body), - }); + state.write_component( + entity, + comp::Actor::Character { + name, + body: comp::Body::Humanoid(body), + }, + ); state.write_component(entity, comp::phys::Pos(Vec3::new(0.0, 0.0, 64.0))); state.write_component(entity, comp::phys::Vel(Vec3::zero())); state.write_component(entity, comp::phys::Dir(Vec3::unit_y())); @@ -145,10 +148,7 @@ impl Server { state.write_component(entity, comp::phys::ForceUpdate); // Set initial animation - state.write_component( - entity, - comp::AnimationHistory::new(comp::Animation::Idle), - ); + state.write_component(entity, comp::AnimationHistory::new(comp::Animation::Idle)); // Tell the client his request was successful client.notify(ServerMsg::StateAnswer(Ok(ClientState::Character))); diff --git a/voxygen/src/menu/char_selection/scene.rs b/voxygen/src/menu/char_selection/scene.rs index fbf7595dce..e8511215f0 100644 --- a/voxygen/src/menu/char_selection/scene.rs +++ b/voxygen/src/menu/char_selection/scene.rs @@ -1,9 +1,3 @@ -use vek::*; -use client::Client; -use common::{ - comp::HumanoidBody, - figure::Segment, -}; use crate::{ anim::{ character::{CharacterSkeleton, IdleAnimation}, @@ -18,6 +12,9 @@ use crate::{ figure::{FigureModelCache, FigureState}, }, }; +use client::Client; +use common::{comp::HumanoidBody, figure::Segment}; +use vek::*; struct Skybox { model: Model, diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index 2977f684b9..414606e0b4 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -8,10 +8,8 @@ use crate::{ window::Window, }; use common::comp::{ + actor::{Belt, BodyType, Chest, Foot, Hand, Head, Pants, Race, Weapon}, HumanoidBody, - actor::{ - Belt, Chest, Foot, BodyType, Hand, Head, Pants, Race, Weapon, - }, }; use conrod_core::{ color, diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 8192c12bee..f6b87ec064 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -14,9 +14,8 @@ use common::{ assets, comp::{ self, - Body, - HumanoidBody, actor::{Belt, Chest, Foot, Hand, Head, Pants, Weapon}, + Body, HumanoidBody, }, figure::Segment, msg, @@ -252,10 +251,9 @@ impl FigureMgr { match actor { comp::Actor::Character { body, .. } => match body { Body::Humanoid(body) => { - let state = self - .states - .entry(entity) - .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new())); + let state = self.states.entry(entity).or_insert_with(|| { + FigureState::new(renderer, CharacterSkeleton::new()) + }); let target_skeleton = match animation_history.current { comp::Animation::Idle => IdleAnimation::update_skeleton( @@ -278,7 +276,7 @@ impl FigureMgr { state.skeleton.interpolate(&target_skeleton); state.update(renderer, pos.0, dir.0); - }, + } // TODO: Non-humanoid bodies }, // TODO: Non-character actors @@ -298,14 +296,20 @@ impl FigureMgr { let tick = client.get_tick(); let ecs = client.state().ecs(); - for (entity, actor) in (&ecs.entities(), &ecs.read_storage::()).join() - { + for (entity, actor) in (&ecs.entities(), &ecs.read_storage::()).join() { match actor { comp::Actor::Character { body, .. } => match body { - Body::Humanoid(body) => if let Some(state) = self.states.get(&entity) { - let model = self.model_cache.get_or_create_model(renderer, *body, tick); - renderer.render_figure(model, globals, &state.locals(), state.bone_consts()); - }, + Body::Humanoid(body) => { + if let Some(state) = self.states.get(&entity) { + let model = self.model_cache.get_or_create_model(renderer, *body, tick); + renderer.render_figure( + model, + globals, + &state.locals(), + state.bone_consts(), + ); + } + } // TODO: Non-humanoid bodies }, // TODO: Non-character actors From edfd2290eb63ced7dd21a44d612705ae4ccfb0e1 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 13 May 2019 10:32:02 +0100 Subject: [PATCH 11/14] Massively sped up VolMap offset calculations Former-commit-id: 8f3cdf57a77691ca60c0921bc86a79c8cfe36539 --- common/src/state.rs | 2 +- common/src/volumes/vol_map.rs | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/common/src/state.rs b/common/src/state.rs index 29cdb59f4a..509ca67ca7 100644 --- a/common/src/state.rs +++ b/common/src/state.rs @@ -110,7 +110,7 @@ impl State { ecs.add_resource(TimeOfDay(0.0)); ecs.add_resource(Time(0.0)); ecs.add_resource(DeltaTime(0.0)); - ecs.add_resource(TerrainMap::new()); + ecs.add_resource(TerrainMap::new().unwrap()); } /// Register a component with the state's ECS diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs index d73ede7ee1..aa7c297428 100644 --- a/common/src/volumes/vol_map.rs +++ b/common/src/volumes/vol_map.rs @@ -19,6 +19,7 @@ pub enum VolMapErr { NoSuchChunk, ChunkErr(ChunkErr), DynaErr(DynaErr), + InvalidChunkSize, } // V = Voxel @@ -31,13 +32,20 @@ pub struct VolMap { impl VolMap { #[inline(always)] - fn chunk_key(pos: Vec3) -> Vec3 { - pos.map2(S::SIZE, |e, sz| e.div_euclid(sz as i32)) + pub fn chunk_key(pos: Vec3) -> Vec3 { + pos.map2(S::SIZE, |e, sz| { + // Horrid, but it's faster than a cheetah with a red bull blood transfusion + let log2 = (sz - 1).count_ones(); + ((((e as i64 + (1 << 32)) as u64) >> log2) - (1 << (32 - log2))) as i32 + }) } #[inline(always)] pub fn chunk_offs(pos: Vec3) -> Vec3 { - pos.map2(S::SIZE, |e, sz| e.rem_euclid(sz as i32)) + pos.map2(S::SIZE, |e, sz| { + // Horrid, but it's even faster than the aforementioned cheetah + (((e as i64 + (1 << 32)) as u64) & (sz - 1) as u64) as i32 + }) } } @@ -150,10 +158,17 @@ impl WriteVol for VolMap } } -impl VolMap { - pub fn new() -> Self { - Self { - chunks: HashMap::new(), +impl VolMap { + pub fn new() -> Result { + if Self::chunk_size() + .map(|e| e.is_power_of_two() && e > 0) + .reduce_and() + { + Ok(Self { + chunks: HashMap::new(), + }) + } else { + Err(VolMapErr::InvalidChunkSize) } } From 0b1ea359faa3b45012906e05595849afe87a5e7d Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 13 May 2019 11:01:46 +0100 Subject: [PATCH 12/14] Adjustments to VolMap Former-commit-id: 53ba7185102e7ff17825891d02bd0e26e5fe1076 --- common/src/volumes/vol_map.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common/src/volumes/vol_map.rs b/common/src/volumes/vol_map.rs index aa7c297428..76fa9a6c84 100644 --- a/common/src/volumes/vol_map.rs +++ b/common/src/volumes/vol_map.rs @@ -26,11 +26,11 @@ pub enum VolMapErr { // S = Size (replace with a const when const generics is a thing) // M = Chunk metadata #[derive(Clone)] -pub struct VolMap { +pub struct VolMap { chunks: HashMap, Arc>>, } -impl VolMap { +impl VolMap { #[inline(always)] pub fn chunk_key(pos: Vec3) -> Vec3 { pos.map2(S::SIZE, |e, sz| { @@ -49,12 +49,12 @@ impl VolMap { } } -impl BaseVol for VolMap { +impl BaseVol for VolMap { type Vox = V; type Err = VolMapErr; } -impl ReadVol for VolMap { +impl ReadVol for VolMap { #[inline(always)] fn get(&self, pos: Vec3) -> Result<&V, VolMapErr> { let ck = Self::chunk_key(pos); @@ -68,7 +68,7 @@ impl ReadVol for VolMap { } } -impl SampleVol for VolMap { +impl SampleVol for VolMap { type Sample = VolMap; /// Take a sample of the terrain by cloning the voxels within the provided range. @@ -121,7 +121,7 @@ impl SampleVol for VolMap // Ok(sample) - let mut sample = VolMap::new(); + let mut sample = VolMap::new()?; let chunk_min = Self::chunk_key(range.min); let chunk_max = Self::chunk_key(range.max); for x in chunk_min.x..=chunk_max.x { @@ -158,7 +158,7 @@ impl WriteVol for VolMap } } -impl VolMap { +impl VolMap { pub fn new() -> Result { if Self::chunk_size() .map(|e| e.is_power_of_two() && e > 0) @@ -214,11 +214,11 @@ impl VolMap { } } -pub struct ChunkIter<'a, V: Vox + Clone, S: VolSize + Clone, M: Clone> { +pub struct ChunkIter<'a, V: Vox, S: VolSize, M> { iter: std::collections::hash_map::Iter<'a, Vec3, Arc>>, } -impl<'a, V: Vox + Clone, S: VolSize + Clone, M: Clone> Iterator for ChunkIter<'a, V, S, M> { +impl<'a, V: Vox, S: VolSize, M> Iterator for ChunkIter<'a, V, S, M> { type Item = (Vec3, &'a Arc>); fn next(&mut self) -> Option { From 4f53be633ef0d3565ebbbeeddceb2eea3a5cf1f4 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 13 May 2019 11:15:03 +0100 Subject: [PATCH 13/14] sync Former-commit-id: 708f80eabb9dc4052d35ed03875ef7ae485d6170 --- voxygen/src/scene/figure.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index f6b87ec064..0e7263553d 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -14,7 +14,7 @@ use common::{ assets, comp::{ self, - actor::{Belt, Chest, Foot, Hand, Head, Pants, Weapon}, + actor::{Belt, Chest, Foot, Hand, Head, Pants, Weapon, Shoulder}, Body, HumanoidBody, }, figure::Segment, @@ -191,7 +191,7 @@ impl FigureModelCache { fn load_left_shoulder(shoulder: Shoulder) -> Mesh { Self::load_mesh( match shoulder { - Shoulder::DefaultShoulder => "shoulder_l.vox", + Shoulder::Default => "shoulder_l.vox", }, Vec3::new(2.5, 0.0, 0.0), ) @@ -200,7 +200,7 @@ impl FigureModelCache { fn load_right_shoulder(shoulder: Shoulder) -> Mesh { Self::load_mesh( match shoulder { - Shoulder::DefaultShoulder => "shoulder_r.vox", + Shoulder::Default => "shoulder_r.vox", }, Vec3::new(2.5, 0.0, 0.0), ) From ee380782fb310d912c132572502dcf09077bfe06 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Mon, 13 May 2019 11:29:35 +0100 Subject: [PATCH 14/14] fmt Former-commit-id: 140f1e4f1809b70881a51a3bd943e1697a9dc0a2 --- voxygen/src/scene/figure.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs index 0e7263553d..9ef9dad08c 100644 --- a/voxygen/src/scene/figure.rs +++ b/voxygen/src/scene/figure.rs @@ -14,7 +14,7 @@ use common::{ assets, comp::{ self, - actor::{Belt, Chest, Foot, Hand, Head, Pants, Weapon, Shoulder}, + actor::{Belt, Chest, Foot, Hand, Head, Pants, Shoulder, Weapon}, Body, HumanoidBody, }, figure::Segment, @@ -276,8 +276,7 @@ impl FigureMgr { state.skeleton.interpolate(&target_skeleton); state.update(renderer, pos.0, dir.0); - } - // TODO: Non-humanoid bodies + } // TODO: Non-humanoid bodies }, // TODO: Non-character actors } @@ -309,8 +308,7 @@ impl FigureMgr { state.bone_consts(), ); } - } - // TODO: Non-humanoid bodies + } // TODO: Non-humanoid bodies }, // TODO: Non-character actors }