# Defold Event - Cross-Context Defold Event System

**URL:** <https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165>\
**Category:** The Defoldmine\
**Created:** [March 2, 2024, 10:44am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165 "2024-03-02T10:44:08Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [March 2, 2024, 10:44am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/1 "2024-03-02T10:44:08Z")

</div>

[![logo](https://defold-forum-bucket.nbg1.your-objectstorage.com/original/3X/7/7/7784cdcf73b780bf55073ba677296611e8a2c842.jpeg)](https://github.com/Insality/defold-event)

# Event

**Event** - is a single file Lua module for the [Defold](https://defold.com/) game engine. It provides a simple and efficient way to manage events and callbacks in your game.

## Features

- **Event Management** : Create, subscribe, unsubscribe, and trigger events.
- **Cross-Context** : You can subscribe to events from different scripts.
- **Callback Management** : Attach callbacks to events with optional data.
- **Logging** : Set a logger to log event activities.
- **Memory Allocations Tracker** : Detects if an event callback causes a huge memory allocations.

## Setup

See the [**Defold-Event**](https://github.com/Insality/defold-event) repository on Github for the Setup, Documentation, API and Use Cases

## Example

You can create a global event module that allows events to be triggered from anywhere within your game (from [USE\_CASES.md](https://github.com/Insality/defold-event/blob/main/USE_CASES.md)).

```lua
-- global_events.lua
-- Create events in the lua module
local event = require("event.event")

local M = {}

M.on_game_start = event.create()
M.on_game_over = event.create()

return M

```

```lua
-- Subscribe to the events from any place
local global_events = require("global_events")

local function on_game_start(self, param1, param2)
    -- Animate GUI elements somehow
end

local function on_game_over(self)
    -- Animate GUI elements somehow
end

function init(self)
    -- The second arg - callback context is optional
    -- Is will be passed as an first argument to the callback
    -- Here we pass the *self* to have an access in the callbacks
    global_events.on_game_start:subscribe(on_game_start, self)
    global_events.on_game_over:subscribe(on_game_over, self)
end

function final(self)
    -- Unsubscribe is mandatory if subscribed instance is destroyed
    global_events.on_game_start:unsubscribe(on_game_start, self)
    global_events.on_game_over:unsubscribe(on_game_over, self)
end

```

```lua
-- Trigger the events from any place
local global_events = require("global_events")

function init(self)
    timer.delay(1, false, function()
         global_events.on_game_start:trigger("param1", "param2")
    end)
end

```

---

<div class="post-metadata">

**Author:** ![d954mas](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/d954mas/32/5401_2.png) [@d954mas](https://forum.defold.com/u/d954mas)\
**Post date:** [March 2, 2024, 11:13am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/2 "2024-03-02T11:13:36Z")

</div>

Cool, i also use have lib for event, that was bases on eve event.

1)Why you use variables in trigger instead of …

```lua
function M:trigger(a, b, c, d, e, f, g, h, i, j)

```

```lua
function Event:trigger(...)

```

2)In my evene lib i use flag to save context or not. For some cases script context is not necessary

3)You use lua\_script\_instance but your implementation has bug. isInstaceValid not worked in Set\_impl

You need to dmScript::SetInstance before check it with dmScript::IsInstanceValid  
You

```lua
static int Set_impl(lua_State* L)
{
    DM_LUA_STACK_CHECK(L, -1);
    if (!dmScript::IsInstanceValid(L))
    {
        dmLogError("Instance is not valid")
        return DM_LUA_ERROR("Instance is not valid");
    }
    dmScript::SetInstance(L);
    return 0;
}

```

My

```lua
static int Set_impl(lua_State* L){
    DM_LUA_STACK_CHECK(L, 0);
    dmScript::GetInstance(L);//current
    lua_pushvalue(L,-2);//move new on top. stack. new->current->new
    dmScript::SetInstance(L);//set new stack. new->current
    if (!dmScript::IsInstanceValid(L)){
        dmScript::SetInstance(L);//set current
        DM_LUA_ERROR("Instance is not valid");
    }else{
        lua_pop(L,1);
    }
    return 0;
}

```

4)You add lua\_script\_instance in you project. I think you need to use custom name for it?  
What happened if i add in same project. Error or some of lua\_script\_instance ovveride another?  
[https://github.com/DanEngelbrecht/LuaScriptInstance](https://github.com/DanEngelbrecht/LuaScriptInstance)  
[https://github.com/Insality/defold-event](https://github.com/Insality/defold-event)

This is how i make events)

```lua
local CLASS = require "libs.middleclass"
local LOG = require "libs.log"

local Event = CLASS.class("EventClass")

function Event:initialize(name)
	self.name = assert(name)
	self.callbacks = {}
end
function Event:subscribe(save_context, callback)
	assert(type(callback) == "function")

	if self:is_subscribed(callback) then
		LOG:e("Event:" .. self.name .. " is already subscribed", 3)
		return
	end

	table.insert(self.callbacks, {
		callback = callback,
		script_context = save_context and lua_script_instance.Get()
	})

	return function() self:unsubscribe(callback) end
end

function Event:unsubscribe(callback)
	assert(type(callback) == "function")

	for index = 1, #self.callbacks do
		local cb = self.callbacks[index]
		if cb.callback == callback then
			table.remove(self.callbacks, index)
			return true
		end
	end

	return false
end

function Event:is_subscribed(callback)
	for index = 1, #self.callbacks do
		local cb = self.callbacks[index]
		if cb.callback == callback then return true end
	end

	return false
end

--- Trigger the event
-- @function event.trigger
-- @tparam args args The args for event trigger
function Event:trigger(...)
	local current_script_context = lua_script_instance.Get()

	for index = 1, #self.callbacks do
		local callback = self.callbacks[index]

		if callback.script_context and current_script_context ~= callback.script_context then
			lua_script_instance.Set(callback.script_context)
		end

		local ok, error = pcall(callback.callback, self, ...)
		if not ok then LOG.e(error) end

		if callback.script_context and current_script_context ~= callback.script_context then
			lua_script_instance.Set(current_script_context)
		end
	end
end

return Event

```

---

<div class="post-metadata">

**Author:** ![Chung\_Xa](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/chung_xa/32/34470_2.png) [@Chung\_Xa](https://forum.defold.com/u/Chung_Xa)\
**Post date:** [March 2, 2024, 11:14am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/3 "2024-03-02T11:14:24Z")

</div>

A question. Does it still face the issue of nodes using in wrong GUI scene or can’t use go in gui script…?

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [March 2, 2024, 11:25am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/4 "2024-03-02T11:25:49Z")

</div>

Thanks for the feedback! @d954mas

> [@d954mas](#):
>
> 1)Why you use variables in trigger instead of …

There is a case, when vargs works incorrect. But don’t remember why exactly, probably in the chain calls with vargs. I hit this issue in the Druid before. From this time I keep this over “…” in my libraries

> [@d954mas](#):
>
> 2)In my evene lib i use flag to save context or not. For some cases script context is not necessary

Sounds good! It’s true that often the Event library should not use context switching at all. Nice part to be improved in future.

> [@d954mas](#):
>
> 3)You use lua\_script\_instance but your implementation has bug

Thanks for this, I’ll take a look!

> [@d954mas](#):
>
> 4)You add lua\_script\_instance in you project. I think you need to use custom name for it?  
> What happened if i add in same project. Error or some of lua\_script\_instance ovveride another?

If there is another copy of lua script instance - it should override and use only one. But I have a notice in README, that if your already using it, you should remove it from dependency. This is exactly the same library with links to it

Since there is a lot of discussion about is it correct or not to use the context changing. I decide to keep the only one place where it used without explicit using this library. Wdyt about this approach?

> [@d954mas](#):
>
> that was bases on eve event

Do you mean Eva? 😃 or different one?

---

<div class="post-metadata">

**Author:** ![d954mas](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/d954mas/32/5401_2.png) [@d954mas](https://forum.defold.com/u/d954mas)\
**Post date:** [March 2, 2024, 11:27am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/5 "2024-03-02T11:27:13Z")

</div>

Yes Eva)

> [@Insality](#):
>
> Do you mean Eva? 😃 or different one?

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [March 2, 2024, 11:27am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/6 "2024-03-02T11:27:23Z")

</div>

> [@Chung\_Xa](#):
>
> A question. Does it still face the issue of nodes using in wrong GUI scene or can’t use go in gui script…?

The event is remember their context when it’s subscribed. So if you subscribe in the one GUI scene and call trigger this event from other scene (GO/GUI), that works correct.

---

<div class="post-metadata">

**Author:** ![d954mas](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/d954mas/32/5401_2.png) [@d954mas](https://forum.defold.com/u/d954mas)\
**Post date:** [March 2, 2024, 11:33am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/7 "2024-03-02T11:33:58Z")

</div>

> [@Insality](#):
>
> Since there is a lot of discussion about is it correct or not to use the context changing. I decide to keep the only one place where it used without explicit using this libra

Context changing is true defold way​😉  
First is was used by @britzl in flow.

> <https://github.com/britzl/ludobits/blob/a43632edf088541a4fe36be5386e2f42df8a3b83/ludobits/m/flow.lua#L83>

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [March 2, 2024, 11:49am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/8 "2024-03-02T11:49:42Z")

</div>

> [@d954mas](#):
>
> Context changing is true defold way​😉

This example definitely looks more like a hidden way than a true way 🙂

Anyway it’s kind of dangerous or advanced thing that should be used carefully. But I like the approach to have events in data and have the ability to subscribe/unsubscribe the GUI logic over it

---

<div class="post-metadata">

**Author:** ![Chung\_Xa](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/chung_xa/32/34470_2.png) [@Chung\_Xa](https://forum.defold.com/u/Chung_Xa)\
**Post date:** [March 2, 2024, 12:21pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/9 "2024-03-02T12:21:39Z")

</div>

Somehows I see it doesn’t look like as its name. If it’s an event, it should have an event name. Here in my opinion, it should be called Callback 😅

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [March 2, 2024, 2:28pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/10 "2024-03-02T14:28:39Z")

</div>

Well, the `callback_instance.subscribe(callback)` sound a little weird 😃

For named events you can use a module approach, like ~

```lua
local M = {
    object_destroyed = event.create(),
    analytics_sent = event.create(),
    another_cool_event = event.create()
}

```

And use it like global event bus

```lua
local events = require("my.events")

events.object_destroyed:subscribe(...)
events.analytics_sent:trigger(...)

```

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [July 20, 2024, 12:21pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/11 "2024-07-20T12:21:32Z")

</div>

There are few releases for Defold Event module

### **V2**

**Changelog**

Now you can use `require("event.events")` to subscribe and trigger events globally by event name

```lua
local events = require("event.events")
events:subscribe("event_id", callback)
events:trigger("event_id", "param1", "param2")

```

```lua
- Add global events module
- The `event:subscribe` and `event:unsubscribe` now return boolean value of success

```

### **V3**

**Changelog**

```lua
- Event Trigger now returns value of last executed callback
- Add `events.is_empty(name)` function
- Add tests for Event and Global Events modules

```

### **V4**

**Changelog**

For context validation fix thanks to @d954mas for pointing out the mistake.

```lua
- Rename `lua_script_instance` to `event_context_manager` to escape conflicts with `lua_script_instance` library
- Fix validate context in `event_context_manager.set`
- Refactor `event_context_manager`
- Add tests for changing context and memory allocations
- Add `event.set_memory_threshold` function. Works only in debug builds.

```

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [August 26, 2024, 9:23am UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/12 "2024-08-26T09:23:15Z")

</div>

There are another few releases for Defold Event module. Check releases here - [GitHub - Insality/defold-event: Cross-Context Defold Event System · GitHub](https://github.com/Insality/defold-event)

### **V5**

```lua
- The `event:trigger(...)` can be called as `event(...)` via `__call` metamethod
- Add default pprint logger. Remove or replace it with `event.set_logger()`
- Add tests for context changing

```

### **V6**

```lua
- Optimize memory allocations per event instance
- Localize functions in the event module for better performance

```

### **V7**

```lua
- Optimize memory allocations per event instance
- Default logger now empty except for errors

```

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [October 3, 2024, 6:43pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/13 "2024-10-03T18:43:56Z")

</div>

There are another few releases for Defold Event module 🙃

Check releases here - [https://github.com/Insality/defold-event](https://github.com/Insality/defold-event)

### **V8**

```lua
- Optimize memory allocations per subscription (~35% less)

```

### **V9**

```lua
- Better error tracebacks in case of error in subscription callback
- Update annotations

```

### **V10**

```lua
- The `event:unsubscribe` now removes all subscriptions with the same function if `callback_context` is not provided
- You can use events instead callbacks in `event:subscribe` and `event:unsubscribe`. The subscribed event will be triggered by the parent event trigger.
- Update docs, Use Cases and API reference

```

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [April 22, 2025, 5:03pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/14 "2025-04-22T17:03:15Z")

</div>

**The Defold-Event v11 is released**

Hello! The update for event module is published. Introducing the `defer` module, which is basically the event queue with various handling mechanisms.

I using this `defer` module to make a some communications between GO and GUI scripts in `init` step. Example: get a atlas info in GUI script (it requires a GO call `go.get` call).

The `event.use_xpcall` is new flag in game.project. Due the `xpcall` is works different between HTML and desktop, I need to make a “wrapper” to keep consistency. This wrapper allows to see a detailed tracebacks in case of errors in events, but required a bit more memory to trigger each event. I usually turn on this option in development.

Changes:

- Introduced the `defer` module. The Defer module provides a queuing mechanism for events. Unlike regular events which are immediately processed, deferred events are stored in a queue until they are explicitly handled by a subscriber. This is useful for events that need to persist until they can be properly handled.
- Add `event.use_xpcall` game.project option to get detailed tracebacks in case of an error in the event callback.
- Moved [detailed API](https://github.com/Insality/defold-event/tree/main/api) documentation to separate files
- Remove annotations files. Now all annotations directly in the code.

Check Repo: [GitHub - Insality/defold-event: Cross-Context Defold Event System · GitHub](https://github.com/Insality/defold-event)  
Tagged Release: [https://github.com/Insality/defold-event/archive/refs/tags/11.zip](https://github.com/Insality/defold-event/archive/refs/tags/11.zip)

---

<div class="post-metadata">

**Author:** ![Insality](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/insality/32/39737_2.png) [@Insality](https://forum.defold.com/u/Insality)\
**Post date:** [March 6, 2026, 2:42pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/15 "2026-03-06T14:42:32Z")

</div>

Hello! There are a bunch of new releases for **Defold Event** library.

# What is new?

## Queues

Queues let you store events and process them later in FIFO order. Unlike regular events that run callbacks immediately, queue events stay in the queue until a handler returns a non-nil value (to mark the event as handled).

Use **instance-based** queues with `queue.create()` or **global** queues via the `queues` module and a string id. Push from anywhere. When you subscribe a handler, it is called for each pending and future events in the queue. You can also process events manually with `process()` or `process_next()` without using subscribers. So you can use queues in a different way.

I’m using queues to store logic events to process them later in UI one by one if required. Or to communicate between GO and GUI context at init step sometimes.

[**Queues API**](https://github.com/Insality/defold-event/blob/main/api/queue_api.md)

**Example — UI events queue processing:**

```lua
local queues = require("event.queues")

local function process_next_event(self)
	queues.process_next("quest_events", function(self, data)
		if data.type == "quest_started" then
			animate_quest_start(data)
		elseif data.type == "quest_completed" then
			animate_quest_complete(data)
		end

		return true
	end, self)
end

```

**Example — Cross-context communication:**

```lua
-- GUI context
local queues = require("event.queues")

function M:init(self)
	queues.push("get_atlas_path", {
		texture_name = gui.get_texture(self.node),
		sender = msg.url(),
	}, self._on_get_atlas_path, self)
end

function M:_on_get_atlas_path(atlas_path)
	local atlas_data = resource.get_atlas(atlas_path)
	local tex_info = resource.get_texture_info(atlas_data.texture)
end

```

```lua
-- GO script
---@param request druid.get_atlas_path_request
---@return string?
local function get_atlas_path(self, request)
	if not is_my_url(request.sender) then
		return nil
	end

	return go.get(request.sender, "textures", { key = request.texture_name })
end

function init(self)
	queues.subscribe("get_atlas_path", get_atlas_path, self)
end

function final(self)
	queues.unsubscribe("get_atlas_path", get_atlas_path, self)
end

```

## Promises

The Promise module wraps asynchronous work and lets you chain with `:next()`, `:catch()`, and `:finally()`. Create a promise with `promise.create(executor)` or use `promise.resolved(value)` / `promise.rejected(reason)`. Use `promise.all()` to wait for multiple promises and `promise.race()` for the first to finish. You can resolve or reject manually with `:resolve()` and `:reject()`, and build pipelines with `:append()` and `:tail()`.

[**Promises API**](https://github.com/Insality/defold-event/blob/main/api/promise_api.md)

**Example — wrap function to promise:**

```lua
local promise = require("event.promise")

---@param url string
---@return promise
local function load_data(url)
	local p = promise.create()

	http.request(url, "GET", function(response)
		if response.status == 200 then
			p:resolve(response.body)
		else
			p:reject(response.status)
		end
	end)

	return p
end

```

**Example — build promise pipeline:**

```lua
local promise = require("event.promise")

function M:load_next_level()
	return promise.resolved()
		:next(self.unload_level, nil, self)
		:next(self.wait_level_unload, nil, self)
		:next(levels.get_next_level, nil, self)
		:next(self.load_level, nil, self)
		:next(self.animate_level_appear, nil, self)
end

```

## Event as callback

You can subscribe an **event** to another event: when the parent triggers, the child event is triggered too. Handy for forwarding or composing events. You can pass a **callback context** when subscribing an event, e.g. extra data that will be passed as the first argument when the child event runs (e.g. `event_2:subscribe(event_1, "extra data")`).

**Example — forward one event to another:**

```lua
local event = require("event.event")

local on_click = event.create(function(self) print("clicked!") end)
local on_ui_action = event.create()
on_ui_action:subscribe(on_click) -- any trigger of on_ui_action also triggers on_click
on_ui_action:trigger()

```

**Example — event with context:**

```lua
local event_1 = event.create(function(self, x, y) print(self, x, y) end)
local event_2 = event.create()
event_2:subscribe(event_1, "my_context") -- event_1 runs with "my_context" as self
event_2:trigger(10, 20) -- prints "my_context", 10, 20

```

## Subscribe Once

Subscribe a handler so it runs **only once** : after the first trigger (or first handled queue event), it is automatically unsubscribed. Available on events and queues: `event:subscribe_once()`, `events.subscribe_once()`, `queue:subscribe_once()`, and `queues.subscribe_once()`. Perfect for one-shot reactions like “when loaded”, “first click”, or “handle next item only”.

**Example — event, one-time:**

```lua
local event = require("event.event")
local on_loaded = event.create()

on_loaded:subscribe_once(function(self) print("Loaded once!") end, self)
on_loaded:trigger() -- runs and unsubscribes
on_loaded:trigger() -- no callback

```

**Example — queue, handle one item then stop:**

```lua
local queue = require("event.queue")
local task_queue = queue.create()

task_queue:subscribe_once(function(self, task)
	return run_task(task) -- return non-nil to handle and auto-unsubscribe
end, self)
task_queue:push(task_a)
task_queue:push(task_b) -- only first is handled by this subscriber

```

## Event Modes

You can set how the event module runs callbacks and handles errors with `event.set_mode(mode)`.

- **`pcall`** (default): continue on error, not full tracebacks.
- **`xpcall`** : continue on error, same idea but with full tracebacks (more memory).
- **`none`** : stop on error, rethrow the error with full traceback.

**Example:**

```lua
local event = require("event.event")

-- Set inside game.project file or in your code:
event.set_mode("pcall") -- safe default: log errors, continue
event.set_mode("xpcall") -- full tracebacks, still continue
event.set_mode("none") -- errors rethrown with full traceback

```

* * *

Full changes for 12-15 versions

#### **V12**

- **MIGRATION** : Replace `require("event.defer")` with `require("event.queues")` in case of using `defer` module
- **BREAKING CHANGE** : Refactored queue system to be instance-based like event system. `queue.lua` now creates queue instances with `queue.create()` instead of global system
- Added `queues.lua` for global queues operations (renamed from old defer.lua functionality)
- Added **Promise** module on top of event module
- Fixed queue event processing order from LIFO to FIFO (events now processed in correct queue order)
- Added `event.set_mode` function to set the event processing mode (`pcall`, `xpcall` and `none`)
- The `none` mode to disable context changing in event callback and using `pcall` by default

#### **V13**

- Added `queue:process_next` function to process exactly one event in the queue with a specific handler (subscribers will not be called)
- Make `promise:resolve` and `promise:reject` public functions
- Added `promise:append` function to append a task to the current promise without reassigning it.
- Added `promise:tail` and `promise:reset` functions to manage the promise tail

#### **V14**

- Enable cross-context for `none` event mode
- In `none` mode, when an error occurs in a callback, the Lua error is rethrown with full traceback

#### **V15**

- subscribe\_once: Added `event:subscribe_once`, `events.subscribe_once`, `queue:subscribe_once`, and `queues.subscribe_once` to subscribe a handler for a single invocation. The handler is automatically unsubscribed after the first call.
- Unsubscribe during trigger: Calling `unsubscribe` from inside a callback no longer breaks the current trigger iteration. Removals are applied after the trigger finishes, so all callbacks in the current trigger still run.
- Fix when `callback_context` for subscription can’t be `false`
- Event as callback: Support for `callback_context` when subscribing an event to another event (e.g. `event_2:subscribe(event_1, "any additional data")`).
- Unsubscribe event from event: Fixed unsubscribing one event from another so the correct subscription is found and removed.
- Various edge cases fixes and improvements.
- Documentation and API pages updates.

---

<div class="post-metadata">

**Author:** ![Pawel](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/pawel/32/24623_2.png) [@Pawel](https://forum.defold.com/u/Pawel)\
**Post date:** [March 6, 2026, 2:48pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/16 "2026-03-06T14:48:35Z")

</div>

Wow! Promises? Queues? This is over the top! 😍

---

<div class="post-metadata">

**Author:** ![totebo](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/totebo/32/36087_2.png) [@totebo](https://forum.defold.com/u/totebo)\
**Post date:** [March 6, 2026, 3:20pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/17 "2026-03-06T15:20:51Z")

</div>

This is wonderful! Keep the features coming! 🙂

Love this library, one of the firsts extensions I add.

---

<div class="post-metadata">

**Author:** ![Mathias](https://forum-defold.b-cdn.net/user_avatar/forum.defold.com/mathias/32/44015_2.png) [@Mathias](https://forum.defold.com/u/Mathias)\
**Post date:** [March 6, 2026, 4:29pm UTC](https://forum.defold.com/t/defold-event-cross-context-defold-event-system/76165/18 "2026-03-06T16:29:33Z")

</div>

Thank you, this lib is MANDATORY for any real project!  
I think I will use Queues for my input manager system! Queue all input event then process them in order in a post-input message, just before the update loop!
