DEMI-PROJECT-PACKAGE »{"files":[{"hash":"sha256:b963f4153e8345bd4fd87f95617c2380a541486d9c86e8af8008f4ed494ee1ac","path":"README.md","size":175},{"hash":"sha256:ea3ee97970442c6e6c5ee42f5f0cd70a1a4c11b2a3de5ae3f08a9f9ce13ef29c","path":"scripts/demi/gameplay/events.lua","size":1283},{"hash":"sha256:c97ba24753584033b2e9e5942844cba5d79f493f126133cd68398faf19205b8d","path":"tests/events_test.lua","size":630}],"format_version":1,"manifest":{"dependencies":{},"engine":"^0.1.0","exported_events":[],"files":["README.md","scripts/demi/gameplay/events.lua","tests/events_test.lua"],"format_version":1,"name":"demi.gameplay.core","public_modules":["demi.gameplay.events"],"version":"1.0.0"},"package_type":"DemiProjectPackage"}# demi.gameplay.core Deterministic, instance-owned event queues for composing gameplay packages. Create one bus per game or scene; this package does not install a singleton. local Events = {} Events.__index = Events function Events.new() return setmetatable({ listeners = {}, queue = {}, next_order = 1 }, Events) end function Events:on(name, callback, priority) assert(type(name) == "string" and type(callback) == "function") local entry = { callback = callback, priority = priority or 0, order = self.next_order, active = true } self.next_order = self.next_order + 1 self.listeners[name] = self.listeners[name] or {} table.insert(self.listeners[name], entry) return function() entry.active = false end end function Events:emit(name, payload) table.insert(self.queue, { name = name, payload = payload }) end function Events:flush() while #self.queue > 0 do local event = table.remove(self.queue, 1) local listeners = self.listeners[event.name] or {} table.sort(listeners, function(a, b) return a.priority == b.priority and a.order < b.order or a.priority > b.priority end) for index = 1, #listeners do if listeners[index].active then listeners[index].callback(event.payload) end end local retained = {} for index = 1, #listeners do if listeners[index].active then table.insert(retained, listeners[index]) end end self.listeners[event.name] = retained end end return Events local Events = require("demi.gameplay.events") Test.case("priority and registration order are deterministic", function() local bus, order = Events.new(), {} bus:on("hit", function() table.insert(order, "late") end, 0) bus:on("hit", function() table.insert(order, "first") end, 10) bus:emit("hit", {}) bus:flush() Test.equal(table.concat(order, ","), "first,late") end) Test.case("unsubscribe during dispatch is safe", function() local bus, calls, stop = Events.new(), 0 stop = bus:on("tick", function() calls = calls + 1; stop() end) bus:emit("tick"); bus:emit("tick"); bus:flush() Test.equal(calls, 1) end)