mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add fundamentals for wiring system.
This commit is contained in:
parent
247ed4d78a
commit
7faa0d3cd9
@ -51,6 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Lift is now calculated for gliders based on dimensions (currently same for all)
|
||||
- Specific music tracks can now play exclusively in towns.
|
||||
- Custom map markers can be placed now
|
||||
- Fundamentals/prototype for wiring system
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -94,6 +94,7 @@ pub enum ChatCommand {
|
||||
Unban,
|
||||
Version,
|
||||
Waypoint,
|
||||
Wiring,
|
||||
Whitelist,
|
||||
World,
|
||||
}
|
||||
@ -157,6 +158,7 @@ pub static CHAT_COMMANDS: &[ChatCommand] = &[
|
||||
ChatCommand::Unban,
|
||||
ChatCommand::Version,
|
||||
ChatCommand::Waypoint,
|
||||
ChatCommand::Wiring,
|
||||
ChatCommand::Whitelist,
|
||||
ChatCommand::World,
|
||||
];
|
||||
@ -529,6 +531,7 @@ impl ChatCommand {
|
||||
ChatCommand::Waypoint => {
|
||||
cmd(vec![], "Set your waypoint to your current position", Admin)
|
||||
},
|
||||
ChatCommand::Wiring => cmd(vec![], "Create wiring element", Admin),
|
||||
ChatCommand::Whitelist => cmd(
|
||||
vec![Any("add/remove", Required), Any("username", Required)],
|
||||
"Adds/removes username to whitelist",
|
||||
@ -602,6 +605,7 @@ impl ChatCommand {
|
||||
ChatCommand::Unban => "unban",
|
||||
ChatCommand::Version => "version",
|
||||
ChatCommand::Waypoint => "waypoint",
|
||||
ChatCommand::Wiring => "wiring",
|
||||
ChatCommand::Whitelist => "whitelist",
|
||||
ChatCommand::World => "world",
|
||||
}
|
||||
|
@ -39,11 +39,13 @@ use core::{convert::TryFrom, ops::Not, time::Duration};
|
||||
use hashbrown::HashSet;
|
||||
use rand::Rng;
|
||||
use specs::{Builder, Entity as EcsEntity, Join, WorldExt};
|
||||
use wiring::{Circuit, Wire, WiringAction, WiringActionEffect, WiringElement};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use vek::*;
|
||||
use world::util::Sampler;
|
||||
|
||||
use crate::{client::Client, login_provider::LoginProvider};
|
||||
use crate::{client::Client, login_provider::LoginProvider, wiring};
|
||||
use scan_fmt::{scan_fmt, scan_fmt_some};
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
@ -149,6 +151,7 @@ fn get_handler(cmd: &ChatCommand) -> CommandHandler {
|
||||
ChatCommand::Unban => handle_unban,
|
||||
ChatCommand::Version => handle_version,
|
||||
ChatCommand::Waypoint => handle_waypoint,
|
||||
ChatCommand::Wiring => handle_spawn_wiring,
|
||||
ChatCommand::Whitelist => handle_whitelist,
|
||||
ChatCommand::World => handle_world,
|
||||
}
|
||||
@ -1702,6 +1705,102 @@ fn handle_waypoint(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_spawn_wiring(
|
||||
server: &mut Server,
|
||||
client: EcsEntity,
|
||||
target: EcsEntity,
|
||||
_args: String,
|
||||
_action: &ChatCommand,
|
||||
) -> CmdResult<()> {
|
||||
// Obviously it is a WIP - use it for debug
|
||||
|
||||
let mut pos = position(server, target, "target")?;
|
||||
pos.0.z += 1.0;
|
||||
pos.0.x += 3.0;
|
||||
|
||||
let mut outputs1 = HashMap::new();
|
||||
outputs1.insert(String::from("color"), wiring::OutputFormula::OnCollide {
|
||||
value: 1.0,
|
||||
});
|
||||
|
||||
let builder1 = server
|
||||
.state
|
||||
.create_wiring(pos, comp::object::Body::Coins, WiringElement {
|
||||
actions: vec![WiringAction {
|
||||
formula: wiring::OutputFormula::Constant { value: 1.0 },
|
||||
threshold: 1.0,
|
||||
effects: vec![WiringActionEffect::SetLight {
|
||||
r: wiring::OutputFormula::Input {
|
||||
name: String::from("color"),
|
||||
},
|
||||
g: wiring::OutputFormula::Input {
|
||||
name: String::from("color"),
|
||||
},
|
||||
b: wiring::OutputFormula::Input {
|
||||
name: String::from("color"),
|
||||
},
|
||||
}],
|
||||
}],
|
||||
inputs: HashMap::new(),
|
||||
outputs: outputs1,
|
||||
});
|
||||
let ent1 = builder1.build();
|
||||
|
||||
pos.0.x += 3.0;
|
||||
let builder2 = server
|
||||
.state
|
||||
.create_wiring(pos, comp::object::Body::Coins, WiringElement {
|
||||
actions: vec![WiringAction {
|
||||
formula: wiring::OutputFormula::Input {
|
||||
name: String::from("color"),
|
||||
},
|
||||
threshold: 1.0,
|
||||
effects: vec![
|
||||
// Another demo:
|
||||
// WiringActionEffect::SetLight {
|
||||
// r: wiring::OutputFormula::Input { name: String::from("color") },
|
||||
// g: wiring::OutputFormula::Input { name: String::from("color") },
|
||||
// b: wiring::OutputFormula::Input { name: String::from("color") }
|
||||
// },
|
||||
WiringActionEffect::SpawnProjectile {
|
||||
constr: comp::ProjectileConstructor::Arrow {
|
||||
damage: 1.0,
|
||||
energy_regen: 0.0,
|
||||
knockback: 0.0,
|
||||
},
|
||||
},
|
||||
],
|
||||
}],
|
||||
inputs: HashMap::new(),
|
||||
outputs: HashMap::new(),
|
||||
});
|
||||
let ent2 = builder2.build();
|
||||
|
||||
pos.0.x += 3.0;
|
||||
let builder3 = server
|
||||
.state
|
||||
.create_wiring(pos, comp::object::Body::TrainingDummy, WiringElement {
|
||||
actions: vec![],
|
||||
inputs: HashMap::new(),
|
||||
outputs: HashMap::new(),
|
||||
})
|
||||
.with(Circuit {
|
||||
wires: vec![Wire {
|
||||
input_entity: ent1,
|
||||
input_field: String::from("color"),
|
||||
output_entity: ent2,
|
||||
output_field: String::from("color"),
|
||||
}],
|
||||
});
|
||||
builder3.build();
|
||||
|
||||
server.notify_client(
|
||||
client,
|
||||
ServerGeneral::server_msg(ChatType::CommandInfo, "Wire"),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_conversion)] // TODO: Pending review in #587
|
||||
fn handle_adminify(
|
||||
server: &mut Server,
|
||||
|
@ -30,6 +30,7 @@ pub mod settings;
|
||||
pub mod state_ext;
|
||||
pub mod sys;
|
||||
#[cfg(not(feature = "worldgen"))] mod test_world;
|
||||
pub mod wiring;
|
||||
|
||||
// Reexports
|
||||
pub use crate::{
|
||||
@ -242,6 +243,8 @@ impl Server {
|
||||
state.ecs_mut().register::<RegionSubscription>();
|
||||
state.ecs_mut().register::<Client>();
|
||||
state.ecs_mut().register::<Presence>();
|
||||
state.ecs_mut().register::<wiring::WiringElement>();
|
||||
state.ecs_mut().register::<wiring::Circuit>();
|
||||
state.ecs_mut().register::<comp::HomeChunk>();
|
||||
state.ecs_mut().register::<login_provider::PendingLogin>();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
client::Client, persistence::PersistedComponents, presence::Presence, settings::Settings,
|
||||
sys::sentinel::DeletedEntities, SpawnPoint,
|
||||
sys::sentinel::DeletedEntities, wiring, SpawnPoint,
|
||||
};
|
||||
use common::{
|
||||
character::CharacterId,
|
||||
@ -76,6 +76,12 @@ pub trait StateExt {
|
||||
) -> EcsEntityBuilder;
|
||||
/// Creates a safezone
|
||||
fn create_safezone(&mut self, range: Option<f32>, pos: comp::Pos) -> EcsEntityBuilder;
|
||||
fn create_wiring(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
object: comp::object::Body,
|
||||
wiring_element: wiring::WiringElement,
|
||||
) -> EcsEntityBuilder;
|
||||
// NOTE: currently only used for testing
|
||||
/// Queues chunk generation in the view distance of the persister, this
|
||||
/// entity must be built before those chunks are received (the builder
|
||||
@ -347,6 +353,34 @@ impl StateExt for State {
|
||||
)]))
|
||||
}
|
||||
|
||||
fn create_wiring(
|
||||
&mut self,
|
||||
pos: comp::Pos,
|
||||
object: comp::object::Body,
|
||||
wiring_element: wiring::WiringElement,
|
||||
) -> EcsEntityBuilder {
|
||||
self.ecs_mut()
|
||||
.create_entity_synced()
|
||||
.with(pos)
|
||||
.with(comp::Vel(Vec3::zero()))
|
||||
.with(comp::Ori::default())
|
||||
.with(comp::Collider::Box {
|
||||
radius: comp::Body::Object(object).radius(),
|
||||
z_min: 0.0,
|
||||
z_max: comp::Body::Object(object).height()
|
||||
})
|
||||
.with(comp::Body::Object(object))
|
||||
.with(comp::Mass(10.0))
|
||||
// .with(comp::Sticky)
|
||||
.with(wiring_element)
|
||||
.with(comp::LightEmitter {
|
||||
col: Rgb::new(0.0, 0.0, 0.0),
|
||||
strength: 2.0,
|
||||
flicker: 1.0,
|
||||
animated: true,
|
||||
})
|
||||
}
|
||||
|
||||
// NOTE: currently only used for testing
|
||||
/// Queues chunk generation in the view distance of the persister, this
|
||||
/// entity must be built before those chunks are received (the builder
|
||||
|
@ -10,6 +10,7 @@ pub mod subscription;
|
||||
pub mod terrain;
|
||||
pub mod terrain_sync;
|
||||
pub mod waypoint;
|
||||
pub mod wiring;
|
||||
|
||||
use common_ecs::{dispatch, run_now, System};
|
||||
use common_systems::{melee, projectile};
|
||||
@ -30,6 +31,7 @@ pub fn add_server_systems(dispatch_builder: &mut DispatcherBuilder) {
|
||||
dispatch::<invite_timeout::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<persistence::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<object::Sys>(dispatch_builder, &[]);
|
||||
dispatch::<wiring::Sys>(dispatch_builder, &[]);
|
||||
}
|
||||
|
||||
pub fn run_sync_systems(ecs: &mut specs::World) {
|
||||
|
75
server/src/sys/wiring.rs
Normal file
75
server/src/sys/wiring.rs
Normal file
@ -0,0 +1,75 @@
|
||||
use crate::wiring::{Circuit, WiringElement};
|
||||
use common::{
|
||||
comp::{LightEmitter, PhysicsState},
|
||||
event::{EventBus, ServerEvent},
|
||||
};
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
use hashbrown::HashMap;
|
||||
use specs::{
|
||||
join::Join, shred::ResourceId, Entities, Entity, Read, ReadStorage, SystemData, World,
|
||||
WriteStorage,
|
||||
};
|
||||
mod compute_outputs;
|
||||
use compute_outputs::compute_outputs;
|
||||
mod dispatch_actions;
|
||||
use dispatch_actions::dispatch_actions;
|
||||
|
||||
#[derive(SystemData)]
|
||||
pub struct WiringData<'a> {
|
||||
pub entities: Entities<'a>,
|
||||
pub event_bus: Read<'a, EventBus<ServerEvent>>,
|
||||
pub circuits: ReadStorage<'a, Circuit>,
|
||||
pub wiring_elements: WriteStorage<'a, WiringElement>,
|
||||
pub light_emitters: WriteStorage<'a, LightEmitter>,
|
||||
pub physics_states: ReadStorage<'a, PhysicsState>,
|
||||
}
|
||||
|
||||
/// This system is responsible for handling wiring (signals and wiring systems)
|
||||
#[derive(Default)]
|
||||
pub struct Sys;
|
||||
impl<'a> System<'a> for Sys {
|
||||
type SystemData = WiringData<'a>;
|
||||
|
||||
const NAME: &'static str = "wiring";
|
||||
const ORIGIN: Origin = Origin::Server;
|
||||
const PHASE: Phase = Phase::Create;
|
||||
|
||||
fn run(_job: &mut Job<Self>, mut system_data: Self::SystemData) {
|
||||
// Calculate new outputs using inputs (those inputs are calculated and populated
|
||||
// in previous tick) Take inputs and wiring_element.outputs and with
|
||||
// that compute new outputs
|
||||
let computed_outputs = compute_outputs(&system_data);
|
||||
// Pass new outputs as inputs for the next tick
|
||||
dispatch_circuit_transport(&computed_outputs, &mut system_data);
|
||||
// Using inputs dispatch actions
|
||||
dispatch_actions(&mut system_data);
|
||||
}
|
||||
}
|
||||
|
||||
fn dispatch_circuit_transport<'a>(
|
||||
computed_outputs: &HashMap<Entity, HashMap<String, f32>>,
|
||||
system_data: &mut WiringData<'a>,
|
||||
) {
|
||||
let WiringData {
|
||||
circuits,
|
||||
wiring_elements,
|
||||
..
|
||||
} = system_data;
|
||||
|
||||
(circuits)
|
||||
.join()
|
||||
.map(|circuit| circuit.wires.iter())
|
||||
.flatten()
|
||||
.for_each(|wire| {
|
||||
let input_value = computed_outputs
|
||||
.get(&wire.input_entity)
|
||||
.and_then(|e| e.get(&wire.input_field))
|
||||
.unwrap_or(&0.0);
|
||||
|
||||
if let Some(wiring_element) = wiring_elements.get_mut(wire.output_entity) {
|
||||
wiring_element
|
||||
.inputs
|
||||
.insert(wire.output_field.clone(), *input_value);
|
||||
}
|
||||
});
|
||||
}
|
94
server/src/sys/wiring/compute_outputs.rs
Normal file
94
server/src/sys/wiring/compute_outputs.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use super::WiringData;
|
||||
use crate::wiring::OutputFormula;
|
||||
use common::comp::PhysicsState;
|
||||
use hashbrown::HashMap;
|
||||
use specs::{join::Join, Entity, ReadStorage};
|
||||
use tracing::warn;
|
||||
|
||||
pub fn compute_outputs(system_data: &WiringData) -> HashMap<Entity, HashMap<String, f32>> {
|
||||
let WiringData {
|
||||
entities,
|
||||
wiring_elements,
|
||||
physics_states,
|
||||
..
|
||||
} = system_data;
|
||||
(&*entities, wiring_elements)
|
||||
.join()
|
||||
.map(|(entity, wiring_element)| {
|
||||
(
|
||||
entity,
|
||||
wiring_element
|
||||
.outputs
|
||||
.iter()
|
||||
.map(
|
||||
|(key, output_formula)| {
|
||||
compute_output_with_key(
|
||||
key,
|
||||
output_formula,
|
||||
&wiring_element.inputs,
|
||||
entity,
|
||||
physics_states,
|
||||
)
|
||||
}, // (String, f32)
|
||||
)
|
||||
.collect::<HashMap<_, _>>(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn compute_output_with_key(
|
||||
// yes, this function is defined only to make one place
|
||||
// look a bit nicer
|
||||
// Don't discuss.
|
||||
key: &str,
|
||||
output_formula: &OutputFormula,
|
||||
inputs: &HashMap<String, f32>,
|
||||
entity: Entity,
|
||||
physics_states: &ReadStorage<PhysicsState>,
|
||||
) -> (String, f32) {
|
||||
(
|
||||
key.to_string(),
|
||||
compute_output(output_formula, inputs, entity, physics_states),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn compute_output(
|
||||
output_formula: &OutputFormula,
|
||||
inputs: &HashMap<String, f32>,
|
||||
entity: Entity,
|
||||
physics_states: &ReadStorage<PhysicsState>,
|
||||
) -> f32 {
|
||||
match output_formula {
|
||||
OutputFormula::Constant { value } => *value,
|
||||
OutputFormula::Input { name } => *inputs.get(name).unwrap_or(&0.0),
|
||||
OutputFormula::Logic(_logic) => {
|
||||
warn!("Not implemented OutputFormula::Logic");
|
||||
0.0
|
||||
},
|
||||
OutputFormula::SineWave { .. } => {
|
||||
warn!("Not implemented OutputFormula::SineWave");
|
||||
0.0
|
||||
},
|
||||
OutputFormula::OnCollide { value } => {
|
||||
output_formula_on_collide(value, entity, physics_states)
|
||||
},
|
||||
OutputFormula::OnInteract { .. } => {
|
||||
warn!("Not implemented OutputFormula::OnInteract");
|
||||
0.0
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn output_formula_on_collide(
|
||||
value: &f32,
|
||||
entity: Entity,
|
||||
physics_states: &ReadStorage<PhysicsState>,
|
||||
) -> f32 {
|
||||
if let Some(ps) = physics_states.get(entity) {
|
||||
if !ps.touch_entities.is_empty() {
|
||||
return *value;
|
||||
}
|
||||
}
|
||||
0.0
|
||||
}
|
111
server/src/sys/wiring/dispatch_actions.rs
Normal file
111
server/src/sys/wiring/dispatch_actions.rs
Normal file
@ -0,0 +1,111 @@
|
||||
use super::{compute_outputs::compute_output, WiringData};
|
||||
use crate::wiring::{OutputFormula, WiringActionEffect};
|
||||
use common::{
|
||||
comp::{object, Body, LightEmitter, PhysicsState, ProjectileConstructor},
|
||||
event::{Emitter, ServerEvent},
|
||||
util::Dir,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use specs::{join::Join, Entity, ReadStorage, WriteStorage};
|
||||
use tracing::warn;
|
||||
use vek::Rgb;
|
||||
|
||||
pub fn dispatch_actions(system_data: &mut WiringData) {
|
||||
let WiringData {
|
||||
entities,
|
||||
event_bus,
|
||||
wiring_elements,
|
||||
light_emitters,
|
||||
physics_states,
|
||||
..
|
||||
} = system_data;
|
||||
let mut server_emitter = event_bus.emitter();
|
||||
|
||||
(&*entities, wiring_elements)
|
||||
.join()
|
||||
.for_each(|(entity, wiring_element)| {
|
||||
wiring_element
|
||||
.actions
|
||||
.iter()
|
||||
.filter(|wiring_action| {
|
||||
compute_output(
|
||||
&wiring_action.formula,
|
||||
&wiring_element.inputs,
|
||||
entity,
|
||||
physics_states,
|
||||
) >= wiring_action.threshold
|
||||
})
|
||||
.for_each(|wiring_action| {
|
||||
dispatch_action(
|
||||
entity,
|
||||
&wiring_element.inputs,
|
||||
&wiring_action.effects,
|
||||
&mut server_emitter,
|
||||
light_emitters,
|
||||
physics_states,
|
||||
);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn dispatch_action(
|
||||
entity: Entity,
|
||||
source: &HashMap<String, f32>,
|
||||
action_effects: &[WiringActionEffect],
|
||||
|
||||
server_emitter: &mut Emitter<ServerEvent>,
|
||||
light_emitters: &mut WriteStorage<LightEmitter>,
|
||||
physics_states: &ReadStorage<PhysicsState>,
|
||||
) {
|
||||
action_effects
|
||||
.iter()
|
||||
.for_each(|action_effect| match action_effect {
|
||||
WiringActionEffect::SetBlockCollidability { .. } => {
|
||||
warn!("Not implemented WiringActionEffect::SetBlockCollidability")
|
||||
},
|
||||
WiringActionEffect::SpawnProjectile { constr } => {
|
||||
dispatch_action_spawn_projectile(entity, constr, server_emitter)
|
||||
},
|
||||
WiringActionEffect::SetLight { r, g, b } => {
|
||||
dispatch_action_set_light(entity, source, r, g, b, light_emitters, physics_states)
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
fn dispatch_action_spawn_projectile(
|
||||
entity: Entity,
|
||||
constr: &ProjectileConstructor,
|
||||
server_emitter: &mut Emitter<ServerEvent>,
|
||||
) {
|
||||
// Use match here if there will be more options
|
||||
// NOTE: constr in RFC is about Arrow projectile
|
||||
server_emitter.emit(ServerEvent::Shoot {
|
||||
entity,
|
||||
dir: Dir::forward(),
|
||||
body: Body::Object(object::Body::Arrow),
|
||||
projectile: constr.create_projectile(None, 1.0, 1.0),
|
||||
light: None,
|
||||
speed: 5.0,
|
||||
object: None,
|
||||
});
|
||||
}
|
||||
|
||||
fn dispatch_action_set_light(
|
||||
entity: Entity,
|
||||
source: &HashMap<String, f32>,
|
||||
r: &OutputFormula,
|
||||
g: &OutputFormula,
|
||||
b: &OutputFormula,
|
||||
|
||||
light_emitters: &mut WriteStorage<LightEmitter>,
|
||||
physics_states: &ReadStorage<PhysicsState>,
|
||||
) {
|
||||
let mut light_emitter = light_emitters.get_mut(entity).unwrap();
|
||||
|
||||
// TODO: make compute_output accept multiple formulas
|
||||
let computed_r = compute_output(r, source, entity, physics_states);
|
||||
let computed_g = compute_output(g, source, entity, physics_states);
|
||||
let computed_b = compute_output(b, source, entity, physics_states);
|
||||
|
||||
light_emitter.col = Rgb::new(computed_r, computed_g, computed_b);
|
||||
}
|
74
server/src/wiring.rs
Normal file
74
server/src/wiring.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use common::comp::ProjectileConstructor;
|
||||
use core::f32;
|
||||
use hashbrown::HashMap;
|
||||
use specs::{Component, Entity};
|
||||
use specs_idvs::IdvStorage;
|
||||
use vek::Vec3;
|
||||
|
||||
pub struct Logic {
|
||||
pub kind: LogicKind,
|
||||
pub left: OutputFormula,
|
||||
pub right: OutputFormula,
|
||||
}
|
||||
|
||||
pub struct WiringElement {
|
||||
pub inputs: HashMap<String, f32>,
|
||||
pub outputs: HashMap<String, OutputFormula>,
|
||||
pub actions: Vec<WiringAction>,
|
||||
}
|
||||
|
||||
pub struct Circuit {
|
||||
pub wires: Vec<Wire>,
|
||||
}
|
||||
|
||||
pub enum OutputFormula {
|
||||
Constant { value: f32 },
|
||||
Input { name: String },
|
||||
Logic(Box<Logic>),
|
||||
|
||||
SineWave { amplitude: f32, frequency: f32 },
|
||||
OnCollide { value: f32 },
|
||||
OnInteract { value: f32 },
|
||||
}
|
||||
|
||||
pub enum LogicKind {
|
||||
Min, // acts like And
|
||||
Max, // acts like Or
|
||||
Sub, // `|x| { 5.0 - x }` acts like Not, depending on reference voltages
|
||||
}
|
||||
|
||||
pub struct WiringAction {
|
||||
pub formula: OutputFormula,
|
||||
pub threshold: f32,
|
||||
pub effects: Vec<WiringActionEffect>,
|
||||
}
|
||||
|
||||
pub enum WiringActionEffect {
|
||||
SpawnProjectile {
|
||||
constr: ProjectileConstructor,
|
||||
},
|
||||
SetBlockCollidability {
|
||||
coords: Vec3<i32>,
|
||||
collidable: bool,
|
||||
},
|
||||
SetLight {
|
||||
r: OutputFormula,
|
||||
g: OutputFormula,
|
||||
b: OutputFormula,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Wire {
|
||||
pub input_field: String,
|
||||
pub output_field: String,
|
||||
pub input_entity: Entity,
|
||||
pub output_entity: Entity,
|
||||
}
|
||||
|
||||
impl Component for WiringElement {
|
||||
type Storage = IdvStorage<Self>;
|
||||
}
|
||||
|
||||
impl Component for Circuit {
|
||||
type Storage = IdvStorage<Self>;
|
||||
}
|
Loading…
Reference in New Issue
Block a user