Clans in Old School RuneScape organiseren evenementen voor hun leden. OSRS Events is het gereedschap daarvoor.
Er zijn vier soorten:
- Een bord “slangen en ladders”
- Een skillrace waarin je een maand lang zoveel mogelijk ervaring in één vaardigheid haalt
- Een droprace op basis van hoeveel bazen je verslaat
- Een bingokaart van 3×3 tot 10×10.
Alleen dat eerste type heeft een bord. Daarom staan een evenement en een bord in het datamodel los van elkaar, anders sleep je bij drie van de vier soorten iets mee wat niet bestaat.
Waarom
Het idee komt rechtstreeks uit mijn eigen clan. Een evenement organiseren kostte telkens onnodig veel moeite: de planning ging handmatig, de standen werden bijgehouden waar het uitkwam en voor bingo trokken we er willekeurige bingosites bij die verder nergens op aansloten. Alles stond los van elkaar en niets was verbonden aan het spel zelf.
Ik wilde één ding waarin het allemaal zit en ben toen begonnen met bouwen.
Daar komt bij dat het om standen gaat en standen roepen de vraag op of ze kloppen. Iemand zegt dat hij die ervaring heeft gehaald; iemand anders moet dat geloven of gaan controleren. Deze applicatie haalt de cijfers zelf op. Elk account draagt een RuneScape-gebruikersnaam met zich mee die wordt bij aanmelden gevraagd. Als je geen gebruikersnaam hebt, wordt je naar een pagina met één invoerveld gestuurd voordat hij zich kan aanmelden voor een evenement. Zonder die naam is er niets op te zoeken, want de officiële scorelijsten werken op accountnaam.
Hoe het werkt
Laravel 13 met Inertia en Vue 3. Geen aparte API-laag: controllers geven een Inertia-response terug en Vue neemt het over. Rendering gaat door een langdraaiend Node-proces zodat de pagina’s server-side gerenderd binnenkomen. Sleutels zijn overal UUID’s, ook in de rollen- en rechtenlaag, waarvoor de standaardimplementatie is overschreven.
Elk evenementtype heeft een eigen live-kanaal via Server-Sent Events. De pagina opent één verbinding en de server duwt er veranderingen doorheen zodat je live iets ziet gebeuren. Dit werkt vrijwel hetzelfde als WebSockets, echter is dat bedoeld om ook pakketten vanuit jou naar de server en anderen te sturen. Dat is hier niet de bedoeling.
Het is een keer helemaal opnieuw gebouwd
Dit begon als een PoC. Een Nuxt-frontend en een losse Node-backend met GraphQL en Prisma, allebei op Vercel, vooral om te zien of ik dat kon. Dat lukte en toen groeide het door tot iets dat andere spelers echt zouden willen gebruiken.
Op dat punt begonnen twee dingen te wringen. Twee applicaties naast elkaar onderhouden viel zwaarder uit dan gedacht en de boel was traag genoeg dat het opviel. Voor een demo maakt dat niets uit. Voor een site waar clanleden elke dag hun stand op bekijken wel.
Dus is de hele applicatie van stack gewisseld: Laravel met Inertia, één codebase in plaats van twee. De oude versie is niet weggegooid maar naar een stale-map verhuisd en daarna is alles er stuk voor stuk overheen gezet.
Dat het in een paar dagen kon, kwam doordat het eerst op een aparte branch is uitgeprobeerd in plaats van meteen in de hoofdlijn.
Kernpunten waar ik trots op ben
- Server-Sent Events met één kanaal per eventtype. De pagina opent één verbinding en de server duwt er veranderingen doorheen zodat je live iets ziet gebeuren. Per kanaal een eventtype toevoegen en de stream versleutelen voor mensen die geen toegang hebben.
- Diepe Discord-koppeling voor het afschermen van evenementen en het indelen van teams. De login haalt ook de servers op waar je lid van bent, waardoor een bord lidmaatschap van een specifieke Discord-server kan worden geëist.
- Uitnodigingssysteem met shortcode, vervaldatum en gebruikslimiet. Het verschil tussen een link die je in een Discord-kanaal durft te plakken en een link die eeuwig blijft werken.
- Claim-en-goedkeurflow met eigen moderatorrollen, voor eventtypes waarbij niets automatisch te verifiëren valt. Een speler claimt, een moderator keurt goed.
- PWA-installatie met servermeldingen bij gebeurtenissen in een evenement, zodat je niet zelf hoeft te blijven kijken.
- De meest feature-rijke UI van alles wat ik heb gebouwd. Veel schermen, veel staten, veel iteraties en het moest tegelijk overzichtelijk blijven voor mensen die er één keer per dag even in kijken.
- Aankomend: een eigen RuneLite-plugin, zodat je voortgang zichtbaar wordt in de client waarin vrijwel iedereen het spel speelt.
Wat er nog niet in zit
Er komt nog een eigen RuneLite-plugin, de software waar vrijwel iedereen het spel mee speelt, zodat je voortgang wordt geautomatiseerd. Dat wordt tegelijk het leerstuk: ik heb eerder een uitbreiding op een bestaande RuneLite-plugin gebouwd en dat beviel goed genoeg om er zelf een plug-in te bouwen.
Verder staan er genoeg dingen op de planning. De voortgang is te volgen op osrs-events.com.
Wat het opleverde
Dezelfde applicatie twee keer gebouwd op twee stacks en dat is een vergelijking die bijna niemand kan maken. Verder is dit het project waar ik met Server-Sent Events heb gewerkt in plaats van met websockets via Reverb, wat een heel ander soort oplossing is voor hetzelfde probleem. En veel nauwe koppelingen plus veel UX-iteraties, omdat het tegelijk gebruiksvriendelijk en visueel rijk moest zijn.