A framework for the Godot engine to create TTRPG games for Advanced 5th Edition, Pathfinder 2nd Edition, and more

Move to Rust, WASM, and MessagePack #1

merged opened by cass.cityboundforest.com targeting main from rust
Labels

None yet.

Participants 1
AT URI
at://did:plc:lsxnahuhdg6llq7lpo3wq6kf/sh.tangled.repo.pull/3mgl3o2u44q22
+117 -141
Diff #0
+17 -39
.gitignore
··· 1 - # Created by https://www.toptal.com/developers/gitignore/api/lua 2 - # Edit at https://www.toptal.com/developers/gitignore?templates=lua 3 - 4 - ### Lua ### 5 - # Compiled Lua sources 6 - luac.out 7 8 - # luarocks build files 9 - *.src.rock 10 - *.zip 11 - *.tar.gz 12 13 - # Object files 14 - *.o 15 - *.os 16 - *.ko 17 - *.obj 18 - *.elf 19 20 - # Precompiled Headers 21 - *.gch 22 - *.pch 23 24 - # Libraries 25 - *.lib 26 - *.a 27 - *.la 28 - *.lo 29 - *.def 30 - *.exp 31 32 - # Shared objects (inc. Windows DLLs) 33 - *.dll 34 - *.so 35 - *.so.* 36 - *.dylib 37 38 - # Executables 39 - *.exe 40 - *.out 41 - *.app 42 - *.i*86 43 - *.x86_64 44 - *.hex 45 46 47 - # End of https://www.toptal.com/developers/gitignore/api/lua
··· 1 + # Created by https://www.toptal.com/developers/gitignore/api/rust 2 + # Edit at https://www.toptal.com/developers/gitignore?templates=rust 3 4 + ### Rust ### 5 + # Generated by Cargo 6 + # will have compiled files and executables 7 + debug/ 8 + target/ 9 10 + # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 11 + # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 12 + Cargo.lock 13 14 + # These are backup files generated by rustfmt 15 + **/*.rs.bk 16 17 + # MSVC Windows builds of rustc generate these, which store debugging information 18 + *.pdb 19 20 + # End of https://www.toptal.com/developers/gitignore/api/rust 21 22 23 + # Added by cargo 24 25 + /target
-3
.gitmodules
··· 1 - [submodule "pf2e"] 2 - path = pf2e 3 - url = https://tangled.org/@cass.cityboundforest.com/dice-wire-pf2e
···
+13
Cargo.toml
···
··· 1 + [package] 2 + authors = ["Cass Forest"] 3 + edition = "2024" 4 + name = "dice-wire" 5 + version = "0.1.0" 6 + 7 + [lib] 8 + crate-type = ["cdylib"] 9 + 10 + [dependencies] 11 + rmp = "0.8.15" 12 + rmpv = { version = "1.3.1", features = ["serde"] } 13 + wasm-bindgen = "0.2.114"
+1 -9
README.md
··· 27 28 ## Usage 29 30 - You can, of course, just use this as a usual Lua program. The code assumes you load the class file, call it, and assign the resulting function returned to a global variable `class`. You can then load the `hooks` file, along with any other libraries you'd like (i.e. the different systems). Due to the nature of this framework, I will not be writing code to load a system's code, but it shouldn't be too difficult to do so. 31 - 32 - After loading everything, call the following code: 33 - 34 - ```lua 35 - Hooks:emit("init") 36 - ``` 37 - 38 - This will call every function callback under the `init` event.
··· 27 28 ## Usage 29 30 + **TODO**: Need to add this later for Rust and MessagePack
-47
class.lua
··· 1 - -- class.lua 2 - -- Compatible with Lua 5.1 (not 5.0). 3 - function class(base, init) 4 - local c = {} -- a new class instance 5 - if not init and type(base) == 'function' then 6 - init = base 7 - base = nil 8 - elseif type(base) == 'table' then 9 - -- our new class is a shallow copy of the base class! 10 - for i,v in pairs(base) do 11 - c[i] = v 12 - end 13 - c._base = base 14 - end 15 - -- the class will be the metatable for all its objects, 16 - -- and they will look up their methods in it. 17 - c.__index = c 18 - 19 - -- expose a constructor which can be called by <classname>(<args>) 20 - local mt = {} 21 - mt.__call = function(class_tbl, ...) 22 - local obj = {} 23 - setmetatable(obj,c) 24 - if init then 25 - init(obj,...) 26 - else 27 - -- make sure that any stuff from the base class is initialized! 28 - if base and base.init then 29 - base.init(obj, ...) 30 - end 31 - end 32 - return obj 33 - end 34 - c.init = init 35 - c.is_a = function(self, klass) 36 - local m = getmetatable(self) 37 - while m do 38 - if m == klass then return true end 39 - m = m._base 40 - end 41 - return false 42 - end 43 - setmetatable(c, mt) 44 - return c 45 - end 46 - 47 - return class
···
-43
hooks.lua
··· 1 - hooks = class(function(self) 2 - self.events = {} 3 - end) 4 - 5 - function hooks:on(event, callback) 6 - if not self.events[event] then 7 - self.events[event] = {} 8 - end 9 - 10 - table.insert(self.events[event], callback) 11 - end 12 - 13 - function hooks:once(event, callback) 14 - local wrapper 15 - wrapper = function(...) 16 - callback(...) 17 - self:off(event, wrapper) 18 - end 19 - 20 - self:on(event, wrapper) 21 - end 22 - 23 - function hooks:off(event, callback) 24 - local list = self.events[event] 25 - if not list then return end 26 - for i, cb in ipairs(list) do 27 - if cb == callback then 28 - table.remove(list, i) 29 - return 30 - end 31 - end 32 - end 33 - 34 - function hooks:emit(event, ...) 35 - local list = self.events[event] 36 - if not list then return end 37 - for _, cb in ipairs(list) do 38 - cb(...) 39 - end 40 - end 41 - 42 - local Hooks = hooks() 43 - return Hooks
···
+86
src/lib.rs
···
··· 1 + use std::collections::HashMap; 2 + use wasm_bindgen::prelude::*; 3 + use rmpv::Value; 4 + 5 + #[wasm_bindgen] 6 + pub struct DiceWire { 7 + hooks: Hooks 8 + } 9 + 10 + impl DiceWire { 11 + pub fn new() -> Self { 12 + Self { 13 + hooks: Hooks::new() 14 + } 15 + } 16 + } 17 + 18 + #[wasm_bindgen] 19 + pub struct Hooks { 20 + events: HashMap<String, Vec<Hook>> 21 + } 22 + 23 + impl Hooks { 24 + pub fn new() -> Self { 25 + Self { 26 + events: HashMap::new() 27 + } 28 + } 29 + 30 + pub fn on<F>(&mut self, event: String, callback: F) 31 + where 32 + F: Fn(&Value) + 'static + Send + Sync 33 + { 34 + self.events.entry(event) 35 + .or_insert_with(Vec::new) 36 + .push(Hook::new(callback, false)); 37 + } 38 + 39 + pub fn once<F>(&mut self, event: String, callback: F) 40 + where 41 + F: Fn(&Value) + 'static + Send + Sync 42 + { 43 + self.events.entry(event) 44 + .or_insert_with(Vec::new) 45 + .push(Hook::new(callback, true)); 46 + } 47 + 48 + pub fn emit(&mut self, event: String, data: &Value) { 49 + if let Some(event_list) = self.events.get_mut(&event) { 50 + for event in event_list.iter_mut() { 51 + event.call(data); 52 + } 53 + } 54 + } 55 + } 56 + 57 + #[wasm_bindgen] 58 + pub struct Hook { 59 + func: Box<dyn Fn(&Value) -> () + Sync + Send>, 60 + once: bool, 61 + called: bool 62 + } 63 + 64 + impl Hook { 65 + pub fn new<F>(callback: F, once: bool) -> Self 66 + where 67 + F: Fn(&Value) -> () + 'static + Send + Sync 68 + { 69 + Self { 70 + func: Box::new(callback), 71 + once, 72 + called: false 73 + } 74 + } 75 + 76 + pub fn call(&mut self, data: &Value) { 77 + if self.once { 78 + if !self.called { 79 + (self.func)(data); 80 + self.called = true; 81 + } 82 + } else { 83 + (self.func)(data); 84 + } 85 + } 86 + }

History

1 round 0 comments
sign up or login to add to the discussion
3 commits
expand
Moving to Rust, MessagePack, and WASM
Adding tutorial
Got it to compile to a WASM, just compile it with the wasm32-unknown-unknown target
expand 0 comments
pull request successfully merged