
Meine Freundsgruppe hat bereits einige Male versucht, DND Kampagnen anzufangen, ist jedoch jedes mal gescheitert da wir keine regelmäßigen in-Person Termine geplant gekriegt haben. Mittlerweile leben wir alle mehrere Stunden voneinander entfernt und brauchten somit eine Lösung. Unser Dungeon Master (DM) hat viele existierende Online Lösungen ausprobiert, doch haben alle entweder zu viel gekostet oder hatten nicht alle Features die man sich gewünscht hat.
Aus diesem Grund habe ich vorgeschlagen, eine eigene Lösung zu erstellen und habe mit dem DND Wissen von dem DM und meiner Programmiererfahrung “How to play DND Online fast” geschaffen.
Wahl des Tech-Stacks
Aus meinen vorigen Projekten habe ich schon viel Erfahrung in der Web-Entwicklung gesammelt, hatte aber das Gefühl, dass eine Webseite nicht optimal wäre. Außerdem wollte ich schon seit einiger Zeit in ein Projekt in Rust bauen und das war die Perfekte Gelegenheit.
Folglich habe ich im Backend Rust mit dem Warp Framework, welches sich als “One of the fastest HTTP implementations” vorstellt benutzt (außerdem war guter Websocket-Support wichtig).
Für das Frontend wollte ich eine Desktop App und habe Tauri 2.0 gefunden. Quasie Electron aber kleiner, schneller, sicherer und allgemein besser. Für das Web-Frontend habe ich Svelte mit Typescript benutzt (Für Typescript war ich sehr dankbar nachdem ich das Projekt für einige Wochen nicht angefasst hatte).
Kommunikation
Wie schon erwähnt habe ich (JSON über) Websockets benutzt, da für die App Realtime-Kommunikation wichtig war.
In früheren Versionen der App wurden sogar Mauspositionen und Markerpositionen über Websockets übertragen, was ich jedoch für Raw UDP ausgewechselt habe. Auf die Idee, Raw UDP zu benutzen bin ich gekommen, da wir in einer Vorlesung in der Uni Low-Level Networking behandelt und als Teil einer Übung unser eigenes Traceroute implementiert haben. Die UDP Kommunikation ist unverschlüsselt und besteht aus einem Byte für den Requesttyp (Maus oder Marker, ich wollte mir offen lassen mehr Kommunikation auf Raw UDP zu wechseln, sobald ich encryption implementiert habe) und zwei f32 bzw. + ein String für die Marker
Für Bilder bin ich jedoch bei normalen HTTPS Requests geblieben.
Features
- Spieler-Spezifisches Fog of War System mit Grid-basierter Karte
- 3D Würfel mit Würfelanimation (Dice-Box)
- Automatische Initiative-Verwaltung (+ Manuelles verschieben vom DM)
- D&D Beyond (inoffizielle) API Integration
- Ein Lineal mit dem man die Distanz in Fuß messen kann, angepasst auf das vom DM eingestellte Grid
Technische Entscheidungen
Um vom Server aus die Clients über UDP zu erreichen und mit dem Stateless Protokoll zu merken, wer eigentlich online ist schicke ich von allen Clients einen Heartbeat an den Server. Das ermöglicht außerdem komplett die NAT Traversal Rabbit Hole zu umgehen.
Für alles außer die Positionen die über UDP übertragen werden, ist kein Packet Loss oder überhaupt Übertragung ohne Verschlüsselung akzeptabel, weswegen dafür noch Websockets benutzt werden.
Svelte hat das Frontend sehr einfach gemacht, da alles reactive ist und die Abstraktion in Komponenten schnelle Entwicklung und das Rendern von z.B. schönen Charakterbögen aus dem JSON von dem Server ermöglicht hat.
Außerdem habe ich mit dem Tauri Updater, der zusätzlich Signaturen der Updates überprüft, Auto Updating mit GitHub Releases eingebaut, damit niemand ausversehen auf einer alten Version der Software bleibt und deshalb Fehler auftreten.
Da Authentication für mein Spiel nicht so wichtig ist, habe ich mich dafür entschieden jedem Nutzer einen Token zuzuweisen, mit welchem er sich einloggen kann und aus welchem Nutzername etc. erschlossen werden.
Warum veröffentliche ich das Programm nicht als Produkt?
Meine App nutzt eine inoffizielle API von D&D Beyond, benutzt deren Icons und beinhaltet getrademarked Begriffe wie “Dungeon Master”. Wenn ich das versuchen würde hätte ich schneller eine Cease & Desist in meinem Briefkasten als ich “Dungeons & Dragons” sagen könnte.
Warum nicht Open Source?
Die App ist im Kern für unsere private Nutzung gedacht und beinhaltet insider Witze. Außerdem setze ich einen Fokus auf schnelle Iteration von Features die speziell für unsere Sessions Sinn ergeben statt für alle Tabletops etc.
Ich habe ein paar Tage nachdem ich diesen Blog-Post veröffentlicht habe für einen Reddit Post mir mal Davinci Resolve 20 heruntergeladen und einen Trailer gemacht :)