mirror of
https://github.com/griffi-gh/kubi.git
synced 2024-11-24 07:48:42 -06:00
player position sync, refactor some stuff
This commit is contained in:
parent
73940d61ff
commit
75c6d127b7
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -954,6 +954,7 @@ dependencies = [
|
|||
"rayon",
|
||||
"serde_json",
|
||||
"shipyard",
|
||||
"static_assertions",
|
||||
"strum",
|
||||
"uflow",
|
||||
"winapi",
|
||||
|
|
|
@ -12,6 +12,9 @@ opt-level = 1
|
|||
[profile.dev.package."*"]
|
||||
opt-level = 1
|
||||
|
||||
[profile.dev.package.uflow]
|
||||
opt-level = 3
|
||||
|
||||
[profile.dev.package.glium]
|
||||
opt-level = 3
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ publish = false
|
|||
kubi-shared = { path = "../kubi-shared" }
|
||||
kubi-logging = { path = "../kubi-logging" }
|
||||
log = "*"
|
||||
shipyard = { git = "https://github.com/leudz/shipyard", rev = "a4f4d27edcf", features = ["thread_local"] }
|
||||
shipyard = { git = "https://github.com/leudz/shipyard", rev = "a4f4d27edcf", default-features = false, features = ["std", "proc", "thread_local"] }
|
||||
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
|
||||
toml = "0.7"
|
||||
glam = { version = "0.23", features = ["debug-glam-assert", "fast-math"] }
|
||||
|
@ -23,6 +23,7 @@ postcard = { version = "1.0", features = ["alloc"] }
|
|||
lz4_flex = { version = "0.10", default-features = false, features = ["std", "checked-decode"] }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["parallel"]
|
||||
parallel = ["shipyard/parallel"]
|
||||
safe_lz4 = ["lz4_flex/safe-encode", "lz4_flex/safe-decode"]
|
||||
nightly = ["hashbrown/nightly", "rand/nightly", "rand/simd_support", "glam/core-simd", "kubi-shared/nightly"]
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
use glam::Mat4;
|
||||
use shipyard::{Component, EntityId, Unique, AllStoragesView, UniqueView, NonSendSync, View, ViewMut, Get};
|
||||
use shipyard::{Component, EntityId, Unique, AllStoragesView, UniqueView, NonSendSync, View, ViewMut, Get, IntoIter};
|
||||
use hashbrown::HashMap;
|
||||
use uflow::SendMode;
|
||||
use std::net::SocketAddr;
|
||||
use kubi_shared::{
|
||||
networking::{
|
||||
client::{ClientIdMap, Client},
|
||||
messages::{ClientToServerMessage, C_POSITION_CHANGED}
|
||||
messages::{ClientToServerMessage, ServerToClientMessage, C_POSITION_CHANGED},
|
||||
channels::CHANNEL_MOVE
|
||||
},
|
||||
transform::Transform
|
||||
};
|
||||
|
@ -35,7 +37,8 @@ pub fn sync_client_positions(
|
|||
events: UniqueView<ServerEvents>,
|
||||
addr_map: UniqueView<ClientAddressMap>,
|
||||
clients: View<Client>,
|
||||
mut transforms: ViewMut<Transform>
|
||||
mut transforms: ViewMut<Transform>,
|
||||
addrs: View<ClientAddress>,
|
||||
) {
|
||||
for event in &events.0 {
|
||||
let Some(message) = check_message_auth::<C_POSITION_CHANGED>(&server, event, &clients, &addr_map) else {
|
||||
|
@ -44,9 +47,34 @@ pub fn sync_client_positions(
|
|||
let ClientToServerMessage::PositionChanged { position, velocity: _, direction } = message.message else {
|
||||
unreachable!()
|
||||
};
|
||||
//Apply position to client
|
||||
|
||||
//log movement (annoying duh)
|
||||
log::debug!("dbg: player moved id: {} coords: {} quat: {}", message.client_id, position, direction);
|
||||
|
||||
//Apply position to server-side client
|
||||
let mut trans = (&mut transforms).get(message.entity_id).unwrap();
|
||||
trans.0 = Mat4::from_rotation_translation(direction, position);
|
||||
|
||||
//Transmit the change to other players
|
||||
for (other_client, other_client_address) in (&clients, &addrs).iter() {
|
||||
if other_client.0 == message.client_id {
|
||||
continue
|
||||
}
|
||||
let Some(client) = server.0.client(&other_client_address.0) else {
|
||||
log::error!("Client with address not found");
|
||||
continue
|
||||
};
|
||||
client.borrow_mut().send(
|
||||
postcard::to_allocvec(
|
||||
&ServerToClientMessage::PlayerPositionChanged {
|
||||
client_id: message.client_id,
|
||||
position,
|
||||
direction
|
||||
}
|
||||
).unwrap().into_boxed_slice(),
|
||||
CHANNEL_MOVE,
|
||||
SendMode::Reliable
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ mod auth;
|
|||
|
||||
use config::read_config;
|
||||
use server::{bind_server, update_server, log_server_errors};
|
||||
use client::init_client_maps;
|
||||
use client::{init_client_maps, sync_client_positions};
|
||||
use auth::authenticate_players;
|
||||
use world::{update_world, init_world};
|
||||
|
||||
|
@ -30,6 +30,7 @@ fn update() -> Workload {
|
|||
log_server_errors,
|
||||
authenticate_players,
|
||||
update_world,
|
||||
sync_client_positions,
|
||||
).into_workload()
|
||||
).into_sequential_workload()
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ pub fn bind_server(
|
|||
endpoint_config: EndpointConfig {
|
||||
active_timeout_ms: config.server.timeout_ms,
|
||||
keepalive: true,
|
||||
keepalive_interval_ms: 1000,
|
||||
keepalive_interval_ms: 300,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
|
|
@ -23,6 +23,7 @@ uflow = "0.7"
|
|||
postcard = { version = "1.0", features = ["alloc"] }
|
||||
serde_json = { version = "1.0", optional = true }
|
||||
lz4_flex = { version = "0.10", default-features = false, features = ["std", "checked-decode"] }
|
||||
static_assertions = "1.1"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3" }
|
||||
|
@ -32,4 +33,4 @@ default = []
|
|||
generate_visualizer_data = ["serde_json", "shipyard/serde1"]
|
||||
safe_lz4 = ["lz4_flex/safe-encode", "lz4_flex/safe-decode"]
|
||||
parallel = ["shipyard/parallel"]
|
||||
nightly = ["hashbrown/nightly", "glam/core-simd", "kubi-shared/nightly"]
|
||||
nightly = ["hashbrown/nightly", "glam/core-simd", "static_assertions/nightly", "kubi-shared/nightly"]
|
||||
|
|
|
@ -6,5 +6,7 @@ out vec4 out_color;
|
|||
uniform vec4 color;
|
||||
|
||||
void main() {
|
||||
// discard fully transparent pixels
|
||||
if (color.w <= 0.) discard;
|
||||
out_color = color;
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
|
||||
out vec4 color;
|
||||
uniform vec4 u_color;
|
||||
|
||||
void main() {
|
||||
color = u_color;
|
||||
// color -= vec4(0, 0, 0, 0.1 * sin(gl_FragCoord.x) * cos(gl_FragCoord.y));
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
#version 300 es
|
||||
|
||||
precision highp float;
|
||||
|
||||
in vec3 position;
|
||||
uniform ivec3 u_position;
|
||||
uniform mat4 perspective;
|
||||
uniform mat4 view;
|
||||
|
||||
void main() {
|
||||
gl_Position = perspective * view * vec4(position + vec3(u_position), 1.);
|
||||
}
|
|
@ -19,20 +19,8 @@ uniform sampler2DArray tex;
|
|||
void main() {
|
||||
// base color from texture
|
||||
color = texture(tex, vec3(v_uv, v_tex_index));
|
||||
// HACKY texture "antialiasing"
|
||||
// color += (
|
||||
// alpha_drop(color, texture(tex, vec3(v_uv + vec2(.000, .001), v_tex_index))) +
|
||||
// alpha_drop(color, texture(tex, vec3(v_uv + vec2(.001, .000), v_tex_index))) +
|
||||
// alpha_drop(color, texture(tex, vec3(v_uv + vec2(.001, .001), v_tex_index))) +
|
||||
// alpha_drop(color, texture(tex, vec3(v_uv - vec2(.000, .001), v_tex_index))) +
|
||||
// alpha_drop(color, texture(tex, vec3(v_uv - vec2(.001, .000), v_tex_index))) +
|
||||
// alpha_drop(color, texture(tex, vec3(v_uv - vec2(.001, .001), v_tex_index)))
|
||||
// ) / 6.;
|
||||
// color /= 2.;
|
||||
// discard fully transparent pixels
|
||||
if (color.w <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
if (color.w <= 0.0) discard;
|
||||
//basic "lighting"
|
||||
float light = abs(v_normal.x) + .8 * abs(v_normal.y) + .6 * abs(v_normal.z);
|
||||
color *= vec4(vec3(light), 1.);
|
||||
|
|
|
@ -63,7 +63,7 @@ fn block_placement_system(
|
|||
(ray.block_position, Block::Air)
|
||||
};
|
||||
//queue place
|
||||
block_event_queue.push(QueuedBlock {
|
||||
block_event_queue.0.push(QueuedBlock {
|
||||
position: place_position,
|
||||
block_type: place_block,
|
||||
soft: place_block != Block::Air,
|
||||
|
|
|
@ -69,9 +69,9 @@ use rendering::{
|
|||
init_window_size,
|
||||
update_window_size,
|
||||
primitives::init_primitives,
|
||||
world::{draw_world, draw_current_chunk_border},
|
||||
selection_box::render_selection_box,
|
||||
world::draw_world,
|
||||
world::draw_current_chunk_border,
|
||||
entities::render_entities,
|
||||
};
|
||||
use block_placement::update_block_placement;
|
||||
use delta_time::{DeltaTime, init_delta_time};
|
||||
|
@ -107,6 +107,7 @@ fn startup() -> Workload {
|
|||
init_delta_time,
|
||||
).into_sequential_workload()
|
||||
}
|
||||
|
||||
fn update() -> Workload {
|
||||
(
|
||||
update_window_size,
|
||||
|
@ -143,6 +144,7 @@ fn update() -> Workload {
|
|||
disconnect_on_exit.run_if(is_multiplayer),
|
||||
).into_sequential_workload()
|
||||
}
|
||||
|
||||
fn render() -> Workload {
|
||||
(
|
||||
clear_background,
|
||||
|
@ -150,10 +152,12 @@ fn render() -> Workload {
|
|||
draw_world,
|
||||
draw_current_chunk_border,
|
||||
render_selection_box,
|
||||
render_entities,
|
||||
).into_sequential_workload().run_if(is_ingame),
|
||||
render_gui,
|
||||
).into_sequential_workload()
|
||||
}
|
||||
|
||||
fn after_frame_end() -> Workload {
|
||||
(
|
||||
clear_events,
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use shipyard::{Unique, AllStoragesView, UniqueView, UniqueViewMut, Workload, IntoWorkload, EntitiesViewMut, Component, ViewMut, SystemModificator, View, IntoIter, WorkloadModificator};
|
||||
use glium::glutin::event_loop::ControlFlow;
|
||||
use std::net::SocketAddr;
|
||||
use uflow::{client::{Client, Config as ClientConfig, Event as ClientEvent}, EndpointConfig};
|
||||
use uflow::{
|
||||
client::{Client, Config as ClientConfig, Event as ClientEvent},
|
||||
EndpointConfig
|
||||
};
|
||||
use kubi_shared::networking::{
|
||||
messages::ServerToClientMessage,
|
||||
state::ClientJoinState,
|
||||
|
@ -71,7 +74,7 @@ fn connect_client(
|
|||
endpoint_config: EndpointConfig {
|
||||
active_timeout_ms: 10000,
|
||||
keepalive: true,
|
||||
keepalive_interval_ms: 1000,
|
||||
keepalive_interval_ms: 300,
|
||||
..Default::default()
|
||||
},
|
||||
}).expect("Client connection failed");
|
||||
|
@ -128,8 +131,8 @@ pub fn update_networking() -> Workload {
|
|||
).into_sequential_workload().run_if(is_join_state::<{ClientJoinState::Connected as u8}>),
|
||||
(
|
||||
(
|
||||
receive_player_connect_events
|
||||
),
|
||||
receive_player_connect_events,
|
||||
).into_workload(),
|
||||
(
|
||||
recv_block_place_events,
|
||||
receive_player_movement_events,
|
||||
|
|
|
@ -4,7 +4,7 @@ use uflow::{SendMode, client::Event as ClientEvent};
|
|||
use kubi_shared::{
|
||||
transform::Transform,
|
||||
networking::{
|
||||
messages::{ClientToServerMessage, ServerToClientMessage, S_PLAYER_POSITION_CHANGED},
|
||||
messages::{ClientToServerMessage, ServerToClientMessage, S_PLAYER_POSITION_CHANGED, S_PLAYER_CONNECTED},
|
||||
channels::CHANNEL_MOVE,
|
||||
client::ClientIdMap,
|
||||
},
|
||||
|
@ -83,7 +83,7 @@ pub fn receive_player_connect_events(
|
|||
let ClientEvent::Receive(data) = &event.0 else {
|
||||
return None
|
||||
};
|
||||
if !event.is_message_of_type::<S_PLAYER_POSITION_CHANGED>() {
|
||||
if !event.is_message_of_type::<S_PLAYER_CONNECTED>() {
|
||||
return None
|
||||
};
|
||||
let Ok(parsed_message) = postcard::from_bytes(data) else {
|
||||
|
|
|
@ -86,6 +86,6 @@ pub fn recv_block_place_events(
|
|||
let ServerToClientMessage::QueueBlock { item } = parsed_message else {
|
||||
unreachable!()
|
||||
};
|
||||
queue.push(item);
|
||||
queue.0.push(item);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,18 +37,19 @@ impl AssetPaths for BlockTexture {
|
|||
}
|
||||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
pub struct BlockTexturesPrefab(pub SrgbTexture2dArray);
|
||||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
pub struct ChunkShaderPrefab(pub Program);
|
||||
|
||||
#[derive(Unique)]
|
||||
pub struct SelBoxShaderPrefab(pub Program);
|
||||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
pub struct ColoredShaderPrefab(pub Program);
|
||||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
pub struct ProgressbarShaderPrefab(pub Program);
|
||||
|
||||
pub fn load_prefabs(
|
||||
|
@ -73,14 +74,6 @@ pub fn load_prefabs(
|
|||
&renderer.display
|
||||
)
|
||||
));
|
||||
storages.add_unique_non_send_sync(SelBoxShaderPrefab(
|
||||
include_shader_prefab!(
|
||||
"selection_box",
|
||||
"../shaders/selection_box.vert",
|
||||
"../shaders/selection_box.frag",
|
||||
&renderer.display
|
||||
)
|
||||
));
|
||||
storages.add_unique_non_send_sync(ColoredShaderPrefab(
|
||||
include_shader_prefab!(
|
||||
"colored",
|
||||
|
|
|
@ -14,14 +14,18 @@ use crate::{events::WindowResizedEvent, settings::{GameSettings, FullscreenMode}
|
|||
pub mod primitives;
|
||||
pub mod world;
|
||||
pub mod selection_box;
|
||||
pub mod entities;
|
||||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
pub struct RenderTarget(pub glium::Frame);
|
||||
|
||||
#[derive(Unique)]
|
||||
#[repr(transparent)]
|
||||
pub struct BackgroundColor(pub Vec3);
|
||||
|
||||
#[derive(Unique, Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct WindowSize(pub UVec2);
|
||||
|
||||
#[derive(Unique)]
|
||||
|
@ -32,7 +36,6 @@ impl Renderer {
|
|||
pub fn init(event_loop: &EventLoop<()>, settings: &GameSettings) -> Self {
|
||||
log::info!("initializing display");
|
||||
|
||||
|
||||
let wb = WindowBuilder::new()
|
||||
.with_title("kubi")
|
||||
.with_maximized(true)
|
||||
|
|
59
kubi/src/rendering/entities.rs
Normal file
59
kubi/src/rendering/entities.rs
Normal file
|
@ -0,0 +1,59 @@
|
|||
use shipyard::{NonSendSync, UniqueViewMut, UniqueView, View, IntoIter, IntoWithId};
|
||||
use glium::{DepthTest, Depth, PolygonMode, BackfaceCullingMode, DrawParameters, Surface, uniform};
|
||||
use kubi_shared::{entity::Entity, transform::Transform};
|
||||
use crate::{
|
||||
prefabs::ColoredShaderPrefab,
|
||||
camera::Camera,
|
||||
settings::GameSettings,
|
||||
player::MainPlayer
|
||||
};
|
||||
use super::{
|
||||
RenderTarget,
|
||||
primitives::cube::CubePrimitive
|
||||
};
|
||||
|
||||
// TODO: entity models
|
||||
pub fn render_entities(
|
||||
mut target: NonSendSync<UniqueViewMut<RenderTarget>>,
|
||||
buffers: NonSendSync<UniqueView<CubePrimitive>>,
|
||||
program: NonSendSync<UniqueView<ColoredShaderPrefab>>,
|
||||
camera: View<Camera>,
|
||||
settings: UniqueView<GameSettings>,
|
||||
entities: View<Entity>,
|
||||
transform: View<Transform>,
|
||||
) {
|
||||
let (camera_id, camera) = camera.iter().with_id().next().expect("No cameras in the scene");
|
||||
|
||||
let draw_parameters = DrawParameters {
|
||||
depth: Depth {
|
||||
test: DepthTest::IfLess,
|
||||
write: true,
|
||||
..Default::default()
|
||||
},
|
||||
multisampling: settings.msaa.is_some(),
|
||||
polygon_mode: PolygonMode::Fill,
|
||||
backface_culling: BackfaceCullingMode::CullClockwise,
|
||||
..Default::default()
|
||||
};
|
||||
let view = camera.view_matrix.to_cols_array_2d();
|
||||
let perspective = camera.perspective_matrix.to_cols_array_2d();
|
||||
|
||||
for (entity_id, (_, trans)) in (&entities, &transform).iter().with_id() {
|
||||
//skip rendering camera holder (as the entity would block the view)
|
||||
if entity_id == camera_id { continue }
|
||||
|
||||
//render entity
|
||||
target.0.draw(
|
||||
&buffers.0,
|
||||
&buffers.1,
|
||||
&program.0,
|
||||
&uniform! {
|
||||
color: [1.0, 1.0, 1.0, 1.0_f32],
|
||||
model: trans.0.to_cols_array_2d(),
|
||||
view: view,
|
||||
perspective: perspective,
|
||||
},
|
||||
&draw_parameters
|
||||
).unwrap();
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
use glam::{Mat4, Vec3, Quat};
|
||||
use shipyard::{View, IntoIter, NonSendSync, UniqueViewMut, UniqueView};
|
||||
use glium::{
|
||||
Surface,
|
||||
|
@ -8,18 +9,21 @@ use glium::{
|
|||
};
|
||||
use crate::{
|
||||
world::raycast::LookingAtBlock,
|
||||
camera::Camera, prefabs::SelBoxShaderPrefab
|
||||
camera::Camera,
|
||||
prefabs::ColoredShaderPrefab
|
||||
};
|
||||
use super::{
|
||||
RenderTarget,
|
||||
primitives::cube::CubePrimitive,
|
||||
};
|
||||
|
||||
const SMOL: f32 = 0.0001;
|
||||
|
||||
pub fn render_selection_box(
|
||||
lookat: View<LookingAtBlock>,
|
||||
camera: View<Camera>,
|
||||
mut target: NonSendSync<UniqueViewMut<RenderTarget>>,
|
||||
program: NonSendSync<UniqueView<SelBoxShaderPrefab>>,
|
||||
program: NonSendSync<UniqueView<ColoredShaderPrefab>>,
|
||||
buffers: NonSendSync<UniqueView<CubePrimitive>>,
|
||||
) {
|
||||
let camera = camera.iter().next().unwrap();
|
||||
|
@ -32,8 +36,12 @@ pub fn render_selection_box(
|
|||
&buffers.1,
|
||||
&program.0,
|
||||
&uniform! {
|
||||
u_color: [0., 0., 0., 0.5_f32],
|
||||
u_position: lookat.block_position.to_array(),
|
||||
color: [0., 0., 0., 0.5_f32],
|
||||
model: Mat4::from_scale_rotation_translation(
|
||||
Vec3::splat(1. + SMOL * 2.),
|
||||
Quat::default(),
|
||||
lookat.block_position.as_vec3() - Vec3::splat(SMOL)
|
||||
).to_cols_array_2d(),
|
||||
perspective: camera.perspective_matrix.to_cols_array_2d(),
|
||||
view: camera.view_matrix.to_cols_array_2d(),
|
||||
},
|
||||
|
@ -41,7 +49,8 @@ pub fn render_selection_box(
|
|||
backface_culling: BackfaceCullingMode::CullClockwise,
|
||||
blend: Blend::alpha_blending(),
|
||||
depth: Depth {
|
||||
test: DepthTest::IfLessOrEqual, //this may be unreliable!
|
||||
//this may be unreliable... unless scale is applied! hacky...
|
||||
test: DepthTest::IfLessOrEqual,
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
|
|
|
@ -191,7 +191,7 @@ fn process_completed_tasks(
|
|||
let mut ops: usize = 0;
|
||||
while let Some(res) = task_manager.receive() {
|
||||
match res {
|
||||
ChunkTaskResponse::LoadedChunk { position, chunk_data, queued } => {
|
||||
ChunkTaskResponse::LoadedChunk { position, chunk_data, mut queued } => {
|
||||
//check if chunk exists
|
||||
let Some(chunk) = world.chunks.get_mut(&position) else {
|
||||
log::warn!("blocks data discarded: chunk doesn't exist");
|
||||
|
@ -213,10 +213,8 @@ fn process_completed_tasks(
|
|||
chunk.current_state = CurrentChunkState::Loaded;
|
||||
|
||||
//push queued blocks
|
||||
//TODO use extend
|
||||
for item in queued {
|
||||
queue.push(item);
|
||||
}
|
||||
queue.0.append(&mut queued);
|
||||
drop(queued); //`queued` is empty after `append`
|
||||
|
||||
//increase ops counter
|
||||
ops += 1;
|
||||
|
|
|
@ -4,16 +4,12 @@ use shipyard::{UniqueViewMut, Unique};
|
|||
use super::ChunkStorage;
|
||||
|
||||
#[derive(Unique, Default, Clone)]
|
||||
pub struct BlockUpdateQueue {
|
||||
queue: Vec<QueuedBlock>
|
||||
}
|
||||
#[repr(transparent)]
|
||||
pub struct BlockUpdateQueue(pub Vec<QueuedBlock>);
|
||||
impl BlockUpdateQueue {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
pub fn push(&mut self, event: QueuedBlock) {
|
||||
self.queue.push(event)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_queued_blocks(
|
||||
|
@ -21,7 +17,7 @@ pub fn apply_queued_blocks(
|
|||
mut world: UniqueViewMut<ChunkStorage>
|
||||
) {
|
||||
//maybe i need to check for desired/current state here before marking as dirty?
|
||||
queue.queue.retain(|&event| {
|
||||
queue.0.retain(|&event| {
|
||||
if let Some(block) = world.get_block_mut(event.position) {
|
||||
if event.soft && *block != Block::Air {
|
||||
return false
|
||||
|
|
Loading…
Reference in a new issue