Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -88,6 +88,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