Create an early scripting engine #2
|
@ -45,6 +45,15 @@ dependencies = [
|
||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
version = "0.2.16"
|
version = "0.2.16"
|
||||||
|
@ -1558,11 +1567,13 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"elua",
|
"elua",
|
||||||
"itertools 0.12.0",
|
"itertools 0.12.0",
|
||||||
|
"lazy_static",
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
"lyra-game",
|
"lyra-game",
|
||||||
"lyra-reflect",
|
"lyra-reflect",
|
||||||
"lyra-resource",
|
"lyra-resource",
|
||||||
"lyra-scripting-derive",
|
"lyra-scripting-derive",
|
||||||
|
"regex",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
@ -2204,6 +2215,35 @@ dependencies = [
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.10.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-automata",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.4.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick",
|
||||||
|
"memchr",
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "renderdoc-sys"
|
name = "renderdoc-sys"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
|
|
@ -6,6 +6,48 @@ function on_init()
|
||||||
|
|
||||||
local e = world:spawn(pos, cube)
|
local e = world:spawn(pos, cube)
|
||||||
print("spawned entity " .. tostring(e))
|
print("spawned entity " .. tostring(e))
|
||||||
|
|
||||||
|
local action_handler_tbl = {
|
||||||
|
layouts = { 0 },
|
||||||
|
actions = {
|
||||||
|
MoveForwardBackward = "Axis",
|
||||||
|
MoveLeftRight = "Axis",
|
||||||
|
MoveUpDown = "Axis",
|
||||||
|
LookLeftRight = "Axis",
|
||||||
|
LookUpDown = "Axis",
|
||||||
|
LookRoll = "Axis",
|
||||||
|
},
|
||||||
|
mappings = {
|
||||||
|
{
|
||||||
|
layout = 0,
|
||||||
|
binds = {
|
||||||
|
MoveForwardBackward = {
|
||||||
|
"key:w=1.0", "key:s=-1.0"
|
||||||
|
},
|
||||||
|
MoveLeftRight = {
|
||||||
|
"key:a=-1.0", "key:d=1.0"
|
||||||
|
},
|
||||||
|
MoveUpDown = {
|
||||||
|
"key:c=1.0", "key:z=-1.0"
|
||||||
|
},
|
||||||
|
LookLeftRight = {
|
||||||
|
"key:left=-1.0", "key:right=1.0",
|
||||||
|
"mouse:axis:x"
|
||||||
|
},
|
||||||
|
LookUpDown = {
|
||||||
|
"key:up=-1.0", "key:down=1.0",
|
||||||
|
"mouse:axis:y",
|
||||||
|
},
|
||||||
|
LookRoll = {
|
||||||
|
"key:e=-1.0", "key:q=1.0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local handler = ActionHandler.new(action_handler_tbl)
|
||||||
|
world:add_resource(handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[ function on_first()
|
--[[ function on_first()
|
||||||
|
@ -25,6 +67,9 @@ function on_update()
|
||||||
|
|
||||||
return t
|
return t
|
||||||
end, Transform)
|
end, Transform)
|
||||||
|
|
||||||
|
--local input = world:resource(Input)
|
||||||
|
--input.
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[ function on_post_update()
|
--[[ function on_post_update()
|
||||||
|
|
|
@ -240,7 +240,7 @@ async fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
let action_handler_plugin = |game: &mut Game| {
|
let action_handler_plugin = |game: &mut Game| {
|
||||||
let action_handler = ActionHandler::new()
|
/* let action_handler = ActionHandler::builder()
|
||||||
.add_layout(LayoutId::from(0))
|
.add_layout(LayoutId::from(0))
|
||||||
|
|
||||||
.add_action(CommonActionLabel::MoveForwardBackward, Action::new(ActionKind::Axis))
|
.add_action(CommonActionLabel::MoveForwardBackward, Action::new(ActionKind::Axis))
|
||||||
|
@ -250,7 +250,7 @@ async fn main() {
|
||||||
.add_action(CommonActionLabel::LookUpDown, Action::new(ActionKind::Axis))
|
.add_action(CommonActionLabel::LookUpDown, Action::new(ActionKind::Axis))
|
||||||
.add_action(CommonActionLabel::LookRoll, Action::new(ActionKind::Axis))
|
.add_action(CommonActionLabel::LookRoll, Action::new(ActionKind::Axis))
|
||||||
|
|
||||||
.add_mapping(ActionMapping::new(LayoutId::from(0), ActionMappingId::from(0))
|
.add_mapping(ActionMapping::builder(LayoutId::from(0), ActionMappingId::from(0))
|
||||||
.bind(CommonActionLabel::MoveForwardBackward, &[
|
.bind(CommonActionLabel::MoveForwardBackward, &[
|
||||||
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
||||||
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0)
|
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0)
|
||||||
|
@ -282,22 +282,9 @@ async fn main() {
|
||||||
.finish()
|
.finish()
|
||||||
);
|
);
|
||||||
|
|
||||||
/* #[allow(unused_variables)]
|
|
||||||
let test_system = |world: &mut World| -> anyhow::Result<()> {
|
|
||||||
let handler = world.get_resource::<ActionHandler>();
|
|
||||||
|
|
||||||
if let Some(alpha) = handler.get_axis_modifier("look_rotate") {
|
|
||||||
debug!("'look_rotate': {alpha}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}; */
|
|
||||||
|
|
||||||
let world = game.world_mut();
|
let world = game.world_mut();
|
||||||
world.add_resource(action_handler);
|
world.add_resource(action_handler);
|
||||||
world.spawn((Vec3::new(0.5, 0.1, 3.0),));
|
game.with_plugin(InputActionPlugin); */
|
||||||
game.with_plugin(InputActionPlugin);
|
|
||||||
//game.with_system("input_test", test_system, &[]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let script_test_plugin = |game: &mut Game| {
|
let script_test_plugin = |game: &mut Game| {
|
||||||
|
@ -322,6 +309,6 @@ async fn main() {
|
||||||
.with_plugin(script_test_plugin)
|
.with_plugin(script_test_plugin)
|
||||||
//.with_plugin(fps_plugin)
|
//.with_plugin(fps_plugin)
|
||||||
.with_plugin(jiggle_plugin)
|
.with_plugin(jiggle_plugin)
|
||||||
.with_plugin(FreeFlyCameraPlugin)
|
//.with_plugin(FreeFlyCameraPlugin)
|
||||||
.run().await;
|
.run().await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -255,7 +255,8 @@ impl World {
|
||||||
/// Will panic if the resource is not in the world. See [`try_get_resource`] for
|
/// Will panic if the resource is not in the world. See [`try_get_resource`] for
|
||||||
/// a function that returns an option.
|
/// a function that returns an option.
|
||||||
pub fn get_resource<T: 'static>(&self) -> Ref<T> {
|
pub fn get_resource<T: 'static>(&self) -> Ref<T> {
|
||||||
self.resources.get(&TypeId::of::<T>()).unwrap()
|
self.resources.get(&TypeId::of::<T>())
|
||||||
|
.expect(&format!("World is missing resource of type '{}'", std::any::type_name::<T>()))
|
||||||
.get()
|
.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +278,8 @@ impl World {
|
||||||
/// Will panic if the resource is not in the world. See [`try_get_resource_mut`] for
|
/// Will panic if the resource is not in the world. See [`try_get_resource_mut`] for
|
||||||
/// a function that returns an option.
|
/// a function that returns an option.
|
||||||
pub fn get_resource_mut<T: 'static>(&self) -> RefMut<T> {
|
pub fn get_resource_mut<T: 'static>(&self) -> RefMut<T> {
|
||||||
self.resources.get(&TypeId::of::<T>()).unwrap()
|
self.resources.get(&TypeId::of::<T>())
|
||||||
|
.expect(&format!("World is missing resource of type '{}'", std::any::type_name::<T>()))
|
||||||
.get_mut()
|
.get_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::{collections::HashMap, ops::Deref, hash::{Hash, DefaultHasher, Hasher},
|
||||||
|
|
||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use lyra_ecs::world::World;
|
use lyra_ecs::world::World;
|
||||||
|
use lyra_reflect::Reflect;
|
||||||
|
|
||||||
use crate::{plugin::Plugin, game::GameStages, EventQueue};
|
use crate::{plugin::Plugin, game::GameStages, EventQueue};
|
||||||
|
|
||||||
|
@ -213,7 +214,7 @@ impl Action {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct LayoutId(u32);
|
pub struct LayoutId(pub u32);
|
||||||
|
|
||||||
impl From<u32> for LayoutId {
|
impl From<u32> for LayoutId {
|
||||||
fn from(value: u32) -> Self {
|
fn from(value: u32) -> Self {
|
||||||
|
@ -240,7 +241,7 @@ impl Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct ActionMappingId(u32);
|
pub struct ActionMappingId(pub u32);
|
||||||
|
|
||||||
impl From<u32> for ActionMappingId {
|
impl From<u32> for ActionMappingId {
|
||||||
fn from(value: u32) -> Self {
|
fn from(value: u32) -> Self {
|
||||||
|
@ -264,6 +265,10 @@ impl ActionMapping {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn builder(layout: LayoutId, id: ActionMappingId) -> ActionMappingBuilder {
|
||||||
|
ActionMappingBuilder::new(ActionMapping::new(layout, id))
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a binding for the action.
|
/// Creates a binding for the action.
|
||||||
///
|
///
|
||||||
/// If the action is not in this layout, this will panic!
|
/// If the action is not in this layout, this will panic!
|
||||||
|
@ -271,7 +276,7 @@ impl ActionMapping {
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
/// * `action` - The label corresponding to the action in this Layout.
|
/// * `action` - The label corresponding to the action in this Layout.
|
||||||
/// * `bind` - The Binding to add to the Action.
|
/// * `bind` - The Binding to add to the Action.
|
||||||
pub fn bind<L>(mut self, action: L, bindings: &[Binding]) -> Self
|
pub fn bind<L>(&mut self, action: L, bindings: &[Binding]) -> &mut Self
|
||||||
where
|
where
|
||||||
L: ActionLabel
|
L: ActionLabel
|
||||||
{
|
{
|
||||||
|
@ -283,32 +288,48 @@ impl ActionMapping {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates multiple binding for the action.
|
|
||||||
///
|
|
||||||
/// If the action is not in this layout, this will panic!
|
|
||||||
///
|
|
||||||
/// Parameters:
|
|
||||||
/// * `action_label` - The label corresponding to the action in this Layout.
|
|
||||||
/// * `bindings` - The list of Bindings to add to the Action.
|
|
||||||
/* pub fn add_bindings(&mut self, action_label: String, bindings: &[Binding]) -> &mut Self {
|
|
||||||
let mut bindings = bindings.to_vec();
|
|
||||||
let action_binds = self.action_binds.entry(action_label)
|
|
||||||
.or_insert_with(Vec::new);
|
|
||||||
action_binds.append(&mut bindings);
|
|
||||||
|
|
||||||
self
|
|
||||||
} */
|
|
||||||
|
|
||||||
pub fn finish(self) -> Self {
|
pub fn finish(self) -> Self {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
pub struct ActionMappingBuilder {
|
||||||
|
mapping: ActionMapping,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActionMappingBuilder {
|
||||||
|
fn new(mapping: ActionMapping) -> Self {
|
||||||
|
Self {
|
||||||
|
mapping,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind<L>(mut self, action: L, bindings: &[Binding]) -> Self
|
||||||
|
where
|
||||||
|
L: ActionLabel
|
||||||
|
{
|
||||||
|
let mut bindings = bindings.to_vec();
|
||||||
|
|
||||||
|
let action_binds = self.mapping.action_binds.entry(action.label_hash()).or_default();
|
||||||
|
action_binds.append(&mut bindings);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> ActionMapping {
|
||||||
|
self.mapping
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default, Reflect)]
|
||||||
pub struct ActionHandler {
|
pub struct ActionHandler {
|
||||||
|
#[reflect(skip)] // TODO: dont just skip all these
|
||||||
pub actions: HashMap<u64, Action>,
|
pub actions: HashMap<u64, Action>,
|
||||||
|
#[reflect(skip)]
|
||||||
pub layouts: HashMap<LayoutId, Layout>,
|
pub layouts: HashMap<LayoutId, Layout>,
|
||||||
|
#[reflect(skip)]
|
||||||
pub current_layout: LayoutId,
|
pub current_layout: LayoutId,
|
||||||
|
#[reflect(skip)]
|
||||||
pub current_mapping: ActionMappingId,
|
pub current_mapping: ActionMappingId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,26 +338,31 @@ impl ActionHandler {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_layout(mut self, id: LayoutId) -> Self {
|
pub fn builder() -> ActionHandlerBuilder {
|
||||||
self.layouts.insert(id, Layout::new());
|
ActionHandlerBuilder::default()
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_action<L>(mut self, label: L, action: Action) -> Self
|
pub fn add_layout(&mut self, id: LayoutId) {
|
||||||
|
self.layouts.insert(id, Layout::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn action<L>(&self, label: L) -> Option<&Action>
|
||||||
|
where
|
||||||
|
L: ActionLabel
|
||||||
|
{
|
||||||
|
self.actions.get(&label.label_hash())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_action<L>(&mut self, label: L, action: Action)
|
||||||
where
|
where
|
||||||
L: ActionLabel
|
L: ActionLabel
|
||||||
{
|
{
|
||||||
self.actions.insert(label.label_hash(), action);
|
self.actions.insert(label.label_hash(), action);
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_mapping(mut self, mapping: ActionMapping) -> Self {
|
pub fn add_mapping(&mut self, mapping: ActionMapping) {
|
||||||
let layout = self.layouts.get_mut(&mapping.layout).unwrap();
|
let layout = self.layouts.get_mut(&mapping.layout).unwrap();
|
||||||
layout.add_mapping(mapping);
|
layout.add_mapping(mapping);
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the action is pressed (or was just pressed).
|
/// Returns true if the action is pressed (or was just pressed).
|
||||||
|
@ -443,6 +469,43 @@ impl ActionHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct ActionHandlerBuilder {
|
||||||
|
handler: ActionHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActionHandlerBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_layout(mut self, id: LayoutId) -> Self {
|
||||||
|
self.handler.layouts.insert(id, Layout::new());
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_action<L>(mut self, label: L, action: Action) -> Self
|
||||||
|
where
|
||||||
|
L: ActionLabel
|
||||||
|
{
|
||||||
|
self.handler.actions.insert(label.label_hash(), action);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_mapping(mut self, mapping: ActionMapping) -> Self {
|
||||||
|
let layout = self.handler.layouts.get_mut(&mapping.layout).unwrap();
|
||||||
|
layout.add_mapping(mapping);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> ActionHandler {
|
||||||
|
self.handler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn actions_system(world: &mut World) -> anyhow::Result<()> {
|
fn actions_system(world: &mut World) -> anyhow::Result<()> {
|
||||||
let keys = world.try_get_resource::<InputButtons<KeyCode>>()
|
let keys = world.try_get_resource::<InputButtons<KeyCode>>()
|
||||||
.map(|r| r.deref().clone());
|
.map(|r| r.deref().clone());
|
||||||
|
|
|
@ -12,3 +12,181 @@ pub use buttons::*;
|
||||||
|
|
||||||
pub mod action;
|
pub mod action;
|
||||||
pub use action::*;
|
pub use action::*;
|
||||||
|
|
||||||
|
pub type KeyCode = winit::event::VirtualKeyCode;
|
||||||
|
|
||||||
|
/// Parses a [`KeyCode`] from a [`&str`].
|
||||||
|
///
|
||||||
|
/// There are some changes to a few keycodes. All the number keys `Key1`, `Key2`, etc., have
|
||||||
|
/// the `Key` prefix removed; so they are expected to be `1`, `2`, etc.
|
||||||
|
pub fn keycode_from_str(s: &str) -> Option<KeyCode> {
|
||||||
|
let s = s.to_lowercase();
|
||||||
|
let s = s.as_str();
|
||||||
|
|
||||||
|
match s {
|
||||||
|
"1" => Some(KeyCode::Key1),
|
||||||
|
"2" => Some(KeyCode::Key2),
|
||||||
|
"3" => Some(KeyCode::Key3),
|
||||||
|
"4" => Some(KeyCode::Key4),
|
||||||
|
"5" => Some(KeyCode::Key5),
|
||||||
|
"6" => Some(KeyCode::Key6),
|
||||||
|
"7" => Some(KeyCode::Key7),
|
||||||
|
"8" => Some(KeyCode::Key8),
|
||||||
|
"9" => Some(KeyCode::Key9),
|
||||||
|
"0" => Some(KeyCode::Key0),
|
||||||
|
"a" => Some(KeyCode::A),
|
||||||
|
"b" => Some(KeyCode::B),
|
||||||
|
"c" => Some(KeyCode::C),
|
||||||
|
"d" => Some(KeyCode::D),
|
||||||
|
"e" => Some(KeyCode::E),
|
||||||
|
"f" => Some(KeyCode::F),
|
||||||
|
"g" => Some(KeyCode::G),
|
||||||
|
"h" => Some(KeyCode::H),
|
||||||
|
"i" => Some(KeyCode::I),
|
||||||
|
"j" => Some(KeyCode::J),
|
||||||
|
"k" => Some(KeyCode::K),
|
||||||
|
"l" => Some(KeyCode::L),
|
||||||
|
"m" => Some(KeyCode::M),
|
||||||
|
"n" => Some(KeyCode::N),
|
||||||
|
"o" => Some(KeyCode::O),
|
||||||
|
"p" => Some(KeyCode::P),
|
||||||
|
"q" => Some(KeyCode::Q),
|
||||||
|
"r" => Some(KeyCode::R),
|
||||||
|
"s" => Some(KeyCode::S),
|
||||||
|
"t" => Some(KeyCode::T),
|
||||||
|
"u" => Some(KeyCode::U),
|
||||||
|
"v" => Some(KeyCode::V),
|
||||||
|
"w" => Some(KeyCode::W),
|
||||||
|
"x" => Some(KeyCode::X),
|
||||||
|
"y" => Some(KeyCode::Y),
|
||||||
|
"z" => Some(KeyCode::Z),
|
||||||
|
"escape" => Some(KeyCode::Escape),
|
||||||
|
"f1" => Some(KeyCode::F1),
|
||||||
|
"f2" => Some(KeyCode::F2),
|
||||||
|
"f3" => Some(KeyCode::F3),
|
||||||
|
"f4" => Some(KeyCode::F4),
|
||||||
|
"f5" => Some(KeyCode::F5),
|
||||||
|
"f6" => Some(KeyCode::F6),
|
||||||
|
"f7" => Some(KeyCode::F7),
|
||||||
|
"f8" => Some(KeyCode::F8),
|
||||||
|
"f9" => Some(KeyCode::F9),
|
||||||
|
"f10" => Some(KeyCode::F10),
|
||||||
|
"f11" => Some(KeyCode::F11),
|
||||||
|
"f12" => Some(KeyCode::F12),
|
||||||
|
"f13" => Some(KeyCode::F13),
|
||||||
|
"f14" => Some(KeyCode::F14),
|
||||||
|
"f15" => Some(KeyCode::F15),
|
||||||
|
"f16" => Some(KeyCode::F16),
|
||||||
|
"f17" => Some(KeyCode::F17),
|
||||||
|
"f18" => Some(KeyCode::F18),
|
||||||
|
"f19" => Some(KeyCode::F19),
|
||||||
|
"f20" => Some(KeyCode::F20),
|
||||||
|
"f21" => Some(KeyCode::F21),
|
||||||
|
"f22" => Some(KeyCode::F22),
|
||||||
|
"f23" => Some(KeyCode::F23),
|
||||||
|
"f24" => Some(KeyCode::F24),
|
||||||
|
"snapshot" => Some(KeyCode::Snapshot),
|
||||||
|
"scroll" => Some(KeyCode::Scroll),
|
||||||
|
"pause" => Some(KeyCode::Pause),
|
||||||
|
"insert" => Some(KeyCode::Insert),
|
||||||
|
"home" => Some(KeyCode::Home),
|
||||||
|
"delete" => Some(KeyCode::Delete),
|
||||||
|
"end" => Some(KeyCode::End),
|
||||||
|
"pagedown" => Some(KeyCode::PageDown),
|
||||||
|
"pageup" => Some(KeyCode::PageUp),
|
||||||
|
"left" => Some(KeyCode::Left),
|
||||||
|
"up" => Some(KeyCode::Up),
|
||||||
|
"right" => Some(KeyCode::Right),
|
||||||
|
"down" => Some(KeyCode::Down),
|
||||||
|
"back" => Some(KeyCode::Back),
|
||||||
|
"return" => Some(KeyCode::Return),
|
||||||
|
"space" => Some(KeyCode::Space),
|
||||||
|
"compose" => Some(KeyCode::Compose),
|
||||||
|
"caret" => Some(KeyCode::Caret),
|
||||||
|
"numlock" => Some(KeyCode::Numlock),
|
||||||
|
"numpad0" => Some(KeyCode::Numpad0),
|
||||||
|
"numpad1" => Some(KeyCode::Numpad1),
|
||||||
|
"numpad2" => Some(KeyCode::Numpad2),
|
||||||
|
"numpad3" => Some(KeyCode::Numpad3),
|
||||||
|
"numpad4" => Some(KeyCode::Numpad4),
|
||||||
|
"numpad5" => Some(KeyCode::Numpad5),
|
||||||
|
"numpad6" => Some(KeyCode::Numpad6),
|
||||||
|
"numpad7" => Some(KeyCode::Numpad7),
|
||||||
|
"numpad8" => Some(KeyCode::Numpad8),
|
||||||
|
"numpad9" => Some(KeyCode::Numpad9),
|
||||||
|
"numpadadd" => Some(KeyCode::NumpadAdd),
|
||||||
|
"numpaddivide" => Some(KeyCode::NumpadDivide),
|
||||||
|
"numpaddecimal" => Some(KeyCode::NumpadDecimal),
|
||||||
|
"numpadcomma" => Some(KeyCode::NumpadComma),
|
||||||
|
"numpadenter" => Some(KeyCode::NumpadEnter),
|
||||||
|
"numpadequals" => Some(KeyCode::NumpadEquals),
|
||||||
|
"numpadmultiply" => Some(KeyCode::NumpadMultiply),
|
||||||
|
"numpadsubtract" => Some(KeyCode::NumpadSubtract),
|
||||||
|
"abntc1" => Some(KeyCode::AbntC1),
|
||||||
|
"abntc2" => Some(KeyCode::AbntC2),
|
||||||
|
"apostrophe" => Some(KeyCode::Apostrophe),
|
||||||
|
"apps" => Some(KeyCode::Apps),
|
||||||
|
"asterisk" => Some(KeyCode::Asterisk),
|
||||||
|
"at" => Some(KeyCode::At),
|
||||||
|
"ax" => Some(KeyCode::Ax),
|
||||||
|
"backslash" => Some(KeyCode::Backslash),
|
||||||
|
"calculator" => Some(KeyCode::Calculator),
|
||||||
|
"capital" => Some(KeyCode::Capital),
|
||||||
|
"colon" => Some(KeyCode::Colon),
|
||||||
|
"comma" => Some(KeyCode::Comma),
|
||||||
|
"convert" => Some(KeyCode::Convert),
|
||||||
|
"equals" => Some(KeyCode::Equals),
|
||||||
|
"grave" => Some(KeyCode::Grave),
|
||||||
|
"kana" => Some(KeyCode::Kana),
|
||||||
|
"kanji" => Some(KeyCode::Kanji),
|
||||||
|
"lalt" => Some(KeyCode::LAlt),
|
||||||
|
"lbracket" => Some(KeyCode::LBracket),
|
||||||
|
"lcontrol" => Some(KeyCode::LControl),
|
||||||
|
"lshift" => Some(KeyCode::LShift),
|
||||||
|
"lwin" => Some(KeyCode::LWin),
|
||||||
|
"mail" => Some(KeyCode::Mail),
|
||||||
|
"mediaselect" => Some(KeyCode::MediaSelect),
|
||||||
|
"mediastop" => Some(KeyCode::MediaStop),
|
||||||
|
"minus" => Some(KeyCode::Minus),
|
||||||
|
"mute" => Some(KeyCode::Mute),
|
||||||
|
"mycomputer" => Some(KeyCode::MyComputer),
|
||||||
|
"navigateforward" => Some(KeyCode::NavigateForward),
|
||||||
|
"navigatebackward" => Some(KeyCode::NavigateBackward),
|
||||||
|
"nexttrack" => Some(KeyCode::NextTrack),
|
||||||
|
"noconvert" => Some(KeyCode::NoConvert),
|
||||||
|
"oem102" => Some(KeyCode::OEM102),
|
||||||
|
"period" => Some(KeyCode::Period),
|
||||||
|
"playpause" => Some(KeyCode::PlayPause),
|
||||||
|
"plus" => Some(KeyCode::Plus),
|
||||||
|
"power" => Some(KeyCode::Power),
|
||||||
|
"prevtrack" => Some(KeyCode::PrevTrack),
|
||||||
|
"ralt" => Some(KeyCode::RAlt),
|
||||||
|
"rbracket" => Some(KeyCode::RBracket),
|
||||||
|
"rcontrol" => Some(KeyCode::RControl),
|
||||||
|
"rshift" => Some(KeyCode::RShift),
|
||||||
|
"rwin" => Some(KeyCode::RWin),
|
||||||
|
"semicolon" => Some(KeyCode::Semicolon),
|
||||||
|
"slash" => Some(KeyCode::Slash),
|
||||||
|
"sleep" => Some(KeyCode::Sleep),
|
||||||
|
"stop" => Some(KeyCode::Stop),
|
||||||
|
"sysrq" => Some(KeyCode::Sysrq),
|
||||||
|
"tab" => Some(KeyCode::Tab),
|
||||||
|
"underline" => Some(KeyCode::Underline),
|
||||||
|
"unlabeled" => Some(KeyCode::Unlabeled),
|
||||||
|
"volumedown" => Some(KeyCode::VolumeDown),
|
||||||
|
"volumeup" => Some(KeyCode::VolumeUp),
|
||||||
|
"wake" => Some(KeyCode::Wake),
|
||||||
|
"webback" => Some(KeyCode::WebBack),
|
||||||
|
"webfavorites" => Some(KeyCode::WebFavorites),
|
||||||
|
"webforward" => Some(KeyCode::WebForward),
|
||||||
|
"webhome" => Some(KeyCode::WebHome),
|
||||||
|
"webrefresh" => Some(KeyCode::WebRefresh),
|
||||||
|
"websearch" => Some(KeyCode::WebSearch),
|
||||||
|
"webstop" => Some(KeyCode::WebStop),
|
||||||
|
"yen" => Some(KeyCode::Yen),
|
||||||
|
"copy" => Some(KeyCode::Copy),
|
||||||
|
"paste" => Some(KeyCode::Paste),
|
||||||
|
"cut" => Some(KeyCode::Cut),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,8 +8,6 @@ use crate::{EventQueue, plugin::Plugin, game::GameStages};
|
||||||
|
|
||||||
use super::{events::*, InputButtons, InputEvent};
|
use super::{events::*, InputButtons, InputEvent};
|
||||||
|
|
||||||
pub type KeyCode = winit::event::VirtualKeyCode;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct InputSystem;
|
pub struct InputSystem;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{any::TypeId, cell::{Ref, RefMut}, ptr::NonNull};
|
use std::{any::{Any, TypeId}, cell::{Ref, RefMut}, ptr::NonNull};
|
||||||
|
|
||||||
use lyra_ecs::{World, ResourceObject};
|
use lyra_ecs::{World, ResourceObject};
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ pub struct ReflectedResource {
|
||||||
fn_reflect: for<'a> fn (world: &'a World) -> Option<Ref<'a, dyn Reflect>>,
|
fn_reflect: for<'a> fn (world: &'a World) -> Option<Ref<'a, dyn Reflect>>,
|
||||||
fn_reflect_mut: for<'a> fn (world: &'a mut World) -> Option<RefMut<'a, dyn Reflect>>,
|
fn_reflect_mut: for<'a> fn (world: &'a mut World) -> Option<RefMut<'a, dyn Reflect>>,
|
||||||
fn_reflect_ptr: fn (world: &mut World) -> Option<NonNull<u8>>,
|
fn_reflect_ptr: fn (world: &mut World) -> Option<NonNull<u8>>,
|
||||||
|
fn_refl_insert: fn (world: &mut World, this: Box<dyn Reflect>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReflectedResource {
|
impl ReflectedResource {
|
||||||
|
@ -27,6 +28,11 @@ impl ReflectedResource {
|
||||||
pub fn reflect_ptr(&self, world: &mut World) -> Option<NonNull<u8>> {
|
pub fn reflect_ptr(&self, world: &mut World) -> Option<NonNull<u8>> {
|
||||||
(self.fn_reflect_ptr)(world)
|
(self.fn_reflect_ptr)(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert the resource into the world.
|
||||||
|
pub fn insert(&self, world: &mut World, this: Box<dyn Reflect>) {
|
||||||
|
(self.fn_refl_insert)(world, this)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ResourceObject + Reflect> FromType<T> for ReflectedResource {
|
impl<T: ResourceObject + Reflect> FromType<T> for ReflectedResource {
|
||||||
|
@ -45,6 +51,13 @@ impl<T: ResourceObject + Reflect> FromType<T> for ReflectedResource {
|
||||||
world.try_get_resource_ptr::<T>()
|
world.try_get_resource_ptr::<T>()
|
||||||
.map(|ptr| ptr.cast::<u8>())
|
.map(|ptr| ptr.cast::<u8>())
|
||||||
},
|
},
|
||||||
|
fn_refl_insert: |world: &mut World, this: Box<dyn Reflect>| {
|
||||||
|
let res = this as Box<dyn Any>;
|
||||||
|
let res = res.downcast::<T>()
|
||||||
|
.expect("Provided a non-matching type to ReflectedResource insert method!");
|
||||||
|
let res = *res;
|
||||||
|
world.add_resource(res);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,6 +23,8 @@ tracing = "0.1.37"
|
||||||
#mlua = { version = "0.9.2", features = ["lua54"], optional = true } # luajit maybe?
|
#mlua = { version = "0.9.2", features = ["lua54"], optional = true } # luajit maybe?
|
||||||
elua = { path = "./elua", optional = true }
|
elua = { path = "./elua", optional = true }
|
||||||
itertools = "0.12.0"
|
itertools = "0.12.0"
|
||||||
|
regex = "1.10.3"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 70e2985cc44fdb30cdf2157c50d2f0e3385e08fa
|
Subproject commit beea6c33fcb2f5bd16f40e1919b61a89b4aaecb6
|
|
@ -61,6 +61,14 @@ impl ReflectBranch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets self as a [`ReflectedResource`], returning `None` if self is not an instance of it.
|
||||||
|
pub fn as_resource(&self) -> Option<&ReflectedResource> {
|
||||||
|
match self {
|
||||||
|
ReflectBranch::Resource(v) => Some(v),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a boolean indicating if `self` is a reflection of a Resource.
|
/// Returns a boolean indicating if `self` is a reflection of a Resource.
|
||||||
pub fn is_resource(&self) -> bool {
|
pub fn is_resource(&self) -> bool {
|
||||||
matches!(self, ReflectBranch::Resource(_))
|
matches!(self, ReflectBranch::Resource(_))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use lyra_ecs::ResourceObject;
|
use lyra_ecs::ResourceObject;
|
||||||
use lyra_reflect::Reflect;
|
use lyra_reflect::Reflect;
|
||||||
|
|
||||||
use crate::{lua::{wrappers::{LuaDeltaTime, LuaModelComponent}, LuaContext, RegisterLuaType, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
use crate::{lua::{wrappers::{LuaActionHandler, LuaDeltaTime, LuaModelComponent}, LuaContext, RegisterLuaType, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptApiProvider, ScriptBorrow, ScriptData, ScriptDynamicBundle, ScriptWorldPtr};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct LyraEcsApiProvider;
|
pub struct LyraEcsApiProvider;
|
||||||
|
@ -21,6 +21,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
||||||
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
|
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
|
||||||
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
|
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
|
||||||
globals.set("ModelComponent", ctx.create_proxy::<LuaModelComponent>()?)?;
|
globals.set("ModelComponent", ctx.create_proxy::<LuaModelComponent>()?)?;
|
||||||
|
globals.set("ActionHandler", ctx.create_proxy::<LuaActionHandler>()?)?;
|
||||||
|
|
||||||
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
||||||
globals.set("DeltaTime", dt_table)?;
|
globals.set("DeltaTime", dt_table)?;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{ptr::NonNull, sync::Arc};
|
use std::{ptr::NonNull, sync::Arc};
|
||||||
|
|
||||||
use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr};
|
use crate::{ScriptBorrow, ScriptEntity, ScriptWorldPtr};
|
||||||
use elua::AsLua;
|
use elua::{AnyUserdata, AsLua, Table};
|
||||||
use lyra_ecs::{query::dynamic::QueryDynamicType, CommandQueue, Commands, DynamicBundle, World};
|
use lyra_ecs::{query::dynamic::QueryDynamicType, CommandQueue, Commands, DynamicBundle, World};
|
||||||
use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry};
|
use lyra_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry};
|
||||||
use lyra_resource::ResourceManager;
|
use lyra_resource::ResourceManager;
|
||||||
|
@ -279,6 +279,32 @@ impl elua::Userdata for ScriptWorldPtr {
|
||||||
Ok(elua::Value::Nil)
|
Ok(elua::Value::Nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.method_mut("add_resource", |_, this, res: elua::Value| {
|
||||||
|
let reflect = match res {
|
||||||
|
elua::Value::Userdata(ud) => ud
|
||||||
|
.execute_method::<_, ScriptBorrow>(FN_NAME_INTERNAL_REFLECT, ())
|
||||||
|
.expect("Type does not implement 'reflect_type' properly"),
|
||||||
|
elua::Value::Table(t) => {
|
||||||
|
let f: elua::Function = t.get(FN_NAME_INTERNAL_REFLECT)?;
|
||||||
|
f.exec::<_, ScriptBorrow>(())
|
||||||
|
.expect("Type does not implement 'reflect_type' properly")
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
panic!("how");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let data = reflect.data
|
||||||
|
.expect("Its expected that 'FN_NAME_INTERNAL_REFLECT' returns data in World:add_resource");
|
||||||
|
|
||||||
|
let res = reflect.reflect_branch.as_resource()
|
||||||
|
.ok_or(elua::Error::runtime("Provided type is not a resource!"))?;
|
||||||
|
|
||||||
|
let world = this.as_mut();
|
||||||
|
res.insert(world, data);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
.method_mut("request_res", |_, this, path: String| {
|
.method_mut("request_res", |_, this, path: String| {
|
||||||
let world = this.as_mut();
|
let world = this.as_mut();
|
||||||
let mut man = world.get_resource_mut::<ResourceManager>();
|
let mut man = world.get_resource_mut::<ResourceManager>();
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
use lyra_game::input::{keycode_from_str, Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource, LayoutId, MouseAxis, MouseInput};
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::{lua::{FN_NAME_INTERNAL_REFLECT, FN_NAME_INTERNAL_REFLECT_TYPE}, ScriptBorrow};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref BINDING_INPUT_RE: Regex = Regex::new(r"(\w+):(\w+)(?:=(-?\d+(?:.\d+)?))?").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct LuaActionHandler {
|
||||||
|
handler: ActionHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
impl elua::Userdata for LuaActionHandler {
|
||||||
|
fn name() -> String {
|
||||||
|
"ActionHandler".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build<'a>(_: &elua::State, builder: &mut elua::UserdataBuilder<'a, Self>) -> elua::Result<()> {
|
||||||
|
builder.function("new", |_, table: elua::Table| {
|
||||||
|
let mut handler = ActionHandler::new();
|
||||||
|
|
||||||
|
// create the layouts
|
||||||
|
let layouts = table.get::<_, elua::Table>("layouts")
|
||||||
|
.map_err(|_| elua::Error::runtime("missing 'layouts' in ActionHandler table"))?;
|
||||||
|
for layout_id in layouts.sequence_iter::<u32>() {
|
||||||
|
let layout_id = layout_id?;
|
||||||
|
|
||||||
|
handler.add_layout(LayoutId(layout_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
let actions = table.get::<_, elua::Table>("actions")
|
||||||
|
.map_err(|_| elua::Error::runtime("missing 'actions' in ActionHandler table"))?;
|
||||||
|
for pair in actions.pairs::<String, String>() {
|
||||||
|
let (action_lbl, action_type) = pair?;
|
||||||
|
let action_type = action_type.to_lowercase();
|
||||||
|
|
||||||
|
let action_type = match action_type.as_str() {
|
||||||
|
"axis" => ActionKind::Axis,
|
||||||
|
"button" => ActionKind::Button,
|
||||||
|
_ => todo!("Handle invalid axis type"),
|
||||||
|
};
|
||||||
|
|
||||||
|
handler.add_action(action_lbl, Action::new(action_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mappings= table.get::<_, elua::Table>("mappings")
|
||||||
|
.map_err(|_| elua::Error::runtime("missing 'mappings' in ActionHandler table"))?;
|
||||||
|
for (map_id, tbl) in mappings.sequence_iter::<elua::Table>().enumerate() {
|
||||||
|
let tbl = tbl?;
|
||||||
|
|
||||||
|
let layout_id = tbl.get::<_, u32>("layout")?;
|
||||||
|
let mut mapping = ActionMapping::new(LayoutId(layout_id), ActionMappingId(map_id as u32));
|
||||||
|
|
||||||
|
let binds_tbl = tbl.get::<_, elua::Table>("binds")
|
||||||
|
.map_err(|_| elua::Error::runtime("missing 'binds' in ActionHandler 'mappings' table"))?;
|
||||||
|
for pair in binds_tbl.pairs::<String, elua::Table>() {
|
||||||
|
let (action_lbl, input_binds) = pair?;
|
||||||
|
|
||||||
|
for input in input_binds.sequence_iter::<String>() {
|
||||||
|
let input = input?.to_lowercase();
|
||||||
|
|
||||||
|
let action = handler.action(&action_lbl)
|
||||||
|
.ok_or(elua::Error::Runtime(format!("Unknown action specified in mapping binds: {}", action_lbl)))?;
|
||||||
|
|
||||||
|
let mut binds = Vec::new();
|
||||||
|
|
||||||
|
let input_split: Vec<&str> = input.split(":").collect();
|
||||||
|
let input_name = input_split[0];
|
||||||
|
let button = input_split[1];
|
||||||
|
|
||||||
|
if action.kind == ActionKind::Axis {
|
||||||
|
if button == "axis" {
|
||||||
|
let axis_name = input_split[2];
|
||||||
|
|
||||||
|
let src = process_axis_string(input_name, axis_name)
|
||||||
|
.ok_or(elua::Error::Runtime(format!("invalid bind '{input_name}', unable to find device or axis for device")))?;
|
||||||
|
binds.push(src.into_binding());
|
||||||
|
} else {
|
||||||
|
// splits 'down=1' into 'down' and '1'
|
||||||
|
let (button, val_str) = button.split_once("=")
|
||||||
|
.ok_or(elua::Error::Runtime(format!("invalid bind string for Axis Action: '{input}' (expected '=' with float)")))?;
|
||||||
|
|
||||||
|
let val = val_str.parse::<f32>()
|
||||||
|
.map_err(|e| elua::Error::Runtime(format!("invalid bind string for Axis Action: '{input}' ({e})")))?;
|
||||||
|
|
||||||
|
let src = process_keyboard_string(button)
|
||||||
|
.ok_or(elua::Error::Runtime(format!("invalid key in bind: '{button}'")))?;
|
||||||
|
binds.push(src.into_binding_modifier(val));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
todo!("Process bindings for Button Actions");
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping.bind(action_lbl.clone(), &binds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.add_mapping(mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(LuaActionHandler {
|
||||||
|
handler,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.method(FN_NAME_INTERNAL_REFLECT, |_, this, ()| {
|
||||||
|
Ok(ScriptBorrow::from_resource::<ActionHandler>(Some(this.handler.clone())))
|
||||||
|
})
|
||||||
|
.method(FN_NAME_INTERNAL_REFLECT_TYPE, |_, _, ()| {
|
||||||
|
Ok(ScriptBorrow::from_resource::<ActionHandler>(None))
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> elua::FromLua<'a> for LuaActionHandler {
|
||||||
|
fn from_lua(_: &'a elua::State, val: elua::Value<'a>) -> elua::Result<Self> {
|
||||||
|
let tyname = val.type_name();
|
||||||
|
let ud = val.as_userdata()
|
||||||
|
.ok_or(elua::Error::type_mismatch("ActionHandler", &tyname))?;
|
||||||
|
let handle = ud.as_ref::<LuaActionHandler>()?;
|
||||||
|
|
||||||
|
Ok(handle.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_keyboard_string(key_name: &str) -> Option<ActionSource> {
|
||||||
|
let key = keycode_from_str(key_name)?;
|
||||||
|
|
||||||
|
Some(ActionSource::Keyboard(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_axis_string(device: &str, axis_name: &str) -> Option<ActionSource> {
|
||||||
|
match device {
|
||||||
|
"mouse" => match axis_name {
|
||||||
|
"y" => Some(ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y))),
|
||||||
|
"x" => Some(ActionSource::Mouse(MouseInput::Axis(MouseAxis::X))),
|
||||||
|
"scroll" | "scrollwheel" => Some(ActionSource::Mouse(MouseInput::Axis(MouseAxis::ScrollWheel))),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,3 +9,6 @@ pub use res_handle::*;
|
||||||
|
|
||||||
pub mod model_comp;
|
pub mod model_comp;
|
||||||
pub use model_comp::*;
|
pub use model_comp::*;
|
||||||
|
|
||||||
|
pub mod input_actions;
|
||||||
|
pub use input_actions::*;
|
Loading…
Reference in New Issue