Skip to content

UdonChat port

TL;DR: UdonChat’s core mechanic — read an InputField, broadcast a chat message, render into a log — translates directly. The package’s UdonStringEvent bus (EventReceiver.SendEvent(name, payload)) goes away: WASM lets scripts call each other’s methods directly, so we replace the bus with a reference + method call. The in-world keyboard subsystem is not ported — CVR has native text input and porting 13 key-tracking scripts adds no value.

Script from UdonChatPort status
ChatControllerPorted (ChatController.cs)
ChatEventHandlerPorted (ChatEventHandler.cs) — directly called, no event bus
UdonLogger + LoggerButtonsPorted as UdonChatLog.cs — simpler rotating buffer
EventEmitter / EventReceiver (UdonStringEvent)Removed — direct calls replace the bus
InWorldKeyboardManager + 12 keyboard scriptsNot ported — use the native keyboard
PlayerTracker, GenericButton*, KeyEventListenerNot ported — UI plumbing specific to the keyboard

From EventReceiver string-dispatch to direct calls

Section titled “From EventReceiver string-dispatch to direct calls”

UdonSharp has no generic function-pointer / delegate surface for cross-behaviour calls, so UdonChat dispatches on string names:

// Udon original — broadcast
receiver.SendEvent("ChatMessage", message.Replace(",", "|"));
// Udon original — handler
switch (e[0])
{
case "ChatMessage": logger.Notice(characterName + ": " + e[1]); break;
}

In WASM you just hold a reference and call the method:

// WASM port — broadcast over the network + deliver to the local handler
Networking.SendMessage(writer.Buffer.Slice(0, writer.Length), null, SendType.Reliable, loopback: true);
// handler invoked on receive
receiver.Handle(author, text);

Broadcast is an explicit Networking.SendMessage with loopback: true so the sender also receives its own message and renders it in the log. The message carries [byte tag, string author, string text]; BufferReaderWriter handles string length prefixing.

Kept. Normalizes common leet substitutions (1→i, 3→e, etc.), lowercases, and checks each blocked word with IndexOf(..., OrdinalIgnoreCase). Runs locally on the sender before broadcast.

  1. Canvas with a world-space InputField for typing, a Text for the log, and a send Button.
  2. Add ChatController next to the InputField. Wire:
    • input → the InputField
    • receiver → the ChatEventHandler (see below)
    • badWords → inspector array
  3. Send button’s OnClick → ChatController.OnSendClicked.
  4. ChatEventHandler on a sibling GameObject, wire its logger field to a UdonChatLog.
  5. UdonChatLog wires its output to the log Text.