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

Commit

Permalink
Add tasks to ecs
Browse files Browse the repository at this point in the history
  • Loading branch information
Mubelotix committed Jan 4, 2024
1 parent d6de431 commit 8f43a42
Show file tree
Hide file tree
Showing 10 changed files with 108 additions and 79 deletions.
2 changes: 1 addition & 1 deletion minecraft-protocol/src/components/slots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub struct SlotItem {

#[cfg_attr(test, derive(PartialEq))]
#[minecraft_enum(VarInt)]
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub enum Hand {
MainHand,
OffHand,
Expand Down
4 changes: 1 addition & 3 deletions minecraft-server/src/entities/entity.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use super::*;

#[derive(Clone)]
#[MinecraftEntity(
inheritable,
descendants { AbstractArrow..., Boat..., Display, FallingBlock, LlamaSpit, Painting, DragonFireball, Fireball..., FireworkRocket, SmallFireball, Interaction..., ItemEntity, ItemFrame..., LivingEntity... EndCrystal, EvokerFangs, WitherSkull, AreaEffectCloud, FishingHook, EyeOfEnder, ThrownItemProjectile... },
defines {
init(self, server_msg_rcvr: BroadcastReceiver<ServerMessage>);
tick(self);
}
)]
pub struct Entity {
Expand All @@ -31,8 +31,6 @@ pub struct Entity {

impl Handler<Entity> {
pub async fn init(self, _server_msg_rcvr: BroadcastReceiver<ServerMessage>) {}

pub async fn tick(self) {}
}

impl Default for Entity {
Expand Down
1 change: 1 addition & 0 deletions minecraft-server/src/entities/living_entity.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;

#[derive(Clone)]
#[MinecraftEntity(
inheritable,
ancestors { Entity },
Expand Down
4 changes: 2 additions & 2 deletions minecraft-server/src/entities/mobs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub use flying::*;
mod bat;
pub use bat::*;

#[derive(Default)]
#[derive(Default, Clone)]
#[MinecraftEntity(
inheritable,
ancestors { LivingEntity, Entity },
Expand All @@ -36,7 +36,7 @@ pub struct AmbientCreature {
pub mob: Mob,
}

#[derive(Default)]
#[derive(Default, Clone)]
#[MinecraftEntity(
inheritable,
ancestors { Mob, LivingEntity, Entity },
Expand Down
4 changes: 4 additions & 0 deletions minecraft-server/src/entities/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ impl AnyEntity {
self.try_as_entity_ref()
}

pub async fn init_task(&self) -> Option<EntityTask> {
EntityTask::init(self).await
}

pub fn to_network(&self) -> Option<minecraft_protocol::ids::entities::Entity> {
use minecraft_protocol::ids::entities::Entity::*;
match self {
Expand Down
2 changes: 1 addition & 1 deletion minecraft-server/src/entities/monsters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub use zombies::*;
mod enderman;
pub use enderman::*;

#[derive(Default)]
#[derive(Default, Clone)]
#[MinecraftEntity(
inheritable,
ancestors { PathfinderMob, Mob, LivingEntity, Entity },
Expand Down
117 changes: 58 additions & 59 deletions minecraft-server/src/entities/monsters/zombies.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
use minecraft_protocol::network;

use super::*;

#[derive(Default)]
#[derive(Default, Clone)]
#[MinecraftEntity(
inheritable,
ancestors { Monster, PathfinderMob, Mob, LivingEntity, Entity },
descendants { ZombieVillager, Husk, Drowned, ZombifiedPiglin },
defines {
Entity.tick(self);
}
)]
pub struct Zombie {
pub monster: Monster,
Expand All @@ -18,71 +13,75 @@ pub struct Zombie {
pub is_becoming_drowned: bool,
}

impl Handler<Zombie> {
pub async fn tick(self) {
// TODO: Stop initializing the task at each tick
let Some(mut newton_task) = NewtonTask::new(self.clone()).await else { return };
newton_task.tick(self).await;
}
const ZOMBIE_SPEED: f64 = 0.2; // Arbitrary value

pub struct ZombieTask {
newton_task: NewtonTask,
target: Option<Eid>,
}

pub async fn sleep_ticks(server_msg_rcvr: &mut BroadcastReceiver<ServerMessage>, t: usize) {
let mut i = 0;
while i < t {
let Ok(msg) = server_msg_rcvr.recv().await else {continue};
if matches!(&msg, &ServerMessage::Tick(_)) { i += 1; }
impl ZombieTask {
pub async fn init(zombie: &Zombie) -> Option<ZombieTask> {
let anyentity: AnyEntity = zombie.to_owned().into();
let Some(newton_task) = NewtonTask::init(&anyentity).await else { return None; };
Some(ZombieTask {
newton_task,
target: None
})
}
}

const ZOOMBIE_SPEED: f64 = 0.2; // Arbitrary value
pub async fn tick(&mut self, h: Handler<Zombie>) {
self.newton_task.tick(h.into()).await;
}
}

pub async fn zombie_ai_task<T: EntityDescendant + ZombieDescendant>(h: Handler<T>, mut server_msg_rcvr: BroadcastReceiver<ServerMessage>) where AnyEntity: TryAsEntityRef<T> {
loop {
sleep_ticks(&mut server_msg_rcvr, 1).await;
// pub async fn zombie_ai_task<T: EntityDescendant + ZombieDescendant>(h: Handler<T>, mut server_msg_rcvr: BroadcastReceiver<ServerMessage>) where AnyEntity: TryAsEntityRef<T> {
// loop {
// sleep_ticks(&mut server_msg_rcvr, 1).await;

let mut self_position = h.observe(|e| e.get_entity().position.clone()).await.unwrap();
let chunk = self_position.chunk_column();
let player_positions = h.world.observe_entities(chunk, |entity| {
let network_entity = entity.to_network().unwrap();
TryAsEntityRef::<Player>::try_as_entity_ref(entity).map(|player| {
(player.get_entity().position.clone(), network_entity)
})
}).await;
// let mut self_position = h.observe(|e| e.get_entity().position.clone()).await.unwrap();
// let chunk = self_position.chunk_column();
// let player_positions = h.world.observe_entities(chunk, |entity| {
// let network_entity = entity.to_network().unwrap();
// TryAsEntityRef::<Player>::try_as_entity_ref(entity).map(|player| {
// (player.get_entity().position.clone(), network_entity)
// })
// }).await;

let Some((target_position, network_entity)) = player_positions.get(0) else { sleep_ticks(&mut server_msg_rcvr, 100).await; continue };
let target_object = CollisionShape {
x1: target_position.x - network_entity.width() as f64 / 2.0,
y1: target_position.y,
z1: target_position.z - network_entity.width() as f64 / 2.0,
x2: target_position.x + network_entity.width() as f64 / 2.0,
y2: target_position.y + network_entity.height() as f64,
z2: target_position.z + network_entity.width() as f64 / 2.0,
};
// let Some((target_position, network_entity)) = player_positions.get(0) else { sleep_ticks(&mut server_msg_rcvr, 100).await; continue };
// let target_object = CollisionShape {
// x1: target_position.x - network_entity.width() as f64 / 2.0,
// y1: target_position.y,
// z1: target_position.z - network_entity.width() as f64 / 2.0,
// x2: target_position.x + network_entity.width() as f64 / 2.0,
// y2: target_position.y + network_entity.height() as f64,
// z2: target_position.z + network_entity.width() as f64 / 2.0,
// };

for _ in 0..50 {
let mut translation = Translation {
x: target_position.x - self_position.x,
y: target_position.y - self_position.y,
z: target_position.z - self_position.z,
};
translation.set_norm(ZOOMBIE_SPEED);
// for _ in 0..50 {
// let mut translation = Translation {
// x: target_position.x - self_position.x,
// y: target_position.y - self_position.y,
// z: target_position.z - self_position.z,
// };
// translation.set_norm(ZOMBIE_SPEED);

let authorized_translation = h.world.try_move(&target_object, &translation).await;
// let authorized_translation = h.world.try_move(&target_object, &translation).await;

let new_pos = h.mutate(|e| {
e.get_entity_mut().position += authorized_translation;
(e.get_entity().position.clone(), EntityChanges::position())
}).await;
self_position = match new_pos {
Some(pos) => pos,
None => break,
};
// let new_pos = h.mutate(|e| {
// e.get_entity_mut().position += authorized_translation;
// (e.get_entity().position.clone(), EntityChanges::position())
// }).await;
// self_position = match new_pos {
// Some(pos) => pos,
// None => break,
// };

sleep_ticks(&mut server_msg_rcvr, 1).await; // TODO: do while
}
// sleep_ticks(&mut server_msg_rcvr, 1).await; // TODO: do while
// }

}
}
// }
// }

#[derive(Default)]
#[MinecraftEntity(
Expand Down
26 changes: 26 additions & 0 deletions minecraft-server/src/entities/tasks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,29 @@ pub use super::*;

mod newton;
pub use newton::*;

//pub trait EntityTask where AnyEntity: TryAsEntityRef<<Self as tasks::EntityTask>::InnerEntity> {
// type InnerEntity;
//
// async fn init(h: Handler<Self::InnerEntity>) -> Option<Box<Self>>;
// async fn tick(&mut self, h: Handler<Self::InnerEntity>);
//}

pub enum EntityTask {
Zombie(ZombieTask),
}

impl EntityTask {
pub async fn init(entity: &AnyEntity) -> Option<EntityTask> {
match entity {
AnyEntity::Zombie(zombie) => ZombieTask::init(zombie).await.map(EntityTask::Zombie),
_ => None,
}
}

pub async fn tick(&mut self, h: Handler<Entity>) {
match self {
EntityTask::Zombie(zombie_task) => zombie_task.tick(h.assume_other()).await,
}
}
}
16 changes: 6 additions & 10 deletions minecraft-server/src/entities/tasks/newton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,30 @@ use crate::CollisionShape;

use super::*;

pub struct NewtonTask<T: EntityDescendant> where AnyEntity: TryAsEntityRef<T> {
pub struct NewtonTask {
width: f64,
height: f64,
_phantom: std::marker::PhantomData<T>,
}

impl<T: EntityDescendant> NewtonTask<T> where AnyEntity: TryAsEntityRef<T> {
/// Initialize a new Newton task for an entity.
/// Returns None if the entity has no network entity or doesn't exist anymore.
pub async fn new(h: Handler<T>) -> Option<NewtonTask<T>> {
let Some(network_entity) = h.observe_any(|any_entity| any_entity.to_network()).await else { return None; };
impl NewtonTask {
pub async fn init(entity: &AnyEntity) -> Option<NewtonTask> {
let network_entity = entity.to_network();

let (width, height) = match network_entity {
Some(network_entity) => (network_entity.width() as f64, network_entity.height() as f64),
None => {
warn!("Entity {} has no network entity", h.eid);
warn!("Entity has no network entity");
return None;
}
};

Some(NewtonTask {
width,
height,
_phantom: std::marker::PhantomData,
})
}

pub async fn tick(&mut self, h: Handler<T>) {
pub async fn tick(&mut self, h: Handler<Entity>) {
// Get data from entity
let Some((mut position, mut velocity)) = h.observe_any(|any_entity| {
let entity = any_entity.as_entity();
Expand Down
11 changes: 8 additions & 3 deletions minecraft-server/src/world/ecs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ use crate::*;
use minecraft_protocol::packets::UUID;
use tokio::sync::RwLock;

pub type EntityTask = Pin<Box<dyn Future<Output = ()> + Send + Sync + 'static>>;
pub type EntityTaskHandle = tokio::task::JoinHandle<()>;

pub struct Entities {
eid_counter: std::sync::atomic::AtomicU32,
uuid_counter: std::sync::atomic::AtomicU64,
pub entities: RwLock<HashMap<Eid, AnyEntity>>,
pub tasks: RwLock<HashMap<Eid, EntityTask>>,

/// A hashmap of chunk positions to get a list of entities in a chunk
pub chunks: RwLock<HashMap<ChunkColumnPosition, HashSet<Eid>>>,
Expand All @@ -22,6 +20,7 @@ impl Entities {
eid_counter: std::sync::atomic::AtomicU32::new(0),
uuid_counter: std::sync::atomic::AtomicU64::new(0),
entities: RwLock::new(HashMap::new()),
tasks: RwLock::new(HashMap::new()),
chunks: RwLock::new(HashMap::new()),
uuids: RwLock::new(HashMap::new()),
}
Expand Down Expand Up @@ -73,15 +72,21 @@ impl Entities {
pub(super) async fn spawn_entity<E>(&self, entity: AnyEntity, world: &'static World, receiver: BroadcastReceiver<ServerMessage>) -> (Eid, UUID)
where AnyEntity: TryAsEntityRef<E>, Handler<E>: EntityExt
{
let task = entity.init_task().await;
let eid = self.eid_counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let uuid = self.uuid_counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst) as u128;
let mut entities = self.entities.write().await;
let mut tasks = self.tasks.write().await;
let mut chunks = self.chunks.write().await;
let mut uuids = self.uuids.write().await;
chunks.entry(entity.as_entity().position.chunk_column()).or_insert(HashSet::new()).insert(eid);
entities.insert(eid, entity);
if let Some(task) = task {
tasks.insert(eid, task);
}
uuids.insert(uuid, eid);
drop(entities);
drop(tasks);
drop(chunks);
drop(uuids);
let h = Handler::<E>::assume(eid, world);
Expand Down

0 comments on commit 8f43a42

Please sign in to comment.