Holds the Udon Code for Udon MQTT
  • C# 70.5%
  • HTML 29.5%
Find a file
Cyrus Otter 8c52f76267 Recompile the manager program asset
UdonMQTTManager U#.asset was stale against its source: the field table
was still at 23 entries and missing _editorInjectedLine and the other
fields the manager has grown. Pure compiler output, no source change.
2026-09-15 17:46:48 +02:00
.forgejo/workflows CI: pull mc from the GitHub release, dl.min.io returns 410 2026-09-12 00:54:09 +02:00
Documentation~ Documentation~: TB2 Protocol Suite wire reference 2026-09-03 14:42:07 +02:00
Editor Editor driver: static Publish/Simulate API for OTTLabsMCP 2026-07-25 16:07:12 +02:00
Examples Examples: match program asset names to their filenames 2026-09-11 20:20:00 +02:00
Plugins Initial commit 2026-04-28 23:23:51 +02:00
Prefabs Remove modem assets, PlayerStats, sounds, textures, and ModemLedController 2026-04-29 23:42:37 +02:00
Udon Recompile the manager program asset 2026-09-15 17:46:48 +02:00
Editor.meta Initial commit 2026-04-28 23:23:51 +02:00
Examples.meta Examples: publish button and subscribe lamp bank 2026-09-11 18:16:51 +02:00
LICENSE Initial commit 2026-04-28 23:23:51 +02:00
LICENSE.meta Initial commit 2026-04-28 23:23:51 +02:00
package.json 2.1.0: ship the publish and subscribe examples 2026-09-11 21:19:01 +02:00
package.json.meta Initial commit 2026-04-28 23:23:51 +02:00
Plugins.meta Initial commit 2026-04-28 23:23:51 +02:00
Prefabs.meta Initial commit 2026-04-28 23:23:51 +02:00
README.md Manager presence: scope topic by managerWorldId, drop plain display name from payload 2026-08-17 01:15:16 +02:00
README.md.meta Remove modem assets, PlayerStats, sounds, textures, and ModemLedController 2026-04-29 23:42:37 +02:00
Udon.meta Initial commit 2026-04-28 23:23:51 +02:00

UdonMQTT

MQTT integration for VRChat worlds via UdonSharp. Bridges a real MQTT broker into a VRChat world -- commands leave via the Unity log file, messages arrive via keyboard stream -- with a full in-Editor driver for testing without leaving Unity.


Architecture

VRChat World (Udon)  --log file-->  Helper App  <-MQTT->  Broker
VRChat World (Udon)  <-keyboard--  Helper App

VRChat does not allow outbound network connections from Udon. UdonMQTT works around this using two separate channels:

  • Egress (Udon -> Broker): UdonMQTTManager writes structured commands to the Unity log (Debug.Log) using the [UdonMQTT] prefix. The helper app tails the Unity log file and executes the corresponding MQTT operations.
  • Ingress (Broker -> Udon): The helper app types base64-encoded JSON into the VRChat window via keyboard simulation. UdonMQTTManager reads Input.inputString each frame, accumulates characters until a newline, then decodes and dispatches the message.

The helper app must be running on the same machine as VRChat.


Components

Component Description
UdonMQTTManager (Udon) Core runtime. Writes commands to the Unity log (egress), reads keyboard-streamed JSON (ingress), handles ping/pong keepalive, and dispatches messages to subscriber scripts.
UdonMQTTEditorDriver (Editor) In-Editor MQTT client. Connects to a real broker during Play Mode, intercepts [UdonMQTT] log lines, and sends responses directly into UdonMQTTManager -- no helper app needed for testing.
UdonMQTT Manager.prefab Pre-configured prefab with UdonMQTTManager ready to drop into a scene.

Setup

1. Place the prefab

Drop UdonMQTT Manager.prefab into your scene. Configure the inspector:

Field Description
managerTopicPrefix MQTT topic prefix for manager status messages. Online/offline presence is published to <prefix>/<managerWorldId>/<md5(display name)> with payload keys status, managerWorldId, time (the player is identified only by the md5 hash in the topic, never by plain name). Default: udonmqtt/manager
managerWorldId Unique identifier for this world/deployment (e.g. ef2026). Must match the helper app config. No spaces or special characters.
whitelistedUsers VRChat display names of players allowed to drive the MQTT connection. Only the first matching player to join will be active.
debugMode Enables verbose logging.

2. Run the helper app

The helper app must be configured with the same managerWorldId and MQTT broker credentials, and must be running on the same machine as VRChat.

