1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

fix falling through blocks on spawn (and triggering anticheats)

This commit is contained in:
mat 2023-09-11 22:58:54 -05:00
parent bcefa64dd1
commit f8cca41361
9 changed files with 73 additions and 61 deletions

View file

@ -6,8 +6,8 @@ use crate::{
interact::{CurrentSequenceNumber, InteractPlugin}, interact::{CurrentSequenceNumber, InteractPlugin},
inventory::{InventoryComponent, InventoryPlugin}, inventory::{InventoryComponent, InventoryPlugin},
local_player::{ local_player::{
death_event, handle_send_packet_event, update_in_loaded_chunk, GameProfileComponent, death_event, handle_send_packet_event, GameProfileComponent, Hunger, LocalPlayer,
Hunger, LocalPlayer, SendPacketEvent, SendPacketEvent,
}, },
mining::{self, MinePlugin}, mining::{self, MinePlugin},
movement::{LastSentLookDirection, PhysicsState, PlayerMovePlugin}, movement::{LastSentLookDirection, PhysicsState, PlayerMovePlugin},
@ -617,7 +617,6 @@ impl Plugin for AzaleaPlugin {
.add_systems( .add_systems(
Update, Update,
( (
update_in_loaded_chunk,
// fire the Death event when the player dies. // fire the Death event when the player dies.
death_event, death_event,
// add GameProfileComponent when we get an AddPlayerEvent // add GameProfileComponent when we get an AddPlayerEvent

View file

@ -36,7 +36,7 @@ pub use client::{
TickBroadcast, TickBroadcast,
}; };
pub use events::Event; pub use events::Event;
pub use local_player::{GameProfileComponent, LocalPlayer, LocalPlayerInLoadedChunk}; pub use local_player::{GameProfileComponent, LocalPlayer};
pub use movement::{ pub use movement::{
PhysicsState, SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection, PhysicsState, SprintDirection, StartSprintEvent, StartWalkEvent, WalkDirection,
}; };

View file

@ -1,17 +1,13 @@
use std::{io, sync::Arc}; use std::{io, sync::Arc};
use azalea_auth::game_profile::GameProfile; use azalea_auth::game_profile::GameProfile;
use azalea_core::{ChunkPos, GameMode}; use azalea_core::GameMode;
use azalea_entity::{Dead, Position}; use azalea_entity::Dead;
use azalea_protocol::packets::game::ServerboundGamePacket; use azalea_protocol::packets::game::ServerboundGamePacket;
use azalea_world::{Instance, InstanceContainer, InstanceName, PartialInstance}; use azalea_world::{Instance, PartialInstance};
use bevy_ecs::{ use bevy_ecs::{
component::Component, component::Component, entity::Entity, event::EventReader, prelude::Event, query::Added,
entity::Entity, system::Query,
event::EventReader,
prelude::Event,
query::Added,
system::{Query, Res},
}; };
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use parking_lot::RwLock; use parking_lot::RwLock;
@ -59,11 +55,6 @@ pub struct LocalPlayer {
#[derive(Component, Clone, Debug, Deref, DerefMut)] #[derive(Component, Clone, Debug, Deref, DerefMut)]
pub struct GameProfileComponent(pub GameProfile); pub struct GameProfileComponent(pub GameProfile);
/// Marks a [`LocalPlayer`] that's in a loaded chunk. This is updated at the
/// beginning of every tick.
#[derive(Component, Clone, Debug, Copy)]
pub struct LocalPlayerInLoadedChunk;
/// The gamemode of a local player. For a non-local player, you can look up the /// The gamemode of a local player. For a non-local player, you can look up the
/// player in the [`TabList`]. /// player in the [`TabList`].
#[derive(Component, Clone, Debug, Copy)] #[derive(Component, Clone, Debug, Copy)]
@ -134,27 +125,6 @@ impl Drop for LocalPlayer {
} }
} }
/// Update the [`LocalPlayerInLoadedChunk`] component for all [`LocalPlayer`]s.
pub fn update_in_loaded_chunk(
mut commands: bevy_ecs::system::Commands,
query: Query<(Entity, &InstanceName, &Position)>,
instance_container: Res<InstanceContainer>,
) {
for (entity, local_player, position) in &query {
let player_chunk_pos = ChunkPos::from(position);
let Some(instance_lock) = instance_container.get(local_player) else {
continue;
};
let in_loaded_chunk = instance_lock.read().chunks.get(&player_chunk_pos).is_some();
if in_loaded_chunk {
commands.entity(entity).insert(LocalPlayerInLoadedChunk);
} else {
commands.entity(entity).remove::<LocalPlayerInLoadedChunk>();
}
}
}
/// Send the "Death" event for [`LocalPlayer`]s that died with no reason. /// Send the "Death" event for [`LocalPlayer`]s that died with no reason.
pub fn death_event(query: Query<&LocalPlayerEvents, Added<Dead>>) { pub fn death_event(query: Query<&LocalPlayerEvents, Added<Dead>>) {
for local_player_events in &query { for local_player_events in &query {

View file

@ -1,7 +1,7 @@
use crate::client::Client; use crate::client::Client;
use crate::local_player::{LocalPlayer, LocalPlayerInLoadedChunk}; use crate::local_player::LocalPlayer;
use azalea_entity::{metadata::Sprinting, Attributes, Jumping}; use azalea_entity::{metadata::Sprinting, Attributes, Jumping};
use azalea_entity::{LastSentPosition, LookDirection, Physics, Position}; use azalea_entity::{InLoadedChunk, LastSentPosition, LookDirection, Physics, Position};
use azalea_physics::PhysicsSet; use azalea_physics::PhysicsSet;
use azalea_protocol::packets::game::serverbound_player_command_packet::ServerboundPlayerCommandPacket; use azalea_protocol::packets::game::serverbound_player_command_packet::ServerboundPlayerCommandPacket;
use azalea_protocol::packets::game::{ use azalea_protocol::packets::game::{
@ -128,7 +128,7 @@ pub fn send_position(
&mut LastSentLookDirection, &mut LastSentLookDirection,
&Sprinting, &Sprinting,
), ),
&LocalPlayerInLoadedChunk, With<InLoadedChunk>,
>, >,
) { ) {
for ( for (
@ -302,7 +302,7 @@ pub fn local_player_ai_step(
&mut Sprinting, &mut Sprinting,
&mut Attributes, &mut Attributes,
), ),
With<LocalPlayerInLoadedChunk>, With<InLoadedChunk>,
>, >,
) { ) {
for (mut physics_state, mut physics, mut sprinting, mut attributes) in query.iter_mut() { for (mut physics_state, mut physics, mut sprinting, mut attributes) in query.iter_mut() {

View file

@ -709,14 +709,18 @@ pub fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::TeleportEntity(p) => { ClientboundGamePacket::TeleportEntity(p) => {
let mut system_state: SystemState<( let mut system_state: SystemState<(
Commands, Commands,
Query<(&EntityIdIndex, &LocalPlayer)>, Query<(&EntityIdIndex, &LocalPlayer, Option<&mut Physics>)>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut commands, mut query) = system_state.get_mut(ecs); let (mut commands, mut query) = system_state.get_mut(ecs);
let (entity_id_index, local_player) = query.get_mut(player_entity).unwrap(); let (entity_id_index, local_player, physics) =
query.get_mut(player_entity).unwrap();
let entity = entity_id_index.get(&MinecraftEntityId(p.id)); let entity = entity_id_index.get(&MinecraftEntityId(p.id));
if let Some(entity) = entity { if let Some(entity) = entity {
if let Some(mut physics) = physics {
physics.on_ground = p.on_ground;
}
let new_position = p.position; let new_position = p.position;
commands.entity(entity).add(RelativeEntityUpdate { commands.entity(entity).add(RelativeEntityUpdate {
partial_world: local_player.partial_instance.clone(), partial_world: local_player.partial_instance.clone(),
@ -740,14 +744,18 @@ pub fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::MoveEntityPos(p) => { ClientboundGamePacket::MoveEntityPos(p) => {
let mut system_state: SystemState<( let mut system_state: SystemState<(
Commands, Commands,
Query<(&EntityIdIndex, &LocalPlayer)>, Query<(&EntityIdIndex, &LocalPlayer, Option<&mut Physics>)>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut commands, mut query) = system_state.get_mut(ecs); let (mut commands, mut query) = system_state.get_mut(ecs);
let (entity_id_index, local_player) = query.get_mut(player_entity).unwrap(); let (entity_id_index, local_player, physics) =
query.get_mut(player_entity).unwrap();
let entity = entity_id_index.get(&MinecraftEntityId(p.entity_id)); let entity = entity_id_index.get(&MinecraftEntityId(p.entity_id));
if let Some(entity) = entity { if let Some(entity) = entity {
if let Some(mut physics) = physics {
physics.on_ground = p.on_ground;
}
let delta = p.delta.clone(); let delta = p.delta.clone();
commands.entity(entity).add(RelativeEntityUpdate { commands.entity(entity).add(RelativeEntityUpdate {
partial_world: local_player.partial_instance.clone(), partial_world: local_player.partial_instance.clone(),
@ -768,14 +776,18 @@ pub fn process_packet_events(ecs: &mut World) {
ClientboundGamePacket::MoveEntityPosRot(p) => { ClientboundGamePacket::MoveEntityPosRot(p) => {
let mut system_state: SystemState<( let mut system_state: SystemState<(
Commands, Commands,
Query<(&EntityIdIndex, &LocalPlayer)>, Query<(&EntityIdIndex, &LocalPlayer, Option<&mut Physics>)>,
)> = SystemState::new(ecs); )> = SystemState::new(ecs);
let (mut commands, mut query) = system_state.get_mut(ecs); let (mut commands, mut query) = system_state.get_mut(ecs);
let (entity_id_index, local_player) = query.get_mut(player_entity).unwrap(); let (entity_id_index, local_player, physics) =
query.get_mut(player_entity).unwrap();
let entity = entity_id_index.get(&MinecraftEntityId(p.entity_id)); let entity = entity_id_index.get(&MinecraftEntityId(p.entity_id));
if let Some(entity) = entity { if let Some(entity) = entity {
if let Some(mut physics) = physics {
physics.on_ground = p.on_ground;
}
let delta = p.delta.clone(); let delta = p.delta.clone();
commands.entity(entity).add(RelativeEntityUpdate { commands.entity(entity).add(RelativeEntityUpdate {
partial_world: local_player.partial_instance.clone(), partial_world: local_player.partial_instance.clone(),

View file

@ -3,9 +3,9 @@ mod relative_updates;
use std::collections::HashSet; use std::collections::HashSet;
use azalea_core::{BlockPos, Vec3}; use azalea_core::{BlockPos, ChunkPos, Vec3};
use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId}; use azalea_world::{InstanceContainer, InstanceName, MinecraftEntityId};
use bevy_app::{App, Plugin, PostUpdate, PreUpdate, Update}; use bevy_app::{App, FixedUpdate, Plugin, PostUpdate, PreUpdate, Update};
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use log::debug; use log::debug;
@ -68,6 +68,7 @@ impl Plugin for EntityPlugin {
), ),
) )
.add_systems(Update, update_bounding_box) .add_systems(Update, update_bounding_box)
.add_systems(FixedUpdate, update_in_loaded_chunk)
.init_resource::<EntityUuidIndex>(); .init_resource::<EntityUuidIndex>();
} }
} }
@ -144,3 +145,29 @@ pub fn update_bounding_box(mut query: Query<(&Position, &mut Physics), Changed<P
physics.bounding_box = bounding_box; physics.bounding_box = bounding_box;
} }
} }
/// Marks an entity that's in a loaded chunk. This is updated at the beginning
/// of every tick.
#[derive(Component, Clone, Debug, Copy)]
pub struct InLoadedChunk;
/// Update the [`InLoadedChunk`] component for all entities in the world.
pub fn update_in_loaded_chunk(
mut commands: bevy_ecs::system::Commands,
query: Query<(Entity, &InstanceName, &Position)>,
instance_container: Res<InstanceContainer>,
) {
for (entity, instance_name, position) in &query {
let player_chunk_pos = ChunkPos::from(position);
let Some(instance_lock) = instance_container.get(instance_name) else {
continue;
};
let in_loaded_chunk = instance_lock.read().chunks.get(&player_chunk_pos).is_some();
if in_loaded_chunk {
commands.entity(entity).insert(InLoadedChunk);
} else {
commands.entity(entity).remove::<InLoadedChunk>();
}
}
}

View file

@ -71,7 +71,9 @@ impl<'a> Iterator for BlockCollisions<'a> {
} }
let chunk = self.get_chunk(item.pos.x, item.pos.z); let chunk = self.get_chunk(item.pos.x, item.pos.z);
let Some(chunk) = chunk else { continue }; let Some(chunk) = chunk else {
continue;
};
let pos = item.pos; let pos = item.pos;
let block_state: BlockState = chunk let block_state: BlockState = chunk

View file

@ -7,8 +7,8 @@ pub mod collision;
use azalea_block::{Block, BlockState}; use azalea_block::{Block, BlockState};
use azalea_core::{math, BlockPos, Vec3}; use azalea_core::{math, BlockPos, Vec3};
use azalea_entity::{ use azalea_entity::{
metadata::Sprinting, move_relative, Attributes, Jumping, Local, LookDirection, Physics, metadata::Sprinting, move_relative, Attributes, InLoadedChunk, Jumping, Local, LookDirection,
Position, Physics, Position,
}; };
use azalea_world::{Instance, InstanceContainer, InstanceName}; use azalea_world::{Instance, InstanceContainer, InstanceName};
use bevy_app::{App, FixedUpdate, Plugin}; use bevy_app::{App, FixedUpdate, Plugin};
@ -26,7 +26,13 @@ pub struct PhysicsSet;
pub struct PhysicsPlugin; pub struct PhysicsPlugin;
impl Plugin for PhysicsPlugin { impl Plugin for PhysicsPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(FixedUpdate, (ai_step, travel).chain().in_set(PhysicsSet)); app.add_systems(
FixedUpdate,
(ai_step, travel)
.chain()
.in_set(PhysicsSet)
.after(azalea_entity::update_in_loaded_chunk),
);
} }
} }
@ -43,7 +49,7 @@ fn travel(
&Attributes, &Attributes,
&InstanceName, &InstanceName,
), ),
With<Local>, (With<Local>, With<InLoadedChunk>),
>, >,
instance_container: Res<InstanceContainer>, instance_container: Res<InstanceContainer>,
) { ) {
@ -126,10 +132,7 @@ pub fn ai_step(
&Sprinting, &Sprinting,
&InstanceName, &InstanceName,
), ),
With<Local>, (With<Local>, With<InLoadedChunk>),
// TODO: ai_step should only run for players in loaded chunks
// With<LocalPlayerInLoadedChunk> maybe there should be an InLoadedChunk/InUnloadedChunk
// component?
>, >,
instance_container: Res<InstanceContainer>, instance_container: Res<InstanceContainer>,
) { ) {

View file

@ -84,7 +84,6 @@ impl Simulation {
MinecraftEntityId(0), MinecraftEntityId(0),
InstanceName(instance_name), InstanceName(instance_name),
azalea_entity::Local, azalea_entity::Local,
azalea_client::LocalPlayerInLoadedChunk,
azalea_entity::Jumping::default(), azalea_entity::Jumping::default(),
azalea_entity::LookDirection::default(), azalea_entity::LookDirection::default(),
Sprinting(true), Sprinting(true),