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:
parent
bcefa64dd1
commit
f8cca41361
9 changed files with 73 additions and 61 deletions
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Add table
Reference in a new issue