mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'imbris/player-list' into 'master'
Show players out of range on the player list, fix another overflow causing bug See merge request veloren/veloren!691
This commit is contained in:
commit
cec303a3c6
@ -10,8 +10,8 @@ pub use specs::{join::Join, saveload::Marker, Entity as EcsEntity, ReadStorage,
|
||||
use common::{
|
||||
comp::{self, ControlEvent, Controller, ControllerInputs, InventoryManip},
|
||||
msg::{
|
||||
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, RequestStateError,
|
||||
ServerError, ServerInfo, ServerMsg, MAX_BYTES_CHAT_MSG,
|
||||
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate,
|
||||
RequestStateError, ServerError, ServerInfo, ServerMsg, MAX_BYTES_CHAT_MSG,
|
||||
},
|
||||
net::PostBox,
|
||||
state::State,
|
||||
@ -52,6 +52,7 @@ pub struct Client {
|
||||
thread_pool: ThreadPool,
|
||||
pub server_info: ServerInfo,
|
||||
pub world_map: Arc<DynamicImage>,
|
||||
pub player_list: HashMap<u64, String>,
|
||||
|
||||
postbox: PostBox<ClientMsg, ServerMsg>,
|
||||
|
||||
@ -71,7 +72,6 @@ pub struct Client {
|
||||
|
||||
impl Client {
|
||||
/// Create a new `Client`.
|
||||
#[allow(dead_code)]
|
||||
pub fn new<A: Into<SocketAddr>>(addr: A, view_distance: Option<u32>) -> Result<Self, Error> {
|
||||
let client_state = ClientState::Connected;
|
||||
let mut postbox = PostBox::to(addr)?;
|
||||
@ -137,6 +137,7 @@ impl Client {
|
||||
thread_pool,
|
||||
server_info,
|
||||
world_map,
|
||||
player_list: HashMap::new(),
|
||||
|
||||
postbox,
|
||||
|
||||
@ -154,7 +155,6 @@ impl Client {
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn with_thread_pool(mut self, thread_pool: ThreadPool) -> Self {
|
||||
self.thread_pool = thread_pool;
|
||||
self
|
||||
@ -282,7 +282,6 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Send a chat message to the server.
|
||||
#[allow(dead_code)]
|
||||
pub fn send_chat(&mut self, msg: String) {
|
||||
match validate_chat_msg(&msg) {
|
||||
Ok(()) => self.postbox.send_message(ClientMsg::chat(msg)),
|
||||
@ -294,7 +293,6 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Remove all cached terrain
|
||||
#[allow(dead_code)]
|
||||
pub fn clear_terrain(&mut self) {
|
||||
self.state.clear_terrain();
|
||||
self.pending_chunks.clear();
|
||||
@ -316,7 +314,6 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Execute a single client tick, handle input and update the game state by the given duration.
|
||||
#[allow(dead_code)]
|
||||
pub fn tick(&mut self, inputs: ControllerInputs, dt: Duration) -> Result<Vec<Event>, Error> {
|
||||
// This tick function is the centre of the Veloren universe. Most client-side things are
|
||||
// managed from here, and as such it's important that it stays organised. Please consult
|
||||
@ -389,6 +386,10 @@ impl Client {
|
||||
// Remove chunks that are too far from the player.
|
||||
let mut chunks_to_remove = Vec::new();
|
||||
self.state.terrain().iter().for_each(|(key, _)| {
|
||||
// Subtract 2 from the offset before computing squared magnitude
|
||||
// 1 for the chunks needed bordering other chunks for meshing
|
||||
// 1 as a buffer so that if the player moves back in that direction the chunks
|
||||
// don't need to be reloaded
|
||||
if (chunk_pos - key)
|
||||
.map(|e: i32| (e.abs() as u32).checked_sub(2).unwrap_or(0))
|
||||
.magnitude_squared()
|
||||
@ -492,7 +493,6 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Clean up the client after a tick.
|
||||
#[allow(dead_code)]
|
||||
pub fn cleanup(&mut self) {
|
||||
// Cleanup the local state
|
||||
self.state.cleanup();
|
||||
@ -531,6 +531,27 @@ impl Client {
|
||||
},
|
||||
ServerMsg::Shutdown => return Err(Error::ServerShutdown),
|
||||
ServerMsg::InitialSync { .. } => return Err(Error::ServerWentMad),
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Init(list)) => {
|
||||
self.player_list = list
|
||||
}
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Add(uid, name)) => {
|
||||
if let Some(old_name) = self.player_list.insert(uid, name.clone()) {
|
||||
warn!("Received msg to insert {} with uid {} into the player list but there was already an entry for {} with the same uid that was overwritten!", name, uid, old_name);
|
||||
}
|
||||
}
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Remove(uid)) => {
|
||||
if self.player_list.remove(&uid).is_none() {
|
||||
warn!("Received msg to remove uid {} from the player list by they weren't in the list!", uid);
|
||||
}
|
||||
}
|
||||
ServerMsg::PlayerListUpdate(PlayerListUpdate::Alias(uid, new_name)) => {
|
||||
if let Some(name) = self.player_list.get_mut(&uid) {
|
||||
*name = new_name;
|
||||
} else {
|
||||
warn!("Received msg to alias player with uid {} to {} but this uid is not in the player list", uid, new_name);
|
||||
}
|
||||
}
|
||||
|
||||
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
|
||||
ServerMsg::Pong => {
|
||||
self.last_server_pong = Instant::now();
|
||||
@ -602,9 +623,11 @@ impl Client {
|
||||
}
|
||||
self.pending_chunks.remove(&key);
|
||||
}
|
||||
ServerMsg::TerrainBlockUpdates(mut blocks) => blocks
|
||||
.drain()
|
||||
.for_each(|(pos, block)| self.state.set_block(pos, block)),
|
||||
ServerMsg::TerrainBlockUpdates(mut blocks) => {
|
||||
blocks.drain().for_each(|(pos, block)| {
|
||||
self.state.set_block(pos, block);
|
||||
});
|
||||
}
|
||||
ServerMsg::StateAnswer(Ok(state)) => {
|
||||
self.client_state = state;
|
||||
}
|
||||
@ -636,24 +659,20 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Get the player's entity.
|
||||
#[allow(dead_code)]
|
||||
pub fn entity(&self) -> EcsEntity {
|
||||
self.entity
|
||||
}
|
||||
|
||||
/// Get the client state
|
||||
#[allow(dead_code)]
|
||||
pub fn get_client_state(&self) -> ClientState {
|
||||
self.client_state
|
||||
}
|
||||
|
||||
/// Get the current tick number.
|
||||
#[allow(dead_code)]
|
||||
pub fn get_tick(&self) -> u64 {
|
||||
self.tick
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_ping_ms(&self) -> f64 {
|
||||
self.last_ping_delta * 1000.0
|
||||
}
|
||||
@ -661,19 +680,16 @@ impl Client {
|
||||
/// Get a reference to the client's worker thread pool. This pool should be used for any
|
||||
/// computationally expensive operations that run outside of the main thread (i.e., threads that
|
||||
/// block on I/O operations are exempt).
|
||||
#[allow(dead_code)]
|
||||
pub fn thread_pool(&self) -> &ThreadPool {
|
||||
&self.thread_pool
|
||||
}
|
||||
|
||||
/// Get a reference to the client's game state.
|
||||
#[allow(dead_code)]
|
||||
pub fn state(&self) -> &State {
|
||||
&self.state
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the client's game state.
|
||||
#[allow(dead_code)]
|
||||
pub fn state_mut(&mut self) -> &mut State {
|
||||
&mut self.state
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ pub enum ClientMsg {
|
||||
Ping,
|
||||
Pong,
|
||||
ChatMsg {
|
||||
chat_type: ChatType,
|
||||
chat_type: ChatType, // This is unused afaik, TODO: remove
|
||||
message: String,
|
||||
},
|
||||
PlayerPhysics {
|
||||
|
@ -5,7 +5,7 @@ pub mod server;
|
||||
// Reexports
|
||||
pub use self::client::ClientMsg;
|
||||
pub use self::ecs_packet::EcsCompPacket;
|
||||
pub use self::server::{RequestStateError, ServerError, ServerInfo, ServerMsg};
|
||||
pub use self::server::{PlayerListUpdate, RequestStateError, ServerError, ServerInfo, ServerMsg};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ClientState {
|
||||
|
@ -23,6 +23,14 @@ pub struct ServerInfo {
|
||||
pub git_date: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum PlayerListUpdate {
|
||||
Init(HashMap<u64, String>),
|
||||
Add(u64, String),
|
||||
Remove(u64),
|
||||
Alias(u64, String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ServerMsg {
|
||||
InitialSync {
|
||||
@ -31,6 +39,7 @@ pub enum ServerMsg {
|
||||
time_of_day: state::TimeOfDay,
|
||||
// world_map: Vec2<usize>, /*, Vec<u32>)*/
|
||||
},
|
||||
PlayerListUpdate(PlayerListUpdate),
|
||||
StateAnswer(Result<ClientState, (RequestStateError, ClientState)>),
|
||||
ForceState(ClientState),
|
||||
Ping,
|
||||
|
@ -326,17 +326,14 @@ impl State {
|
||||
|
||||
// Apply terrain changes
|
||||
let mut terrain = self.ecs.write_resource::<TerrainGrid>();
|
||||
self.ecs
|
||||
.read_resource::<BlockChange>()
|
||||
.blocks
|
||||
.iter()
|
||||
.for_each(|(pos, block)| {
|
||||
let _ = terrain.set(*pos, *block);
|
||||
});
|
||||
self.ecs.write_resource::<TerrainChanges>().modified_blocks = std::mem::replace(
|
||||
let mut modified_blocks = std::mem::replace(
|
||||
&mut self.ecs.write_resource::<BlockChange>().blocks,
|
||||
Default::default(),
|
||||
);
|
||||
// Apply block modifications
|
||||
// Only include in `TerrainChanges` if successful
|
||||
modified_blocks.retain(|pos, block| terrain.set(*pos, *block).is_ok());
|
||||
self.ecs.write_resource::<TerrainChanges>().modified_blocks = modified_blocks;
|
||||
|
||||
// Process local events
|
||||
let events = self.ecs.read_resource::<EventBus<LocalEvent>>().recv_all();
|
||||
|
@ -167,6 +167,8 @@ impl<V: RectRasterableVol> VolGrid2d<V> {
|
||||
|
||||
pub struct CachedVolGrid2d<'a, V: RectRasterableVol> {
|
||||
vol_grid_2d: &'a VolGrid2d<V>,
|
||||
// This can't be invalidated by mutations of the chunks hashmap since we hold an immutable
|
||||
// reference to the `VolGrid2d`
|
||||
cache: Option<(Vec2<i32>, Arc<V>)>,
|
||||
}
|
||||
impl<'a, V: RectRasterableVol> CachedVolGrid2d<'a, V> {
|
||||
@ -178,9 +180,9 @@ impl<'a, V: RectRasterableVol> CachedVolGrid2d<'a, V> {
|
||||
}
|
||||
}
|
||||
impl<'a, V: RectRasterableVol + ReadVol> CachedVolGrid2d<'a, V> {
|
||||
// Note: this may be invalidated by mutations of the chunks hashmap
|
||||
#[inline(always)]
|
||||
pub fn get(&mut self, pos: Vec3<i32>) -> Result<&V::Vox, VolGrid2dError<V>> {
|
||||
// Calculate chunk key from block pos
|
||||
let ck = VolGrid2d::<V>::chunk_key(pos);
|
||||
let chunk = if self
|
||||
.cache
|
||||
@ -188,13 +190,16 @@ impl<'a, V: RectRasterableVol + ReadVol> CachedVolGrid2d<'a, V> {
|
||||
.map(|(key, _)| *key == ck)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
// If the chunk with that key is in the cache use that
|
||||
&self.cache.as_ref().unwrap().1
|
||||
} else {
|
||||
// Otherwise retrieve from the hashmap
|
||||
let chunk = self
|
||||
.vol_grid_2d
|
||||
.chunks
|
||||
.get(&ck)
|
||||
.ok_or(VolGrid2dError::NoSuchChunk)?;
|
||||
// Store most recently looked up chunk in the cache
|
||||
self.cache = Some((ck, chunk.clone()));
|
||||
chunk
|
||||
};
|
||||
|
@ -8,11 +8,11 @@ use common::{
|
||||
assets, comp,
|
||||
event::{EventBus, ServerEvent},
|
||||
hierarchical::ChunkPath,
|
||||
msg::ServerMsg,
|
||||
msg::{PlayerListUpdate, ServerMsg},
|
||||
npc::{get_npc_name, NpcKind},
|
||||
pathfinding::WorldPath,
|
||||
state::TimeOfDay,
|
||||
sync::WorldSyncExt,
|
||||
sync::{Uid, WorldSyncExt},
|
||||
terrain::{Block, BlockKind, TerrainChunkSize},
|
||||
vol::RectVolSize,
|
||||
};
|
||||
@ -407,6 +407,19 @@ fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &C
|
||||
.write_storage::<comp::Player>()
|
||||
.get_mut(entity)
|
||||
.map(|player| player.alias = alias);
|
||||
|
||||
// Update name on client player lists
|
||||
let ecs = server.state.ecs();
|
||||
if let (Some(uid), Some(player)) = (
|
||||
ecs.read_storage::<Uid>().get(entity),
|
||||
ecs.read_storage::<comp::Player>().get(entity),
|
||||
) {
|
||||
let msg = ServerMsg::PlayerListUpdate(PlayerListUpdate::Alias(
|
||||
(*uid).into(),
|
||||
player.alias.clone(),
|
||||
));
|
||||
server.state.notify_registered_clients(msg);
|
||||
}
|
||||
} else {
|
||||
server.notify_client(entity, ServerMsg::private(String::from(action.help_string)));
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ use common::{
|
||||
assets, comp,
|
||||
effect::Effect,
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{ClientMsg, ClientState, ServerError, ServerInfo, ServerMsg},
|
||||
msg::{ClientMsg, ClientState, PlayerListUpdate, ServerError, ServerInfo, ServerMsg},
|
||||
net::PostOffice,
|
||||
state::{BlockChange, State, TimeOfDay},
|
||||
sync::{Uid, WorldSyncExt},
|
||||
@ -762,6 +762,17 @@ impl Server {
|
||||
}
|
||||
|
||||
ServerEvent::ClientDisconnect(entity) => {
|
||||
// Tell other clients to remove from player list
|
||||
if let (Some(uid), Some(_)) = (
|
||||
state.read_storage::<Uid>().get(entity),
|
||||
state.read_storage::<comp::Player>().get(entity),
|
||||
) {
|
||||
state.notify_registered_clients(ServerMsg::PlayerListUpdate(
|
||||
PlayerListUpdate::Remove((*uid).into()),
|
||||
))
|
||||
}
|
||||
|
||||
// Delete client entity
|
||||
if let Err(err) = state.delete_entity_recorded(entity) {
|
||||
error!("Failed to delete disconnected client: {:?}", err);
|
||||
}
|
||||
|
@ -3,12 +3,16 @@ use crate::{auth_provider::AuthProvider, client::Client, CLIENT_TIMEOUT};
|
||||
use common::{
|
||||
comp::{Admin, Body, CanBuild, Controller, ForceUpdate, Ori, Player, Pos, Vel},
|
||||
event::{EventBus, ServerEvent},
|
||||
msg::{validate_chat_msg, ChatMsgValidationError, MAX_BYTES_CHAT_MSG},
|
||||
msg::{ClientMsg, ClientState, RequestStateError, ServerMsg},
|
||||
msg::{
|
||||
validate_chat_msg, ChatMsgValidationError, ClientMsg, ClientState, PlayerListUpdate,
|
||||
RequestStateError, ServerMsg, MAX_BYTES_CHAT_MSG,
|
||||
},
|
||||
state::{BlockChange, Time},
|
||||
sync::Uid,
|
||||
terrain::{Block, TerrainGrid},
|
||||
vol::Vox,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use specs::{
|
||||
Entities, Join, Read, ReadExpect, ReadStorage, System, Write, WriteExpect, WriteStorage,
|
||||
};
|
||||
@ -22,6 +26,7 @@ impl<'a> System<'a> for Sys {
|
||||
Read<'a, Time>,
|
||||
ReadExpect<'a, TerrainGrid>,
|
||||
Write<'a, SysTimer<Self>>,
|
||||
ReadStorage<'a, Uid>,
|
||||
ReadStorage<'a, Body>,
|
||||
ReadStorage<'a, CanBuild>,
|
||||
ReadStorage<'a, Admin>,
|
||||
@ -44,6 +49,7 @@ impl<'a> System<'a> for Sys {
|
||||
time,
|
||||
terrain,
|
||||
mut timer,
|
||||
uids,
|
||||
bodies,
|
||||
can_build,
|
||||
admins,
|
||||
@ -64,6 +70,14 @@ impl<'a> System<'a> for Sys {
|
||||
|
||||
let mut new_chat_msgs = Vec::new();
|
||||
|
||||
// Player list to send new players.
|
||||
let player_list = (&uids, &players)
|
||||
.join()
|
||||
.map(|(uid, player)| ((*uid).into(), player.alias.clone()))
|
||||
.collect::<HashMap<_, _>>();
|
||||
// List of new players to update player lists of all clients.
|
||||
let mut new_players = Vec::new();
|
||||
|
||||
for (entity, client) in (&entities, &mut clients).join() {
|
||||
let mut disconnect = false;
|
||||
let new_msgs = client.postbox.new_messages();
|
||||
@ -127,10 +141,18 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
match client.client_state {
|
||||
ClientState::Connected => {
|
||||
// Add Player component to this client
|
||||
let _ = players.insert(entity, player);
|
||||
|
||||
// Tell the client its request was successful.
|
||||
client.allow_state(ClientState::Registered);
|
||||
|
||||
// Send initial player list
|
||||
client.notify(ServerMsg::PlayerListUpdate(PlayerListUpdate::Init(
|
||||
player_list.clone(),
|
||||
)));
|
||||
// Add to list to notify all clients of the new player
|
||||
new_players.push(entity);
|
||||
}
|
||||
// Use RequestState instead (No need to send `player` again).
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
@ -281,6 +303,20 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle new players.
|
||||
// Tell all clients to add them to the player list.
|
||||
for entity in new_players {
|
||||
if let (Some(uid), Some(player)) = (uids.get(entity), players.get(entity)) {
|
||||
let msg = ServerMsg::PlayerListUpdate(PlayerListUpdate::Add(
|
||||
(*uid).into(),
|
||||
player.alias.clone(),
|
||||
));
|
||||
for client in (&mut clients).join().filter(|c| c.is_registered()) {
|
||||
client.notify(msg.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle new chat messages.
|
||||
for (entity, msg) in new_chat_msgs {
|
||||
match msg {
|
||||
|
@ -71,6 +71,9 @@ impl<'a> System<'a> for Sys {
|
||||
})
|
||||
{
|
||||
let chunk_pos = terrain.pos_key(pos.0.map(|e| e as i32));
|
||||
// Subtract 2 from the offset before computing squared magnitude
|
||||
// 1 since chunks need neighbors to be meshed
|
||||
// 1 to act as a buffer if the player moves in that direction
|
||||
let adjusted_dist_sqr = (Vec2::from(chunk_pos) - Vec2::from(key))
|
||||
.map(|e: i32| (e.abs() as u32).checked_sub(2).unwrap_or(0))
|
||||
.magnitude_squared();
|
||||
|
@ -1,13 +1,11 @@
|
||||
use super::{img_ids::Imgs, Fonts, Show, TEXT_COLOR, TEXT_COLOR_3};
|
||||
|
||||
use common::comp;
|
||||
use conrod_core::{
|
||||
color,
|
||||
widget::{self, Button, Image, Rectangle, Scrollbar, Text},
|
||||
widget_ids, /*, Color*/
|
||||
Colorable, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
use specs::{Join, WorldExt};
|
||||
|
||||
use client::{self, Client};
|
||||
|
||||
@ -178,25 +176,12 @@ impl<'a> Widget for Social<'a> {
|
||||
|
||||
// Players list
|
||||
// TODO: this list changes infrequently enough that it should not have to be recreated every frame
|
||||
let ecs = self.client.state().ecs();
|
||||
let players = ecs.read_storage::<comp::Player>();
|
||||
let mut count = 0;
|
||||
for player in players.join() {
|
||||
if ids.player_names.len() <= count {
|
||||
ids.update(|ids| {
|
||||
ids.player_names
|
||||
.resize(count + 1, &mut ui.widget_id_generator())
|
||||
})
|
||||
}
|
||||
|
||||
Text::new(&player.alias)
|
||||
.down_from(ids.online_title, count as f64 * (15.0 + 3.0))
|
||||
.font_size(15)
|
||||
.font_id(self.fonts.cyri)
|
||||
.color(TEXT_COLOR)
|
||||
.set(ids.player_names[count], ui);
|
||||
|
||||
count += 1;
|
||||
let count = self.client.player_list.len();
|
||||
if ids.player_names.len() < count {
|
||||
ids.update(|ids| {
|
||||
ids.player_names
|
||||
.resize(count, &mut ui.widget_id_generator())
|
||||
})
|
||||
}
|
||||
Text::new(&format!("{} player(s) online\n", count))
|
||||
.top_left_with_margins_on(ids.content_align, -2.0, 7.0)
|
||||
@ -204,6 +189,14 @@ impl<'a> Widget for Social<'a> {
|
||||
.font_id(self.fonts.cyri)
|
||||
.color(TEXT_COLOR)
|
||||
.set(ids.online_title, ui);
|
||||
for (i, (_, player_alias)) in self.client.player_list.iter().enumerate() {
|
||||
Text::new(player_alias)
|
||||
.down(3.0)
|
||||
.font_size(15)
|
||||
.font_id(self.fonts.cyri)
|
||||
.color(TEXT_COLOR)
|
||||
.set(ids.player_names[i], ui);
|
||||
}
|
||||
}
|
||||
|
||||
// Friends Tab
|
||||
|
@ -17,7 +17,7 @@ use common::{
|
||||
use crossbeam::channel;
|
||||
use dot_vox::DotVoxData;
|
||||
use frustum_query::frustum::Frustum;
|
||||
use hashbrown::HashMap;
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
use std::{f32, fmt::Debug, i32, marker::PhantomData, ops::Mul, time::Duration};
|
||||
use vek::*;
|
||||
|
||||
@ -836,31 +836,48 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
.map(|(p, _)| *p)
|
||||
{
|
||||
let chunk_pos = client.state().terrain().pos_key(pos);
|
||||
let new_mesh_state = ChunkMeshState {
|
||||
pos: chunk_pos,
|
||||
started_tick: current_tick,
|
||||
active_worker: None,
|
||||
};
|
||||
// Only mesh if this chunk has all its neighbors
|
||||
// If it does have all its neighbors either it should have already been meshed or is in
|
||||
// mesh_todo
|
||||
match self.mesh_todo.entry(chunk_pos) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
entry.insert(new_mesh_state);
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
if self.chunks.contains_key(&chunk_pos) {
|
||||
entry.insert(new_mesh_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.mesh_todo.insert(
|
||||
chunk_pos,
|
||||
ChunkMeshState {
|
||||
pos: chunk_pos,
|
||||
started_tick: current_tick,
|
||||
active_worker: None,
|
||||
},
|
||||
);
|
||||
|
||||
// Handle chunks on chunk borders
|
||||
// Handle block changes on chunk borders
|
||||
for x in -1..2 {
|
||||
for y in -1..2 {
|
||||
let neighbour_pos = pos + Vec3::new(x, y, 0);
|
||||
let neighbour_chunk_pos = client.state().terrain().pos_key(neighbour_pos);
|
||||
|
||||
if neighbour_chunk_pos != chunk_pos {
|
||||
self.mesh_todo.insert(
|
||||
neighbour_chunk_pos,
|
||||
ChunkMeshState {
|
||||
pos: neighbour_chunk_pos,
|
||||
started_tick: current_tick,
|
||||
active_worker: None,
|
||||
},
|
||||
);
|
||||
let new_mesh_state = ChunkMeshState {
|
||||
pos: neighbour_chunk_pos,
|
||||
started_tick: current_tick,
|
||||
active_worker: None,
|
||||
};
|
||||
// Only mesh if this chunk has all its neighbors
|
||||
match self.mesh_todo.entry(neighbour_chunk_pos) {
|
||||
Entry::Occupied(mut entry) => {
|
||||
entry.insert(new_mesh_state);
|
||||
}
|
||||
Entry::Vacant(entry) => {
|
||||
if self.chunks.contains_key(&neighbour_chunk_pos) {
|
||||
entry.insert(new_mesh_state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remesh all neighbours because we have complex lighting now
|
||||
|
Loading…
Reference in New Issue
Block a user