feat(plugin-api): expose some more entity flags

This commit is contained in:
Alexander Medvedev 2026-04-25 21:18:10 +02:00
parent 7a8f11b984
commit ee11ba746f
14 changed files with 212 additions and 90 deletions

View File

@ -170,6 +170,26 @@ interface player {
is-sprinting: func() -> bool; is-sprinting: func() -> bool;
/// Sets whether the player is currently sprinting. /// Sets whether the player is currently sprinting.
set-sprinting: func(sprinting: bool); set-sprinting: func(sprinting: bool);
/// Returns whether the player is currently swimming.
is-swimming: func() -> bool;
/// Sets whether the player is currently swimming.
set-swimming: func(swimming: bool);
/// Returns whether the player is currently invisible.
is-invisible: func() -> bool;
/// Sets whether the player is currently invisible.
set-invisible: func(invisible: bool);
/// Returns whether the player is currently glowing.
is-glowing: func() -> bool;
/// Sets whether the player is currently glowing.
set-glowing: func(glowing: bool);
/// Returns whether the player is currently flying due to a fall.
is-fall-flying: func() -> bool;
/// Sets whether the player is currently flying due to a fall.
set-fall-flying: func(fall-flying: bool);
/// Returns whether the player is currently on fire. Note: this is only visually like fire, there is no actual logic.
is-on-fire: func() -> bool;
/// Sets whether the player is visually on fire. Note: this is only visually like fire, there is no actual logic.
set-on-fire: func(on-fire: bool);
/// Returns whether the player is currently on the ground. /// Returns whether the player is currently on the ground.
is-on-ground: func() -> bool; is-on-ground: func() -> bool;
/// Returns whether the player is currently flying. /// Returns whether the player is currently flying.

View File

@ -124,7 +124,7 @@ impl LevelChannel {
ret ret
} }
pub fn notify(&self) { pub fn notify(&self) {
let val = self.value.lock().unwrap(); let val = self.value.lock().unwrap_or_else(|e| e.into_inner());
drop(val); drop(val);
self.notify.notify_one(); self.notify.notify_one();
} }

View File

@ -59,8 +59,12 @@ impl DAG {
if !self.nodes.contains_key(to) || !self.nodes.contains_key(from) { if !self.nodes.contains_key(to) || !self.nodes.contains_key(from) {
return; return;
} }
self.nodes.get_mut(to).unwrap().in_degree += 1; if let Some(node) = self.nodes.get_mut(to) {
let edge = &mut self.nodes.get_mut(from).unwrap().edge; node.in_degree += 1;
*edge = self.edges.insert(Edge::new(to, *edge)); }
if let Some(node) = self.nodes.get_mut(from) {
let edge = &mut node.edge;
*edge = self.edges.insert(Edge::new(to, *edge));
}
} }
} }

View File

