Skip to content

WhatsDab

Latest release1.1.0
DownloadGitHub · Thunderstore
RequiresMelonLoader 0.7.3, Sideload 1.10.0

🛟 Need help or found a bug? Get support at support.doodesch.de/whatsdab.

Text the people in your lobby from the phone you already carry. Threads, unread counts, group chat and one-to-one, in both orientations.

Built on Sideload, which is a hard requirement - the whole interface is three web files rather than hand-built panels, and the mod’s own C# is one Apps.Register call plus the chat itself.

WhatsDab appears on the in game phone as its own app, and it texts the people actually in your Steam lobby. One thread per player plus a group thread for everyone, with a contact list and the conversation side by side, a search filter, unread counts per thread and in total, coloured avatars, day separators, bubbles with the sender’s name in groups, timestamps, a delivery tick, a typing indicator in both the conversation and the contact list, and a send bar.

Any lobby works - plain co-op, one a gamemode opened, one from the main menu. It rides the same Steam lobby chat the game already uses for its own messages, so there is no server, no FishNet and no other mod in the way. Side Hustle is not required.

The phone turns with the game’s own rotate keys - the app has no button for it, and the key strip at the bottom left says which key. Landscape keeps the two panes side by side; portrait switches to push navigation - the list, then the conversation, with a back arrow. That is one @media (orientation: portrait) block in app.css, not a second layout.

Right-click goes back the way it does everywhere else on the phone: out of a conversation first, and only from the list does it close the app.

With a conversation on screen the keyboard belongs to the message box, so you can just type. Before that, every letter was still a game binding: “hello” walked you forward, crouched you and swapped two inventory slots unless you clicked the box first. Escape and right-click still leave, on the first press. Click the search field and it keeps the keyboard for as long as you are searching.

Press Enter and WhatsDab opens on the Everyone chat with the cursor already in the message box, phone in your pocket or not - so answering somebody is one key rather than a phone, a home screen, an app and a click. Enter still belongs to the game where the game wants it: nothing happens while you are typing, paused, or at a station, a shop or the console, and nothing happens outside a lobby. Sideload owns the key and turns it off in one place (AppKeys in MelonPreferences.cfg); with a second messenger installed it hands Enter to whichever app messaged you last.

Conversations live in memory for the session and are deliberately never written to disk: a chat log on someone’s drive is not what people expect from a lobby chat, and the name shown is whatever a player already goes by in game, so a privacy mod that renames them is respected here too. Leave the lobby and the conversations are gone.

A development build swaps the lobby for a scripted conversation, so the whole interface is exercisable from a single player save without a second machine.

To answer one question: can somebody else build with this framework without knowing its internals? The project references no Unity assembly, no IL2CPP interop and not Sideload itself - only MelonLoader plus the single file Sideload.Api shim, which finds the host by reflection. That is the whole point. A mod author writes game logic in C# and the entire interface in web files, and ships one DLL.

The same screen exists in Side Hustle as hand built uGUI, which makes the comparison concrete:

uGUI (SideHustle Messenger)Sideload (this mod)
Interface781 lines of C#518 lines of HTML/CSS/JS
Logic + data489 lines of C#475 lines of C#
Changing the layoutrebuild, restart the gamesave the file

What sits in those lines matters more than how many there are: the uGUI version spends 60 of them computing a chat bubble’s width, line count and height from text measurements. In CSS the same bubble is align-self, max-width and padding.

WhatsDab/
Core.cs MelonMod: one Register call, then only data
Chat/IChatSource.cs where conversations come from - the seam between the two halves below
Chat/ChatBackend.cs the ENTIRE seam to the interface: 6 calls in, 1 event out
Chat/DemoSource.cs the scripted conversation, so the app works with no lobby running
Chat/ChatModel.cs threads, messages, unread counts, all in memory
Chat/Json.cs a tiny JSON writer (no parser needed on the C# side)
Lobby/LobbySource.cs the real one: everyone in your Steam lobby
Lobby/ChatTransport.cs send and receive over Steam lobby chat
Lobby/ChatEnvelope.cs the wire format
Lobby/ChatStore.cs conversations, unread counts, echo reconciliation
Lobby/Contacts.cs lobby members, resolved to display names
Assets/whatsdab/ index.html, app.css, app.js, icon.png - the app itself

The two halves meet at IChatSource, and that seam has already paid off once: the lobby transport was added under it without ChatBackend or a single line of the interface changing. Chat/ compiles without any game reference, which is what lets the headless suite run the page’s JavaScript against the real handlers in a second.

Assets/whatsdab/ also carries preview.html and s1-mock.js. Those two are authoring tools, not part of the app: open preview.html in Chrome and the shipped app.js and app.css run in a 733x400 frame without launching the game. They are excluded from the embedded bundle rather than shipped as dead weight.

AppHandle app = Apps.Register("whatsdab", "WhatsDab.Assets.whatsdab", title: "WhatsDab");
app.OnCall("chat.threads", _ => Threads()) // answers s1.call('chat.threads') in the page
.OnCall("chat.thread", Conversation)
.OnCall("chat.send", Send);
app.Emit("chat.changed", unread.ToString()); // reaches s1.on('chat.changed', fn) in the page

Strings both ways, JSON for anything structured. No CLR object reaches the script and no script object reaches the mod, which is why app.css can be rewritten from scratch without touching ChatBackend.cs.

One detail worth stealing: the event is pushed from the update loop when a revision counter changes, not from inside a handler. Emitting from inside an OnCall re-enters the script engine while it is still on the stack.

ComponentVersion / Source
Schedule IIL2CPP (current Steam public build)
MelonLoader0.7.3+
Sideload1.10.0+ - the framework that renders the app, and the source of the Enter key

Install with a mod manager (r2modman / Gale) from the Schedule I community; MelonLoader and Sideload are pulled in automatically.

  1. Install MelonLoader 0.7.3 for Schedule I.
  2. Install Sideload and its support libraries.
  3. Drop WhatsDab.dll into your Schedule I Mods/ folder.
  4. Open the phone in game. WhatsDab is on the home screen.

None. This mod registers no MelonPreferences entries and has nothing to tune. The Enter key is Sideload’s, and AppKeys under Sideload_01_Main switches it off along with every other app key; see the Sideload README.

Any file under Mods/whatsdab/ overrides the copy embedded in the DLL. Copy index.html, app.css and app.js into that folder, edit them, and the changes are picked up the next time the page builds. With Sideload’s Chrome DevTools switched on, Page.reload in the inspector rebuilds from disk on the spot. That is also the mechanism players use to reskin an app.

  • IL2CPP build only (current Steam public branch).
  • Nothing is added to the world and nothing is written to a save. What does travel between players is chat text, over the Steam lobby’s own chat channel - so everyone in the lobby needs WhatsDab to take part, and players without it are unaffected.
  • Without Sideload installed the shim binds nothing, every call is a no op and the mod simply does nothing rather than throwing.
  • DooDesch - mod author.
  • Built on Sideload.

Provided as-is under the MIT License.