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

fix shared worlds*

*there's a bug that entities and bots will have their positions exaggerated because the relative movement packet is applied for every entity once per bot
This commit is contained in:
mat 2022-11-22 18:48:37 -06:00
parent 93bebefe83
commit d41d6480ea
7 changed files with 66 additions and 9 deletions

1
Cargo.lock generated
View file

@ -406,6 +406,7 @@ version = "0.2.0"
dependencies = [
"anyhow",
"azalea",
"azalea-protocol",
"env_logger",
"parking_lot",
"rand",

View file

@ -34,7 +34,7 @@ use azalea_world::{
entity::{metadata, Entity, EntityData, EntityMetadata},
WeakWorld, WeakWorldContainer, World,
};
use log::{debug, error, info, warn};
use log::{debug, error, info, trace, warn};
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::{
collections::HashMap,
@ -751,8 +751,29 @@ impl Client {
.update_view_center(&ChunkPos::new(p.x, p.z));
}
ClientboundGamePacket::LevelChunkWithLight(p) => {
debug!("Got chunk with light packet {} {}", p.x, p.z);
// warn!("Got chunk with light packet {} {}", p.x, p.z);
let pos = ChunkPos::new(p.x, p.z);
// OPTIMIZATION: if we already know about the chunk from the
// shared world (and not ourselves), then we don't need to
// parse it again. This is only used when we have a shared
// world, since we check that the chunk isn't currently owned
// by this client.
let shared_has_chunk = client.world.read().get_chunk(&pos).is_some();
let this_client_has_chunk = client
.world
.read()
.chunk_storage
.limited_get(&pos)
.is_some();
if shared_has_chunk && !this_client_has_chunk {
trace!(
"Skipping parsing chunk {:?} because we already know about it",
pos
);
return Ok(());
}
// let chunk = Chunk::read_with_world_height(&mut p.chunk_data);
// debug("chunk {:?}")
if let Err(e) = client

View file

@ -1,4 +1,4 @@
use crate::WeakWorld;
use crate::{WeakWorld, World};
use azalea_core::ResourceLocation;
use log::error;
use std::{

View file

@ -7,12 +7,17 @@ use azalea_block::BlockState;
use azalea_buf::BufReadError;
use azalea_core::{BlockPos, ChunkPos, PositionDelta8, Vec3};
use parking_lot::{Mutex, RwLock};
use std::{io::Cursor, sync::Arc};
use std::fmt::Debug;
use std::{fmt::Formatter, io::Cursor, sync::Arc};
use uuid::Uuid;
/// A world is a collection of chunks and entities. They're called "levels" in Minecraft's source code.
#[derive(Debug, Default)]
#[derive(Default)]
pub struct World {
// we just need to keep a strong reference to `shared` so it doesn't get
// dropped, we don't need to do anything with it
_shared: Arc<WeakWorld>,
pub chunk_storage: LimitedChunkStorage,
pub entity_storage: EntityStorage,
}
@ -27,6 +32,7 @@ pub struct WeakWorld {
impl World {
pub fn new(chunk_radius: u32, shared: Arc<WeakWorld>) -> Self {
World {
_shared: shared.clone(),
chunk_storage: LimitedChunkStorage::new(chunk_radius, shared.chunk_storage.clone()),
entity_storage: EntityStorage::new(shared.entity_storage.clone()),
}
@ -156,3 +162,12 @@ impl WeakWorld {
self.chunk_storage.read().min_y
}
}
impl Debug for World {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("World")
.field("chunk_storage", &self.chunk_storage)
.field("entity_storage", &self.entity_storage)
.finish()
}
}

View file

@ -15,7 +15,7 @@ use log::error;
use parking_lot::{Mutex, RwLock};
use std::{future::Future, net::SocketAddr, sync::Arc, time::Duration};
use thiserror::Error;
use tokio::sync::mpsc::{self, UnboundedSender};
use tokio::sync::mpsc::{self, UnboundedSender};
/// A helper macro that generates a [`Plugins`] struct from a list of objects
/// that implement [`Plugin`].
@ -47,7 +47,7 @@ pub struct Swarm<S> {
resolved_address: SocketAddr,
address: ServerAddress,
world_container: Arc<RwLock<WeakWorldContainer>>,
pub worlds: Arc<RwLock<WeakWorldContainer>>,
/// Plugins that are set for new bots
plugins: Plugins,
@ -161,7 +161,7 @@ pub async fn start_swarm<
resolved_address,
address,
world_container,
worlds: world_container,
plugins,
bots_tx,
@ -265,7 +265,7 @@ where
// tx is moved to the bot so it can send us events
// rx is used to receive events from the bot
let (tx, mut rx) = mpsc::unbounded_channel();
let mut bot = Client::new(game_profile, conn, Some(self.world_container.clone()));
let mut bot = Client::new(game_profile, conn, Some(self.worlds.clone()));
tx.send(Event::Initialize).unwrap();
bot.start_tasks(tx);

View file

@ -10,6 +10,7 @@ version = "0.2.0"
[dependencies]
anyhow = "1.0.65"
azalea = {path = "../azalea"}
azalea-protocol = {path = "../azalea-protocol"}
env_logger = "0.9.1"
parking_lot = {version = "^0.12.1", features = ["deadlock_detection"]}
rand = "0.8.5"

View file

@ -1,6 +1,7 @@
use azalea::pathfinder::BlockPosGoal;
use azalea::{prelude::*, BlockPos, Swarm, SwarmEvent};
use azalea::{Account, Client, Event};
use azalea_protocol::packets::game::serverbound_client_command_packet::ServerboundClientCommandPacket;
use std::time::Duration;
#[derive(Default, Clone)]
@ -96,6 +97,11 @@ async fn handle(bot: Client, event: Event, _state: State) -> anyhow::Result<()>
Event::Initialize => {
println!("initialized");
}
Event::Death(_) => {
bot.write_packet(ServerboundClientCommandPacket {
action: azalea_protocol::packets::game::serverbound_client_command_packet::Action::PerformRespawn,
}.get()).await?;
}
_ => {}
}
@ -115,6 +121,19 @@ async fn swarm_handle(
}
SwarmEvent::Chat(m) => {
println!("swarm chat message: {}", m.message().to_ansi(None));
if m.message().to_string() == "<py5> world" {
let worlds = swarm.worlds.read();
for (name, world) in &swarm.worlds.read().worlds {
println!("world name: {}", name);
if let Some(w) = world.upgrade() {
for chunk_pos in w.chunk_storage.read().chunks.values() {
println!("chunk: {:?}", chunk_pos);
}
} else {
println!("nvm world is gone");
}
}
}
}
_ => {}
}