diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2022-08-29 20:41:01 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-29 20:41:01 -0500 |
| commit | f42d630544165d11a544224ac273d6aaf89d8095 (patch) | |
| tree | 94bd73771ecb582d89a87cdca8e21b2d6573ef12 /azalea-client/src/client.rs | |
| parent | 2ea804401f54a45765860201d10d0569d07862ec (diff) | |
| download | azalea-drasl-f42d630544165d11a544224ac273d6aaf89d8095.tar.xz | |
Physics (#11)
* Put physics module in azalea-entity
* port aabb
* add more stuff to PositionXYZ
* azalea-physics
* important collision things
* more physics stuff
* backup because i'm about to delete shapes
* more shape stuff
* CubeVoxelShape
* no compile errors???
insane
* impl VoxelShape for ArrayVoxelShape
* Shapes stuff
* collide_x but it doesn't work yet
* binary_search
* it compiles
* Entity has bounding box
* Update discrete_voxel_shape.rs
* Entity::make_bounding_box
* ok i'm about to merge az-entity and az-world
might be a terrible idea which is why i'm committing first
* ok so i moved entity to world
* on_pos and move_entity compiles
* add send_position
* move collision stuff to collision module in az-physics
* dimension is no longer an Option
* start trying to do collision for the client
* collision works :tada:
* start adding palette resizing
* get_and_set (pain)
* it compiles but probably won't work
* add a test
* remove printlns
* add more tests for palette stuff
* ClientboundMoveVec3Packet -> ClientboundMoveEntityPosPacket
i think i changed this on accident once
* palette resizing works
todo: remove the printlns
* Remove printlns in palette.rs
* fix issues from merge
* fixes + work a bit more on physics
* Better entities (#19)
* well it compiles
* add tests to entity storage
* add suggestions in azalea-brigadier
* this probably causes ub
* fix brigadiersuggestions
* get rid of entityid
* test From<EntityMut> for EntityRef
* don't mention other libraries since there's too many
* fix warnings
* do todos in brigadier suggestions
* work on physics
* more physics stuff
* remove trait feature on az-block
i think rust gets confused and compiles the macro without the feature
* bump ahash
* aes tests in az-crypto
* optimize aes's deps
* fix crashes
* fix section_index for negative numbers and test
* fix BlockPos protocol implementation
* remove some debug prints
* prepare to add ai_step
* make ai step work
* clippy
Diffstat (limited to 'azalea-client/src/client.rs')
| -rw-r--r-- | azalea-client/src/client.rs | 213 |
1 files changed, 142 insertions, 71 deletions
diff --git a/azalea-client/src/client.rs b/azalea-client/src/client.rs index fcb624b4..c495bc5c 100644 --- a/azalea-client/src/client.rs +++ b/azalea-client/src/client.rs @@ -1,7 +1,7 @@ use crate::{Account, Player}; use azalea_auth::game_profile::GameProfile; -use azalea_core::{ChunkPos, EntityPos, PositionDelta, PositionDeltaTrait, ResourceLocation}; -use azalea_entity::Entity; +use azalea_block::BlockState; +use azalea_core::{ChunkPos, ResourceLocation, Vec3}; use azalea_protocol::{ connect::{Connection, ConnectionError}, packets::{ @@ -11,7 +11,7 @@ use azalea_protocol::{ serverbound_accept_teleportation_packet::ServerboundAcceptTeleportationPacket, serverbound_custom_payload_packet::ServerboundCustomPayloadPacket, serverbound_keep_alive_packet::ServerboundKeepAlivePacket, - serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPacketPosRot, + serverbound_move_player_pos_rot_packet::ServerboundMovePlayerPosRotPacket, ClientboundGamePacket, ServerboundGamePacket, }, handshake::client_intention_packet::ClientIntentionPacket, @@ -25,6 +25,7 @@ use azalea_protocol::{ read::ReadPacketError, resolver, ServerAddress, }; +use azalea_world::entity::EntityData; use azalea_world::Dimension; use std::{ fmt::Debug, @@ -66,8 +67,10 @@ pub struct Client { game_profile: GameProfile, pub conn: Arc<tokio::sync::Mutex<Connection<ClientboundGamePacket, ServerboundGamePacket>>>, pub player: Arc<Mutex<Player>>, - pub dimension: Arc<Mutex<Option<Dimension>>>, - // game_loop + pub dimension: Arc<Mutex<Dimension>>, + + /// Minecraft only sends a movement packet either after 20 ticks or if the player moved enough. This is that tick counter. + pub position_remainder: u32, } /// Whether we should ignore errors when decoding packets. @@ -181,7 +184,9 @@ impl Client { game_profile, conn, player: Arc::new(Mutex::new(Player::default())), - dimension: Arc::new(Mutex::new(None)), + dimension: Arc::new(Mutex::new(Dimension::default())), + + position_remainder: 0, }; // just start up the game loop and we're ready! @@ -298,16 +303,10 @@ impl Client { let mut dimension_lock = client.dimension.lock().unwrap(); // the 16 here is our render distance // i'll make this an actual setting later - *dimension_lock = Some(Dimension::new(16, height, min_y)); + *dimension_lock = Dimension::new(16, height, min_y); - let entity = - Entity::new(p.player_id, client.game_profile.uuid, EntityPos::default()); - dimension_lock - .as_mut() - .expect( - "Dimension doesn't exist! We should've gotten a login packet by now.", - ) - .add_entity(entity); + let entity = EntityData::new(client.game_profile.uuid, Vec3::default()); + dimension_lock.add_entity(p.player_id, entity); let mut player_lock = client.player.lock().unwrap(); @@ -368,42 +367,42 @@ impl Client { println!("Got player position packet {:?}", p); let (new_pos, y_rot, x_rot) = { - let player_lock = client.player.lock().unwrap(); - let player_entity_id = player_lock.entity_id; - drop(player_lock); + let player_entity_id = { + let player_lock = client.player.lock().unwrap(); + player_lock.entity_id + }; let mut dimension_lock = client.dimension.lock().unwrap(); - let dimension = dimension_lock.as_mut().unwrap(); - let player_entity = dimension - .mut_entity_by_id(player_entity_id) + let mut player_entity = dimension_lock + .entity_mut(player_entity_id) .expect("Player entity doesn't exist"); - let delta_movement = &player_entity.delta; + let delta_movement = player_entity.delta; let is_x_relative = p.relative_arguments.x; let is_y_relative = p.relative_arguments.y; let is_z_relative = p.relative_arguments.z; let (delta_x, new_pos_x) = if is_x_relative { - player_entity.old_pos.x += p.x; - (delta_movement.x(), player_entity.pos().x + p.x) + player_entity.last_pos.x += p.x; + (delta_movement.x, player_entity.pos().x + p.x) } else { - player_entity.old_pos.x = p.x; + player_entity.last_pos.x = p.x; (0.0, p.x) }; let (delta_y, new_pos_y) = if is_y_relative { - player_entity.old_pos.y += p.y; - (delta_movement.y(), player_entity.pos().y + p.y) + player_entity.last_pos.y += p.y; + (delta_movement.y, player_entity.pos().y + p.y) } else { - player_entity.old_pos.y = p.y; + player_entity.last_pos.y = p.y; (0.0, p.y) }; let (delta_z, new_pos_z) = if is_z_relative { - player_entity.old_pos.z += p.z; - (delta_movement.z(), player_entity.pos().z + p.z) + player_entity.last_pos.z += p.z; + (delta_movement.z, player_entity.pos().z + p.z) } else { - player_entity.old_pos.z = p.z; + player_entity.last_pos.z = p.z; (0.0, p.z) }; @@ -416,21 +415,21 @@ impl Client { x_rot += player_entity.y_rot; } - player_entity.delta = PositionDelta { - xa: delta_x, - ya: delta_y, - za: delta_z, + player_entity.delta = Vec3 { + x: delta_x, + y: delta_y, + z: delta_z, }; player_entity.set_rotation(y_rot, x_rot); // TODO: minecraft sets "xo", "yo", and "zo" here but idk what that means // so investigate that ig - let new_pos = EntityPos { + let new_pos = Vec3 { x: new_pos_x, y: new_pos_y, z: new_pos_z, }; - dimension - .move_entity(player_entity_id, new_pos) + dimension_lock + .set_entity_pos(player_entity_id, new_pos) .expect("The player entity should always exist"); (new_pos, y_rot, x_rot) @@ -442,7 +441,7 @@ impl Client { .await?; conn_lock .write( - ServerboundMovePlayerPacketPosRot { + ServerboundMovePlayerPosRotPacket { x: new_pos.x, y: new_pos.y, z: new_pos.z, @@ -463,8 +462,6 @@ impl Client { client .dimension .lock()? - .as_mut() - .unwrap() .update_view_center(&ChunkPos::new(p.x, p.z)); } ClientboundGamePacket::ClientboundLevelChunkWithLightPacket(p) => { @@ -475,8 +472,6 @@ impl Client { client .dimension .lock()? - .as_mut() - .expect("Dimension doesn't exist! We should've gotten a login packet by now.") .replace_with_packet_data(&pos, &mut p.chunk_data.data.as_slice()) .unwrap(); } @@ -485,13 +480,8 @@ impl Client { } ClientboundGamePacket::ClientboundAddEntityPacket(p) => { println!("Got add entity packet {:?}", p); - let entity = Entity::from(p); - client - .dimension - .lock()? - .as_mut() - .expect("Dimension doesn't exist! We should've gotten a login packet by now.") - .add_entity(entity); + let entity = EntityData::from(p); + client.dimension.lock()?.add_entity(p.id, entity); } ClientboundGamePacket::ClientboundSetEntityDataPacket(_p) => { // println!("Got set entity data packet {:?}", p); @@ -507,13 +497,8 @@ impl Client { } ClientboundGamePacket::ClientboundAddPlayerPacket(p) => { println!("Got add player packet {:?}", p); - let entity = Entity::from(p); - client - .dimension - .lock()? - .as_mut() - .expect("Dimension doesn't exist! We should've gotten a login packet by now.") - .add_entity(entity); + let entity = EntityData::from(p); + client.dimension.lock()?.add_entity(p.id, entity); } ClientboundGamePacket::ClientboundInitializeBorderPacket(p) => { println!("Got initialize border packet {:?}", p); @@ -535,12 +520,11 @@ impl Client { } ClientboundGamePacket::ClientboundTeleportEntityPacket(p) => { let mut dimension_lock = client.dimension.lock()?; - let dimension = dimension_lock.as_mut().unwrap(); - dimension - .move_entity( + dimension_lock + .set_entity_pos( p.id, - EntityPos { + Vec3 { x: p.x, y: p.y, z: p.z, @@ -556,17 +540,15 @@ impl Client { } ClientboundGamePacket::ClientboundMoveEntityPosPacket(p) => { let mut dimension_lock = client.dimension.lock()?; - let dimension = dimension_lock.as_mut().unwrap(); - dimension + dimension_lock .move_entity_with_delta(p.entity_id, &p.delta) .map_err(|e| HandleError::Other(e.into()))?; } ClientboundGamePacket::ClientboundMoveEntityPosRotPacket(p) => { let mut dimension_lock = client.dimension.lock()?; - let dimension = dimension_lock.as_mut().unwrap(); - dimension + dimension_lock .move_entity_with_delta(p.entity_id, &p.delta) .map_err(|e| HandleError::Other(e.into()))?; } @@ -603,6 +585,16 @@ impl Client { ClientboundGamePacket::ClientboundBlockUpdatePacket(p) => { println!("Got block update packet {:?}", p); // TODO: update world + let mut dimension = client.dimension.lock()?; + // dimension.get_block_state(pos) + if let Ok(block_state) = BlockState::try_from(p.block_state) { + dimension.set_block_state(&p.pos, block_state); + } else { + eprintln!( + "Non-existent block state for block update packet {}", + p.block_state + ); + } } ClientboundGamePacket::ClientboundAnimatePacket(p) => { println!("Got animate packet {:?}", p); @@ -626,28 +618,107 @@ impl Client { ClientboundGamePacket::ClientboundUpdateMobEffectPacket(p) => { println!("Got update mob effect packet {:?}", p); } - _ => panic!("Unexpected packet {:?}", packet), + ClientboundGamePacket::ClientboundAddExperienceOrbPacket(_) => {} + ClientboundGamePacket::ClientboundAwardStatsPacket(_) => {} + ClientboundGamePacket::ClientboundBlockChangedAckPacket(_) => {} + ClientboundGamePacket::ClientboundBlockDestructionPacket(_) => {} + ClientboundGamePacket::ClientboundBlockEntityDataPacket(_) => {} + ClientboundGamePacket::ClientboundBlockEventPacket(_) => {} + ClientboundGamePacket::ClientboundBossEventPacket(_) => {} + ClientboundGamePacket::ClientboundChatPreviewPacket(_) => {} + ClientboundGamePacket::ClientboundCommandSuggestionsPacket(_) => {} + ClientboundGamePacket::ClientboundContainerSetDataPacket(_) => {} + ClientboundGamePacket::ClientboundContainerSetSlotPacket(_) => {} + ClientboundGamePacket::ClientboundCooldownPacket(_) => {} + ClientboundGamePacket::ClientboundCustomChatCompletionsPacket(_) => {} + ClientboundGamePacket::ClientboundCustomSoundPacket(_) => {} + ClientboundGamePacket::ClientboundDeleteChatPacket(_) => {} + ClientboundGamePacket::ClientboundExplodePacket(_) => {} + ClientboundGamePacket::ClientboundForgetLevelChunkPacket(_) => {} + ClientboundGamePacket::ClientboundHorseScreenOpenPacket(_) => {} + ClientboundGamePacket::ClientboundMapItemDataPacket(_) => {} + ClientboundGamePacket::ClientboundMerchantOffersPacket(_) => {} + ClientboundGamePacket::ClientboundMoveVehiclePacket(_) => {} + ClientboundGamePacket::ClientboundOpenBookPacket(_) => {} + ClientboundGamePacket::ClientboundOpenScreenPacket(_) => {} + ClientboundGamePacket::ClientboundOpenSignEditorPacket(_) => {} + ClientboundGamePacket::ClientboundPingPacket(_) => {} + ClientboundGamePacket::ClientboundPlaceGhostRecipePacket(_) => {} + ClientboundGamePacket::ClientboundPlayerChatHeaderPacket(_) => {} + ClientboundGamePacket::ClientboundPlayerCombatEndPacket(_) => {} + ClientboundGamePacket::ClientboundPlayerCombatEnterPacket(_) => {} + ClientboundGamePacket::ClientboundPlayerCombatKillPacket(_) => {} + ClientboundGamePacket::ClientboundPlayerLookAtPacket(_) => {} + ClientboundGamePacket::ClientboundRemoveMobEffectPacket(_) => {} + ClientboundGamePacket::ClientboundResourcePackPacket(_) => {} + ClientboundGamePacket::ClientboundRespawnPacket(_) => {} + ClientboundGamePacket::ClientboundSelectAdvancementsTabPacket(_) => {} + ClientboundGamePacket::ClientboundSetActionBarTextPacket(_) => {} + ClientboundGamePacket::ClientboundSetBorderCenterPacket(_) => {} + ClientboundGamePacket::ClientboundSetBorderLerpSizePacket(_) => {} + ClientboundGamePacket::ClientboundSetBorderSizePacket(_) => {} + ClientboundGamePacket::ClientboundSetBorderWarningDelayPacket(_) => {} + ClientboundGamePacket::ClientboundSetBorderWarningDistancePacket(_) => {} + ClientboundGamePacket::ClientboundSetCameraPacket(_) => {} + ClientboundGamePacket::ClientboundSetChunkCacheRadiusPacket(_) => {} + ClientboundGamePacket::ClientboundSetDisplayChatPreviewPacket(_) => {} + ClientboundGamePacket::ClientboundSetDisplayObjectivePacket(_) => {} + ClientboundGamePacket::ClientboundSetEntityMotionPacket(_) => {} + ClientboundGamePacket::ClientboundSetObjectivePacket(_) => {} + ClientboundGamePacket::ClientboundSetPassengersPacket(_) => {} + ClientboundGamePacket::ClientboundSetPlayerTeamPacket(_) => {} + ClientboundGamePacket::ClientboundSetScorePacket(_) => {} + ClientboundGamePacket::ClientboundSetSimulationDistancePacket(_) => {} + ClientboundGamePacket::ClientboundSetSubtitleTextPacket(_) => {} + ClientboundGamePacket::ClientboundSetTitleTextPacket(_) => {} + ClientboundGamePacket::ClientboundSetTitlesAnimationPacket(_) => {} + ClientboundGamePacket::ClientboundSoundEntityPacket(_) => {} + ClientboundGamePacket::ClientboundStopSoundPacket(_) => {} + ClientboundGamePacket::ClientboundTabListPacket(_) => {} + ClientboundGamePacket::ClientboundTagQueryPacket(_) => {} + ClientboundGamePacket::ClientboundTakeItemEntityPacket(_) => {} } Ok(()) } /// Runs game_tick every 50 milliseconds. - async fn game_tick_loop(client: Client, tx: UnboundedSender<Event>) { + async fn game_tick_loop(mut client: Client, tx: UnboundedSender<Event>) { let mut game_tick_interval = time::interval(time::Duration::from_millis(50)); // TODO: Minecraft bursts up to 10 ticks and then skips, we should too game_tick_interval.set_missed_tick_behavior(time::MissedTickBehavior::Burst); loop { game_tick_interval.tick().await; - Self::game_tick(&client, &tx).await; + Self::game_tick(&mut client, &tx).await; } } /// Runs every 50 milliseconds. - async fn game_tick(client: &Client, tx: &UnboundedSender<Event>) { - if client.dimension.lock().unwrap().is_none() { - return; + async fn game_tick(client: &mut Client, tx: &UnboundedSender<Event>) { + // return if there's no chunk at the player's position + { + let dimension_lock = client.dimension.lock().unwrap(); + let player_lock = client.player.lock().unwrap(); + let player_entity = player_lock.entity(&dimension_lock); + let player_entity = if let Some(player_entity) = player_entity { + player_entity + } else { + return; + }; + let player_chunk_pos: ChunkPos = player_entity.pos().into(); + if dimension_lock[&player_chunk_pos].is_none() { + return; + } } + + // TODO: if we're a passenger, send the required packets + + if let Err(e) = client.send_position().await { + println!("Error sending position: {:?}", e); + } + + // TODO: minecraft does ambient sounds here + tx.send(Event::GameTick).unwrap(); } } |