@ -923,7 +923,7 @@ impl ProtoChunk {
terrain_cache.terrain_builder.place_iceberg( terrain_cache.terrain_builder.place_iceberg(
self, self,
Biome::from_id(this_biome).unwrap(), Biome::from_id(this_biome).unwrap_or(&Biome::PLAINS),
x, x,
z, z,
surface_estimate, surface_estimate,

View File

@ -369,7 +369,8 @@ impl SkyLightPropagator {
} }
} }
Chunk::Level(c) => { Chunk::Level(c) => {
let mut light_engine = c.light_engine.lock().unwrap(); let mut light_engine =
c.light_engine.lock().unwrap_or_else(|e| e.into_inner());
if section_idx < light_engine.sky_light.len() { if section_idx < light_engine.sky_light.len() {
light_engine.sky_light[section_idx] light_engine.sky_light[section_idx]
.set(local_x, local_y, local_z, 15); .set(local_x, local_y, local_z, 15);
@ -406,7 +407,8 @@ impl SkyLightPropagator {
} }
} }
Chunk::Level(c) => { Chunk::Level(c) => {
let mut light_engine = c.light_engine.lock().unwrap(); let mut light_engine =
c.light_engine.lock().unwrap_or_else(|e| e.into_inner());
if section_idx < light_engine.sky_light.len() { if section_idx < light_engine.sky_light.len() {
light_engine.sky_light[section_idx] light_engine.sky_light[section_idx]
.set(local_x, local_y, local_z, light_val); .set(local_x, local_y, local_z, light_val);

View File

@ -372,7 +372,7 @@ impl DynamicLightEngine {
return; return;
} }
LightingEngineConfig::Dark => { LightingEngineConfig::Dark => {
self.set_sky_light_level(level, &pos, 0).await.unwrap(); self.set_sky_light_level(level, &pos, 0).await.ok();
return; return;
} }
LightingEngineConfig::Default => {} LightingEngineConfig::Default => {}
@ -484,7 +484,7 @@ impl DynamicLightEngine {
let section_index = let section_index =
(relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE; (relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE;
// Bounds check for section index // Bounds check for section index
let mut light_engine = chunk.light_engine.lock().unwrap(); let mut light_engine = chunk.light_engine.lock().unwrap_or_else(|e| e.into_inner());
if section_index >= light_engine.block_light.len() { if section_index >= light_engine.block_light.len() {
return Err("Invalid section index".to_string()); return Err("Invalid section index".to_string());
} }
@ -511,7 +511,7 @@ impl DynamicLightEngine {
let section_index = let section_index =
(relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE; (relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE;
let light_engine = chunk.light_engine.lock().unwrap(); let light_engine = chunk.light_engine.lock().unwrap_or_else(|e| e.into_inner());
// Bounds check for section index (lock the light engine) // Bounds check for section index (lock the light engine)
if section_index >= light_engine.sky_light.len() { if section_index >= light_engine.sky_light.len() {
return 15; return 15;
@ -538,7 +538,7 @@ impl DynamicLightEngine {
let section_index = let section_index =
(relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE; (relative.y - chunk.section.min_y) as usize / BlockPalette::SIZE;
// Bounds check for section index // Bounds check for section index
let mut light_engine = chunk.light_engine.lock().unwrap(); let mut light_engine = chunk.light_engine.lock().unwrap_or_else(|e| e.into_inner());
if section_index >= light_engine.sky_light.len() { if section_index >= light_engine.sky_light.len() {
return Err("Invalid section index".to_string()); return Err("Invalid section index".to_string());
} }

View File

@ -76,7 +76,7 @@ pub fn set_block_light(cache: &mut Cache, pos: BlockPos, level: u8) {
match &mut cache.chunks[idx] { match &mut cache.chunks[idx] {
Chunk::Level(c) => { Chunk::Level(c) => {
let mut light_engine = c.light_engine.lock().unwrap(); let mut light_engine = c.light_engine.lock().unwrap_or_else(|e| e.into_inner());
if section_y < light_engine.block_light.len() { if section_y < light_engine.block_light.len() {
light_engine.block_light[section_y].set(x, y, z, level); light_engine.block_light[section_y].set(x, y, z, level);
c.dirty.store(true, std::sync::atomic::Ordering::Relaxed); c.dirty.store(true, std::sync::atomic::Ordering::Relaxed);
@ -143,7 +143,7 @@ pub fn set_sky_light(cache: &mut Cache, pos: BlockPos, level: u8) {
match &mut cache.chunks[idx] { match &mut cache.chunks[idx] {
Chunk::Level(c) => { Chunk::Level(c) => {
let mut light_engine = c.light_engine.lock().unwrap(); let mut light_engine = c.light_engine.lock().unwrap_or_else(|e| e.into_inner());
if section_y < light_engine.sky_light.len() { if section_y < light_engine.sky_light.len() {
light_engine.sky_light[section_y].set(x, y, z, level); light_engine.sky_light[section_y].set(x, y, z, level);
c.dirty.store(true, std::sync::atomic::Ordering::Relaxed); c.dirty.store(true, std::sync::atomic::Ordering::Relaxed);

View File

@ -394,17 +394,15 @@ impl PoiStorage {
} }
fn get_or_load_region(&mut self, rx: i32, rz: i32) -> &mut PoiRegion { fn get_or_load_region(&mut self, rx: i32, rz: i32) -> &mut PoiRegion {
if !self.regions.contains_key(&(rx, rz)) { let path = self.region_path(rx, rz);
let path = self.region_path(rx, rz); self.regions.entry((rx, rz)).or_insert_with(|| {
let region = PoiRegion::load(&path).unwrap_or_else(|e| { PoiRegion::load(&path).unwrap_or_else(|e| {
if path.exists() { if path.exists() {
warn!("Failed to load POI region {}: {}", path.display(), e); warn!("Failed to load POI region {}: {}", path.display(), e);
} }
PoiRegion::new() PoiRegion::new()
}); })
self.regions.insert((rx, rz), region); })
}
self.regions.get_mut(&(rx, rz)).unwrap()
} }
pub fn add(&mut self, pos: BlockPos, poi_type: &str) { pub fn add(&mut self, pos: BlockPos, poi_type: &str) {

View File

@ -22,12 +22,12 @@ impl<'a, T: std::hash::Hash + Eq> ChunkTickScheduler<&'a T> {
self.offset.store(next_offset, Ordering::SeqCst); self.offset.store(next_offset, Ordering::SeqCst);
let res = { let res = {
let mut queue = self.tick_queue.lock().unwrap(); let mut queue = self.tick_queue.lock().unwrap_or_else(|e| e.into_inner());
std::mem::take(&mut queue[current_offset]) std::mem::take(&mut queue[current_offset])
}; };
if !res.is_empty() { if !res.is_empty() {
let mut set = self.queued_ticks.lock().unwrap(); let mut set = self.queued_ticks.lock().unwrap_or_else(|e| e.into_inner());
for next_tick in &res { for next_tick in &res {
set.remove(&(next_tick.position, next_tick.value)); set.remove(&(next_tick.position, next_tick.value));
} }
@ -36,10 +36,10 @@ impl<'a, T: std::hash::Hash + Eq> ChunkTickScheduler<&'a T> {
} }
pub fn schedule_tick(&self, tick: &ScheduledTick<&'a T>, sub_tick_order: u64) { pub fn schedule_tick(&self, tick: &ScheduledTick<&'a T>, sub_tick_order: u64) {
let mut set = self.queued_ticks.lock().unwrap(); let mut set = self.queued_ticks.lock().unwrap_or_else(|e| e.into_inner());
if set.insert((tick.position, tick.value)) { if set.insert((tick.position, tick.value)) {
let mut queue = self.tick_queue.lock().unwrap(); let mut queue = self.tick_queue.lock().unwrap_or_else(|e| e.into_inner());
let offset = self.offset.load(Ordering::SeqCst); let offset = self.offset.load(Ordering::SeqCst);
let index = (offset + tick.delay as usize) % MAX_TICK_DELAY; let index = (offset + tick.delay as usize) % MAX_TICK_DELAY;
@ -53,13 +53,16 @@ impl<'a, T: std::hash::Hash + Eq> ChunkTickScheduler<&'a T> {
} }
pub fn is_scheduled(&self, pos: BlockPos, value: &T) -> bool { pub fn is_scheduled(&self, pos: BlockPos, value: &T) -> bool {
self.queued_ticks.lock().unwrap().contains(&(pos, value)) self.queued_ticks
.lock()
.unwrap_or_else(|e| e.into_inner())
.contains(&(pos, value))
} }
#[must_use] #[must_use]
pub fn to_vec(&self) -> Vec<ScheduledTick<&'a T>> { pub fn to_vec(&self) -> Vec<ScheduledTick<&'a T>> {
let offset = self.offset.load(Ordering::SeqCst); let offset = self.offset.load(Ordering::SeqCst);
let queue = self.tick_queue.lock().unwrap(); let queue = self.tick_queue.lock().unwrap_or_else(|e| e.into_inner());
let mut res = Vec::new(); let mut res = Vec::new();
for i in 0..MAX_TICK_DELAY { for i in 0..MAX_TICK_DELAY {
@ -84,7 +87,11 @@ impl<'a, T: std::hash::Hash + Eq + 'static> FromIterator<ScheduledTick<&'a T>>
let (lower, _) = iter.size_hint(); let (lower, _) = iter.size_hint();
if lower > 0 { if lower > 0 {
scheduler.queued_ticks.lock().unwrap().reserve(lower); scheduler
.queued_ticks
.lock()
.unwrap_or_else(|e| e.into_inner())
.reserve(lower);
} }
for tick in iter { for tick in iter {

View File

@ -413,6 +413,8 @@ pub struct Entity {
pub sneaking: AtomicBool, pub sneaking: AtomicBool,
/// Indicates whether the entity is sprinting /// Indicates whether the entity is sprinting
pub sprinting: AtomicBool, pub sprinting: AtomicBool,
/// Indicates whether the entity is swimming
pub swimming: AtomicBool,
/// Indicates whether the entity is invisible /// Indicates whether the entity is invisible
pub invisible: AtomicBool, pub invisible: AtomicBool,
/// Indicates whether the entity is glowing /// Indicates whether the entity is glowing
@ -568,6 +570,7 @@ impl Entity {
get_section_cord(floor_z), get_section_cord(floor_z),
)), )),
sneaking: AtomicBool::new(false), sneaking: AtomicBool::new(false),
swimming: AtomicBool::new(false),
invisible: AtomicBool::new(false), invisible: AtomicBool::new(false),
glowing: AtomicBool::new(false), glowing: AtomicBool::new(false),
world: ArcSwap::new(world), world: ArcSwap::new(world),
@ -2021,6 +2024,13 @@ impl Entity {
self.set_flag(Flag::Sneaking, sneaking).await; self.set_flag(Flag::Sneaking, sneaking).await;
} }
pub async fn set_swimming(&self, invisible: bool) {
if self.swimming.load(Ordering::Relaxed) != invisible {
self.swimming.store(invisible, Relaxed);
self.set_flag(Flag::Swimming, invisible).await;
}
}
/// Sets whether the entity is invisible and sends updated metadata. /// Sets whether the entity is invisible and sends updated metadata.
pub async fn set_invisible(&self, invisible: bool) { pub async fn set_invisible(&self, invisible: bool) {
if self.invisible.load(Ordering::Relaxed) != invisible { if self.invisible.load(Ordering::Relaxed) != invisible {

View File

@ -241,7 +241,7 @@ impl PumpkinServer {
); );
let rcon_server = server.clone(); let rcon_server = server.clone();
server.spawn_task(async move { server.spawn_task(async move {
RCONServer::run(&rcon, rcon_server).await.unwrap(); RCONServer::run(&rcon, rcon_server).await;
}); });
} }
@ -414,7 +414,6 @@ impl PumpkinServer {
} }
} }
#[expect(clippy::too_many_lines)]
pub async fn unified_listener_task( pub async fn unified_listener_task(
&self, &self,
master_client_id_counter: &mut u64, master_client_id_counter: &mut u64,
@ -490,9 +489,7 @@ impl PumpkinServer {
udp_result = resolve_some(self.udp_socket.as_ref(), |sock: &Arc<UdpSocket>| sock.recv_from(&mut udp_buf)) => { udp_result = resolve_some(self.udp_socket.as_ref(), |sock: &Arc<UdpSocket>| sock.recv_from(&mut udp_buf)) => {
match udp_result { match udp_result {
Ok((len, client_addr)) => { Ok((len, client_addr)) => {
if len == 0 { if len > 0 {
warn!("Received empty UDP packet from {client_addr}");
} else {
let id = udp_buf[0]; let id = udp_buf[0];
let is_online = id & 128 != 0; let is_online = id & 128 != 0;
@ -504,35 +501,23 @@ impl PumpkinServer {
let client = client.clone(); let client = client.clone();
let reader = Cursor::new(udp_buf[..len].to_vec()); let reader = Cursor::new(udp_buf[..len].to_vec());
let server = self.server.clone(); let server = self.server.clone();
tasks.spawn(async move { tasks.spawn(async move {
client.process_packet(&server, reader).await; client.process_packet(&server, reader).await;
}); });
} else if let Ok(packet) = BedrockClient::is_connection_request(&mut Cursor::new(&udp_buf[4..len])) { } else if let Some(sock) = self.udp_socket.as_ref()
*master_client_id_counter += 1; && let Ok(packet) = BedrockClient::is_connection_request(&mut Cursor::new(&udp_buf[4..len])) {
*master_client_id_counter += 1;
let mut platform = BedrockClient::new(self.udp_socket.clone().unwrap(), client_addr, be_clients); let mut platform = BedrockClient::new(sock.clone(), client_addr, be_clients);
platform.handle_connection_request(packet).await; platform.handle_connection_request(packet).await;
platform.start_outgoing_packet_task(); platform.start_outgoing_packet_task();
clients_guard.insert(client_addr, Arc::new(platform));
clients_guard.insert(client_addr, }
Arc::new( } else if let Some(sock) = self.udp_socket.as_ref() {
platform let _ = BedrockClient::handle_offline_packet(&self.server, id, &mut Cursor::new(&udp_buf[1..len]), client_addr, sock).await;
));
}
} else {
// Please keep the function as simple as possible!
// We dont care about the result, the client just resends the packet
// Since offline packets are very small we dont need to move and clone the data
let _ = BedrockClient::handle_offline_packet(&self.server, id, &mut Cursor::new(&udp_buf[1..len]), client_addr, self.udp_socket.as_ref().unwrap()).await;
} }
} }
} }
// Since all packets go over this match statement, there should be not waiting Err(e) => error!("UDP socket error: {e}"),
Err(e) => {
error!("{e}");
}
} }
}, },

View File

@ -124,7 +124,13 @@ impl BedrockClient {
} }
pub fn start_outgoing_packet_task(&mut self) { pub fn start_outgoing_packet_task(&mut self) {
let mut packet_receiver = self.outgoing_packet_queue_recv.take().unwrap(); let Some(mut packet_receiver) = self.outgoing_packet_queue_recv.take() else {
error!(
"Outgoing packet receiver was already taken for {}",
self.address
);
return;
};
let close_token = self.close_token.clone(); let close_token = self.close_token.clone();
let writer = self.network_writer.clone(); let writer = self.network_writer.clone();
let addr = self.address; let addr = self.address;
@ -168,8 +174,10 @@ impl BedrockClient {
if let Some(packet) = packet if let Some(packet) = packet
&& let Err(error) = self.handle_packet_payload(server, packet).await && let Err(error) = self.handle_packet_payload(server, packet).await
{ {
let _text = format!("Error while reading incoming packet {error}"); error!(
error!("Failed to read incoming packet with : {error}"); "Failed to handle packet payload for {}: {}",
self.address, error
);
self.kick(DisconnectReason::BadPacket, error.to_string()) self.kick(DisconnectReason::BadPacket, error.to_string())
.await; .await;
} }
@ -240,19 +248,23 @@ impl BedrockClient {
socket: &UdpSocket, socket: &UdpSocket,
) { ) {
let mut data = Vec::new(); let mut data = Vec::new();
let writer = &mut data; if let Err(err) = Self::write_raw_packet(packet, &mut data) {
Self::write_raw_packet(packet, writer).unwrap(); error!("Failed to write offline packet: {err}");
return;
}
// We dont care if it works, if not the client will try again! // We dont care if it works, if not the client will try again!
let _ = socket.send_to(&data, addr).await; let _ = socket.send_to(&data, addr).await;
} }
pub async fn send_game_packet<P: BClientPacket>(&self, packet: &P) { pub async fn send_game_packet<P: BClientPacket>(&self, packet: &P) {
let mut packet_buf = Vec::new(); let mut packet_buf = Vec::new();
self.write_game_packet(packet, &mut packet_buf) match self.write_game_packet(packet, &mut packet_buf).await {
.await Ok(()) => {
.unwrap(); self.send_framed_packet_data(packet_buf, RakReliability::Unreliable)
self.send_framed_packet_data(packet_buf, RakReliability::Unreliable) .await;
.await; }
Err(err) => error!("Failed to write game packet: {err}"),
}
} }
pub async fn write_game_packet_to_set<P: BClientPacket>( pub async fn write_game_packet_to_set<P: BClientPacket>(
@ -261,9 +273,12 @@ impl BedrockClient {
frame_set: &mut FrameSet, frame_set: &mut FrameSet,
) { ) {
let mut payload = Vec::new(); let mut payload = Vec::new();
self.write_game_packet(packet, &mut payload).await.unwrap(); match self.write_game_packet(packet, &mut payload).await {
Ok(()) => {
frame_set.frames.push(Frame::new_unreliable(payload)); frame_set.frames.push(Frame::new_unreliable(payload));
}
Err(err) => error!("Failed to write game packet to set: {err}"),
}
} }
pub async fn send_framed_packet<P: BClientPacket>( pub async fn send_framed_packet<P: BClientPacket>(
@ -272,8 +287,10 @@ impl BedrockClient {
reliability: RakReliability, reliability: RakReliability,
) { ) {
let mut packet_buf = Vec::new(); let mut packet_buf = Vec::new();
Self::write_raw_packet(packet, &mut packet_buf).unwrap(); match Self::write_raw_packet(packet, &mut packet_buf) {
self.send_framed_packet_data(packet_buf, reliability).await; Ok(()) => self.send_framed_packet_data(packet_buf, reliability).await,
Err(err) => error!("Failed to write framed packet: {err}"),
}
} }
pub async fn send_framed_packet_data( pub async fn send_framed_packet_data(
@ -341,23 +358,22 @@ impl BedrockClient {
pub async fn send_frame_set(&self, mut frame_set: FrameSet, id: u8) { pub async fn send_frame_set(&self, mut frame_set: FrameSet, id: u8) {
frame_set.sequence = u24(self.output_sequence_number.fetch_add(1, Ordering::Relaxed)); frame_set.sequence = u24(self.output_sequence_number.fetch_add(1, Ordering::Relaxed));
let mut frame_set_buf = Vec::new(); let mut frame_set_buf = Vec::new();
frame_set.write_packet_data(&mut frame_set_buf, id).unwrap();
// I dont know if thats the right place to make encryption & decoding if let Err(err) = frame_set.write_packet_data(&mut frame_set_buf, id) {
error!("Failed to write frame set data: {err}");
return;
}
if let Err(err) = self if let Err(err) = self
.network_writer .network_writer
.lock() .lock()
.await .await
.write_packet(&frame_set_buf, self.address, &self.socket) .write_packet(&frame_set_buf, self.address, &self.socket)
.await .await
&& !self.is_closed()
{ {
// It is expected that the packet will fail if we are closed warn!("Failed to send packet to client {}: {}", self.address, err);
if !self.is_closed() { self.close_token.cancel();
warn!("Failed to send packet to client: {err}");
// We now need to close the connection to the client since the stream is in an
// unknown state
self.close_token.cancel();
}
} }
} }
@ -376,9 +392,9 @@ impl BedrockClient {
self.close_token.is_cancelled() self.close_token.is_cancelled()
} }
pub async fn send_ack(&self, ack: &Ack) { pub async fn send_ack(&self, ack: &Ack) -> Result<(), Error> {
let mut packet_buf = Vec::new(); let mut packet_buf = Vec::new();
ack.write(&mut packet_buf).unwrap(); ack.write(&mut packet_buf)?;
if let Err(err) = self if let Err(err) = self
.network_writer .network_writer
@ -387,9 +403,11 @@ impl BedrockClient {
.write_packet(&packet_buf, self.address, &self.socket) .write_packet(&packet_buf, self.address, &self.socket)
.await .await
{ {
warn!("Failed to send packet to client: {err}"); warn!("Failed to send ACK to {}: {err}", self.address);
self.close().await; self.close().await;
return Err(err);
} }
Ok(())
} }
pub async fn handle_packet_payload( pub async fn handle_packet_payload(
@ -425,7 +443,7 @@ impl BedrockClient {
frame_set: FrameSet, frame_set: FrameSet,
) -> Result<(), Error> { ) -> Result<(), Error> {
// TODO: Send all ACKs in short intervals in batches // TODO: Send all ACKs in short intervals in batches
self.send_ack(&Ack::new(vec![frame_set.sequence.0])).await; self.send_ack(&Ack::new(vec![frame_set.sequence.0])).await?;
// TODO // TODO
for frame in frame_set.frames { for frame in frame_set.frames {
self.handle_frame(server, frame).await?; self.handle_frame(server, frame).await?;
@ -511,9 +529,14 @@ impl BedrockClient {
.await; .await;
} }
_ => { _ => {
return self let player_lock = self.player.lock().await;
.handle_play_packet(self.player.lock().await.as_ref().unwrap(), server, packet) if let Some(player) = player_lock.as_ref() {
.await; return self.handle_play_packet(player, server, packet).await;
}
debug!(
"Received game packet {} before player was initialized",
packet.id
);
} }
} }
Ok(()) Ok(())

View File

@ -17,7 +17,7 @@ mod packet;
pub struct RCONServer; pub struct RCONServer;
impl RCONServer { impl RCONServer {
pub async fn run(config: &RCONConfig, server: Arc<Server>) -> Result<(), std::io::Error> { pub async fn run(config: &RCONConfig, server: Arc<Server>) {
let listener = tokio::net::TcpListener::bind(config.address).await.unwrap(); let listener = tokio::net::TcpListener::bind(config.address).await.unwrap();
let password = Arc::new(config.password.clone()); let password = Arc::new(config.password.clone());
@ -35,10 +35,9 @@ impl RCONServer {
}; };
// Asynchronously wait for an inbound socket. // Asynchronously wait for an inbound socket.
let Some(result) = await_new_client().await else { let Some(Ok((connection, address))) = await_new_client().await else {
break; break;
}; };
let (connection, address) = result?;
if config.max_connections != 0 && connections >= config.max_connections { if config.max_connections != 0 && connections >= config.max_connections {
continue; continue;
@ -53,7 +52,6 @@ impl RCONServer {
debug!("closed RCON connection"); debug!("closed RCON connection");
connections -= 1; connections -= 1;
} }
Ok(())
} }
} }

View File

@ -685,6 +685,81 @@ impl pumpkin::plugin::player::HostPlayer for PluginHostState {
Ok(()) Ok(())
} }
async fn is_swimming(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
let player = player_from_resource(self, &player)?;
Ok(player.get_entity().swimming.load(Ordering::Relaxed))
}
async fn set_swimming(
&mut self,
player: Resource<Player>,
swimming: bool,
) -> wasmtime::Result<()> {
let player = player_from_resource(self, &player)?;
player.get_entity().set_swimming(swimming).await;
Ok(())
}
async fn is_invisible(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
let player = player_from_resource(self, &player)?;
Ok(player.get_entity().invisible.load(Ordering::Relaxed))
}
async fn set_invisible(
&mut self,
player: Resource<Player>,
invisible: bool,
) -> wasmtime::Result<()> {
let player = player_from_resource(self, &player)?;
player.get_entity().set_invisible(invisible).await;
Ok(())
}
async fn is_glowing(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
let player = player_from_resource(self, &player)?;
Ok(player.get_entity().glowing.load(Ordering::Relaxed))
}
async fn set_glowing(
&mut self,
player: Resource<Player>,
glowing: bool,
) -> wasmtime::Result<()> {
let player = player_from_resource(self, &player)?;
player.get_entity().set_glowing(glowing).await;
Ok(())
}
async fn is_fall_flying(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
let player = player_from_resource(self, &player)?;
Ok(player.get_entity().fall_flying.load(Ordering::Relaxed))
}
async fn set_fall_flying(
&mut self,
player: Resource<Player>,
fall_flying: bool,
) -> wasmtime::Result<()> {
let player = player_from_resource(self, &player)?;
player.get_entity().set_fall_flying(fall_flying).await;
Ok(())
}
async fn is_on_fire(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
let player = player_from_resource(self, &player)?;
Ok(player.get_entity().has_visual_fire.load(Ordering::Relaxed))
}
async fn set_on_fire(
&mut self,
player: Resource<Player>,
on_fire: bool,
) -> wasmtime::Result<()> {
let player = player_from_resource(self, &player)?;
player.get_entity().set_on_fire(on_fire).await;
Ok(())
}
async fn is_on_ground(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> { async fn is_on_ground(&mut self, player: Resource<Player>) -> wasmtime::Result<bool> {
let player = player_from_resource(self, &player)?; let player = player_from_resource(self, &player)?;
Ok(player.get_entity().on_ground.load(Ordering::Relaxed)) Ok(player.get_entity().on_ground.load(Ordering::Relaxed))