Create an early scripting engine #2
|
@ -45,6 +45,15 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.16"
|
||||
|
@ -1558,11 +1567,13 @@ dependencies = [
|
|||
"anyhow",
|
||||
"elua",
|
||||
"itertools 0.12.0",
|
||||
"lazy_static",
|
||||
"lyra-ecs",
|
||||
"lyra-game",
|
||||
"lyra-reflect",
|
||||
"lyra-resource",
|
||||
"lyra-scripting-derive",
|
||||
"regex",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
@ -2204,6 +2215,35 @@ dependencies = [
|
|||
"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]]
|
||||
name = "renderdoc-sys"
|
||||
version = "0.7.1"
|
||||
|
|
|
@ -6,6 +6,48 @@ function on_init()
|
|||
|
||||
local e = world:spawn(pos, cube)
|
||||
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
|
||||
|
||||
--[[ function on_first()
|
||||
|
@ -25,6 +67,9 @@ function on_update()
|
|||
|
||||
return t
|
||||
end, Transform)
|
||||
|
||||
--local input = world:resource(Input)
|
||||
--input.
|
||||
end
|
||||
|
||||
--[[ function on_post_update()
|
||||
|
|
|
@ -240,7 +240,7 @@ async fn main() {
|
|||
};
|
||||
|
||||
let action_handler_plugin = |game: &mut Game| {
|
||||
let action_handler = ActionHandler::new()
|
||||
/* let action_handler = ActionHandler::builder()
|
||||
.add_layout(LayoutId::from(0))
|
||||
|
||||
.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::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, &[
|
||||
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0)
|
||||
|
@ -282,22 +282,9 @@ async fn main() {
|
|||
.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();
|
||||
world.add_resource(action_handler);
|
||||
world.spawn((Vec3::new(0.5, 0.1, 3.0),));
|
||||
game.with_plugin(InputActionPlugin);
|
||||
//game.with_system("input_test", test_system, &[]);
|
||||
game.with_plugin(InputActionPlugin); */
|
||||
};
|
||||
|
||||
let script_test_plugin = |game: &mut Game| {
|
||||
|
@ -322,6 +309,6 @@ async fn main() {
|
|||
.with_plugin(script_test_plugin)
|
||||
//.with_plugin(fps_plugin)
|
||||
.with_plugin(jiggle_plugin)
|
||||
.with_plugin(FreeFlyCameraPlugin)
|
||||
//.with_plugin(FreeFlyCameraPlugin)
|
||||
.run().await;
|
||||
}
|
||||
|
|
|
@ -255,7 +255,8 @@ impl World {
|
|||
/// Will panic if the resource is not in the world. See [`try_get_resource`] for
|
||||
/// a function that returns an option.
|
||||
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()
|
||||
}
|
||||
|
||||
|
@ -277,7 +278,8 @@ impl World {
|
|||
/// Will panic if the resource is not in the world. See [`try_get_resource_mut`] for
|
||||
/// a function that returns an option.
|
||||
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()
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::{collections::HashMap, ops::Deref, hash::{Hash, DefaultHasher, Hasher},
|
|||
|
||||
use glam::Vec2;
|
||||
use lyra_ecs::world::World;
|
||||
use lyra_reflect::Reflect;
|
||||
|
||||
use crate::{plugin::Plugin, game::GameStages, EventQueue};
|
||||
|
||||
|
@ -213,7 +214,7 @@ impl Action {
|
|||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct LayoutId(u32);
|
||||
pub struct LayoutId(pub u32);
|
||||
|
||||
impl From<u32> for LayoutId {
|
||||
fn from(value: u32) -> Self {
|
||||
|
@ -240,7 +241,7 @@ impl Layout {
|
|||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct ActionMappingId(u32);
|
||||
pub struct ActionMappingId(pub u32);
|
||||
|
||||
impl From<u32> for ActionMappingId {
|
||||
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.
|
||||
///
|
||||
/// If the action is not in this layout, this will panic!
|
||||
|
@ -271,7 +276,7 @@ impl ActionMapping {
|
|||
/// Parameters:
|
||||
/// * `action` - The label corresponding to the action in this Layout.
|
||||
/// * `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
|
||||
L: ActionLabel
|
||||
{
|
||||
|
@ -283,32 +288,48 @@ impl ActionMapping {
|
|||
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 {
|
||||
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 {
|
||||
#[reflect(skip)] // TODO: dont just skip all these
|
||||
pub actions: HashMap<u64, Action>,
|
||||
#[reflect(skip)]
|
||||
pub layouts: HashMap<LayoutId, Layout>,
|
||||
#[reflect(skip)]
|
||||
pub current_layout: LayoutId,
|
||||
#[reflect(skip)]
|
||||
pub current_mapping: ActionMappingId,
|
||||
}
|
||||
|
||||
|
@ -317,26 +338,31 @@ impl ActionHandler {
|
|||
Self::default()
|
||||
}
|
||||
|
||||
pub fn add_layout(mut self, id: LayoutId) -> Self {
|
||||
self.layouts.insert(id, Layout::new());
|
||||
|
||||
self
|
||||
pub fn builder() -> ActionHandlerBuilder {
|
||||
ActionHandlerBuilder::default()
|
||||
}
|
||||
|
||||
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
|
||||
L: ActionLabel
|
||||
{
|
||||
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();
|
||||
layout.add_mapping(mapping);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
/// 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<()> {
|
||||
let keys = world.try_get_resource::<InputButtons<KeyCode>>()
|
||||
.map(|r| r.deref().clone());
|
||||
|
|
|
@ -11,4 +11,182 @@ pub mod buttons;
|
|||
pub use buttons::*;
|
||||
|
||||
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};
|
||||
|
||||
pub type KeyCode = winit::event::VirtualKeyCode;
|
||||
|
||||
#[derive(Default)]
|
||||
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};
|
||||
|
||||
|
@ -11,6 +11,7 @@ pub struct ReflectedResource {
|
|||
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_ptr: fn (world: &mut World) -> Option<NonNull<u8>>,
|
||||
fn_refl_insert: fn (world: &mut World, this: Box<dyn Reflect>),
|
||||
}
|
||||
|
||||
impl ReflectedResource {
|
||||
|
@ -27,6 +28,11 @@ impl ReflectedResource {
|
|||
pub fn reflect_ptr(&self, world: &mut World) -> Option<NonNull<u8>> {
|
||||
(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 {
|
||||
|
@ -45,6 +51,13 @@ impl<T: ResourceObject + Reflect> FromType<T> for ReflectedResource {
|
|||
world.try_get_resource_ptr::<T>()
|
||||
.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?
|
||||
elua = { path = "./elua", optional = true }
|
||||
itertools = "0.12.0"
|
||||
regex = "1.10.3"
|
||||
lazy_static = "1.4.0"
|
||||
|
||||
|
||||
[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.
|
||||
pub fn is_resource(&self) -> bool {
|
||||
matches!(self, ReflectBranch::Resource(_))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use lyra_ecs::ResourceObject;
|
||||
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)]
|
||||
pub struct LyraEcsApiProvider;
|
||||
|
@ -21,6 +21,7 @@ impl ScriptApiProvider for LyraEcsApiProvider {
|
|||
globals.set("World", ctx.create_proxy::<ScriptWorldPtr>()?)?;
|
||||
globals.set("DynamicBundle", ctx.create_proxy::<ScriptDynamicBundle>()?)?;
|
||||
globals.set("ModelComponent", ctx.create_proxy::<LuaModelComponent>()?)?;
|
||||
globals.set("ActionHandler", ctx.create_proxy::<LuaActionHandler>()?)?;
|
||||
|
||||
let dt_table = create_reflect_table::<lyra_game::DeltaTime>(&ctx)?;
|
||||
globals.set("DeltaTime", dt_table)?;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{ptr::NonNull, sync::Arc};
|
||||
|
||||
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_reflect::{ReflectWorldExt, RegisteredType, TypeRegistry};
|
||||
use lyra_resource::ResourceManager;
|
||||
|
@ -279,6 +279,32 @@ impl elua::Userdata for ScriptWorldPtr {
|
|||
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| {
|
||||
let world = this.as_mut();
|
||||
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
|
||||
}
|
||||
}
|
|
@ -8,4 +8,7 @@ pub mod res_handle;
|
|||
pub use res_handle::*;
|
||||
|
||||
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