Skip to content

Commit

Permalink
Added listening for traits.
Browse files Browse the repository at this point in the history
  • Loading branch information
facundo-villa committed Feb 11, 2024
1 parent 0f45468 commit 420d386
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 155 deletions.
10 changes: 7 additions & 3 deletions src/core/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ pub trait Entity: intertrait::CastFrom + downcast_rs::Downcast + std::any::Any +
}

fn get_traits(&self) -> Vec<EntityTrait> { vec![] }

fn call_listeners(&self, listener: &BasicListener, handle: EntityHandle<Self>) where Self: Sized {
listener.invoke_for(handle, self);
}
}

pub unsafe fn get_entity_trait_for_type<T: Entity + ?Sized>() -> EntityTrait {
Expand Down Expand Up @@ -177,7 +181,7 @@ pub struct EntityBuilder<'c, T> {
pub(super) subscribe_to: Vec<Box<dyn Fn(EntityHandle<T>) + 'c>>,
}

impl <'c, T: 'static> EntityBuilder<'c, T> {
impl <'c, T: Entity + 'static> EntityBuilder<'c, T> {
fn default(create: std::boxed::Box<CreateFunction<'c, T>>) -> Self {
Self {
create,
Expand Down Expand Up @@ -214,13 +218,13 @@ impl <'c, T: 'static> EntityBuilder<'c, T> {
self
}

pub fn listen_to<C: Entity>(mut self,) -> Self where T: std::any::Any + EntitySubscriber<C> + 'static, C: 'static {
pub fn listen_to<C: Entity + ?Sized + 'static>(mut self,) -> Self where T: EntitySubscriber<C> {
self.listens_to.push(Box::new(move |domain_handle, e| {
let l = domain_handle.write_sync();
let l = l.deref();

if let Some(l) = l.get_listener() {
l.add_listener::<T, C>(e);
l.add_listener(e);
} else {
log::error!("Entity listens to but wasn't spawned in a domain.");
}
Expand Down
65 changes: 27 additions & 38 deletions src/core/listener.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,47 @@
use std::ops::{Deref, DerefMut};
use std::{any::Any, borrow::Borrow, ops::{Deref, DerefMut}};

use intertrait::cast::CastMut;

use crate::utils;

use super::{entity::{get_entity_trait_for_type, EntityTrait, TraitObject}, Entity, EntityHandle};

pub trait Listener: Entity {
/// Notifies all listeners of the given type that the given entity has been created.
fn invoke_for<T: Entity + 'static>(&self, handle: EntityHandle<T>);
fn invoke_for_trait<T: Entity + 'static>(&self, handle: EntityHandle<T>, r#type: EntityTrait);
fn invoke_for<T: Entity + ?Sized + 'static>(&self, handle: EntityHandle<T>, reference: &T);

/// Subscribes the given listener `L` to the given entity type `T`.
fn add_listener<L, T: Entity + 'static>(&self, listener: EntityHandle<L>) where L: EntitySubscriber<T> + 'static;
fn add_listener<T: Entity + ?Sized>(&self, listener: EntityHandle<dyn EntitySubscriber<T>>);
}

pub trait EntitySubscriber<T: ?Sized> {
fn on_create<'a>(&'a mut self, handle: EntityHandle<T>, params: &T) -> impl std::future::Future<Output = ()>;
fn on_update(&'static mut self, handle: EntityHandle<T>, params: &T) -> impl std::future::Future<Output = ()>;
pub trait EntitySubscriber<T: ?Sized>: Entity {
fn on_create<'a>(&'a mut self, handle: EntityHandle<T>, params: &'a T) -> utils::BoxedFuture<'a, ()>;
}

pub struct BasicListener {
listeners: std::sync::RwLock<std::collections::HashMap<EntityTrait, List>>,
listeners: std::sync::RwLock<std::collections::HashMap<EntityTrait, Box<dyn std::any::Any>>>,
}

struct List {
l: Vec<Box<dyn Fn(EntityHandle<dyn Entity>)>>,
struct List<T: ?Sized> {
/// List of listeners for a given entity type. (EntityHandle<dyn EntitySubscriber<T>>)
listeners: Vec<EntityHandle<dyn EntitySubscriber<T>>>,
}

impl List {
impl <T: ?Sized + 'static> List<T> {
fn new() -> Self {
List {
l: Vec::new(),
listeners: Vec::new(),
}
}

fn invoke_for<T: Entity>(&self, listenee: EntityHandle<T>) {
for f in &self.l {
f(listenee.clone());
fn invoke_for(&self, listenee_handle: EntityHandle<T>, listenee: &T) {
for f in &self.listeners {
smol::block_on(f.write_sync().deref_mut().on_create(listenee_handle.clone(), listenee));
}
}

fn push(&mut self, f: Box<dyn Fn(EntityHandle<dyn Entity>)>) {
self.l.push(f);
fn push(&mut self, f: EntityHandle<dyn EntitySubscriber<T>>) {
self.listeners.push(f);
}
}

Expand All @@ -53,36 +54,24 @@ impl BasicListener {
}

impl Listener for BasicListener {
fn invoke_for<T: Entity + std::any::Any + 'static>(&self, handle: EntityHandle<T>) {
fn invoke_for<T: Entity + ?Sized + 'static>(&self, handle: EntityHandle<T>, reference: &T) {
let listeners = self.listeners.read().unwrap();

if let Some(listeners) = listeners.get(&unsafe { get_entity_trait_for_type::<T>() }) {
listeners.invoke_for(handle);
}
}

fn invoke_for_trait<T: Entity + 'static>(&self, handle: EntityHandle<T>, r#type: EntityTrait) {
let listeners = self.listeners.read().unwrap();

if let Some(listeners) = listeners.get(&r#type) {
listeners.invoke_for(handle);
if let Some(listeners) = listeners.downcast_ref::<List<T>>() {
listeners.invoke_for(handle, reference);
}
}
}

fn add_listener<L, T: Entity + 'static>(&self, listener: EntityHandle<L>) where L: EntitySubscriber<T> + 'static {
fn add_listener<T: Entity + ?Sized>(&self, listener: EntityHandle<dyn EntitySubscriber<T>>) {
let mut listeners = self.listeners.write().unwrap();

let listeners = listeners.entry(unsafe { get_entity_trait_for_type::<T>() }).or_insert_with(|| List::new());
let listeners = listeners.entry(unsafe { get_entity_trait_for_type::<T>() }).or_insert_with(|| Box::new(List::<T>::new()));

listeners.push(Box::new(
move |handle| {
if let Some(cast_handle) = handle.downcast::<T>() {
let s = cast_handle.read_sync();
let s = s.deref();
smol::block_on(listener.write_sync().deref_mut().on_create(cast_handle, s));
}
}
));
if let Some(listeners) = listeners.downcast_mut::<List<T>>() {
listeners.push(listener,);
}
}
}

Expand Down
11 changes: 3 additions & 8 deletions src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ use self::entity::EntityTrait;

struct NoneListener {}
impl Listener for NoneListener {
fn invoke_for<T: 'static>(&self, _: EntityHandle<T>) {}
fn invoke_for_trait<T: 'static>(&self, _: EntityHandle<T>, _: EntityTrait) {}
fn add_listener<L, T: ?Sized + 'static>(&self, _: EntityHandle<L>) where L: EntitySubscriber<T> + 'static { }
fn invoke_for<T: ?Sized + 'static>(&self, _: EntityHandle<T>, _: &T) {}
fn add_listener<T: ?Sized + 'static>(&self, _: EntityHandle<dyn EntitySubscriber<T>>) {}
}

impl Entity for NoneListener {}
Expand Down Expand Up @@ -59,11 +58,7 @@ impl <R: Entity + 'static> SpawnHandler<R> for R {

if let Some(listener) = listener {
if let Some(listener) = listener.write_sync().deref().get_listener() {
for r#trait in traits {
listener.invoke_for_trait(handle.clone(), r#trait)
}

listener.invoke_for(handle.clone());
handle.read_sync().deref().call_listeners(listener, handle.clone());
}
}

Expand Down
107 changes: 55 additions & 52 deletions src/core/orchestrator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,10 @@ mod tests {
}

impl EntitySubscriber<Component> for System {
async fn on_create<'a>(&'a mut self, handle: EntityHandle<Component>, component: &Component) {
fn on_create<'a>(&'a mut self, handle: EntityHandle<Component>, component: &Component) -> utils::BoxedFuture<'a, ()> {
println!("Component created: {} {}", component.name, component.value);
Box::pin(async move { })
}

async fn on_update(&'static mut self, handle: EntityHandle<Component>, params: &Component) {}
}

let _: EntityHandle<System> = spawn(System::new());
Expand Down Expand Up @@ -156,13 +156,13 @@ mod tests {
static mut COUNTER: u32 = 0;

impl EntitySubscriber<Component> for System {
async fn on_create<'a>(&'a mut self, _: EntityHandle<Component>, _: &Component) {
unsafe {
COUNTER += 1;
}
fn on_create<'a>(&'a mut self, _: EntityHandle<Component>, _: &Component) -> utils::BoxedFuture<()> {
Box::pin(async move {
unsafe {
COUNTER += 1;
}
})
}

async fn on_update(&'static mut self, _: EntityHandle<Component>, _: &Component) {}
}

let listener_handle = spawn(BasicListener::new());
Expand All @@ -176,65 +176,68 @@ mod tests {
assert_eq!(unsafe { COUNTER }, 1);
}

// #[test]
// fn listen_for_traits() {
// let orchestrator = Orchestrator::new_handle();

// trait Boo: Entity {
// fn get_name(&self) -> String;
// fn get_value(&self) -> u32;
// }
#[test]
fn listen_for_traits() {
let orchestrator = Orchestrator::new_handle();

// struct Component {
// name: String,
// value: u32,
// }
trait Boo: Entity {
fn get_name(&self) -> String;
fn get_value(&self) -> u32;
}

// impl Entity for Component {
// fn get_traits(&self) -> Vec<EntityTrait> { vec![unsafe { get_entity_trait_for_type::<dyn Boo>() }] }
// }
struct Component {
name: String,
value: u32,
}

// impl Boo for Component {
// fn get_name(&self) -> String { self.name.clone() }
// fn get_value(&self) -> u32 { self.value }
// }
impl Entity for Component {
fn get_traits(&self) -> Vec<EntityTrait> { vec![unsafe { get_entity_trait_for_type::<dyn Boo>() }] }
fn call_listeners(&self, listener: &BasicListener, handle: EntityHandle<Self>) where Self: Sized {
// listener.invoke_for(handle);
listener.invoke_for(handle as EntityHandle<dyn Boo>, self);
}
}

// let handle: EntityHandle<Component> = spawn(Component { name: "test".to_string(), value: 1 });
impl Boo for Component {
fn get_name(&self) -> String { self.name.clone() }
fn get_value(&self) -> u32 { self.value }
}

// struct System {
let handle: EntityHandle<Component> = spawn(Component { name: "test".to_string(), value: 1 });

// }
struct System {

// impl Entity for System {}
}

// impl System {
// fn new() -> EntityBuilder<'static, System> {
// EntityBuilder::new(System {}).listen_to::<dyn Boo>()
// }
// }
impl Entity for System {}

// static mut COUNTER: u32 = 0;
impl System {
fn new() -> EntityBuilder<'static, System> {
EntityBuilder::new(System {}).listen_to::<dyn Boo>()
}
}

// impl EntitySubscriber<dyn Boo> for System {
// async fn on_create<'a>(&'a mut self, _: EntityHandle<dyn Boo>, _: &(dyn Boo + 'static)) {
// unsafe {
// COUNTER += 1;
// }
// }
static mut COUNTER: u32 = 0;

// async fn on_update(&'static mut self, _: EntityHandle<dyn Boo>, _: &(dyn Boo + 'static)) {}
// }
impl EntitySubscriber<dyn Boo> for System {
fn on_create<'a>(&'a mut self, _: EntityHandle<dyn Boo>, _: &(dyn Boo + 'static)) -> utils::BoxedFuture<'a, ()> {
unsafe {
COUNTER += 1;
}
Box::pin(async move { })
}
}

// let listener_handle = spawn(BasicListener::new());
let listener_handle = spawn(BasicListener::new());

// let _: EntityHandle<System> = spawn_as_child(listener_handle.clone(), System::new());
let _: EntityHandle<System> = spawn_as_child(listener_handle.clone(), System::new());

// assert_eq!(unsafe { COUNTER }, 0);
assert_eq!(unsafe { COUNTER }, 0);

// let component: EntityHandle<Component> = spawn_as_child(listener_handle.clone(), Component { name: "test".to_string(), value: 1 });
let component: EntityHandle<Component> = spawn_as_child(listener_handle.clone(), Component { name: "test".to_string(), value: 1 });

// assert_eq!(unsafe { COUNTER }, 1);
// }
assert_eq!(unsafe { COUNTER }, 1);
}

#[test]
fn events() {
Expand Down
9 changes: 8 additions & 1 deletion src/gameplay/object.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use maths_rs::mat::{MatScale, MatTranslate};

use crate::{core::{entity::{get_entity_trait_for_type, EntityBuilder, EntityTrait}, event::Event, spawn, spawn_as_child, Entity, EntityHandle}, physics, rendering::mesh, Vector3};
use crate::{core::{entity::{get_entity_trait_for_type, EntityBuilder, EntityTrait}, event::Event, listener::{BasicListener, EntitySubscriber, Listener}, spawn, spawn_as_child, Entity, EntityHandle}, physics, rendering::mesh, Vector3};

pub struct Object {
position: Vector3,
Expand All @@ -25,6 +25,13 @@ impl Object {

impl Entity for Object {
fn get_traits(&self) -> Vec<EntityTrait> { vec![unsafe { get_entity_trait_for_type::<dyn physics::PhysicsEntity>() }] }

fn call_listeners(&self, listener: &BasicListener, handle: EntityHandle<Self>,) where Self: Sized {
let s: EntityHandle<dyn physics::PhysicsEntity> = handle.clone();

listener.invoke_for(handle, self);
listener.invoke_for(s, self);
}
}

impl physics::PhysicsEntity for Object {
Expand Down
10 changes: 4 additions & 6 deletions src/gameplay/space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@ impl Domain for Space {
}

impl Listener for Space {
fn invoke_for<T: Entity + 'static>(&self, handle: EntityHandle<T>) {
self.listener.invoke_for(handle);
fn invoke_for<T: Entity +?Sized + 'static>(&self, handle: EntityHandle<T>, reference: &T) {
self.listener.invoke_for(handle, reference);
}

fn invoke_for_trait<T: Entity + 'static>(&self, handle: EntityHandle<T>, r#type: EntityTrait) { self.listener.invoke_for_trait(handle, r#type); }

fn add_listener<L, T: Entity + 'static>(&self, listener: EntityHandle<L>) where L: EntitySubscriber<T> + 'static {
self.listener.add_listener::<L, T>(listener);
fn add_listener<T: Entity + ?Sized + 'static>(&self, listener: EntityHandle<dyn EntitySubscriber<T>>) {
self.listener.add_listener::<T>(listener);
}
}

Expand Down
Loading

0 comments on commit 420d386

Please sign in to comment.