From 4d756b302a669e35dabae86b24b4dea87cc3f4ee Mon Sep 17 00:00:00 2001 From: Iaiao Date: Tue, 25 Jan 2022 17:12:13 +0200 Subject: [PATCH] Add events to quill API (#522) * Add events to quill API * Split it into 3 host calls * format --- feather/plugin-host/src/host_calls.rs | 4 ++ .../plugin-host/src/host_calls/component.rs | 38 ++++++++++------- feather/plugin-host/src/host_calls/event.rs | 42 +++++++++++++++++++ quill/api/src/entity.rs | 18 ++++++++ quill/api/src/game.rs | 11 +++++ quill/sys/src/lib.rs | 21 +++++++++- 6 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 feather/plugin-host/src/host_calls/event.rs diff --git a/feather/plugin-host/src/host_calls.rs b/feather/plugin-host/src/host_calls.rs index bf90ccb81..91c0109f4 100644 --- a/feather/plugin-host/src/host_calls.rs +++ b/feather/plugin-host/src/host_calls.rs @@ -12,6 +12,7 @@ mod block; mod component; mod entity; mod entity_builder; +mod event; mod plugin_message; mod query; mod system; @@ -49,6 +50,7 @@ use block::*; use component::*; use entity::*; use entity_builder::*; +use event::*; use plugin_message::*; use query::*; use system::*; @@ -57,6 +59,8 @@ host_calls! { "register_system" => register_system, "entity_get_component" => entity_get_component, "entity_set_component" => entity_set_component, + "entity_add_event" => entity_add_event, + "add_event" => add_event, "entity_builder_new_empty" => entity_builder_new_empty, "entity_builder_new" => entity_builder_new, "entity_builder_add_component" => entity_builder_add_component, diff --git a/feather/plugin-host/src/host_calls/component.rs b/feather/plugin-host/src/host_calls/component.rs index 85e33089f..b9722255d 100644 --- a/feather/plugin-host/src/host_calls/component.rs +++ b/feather/plugin-host/src/host_calls/component.rs @@ -43,26 +43,36 @@ pub fn entity_get_component( Ok(()) } -struct SetComponentVisitor<'a> { - cx: &'a PluginContext, - entity: Entity, - bytes_ptr: PluginPtr, - bytes_len: u32, +pub(crate) struct InsertComponentVisitor<'a> { + pub cx: &'a PluginContext, + pub bytes_ptr: PluginPtr, + pub bytes_len: u32, + pub action: SetComponentAction, +} + +pub(crate) enum SetComponentAction { + SetComponent(Entity), + AddEntityEvent(Entity), + AddEvent, } -impl<'a> ComponentVisitor> for SetComponentVisitor<'a> { +impl<'a> ComponentVisitor> for InsertComponentVisitor<'a> { fn visit(self) -> anyhow::Result<()> { let component = self .cx .read_component::(self.bytes_ptr, self.bytes_len)?; let mut game = self.cx.game_mut(); - let existing_component = game.ecs.get_mut::(self.entity); - if let Ok(mut existing_component) = existing_component { - *existing_component = component; - } else { - drop(existing_component); - let _ = game.ecs.insert(self.entity, component); + match self.action { + SetComponentAction::SetComponent(entity) => { + let _ = game.ecs.insert(entity, component); + } + SetComponentAction::AddEntityEvent(entity) => { + let _ = game.ecs.insert_entity_event(entity, component); + } + SetComponentAction::AddEvent => { + game.ecs.insert_event(component); + } } Ok(()) @@ -79,11 +89,11 @@ pub fn entity_set_component( ) -> anyhow::Result<()> { let entity = Entity::from_bits(entity); let component = HostComponent::from_u32(component).context("invalid component")?; - let visitor = SetComponentVisitor { + let visitor = InsertComponentVisitor { cx, - entity, bytes_ptr, bytes_len, + action: SetComponentAction::SetComponent(entity), }; component.visit(visitor) } diff --git a/feather/plugin-host/src/host_calls/event.rs b/feather/plugin-host/src/host_calls/event.rs new file mode 100644 index 000000000..649ffce65 --- /dev/null +++ b/feather/plugin-host/src/host_calls/event.rs @@ -0,0 +1,42 @@ +use crate::context::{PluginContext, PluginPtr}; +use crate::host_calls::component::{InsertComponentVisitor, SetComponentAction}; +use anyhow::Context; +use feather_ecs::Entity; +use feather_plugin_host_macros::host_function; +use quill_common::HostComponent; + +#[host_function] +pub fn entity_add_event( + cx: &PluginContext, + entity: u64, + event: u32, + bytes_ptr: PluginPtr, + bytes_len: u32, +) -> anyhow::Result<()> { + let entity = Entity::from_bits(entity); + let event = HostComponent::from_u32(event).context("invalid component")?; + let visitor = InsertComponentVisitor { + cx, + bytes_ptr, + bytes_len, + action: SetComponentAction::AddEntityEvent(entity), + }; + event.visit(visitor) +} + +#[host_function] +pub fn add_event( + cx: &PluginContext, + event: u32, + bytes_ptr: PluginPtr, + bytes_len: u32, +) -> anyhow::Result<()> { + let event = HostComponent::from_u32(event).context("invalid component")?; + let visitor = InsertComponentVisitor { + cx, + bytes_ptr, + bytes_len, + action: SetComponentAction::AddEvent, + }; + event.visit(visitor) +} diff --git a/quill/api/src/entity.rs b/quill/api/src/entity.rs index cd6217e09..5d2ddcaa7 100644 --- a/quill/api/src/entity.rs +++ b/quill/api/src/entity.rs @@ -89,6 +89,24 @@ impl Entity { } } + /// Inserts an event to the entity. + /// + /// If the entity already has this event, + /// the event is overwritten. + pub fn insert_event(&self, event: T) { + let host_component = T::host_component(); + let bytes = event.to_cow_bytes(); + + unsafe { + quill_sys::entity_add_event( + self.id.0, + host_component, + bytes.as_ptr().into(), + bytes.len() as u32, + ); + } + } + /// Sends the given message to this entity. /// /// The message sends as a "system" message. diff --git a/quill/api/src/game.rs b/quill/api/src/game.rs index 9a72ab982..7fd5657c8 100644 --- a/quill/api/src/game.rs +++ b/quill/api/src/game.rs @@ -4,6 +4,7 @@ use libcraft_blocks::BlockState; use libcraft_core::{BlockPosition, ChunkPosition, Position, CHUNK_HEIGHT}; use libcraft_particles::Particle; use quill_common::entity_init::EntityInit; +use quill_common::Component; use crate::{ query::{Query, QueryIter}, @@ -218,6 +219,16 @@ impl Game { ) } } + + /// Inserts an event to the world. + pub fn insert_event(&self, event: T) { + let host_component = T::host_component(); + let bytes = event.to_cow_bytes(); + + unsafe { + quill_sys::add_event(host_component, bytes.as_ptr().into(), bytes.len() as u32); + } + } } fn check_y_bound(pos: BlockPosition) -> Result<(), BlockAccessError> { diff --git a/quill/sys/src/lib.rs b/quill/sys/src/lib.rs index e33eebb15..c0b6d8f79 100644 --- a/quill/sys/src/lib.rs +++ b/quill/sys/src/lib.rs @@ -76,7 +76,6 @@ extern "C" { /// component. /// /// This will overwrite any existing component of the same type. - /// /// Does nothing if `entity` does not exist. pub fn entity_set_component( entity: EntityId, @@ -85,6 +84,26 @@ extern "C" { bytes_len: u32, ); + /// Adds an event for an entity. + /// + /// `bytes_ptr` is a pointer to the serialized + /// event. + /// + /// This will overwrite any existing event of the same type. + /// Does nothing if `entity` does not exist. + pub fn entity_add_event( + entity: EntityId, + event: HostComponent, + bytes_ptr: Pointer, + bytes_len: u32, + ); + + /// Adds a global event. + /// + /// `bytes_ptr` is a pointer to the serialized + /// component. + pub fn add_event(event: HostComponent, bytes_ptr: Pointer, bytes_len: u32); + /// Sends a message to an entity. /// /// The given message should be in the JSON format.