Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Commit

Permalink
Optimize newton
Browse files Browse the repository at this point in the history
  • Loading branch information
Mubelotix committed Jan 4, 2024
1 parent 3bbdfc8 commit 1298a82
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 31 deletions.
1 change: 1 addition & 0 deletions minecraft-server/src/entities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub use minecraft_protocol::{
nbt::NbtTag,
packets::UUID
};
pub use crate::world::EntityChangeSet;
pub use crate::prelude::*;
use std::{pin::Pin, future::Future};

Expand Down
4 changes: 2 additions & 2 deletions minecraft-server/src/entities/monsters/zombies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ impl ZombieTask {
})
}

pub async fn tick(&mut self, h: Handler<Zombie>) {
self.newton_task.tick(h.into()).await;
pub async fn tick(&mut self, h: Handler<Zombie>, entity_change_set: &EntityChangeSet) {
self.newton_task.tick(h.into(), entity_change_set).await;
}
}

Expand Down
4 changes: 2 additions & 2 deletions minecraft-server/src/entities/tasks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ impl EntityTask {
}
}

pub async fn tick(&mut self, h: Handler<Entity>) {
pub async fn tick(&mut self, h: Handler<Entity>, entity_change_set: &EntityChangeSet) {
match self {
EntityTask::Zombie(zombie_task) => zombie_task.tick(h.assume_other()).await,
EntityTask::Zombie(zombie_task) => zombie_task.tick(h.assume_other(), entity_change_set).await,
}
}
}
40 changes: 15 additions & 25 deletions minecraft-server/src/entities/tasks/newton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use super::*;
pub struct NewtonTask {
width: f64,
height: f64,
on_ground: bool,
}

impl NewtonTask {
Expand All @@ -22,20 +23,25 @@ impl NewtonTask {
Some(NewtonTask {
width,
height,
on_ground: false,
})
}

pub async fn tick(&mut self, h: Handler<Entity>) {
pub async fn tick(&mut self, h: Handler<Entity>, entity_change_set: &EntityChangeSet) {
// If it was on ground before and hasn't moved since, skip the turn
// TODO: detect if the ground is destroyed
if self.on_ground && !entity_change_set.get(&h.eid).copied().unwrap_or_default().position_changed() {
return;
}

// Get data from entity
let Some((mut position, mut velocity)) = h.observe_any(|any_entity| {
let entity = any_entity.as_entity();
(entity.position.clone(), entity.velocity.clone())
}).await else { return; };

// Apply velocity and collisions
let mut changes = EntityChanges::nothing();
let mut new_velocity = velocity.clone();
new_velocity.y -= 9.81/20.0;
velocity.y -= 9.81/20.0;
let bounding_box = CollisionShape {
x1: position.x - self.width/2.0,
y1: position.y,
Expand All @@ -44,37 +50,21 @@ impl NewtonTask {
y2: position.y + self.height,
z2: position.z + self.width/2.0,
};
let new_velocity = h.world.try_move(&bounding_box, &new_velocity).await;
if velocity.x != new_velocity.x {
velocity.x = 0.0;
changes += EntityChanges::velocity();
}
if velocity.y != new_velocity.y {
velocity.y = 0.0;
changes += EntityChanges::velocity();
}
if velocity.z != new_velocity.z {
velocity.z = 0.0;
changes += EntityChanges::velocity();
}
if !new_velocity.is_zero() {
changes += EntityChanges::position();
position += new_velocity;
let new_velocity = h.world.try_move(&bounding_box, &velocity).await;
self.on_ground = velocity.y < 0.0 && new_velocity.y >= 0.0;
if !velocity.is_zero() {
position += new_velocity.clone();
}

// TODO(feat): Apply air resistance to x and z velocity
// Keep in mind that velocity shouldn't flicker when constantly kept up by another task but slowed down in this task

// Mutate entity
// TODO(correctness): Before modifying entity values, we should ensure the original values we based the changes on are still the same
if changes.nothing_changed() {
return;
}
h.mutate(|entity| {
let entity = entity.get_entity_mut();
entity.velocity = velocity;
entity.velocity = new_velocity;
entity.position = position;
((), changes)
}).await;
}
}
5 changes: 3 additions & 2 deletions minecraft-server/src/world/ecs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub struct Entities {
uuid_counter: std::sync::atomic::AtomicU64,
tasks: RwLock<HashMap<Eid, EntityTask>>,
entities: RwLock<HashMap<Eid, AnyEntity>>,
change_set: RwLock<HashMap<Eid, EntityChanges>>,
change_set: RwLock<EntityChangeSet>,

/// A hashmap of chunk positions to get a list of entities in a chunk
chunks: RwLock<HashMap<ChunkColumnPosition, HashSet<Eid>>>,
Expand Down Expand Up @@ -122,10 +122,11 @@ impl Entities {
}

pub(super) async fn tick(&self, world: &'static World) {
let entity_change_set = std::mem::take(&mut *self.change_set.write().await);
let mut tasks = self.tasks.write().await;
for (eid, task) in tasks.iter_mut() {
let h = Handler::<Entity>::assume(*eid, world);
task.tick(h).await;
task.tick(h, &entity_change_set).await;
}
}
}
2 changes: 2 additions & 0 deletions minecraft-server/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use ecs::*;
mod collisions;
pub use collisions::*;

pub type EntityChangeSet = HashMap<Eid, EntityChanges>;

/// World is the union of the map and entities.
/// World handles loaded chunks and entities.
/// It is responsible for notifying players of changes in the world.
Expand Down

0 comments on commit 1298a82

Please sign in to comment.