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

Commit 1298a82

Browse files
committed
Optimize newton
1 parent 3bbdfc8 commit 1298a82

File tree

6 files changed

+25
-31
lines changed

6 files changed

+25
-31
lines changed

minecraft-server/src/entities/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub use minecraft_protocol::{
4747
nbt::NbtTag,
4848
packets::UUID
4949
};
50+
pub use crate::world::EntityChangeSet;
5051
pub use crate::prelude::*;
5152
use std::{pin::Pin, future::Future};
5253

minecraft-server/src/entities/monsters/zombies.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ impl ZombieTask {
3030
})
3131
}
3232

33-
pub async fn tick(&mut self, h: Handler<Zombie>) {
34-
self.newton_task.tick(h.into()).await;
33+
pub async fn tick(&mut self, h: Handler<Zombie>, entity_change_set: &EntityChangeSet) {
34+
self.newton_task.tick(h.into(), entity_change_set).await;
3535
}
3636
}
3737

minecraft-server/src/entities/tasks/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ impl EntityTask {
2222
}
2323
}
2424

25-
pub async fn tick(&mut self, h: Handler<Entity>) {
25+
pub async fn tick(&mut self, h: Handler<Entity>, entity_change_set: &EntityChangeSet) {
2626
match self {
27-
EntityTask::Zombie(zombie_task) => zombie_task.tick(h.assume_other()).await,
27+
EntityTask::Zombie(zombie_task) => zombie_task.tick(h.assume_other(), entity_change_set).await,
2828
}
2929
}
3030
}

minecraft-server/src/entities/tasks/newton.rs

+15-25
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::*;
55
pub struct NewtonTask {
66
width: f64,
77
height: f64,
8+
on_ground: bool,
89
}
910

1011
impl NewtonTask {
@@ -22,20 +23,25 @@ impl NewtonTask {
2223
Some(NewtonTask {
2324
width,
2425
height,
26+
on_ground: false,
2527
})
2628
}
2729

28-
pub async fn tick(&mut self, h: Handler<Entity>) {
30+
pub async fn tick(&mut self, h: Handler<Entity>, entity_change_set: &EntityChangeSet) {
31+
// If it was on ground before and hasn't moved since, skip the turn
32+
// TODO: detect if the ground is destroyed
33+
if self.on_ground && !entity_change_set.get(&h.eid).copied().unwrap_or_default().position_changed() {
34+
return;
35+
}
36+
2937
// Get data from entity
3038
let Some((mut position, mut velocity)) = h.observe_any(|any_entity| {
3139
let entity = any_entity.as_entity();
3240
(entity.position.clone(), entity.velocity.clone())
3341
}).await else { return; };
3442

3543
// Apply velocity and collisions
36-
let mut changes = EntityChanges::nothing();
37-
let mut new_velocity = velocity.clone();
38-
new_velocity.y -= 9.81/20.0;
44+
velocity.y -= 9.81/20.0;
3945
let bounding_box = CollisionShape {
4046
x1: position.x - self.width/2.0,
4147
y1: position.y,
@@ -44,37 +50,21 @@ impl NewtonTask {
4450
y2: position.y + self.height,
4551
z2: position.z + self.width/2.0,
4652
};
47-
let new_velocity = h.world.try_move(&bounding_box, &new_velocity).await;
48-
if velocity.x != new_velocity.x {
49-
velocity.x = 0.0;
50-
changes += EntityChanges::velocity();
51-
}
52-
if velocity.y != new_velocity.y {
53-
velocity.y = 0.0;
54-
changes += EntityChanges::velocity();
55-
}
56-
if velocity.z != new_velocity.z {
57-
velocity.z = 0.0;
58-
changes += EntityChanges::velocity();
59-
}
60-
if !new_velocity.is_zero() {
61-
changes += EntityChanges::position();
62-
position += new_velocity;
53+
let new_velocity = h.world.try_move(&bounding_box, &velocity).await;
54+
self.on_ground = velocity.y < 0.0 && new_velocity.y >= 0.0;
55+
if !velocity.is_zero() {
56+
position += new_velocity.clone();
6357
}
6458

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

6862
// Mutate entity
6963
// TODO(correctness): Before modifying entity values, we should ensure the original values we based the changes on are still the same
70-
if changes.nothing_changed() {
71-
return;
72-
}
7364
h.mutate(|entity| {
7465
let entity = entity.get_entity_mut();
75-
entity.velocity = velocity;
66+
entity.velocity = new_velocity;
7667
entity.position = position;
77-
((), changes)
7868
}).await;
7969
}
8070
}

minecraft-server/src/world/ecs.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub struct Entities {
88
uuid_counter: std::sync::atomic::AtomicU64,
99
tasks: RwLock<HashMap<Eid, EntityTask>>,
1010
entities: RwLock<HashMap<Eid, AnyEntity>>,
11-
change_set: RwLock<HashMap<Eid, EntityChanges>>,
11+
change_set: RwLock<EntityChangeSet>,
1212

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

124124
pub(super) async fn tick(&self, world: &'static World) {
125+
let entity_change_set = std::mem::take(&mut *self.change_set.write().await);
125126
let mut tasks = self.tasks.write().await;
126127
for (eid, task) in tasks.iter_mut() {
127128
let h = Handler::<Entity>::assume(*eid, world);
128-
task.tick(h).await;
129+
task.tick(h, &entity_change_set).await;
129130
}
130131
}
131132
}

minecraft-server/src/world/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use ecs::*;
1111
mod collisions;
1212
pub use collisions::*;
1313

14+
pub type EntityChangeSet = HashMap<Eid, EntityChanges>;
15+
1416
/// World is the union of the map and entities.
1517
/// World handles loaded chunks and entities.
1618
/// It is responsible for notifying players of changes in the world.

0 commit comments

Comments
 (0)