Skip to content

Commit

Permalink
Add events to quill API (#522)
Browse files Browse the repository at this point in the history
* Add events to quill API

* Split it into 3 host calls

* format
  • Loading branch information
Iaiao authored Jan 25, 2022
1 parent eaffe46 commit 4d756b3
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 15 deletions.
4 changes: 4 additions & 0 deletions feather/plugin-host/src/host_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod block;
mod component;
mod entity;
mod entity_builder;
mod event;
mod plugin_message;
mod query;
mod system;
Expand Down Expand Up @@ -49,6 +50,7 @@ use block::*;
use component::*;
use entity::*;
use entity_builder::*;
use event::*;
use plugin_message::*;
use query::*;
use system::*;
Expand All @@ -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,
Expand Down
38 changes: 24 additions & 14 deletions feather/plugin-host/src/host_calls/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,36 @@ pub fn entity_get_component(
Ok(())
}

struct SetComponentVisitor<'a> {
cx: &'a PluginContext,
entity: Entity,
bytes_ptr: PluginPtr<u8>,
bytes_len: u32,
pub(crate) struct InsertComponentVisitor<'a> {
pub cx: &'a PluginContext,
pub bytes_ptr: PluginPtr<u8>,
pub bytes_len: u32,
pub action: SetComponentAction,
}

pub(crate) enum SetComponentAction {
SetComponent(Entity),
AddEntityEvent(Entity),
AddEvent,
}

impl<'a> ComponentVisitor<anyhow::Result<()>> for SetComponentVisitor<'a> {
impl<'a> ComponentVisitor<anyhow::Result<()>> for InsertComponentVisitor<'a> {
fn visit<T: quill_common::Component>(self) -> anyhow::Result<()> {
let component = self
.cx
.read_component::<T>(self.bytes_ptr, self.bytes_len)?;
let mut game = self.cx.game_mut();

let existing_component = game.ecs.get_mut::<T>(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(())
Expand All @@ -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)
}
42 changes: 42 additions & 0 deletions feather/plugin-host/src/host_calls/event.rs
Original file line number Diff line number Diff line change
@@ -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<u8>,
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<u8>,
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)
}
18 changes: 18 additions & 0 deletions quill/api/src/entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: Component>(&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.
Expand Down
11 changes: 11 additions & 0 deletions quill/api/src/game.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -218,6 +219,16 @@ impl Game {
)
}
}

/// Inserts an event to the world.
pub fn insert_event<T: Component>(&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> {
Expand Down
21 changes: 20 additions & 1 deletion quill/sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<u8>,
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<u8>, bytes_len: u32);

/// Sends a message to an entity.
///
/// The given message should be in the JSON format.
Expand Down

0 comments on commit 4d756b3

Please sign in to comment.