3. Authorization

Only players listed in whitelistedUsers will have an active UdonMQTTManager. For all other players the GameObject is disabled on join. The authorized player's client is the sole bridge between VRChat and the MQTT broker.


In-Editor Testing

The Editor MQTT Driver (OTT Labs -> UdonMQTT -> Editor MQTT Settings...) connects to a real MQTT broker during Unity Play Mode, eliminating the need for the helper app during development.

Connection settings

Configure host, port, TLS, and credentials in the settings window. Settings are saved to EditorPrefs and persist between sessions. Changes take effect on the next Play Mode entry.

Scenario testing tools

Tool What it does
Connection Flap Repeatedly force-drops and reconnects to stress-test reconnect handling in your subscriber scripts. Configurable drop count and connected duration.
Message Blackhole Silently discards all incoming MQTT messages before they reach Udon, without disconnecting. Useful for testing stale-state handling.
Ping Timeout Simulation Suppresses the editor's PING response so Udon never receives the session key. Simulates an unresponsive helper app or bridge timeout.
Manual JSON Send Sends raw JSON directly into UdonMQTTManager, bypassing MQTT entirely. Quick-fill buttons for msg, key, sub-ok, and unsub-ok message types.
Test Publish Publishes a message to any topic from the editor. "Publish (no connection)" sends directly into Udon without going through the broker.
Active Subscriptions Live view of all topic filters and their connection IDs.

The driver auto-reconnects with exponential backoff (2s-60s) on unexpected disconnection and resubscribes all active topics after reconnect.


Using UdonMQTT in your own scripts

Call the following methods on UdonMQTTManager from any UdonSharpBehaviour. All methods are no-ops if the local player is not authorized or the connection is not yet established.

Subscribe

bool ok = mqttManager._u_MQTTSubscribe(connectionID, topic, this);
  • connectionID -- an integer slot (0-254). Each subscription occupies one slot.
  • topic -- MQTT topic string (broker-side wildcards + and # are supported).
  • Returns true if the subscribe command was sent.

Your script receives the following events from UdonMQTTManager:

Event When
_u_MQTTSubscribedTopic Broker confirmed subscription.
_u_MQTTDataReceived A message arrived. Read mqttData (string) from the program variable.
_u_MQTTUnsubscribedTopic Broker confirmed unsubscription.
_u_MQTTResubscribedTopic Resubscription confirmed after _u_MQTTResubscribe.
_u_HelperReconnected Helper app reconnected after a lost connection. Use this to re-issue subscriptions if needed.

Resubscribe (change topic on an existing slot)

bool ok = mqttManager._u_MQTTResubscribe(connectionID, newTopic);

Publish

bool ok = mqttManager._u_MQTTPublish(topic, data, retain);
  • retain -- if true, the broker stores the message and delivers it to future subscribers.
  • Returns true if the command was sent (does not confirm broker receipt).

Unsubscribe

bool ok = mqttManager._u_MQTTUnsubscribe(connectionID, topic);

Protocol reference

This section is for helper app authors.

Outbound commands (Udon -> helper, via Unity log)

All log lines start with [UdonMQTT]. The session key is a 16-character random alphanumeric string exchanged at startup.

Log line Meaning
[UdonMQTT] PING Heartbeat -- respond with the session key.
[UdonMQTT] RESET Session started or ended -- reset all state.
[UdonMQTT] ONLINE Authorized player came online.
[UdonMQTT] <key> PUB <topic_b64> <data_b64> Publish (no retain).
[UdonMQTT] <key> PUBR <topic_b64> <data_b64> Publish with retain.
[UdonMQTT] <key> SUB <id> <topic_b64> Subscribe slot id to topic.
[UdonMQTT] <key> UNSUB <id> Unsubscribe slot id.
[UdonMQTT] <key> RESUB <id> <topic_b64> Move slot id to a new topic.

Topics and payloads are base64-encoded UTF-16 LE strings.

Inbound messages (helper -> Udon, via keyboard stream)

Each message is a base64-encoded JSON object terminated by a newline character, typed into the VRChat window.

T field Other fields Meaning
"k" d: session key Session key / PING response. Triggers online state.
"s" i: slot id, d: topic Subscribe confirmed.
"r" i: slot id, d: topic Resubscribe confirmed.
"u" i: slot id Unsubscribe confirmed.
"m" i: slot id, d: payload Message received on topic subscribed to slot i.

The manager validates the session key on all commands except "k". Up to 255 simultaneous slots are supported.