feat(plugin-api): expose some more entity flags
This commit is contained in:
parent
7a8f11b984
commit
ee11ba746f
@ -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.
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
if let Some(node) = self.nodes.get_mut(from) {
|
||||||
|
let edge = &mut node.edge;
|
||||||
*edge = self.edges.insert(Edge::new(to, *edge));
|
*edge = self.edges.insert(Edge::new(to, *edge));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
let region = PoiRegion::load(&path).unwrap_or_else(|e| {
|
self.regions.entry((rx, rz)).or_insert_with(|| {
|
||||||
|
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) {
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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()
|
||||||
|
&& let Ok(packet) = BedrockClient::is_connection_request(&mut Cursor::new(&udp_buf[4..len])) {
|
||||||
*master_client_id_counter += 1;
|
*master_client_id_counter += 1;
|
||||||
|
let mut platform = BedrockClient::new(sock.clone(), client_addr, be_clients);
|
||||||
let mut platform = BedrockClient::new(self.udp_socket.clone().unwrap(), 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(
|
|
||||||
platform
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else if let Some(sock) = self.udp_socket.as_ref() {
|
||||||
// Please keep the function as simple as possible!
|
let _ = BedrockClient::handle_offline_packet(&self.server, id, &mut Cursor::new(&udp_buf[1..len]), client_addr, sock).await;
|
||||||
// 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!("{e}");
|
|
||||||
}
|
}
|
||||||
|
Err(e) => error!("UDP socket error: {e}"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -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,20 +248,24 @@ 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>(
|
||||||
&self,
|
&self,
|
||||||
@ -261,10 +273,13 @@ 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>(
|
||||||
&self,
|
&self,
|
||||||
@ -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,25 +358,24 @@ 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() {
|
|
||||||
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();
|
self.close_token.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn close(&self) {
|
pub async fn close(&self) {
|
||||||
self.close_token.cancel();
|
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(())
|
||||||
|
|||||||
@ -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(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user