Kay Smits
Alle projecten

Pigeon Mail

Mobiele game waarin duiven je berichten over een echte wereldkaart bezorgen.

Rol
Game, backend en infrastructuur
Periode
2025 - 2026
Stack
  • Unity 6
  • C#
  • Laravel
  • Mapbox
  • Firebase

Je stuurt een bericht mee met een duif, die daadwerkelijk een route over de kaart aflegt en er tijd over doet. Daaromheen accounts, vrienden, een winkel en statistieken.

Het beheerportaal van Pigeon Mail

De duif is serverstaat, niet appstaat

Een reis staat als rij in de database met een beginpunt, een huidige positie en een tijdstempel. Een wachtrij-job verplaatst elke actieve reis met de vliegsnelheid van die duif in meters per seconde, schrijft per stap een logregel met de afgelegde meters, en zet de reis op aangekomen zodra de bestemming is bereikt. De app tekent alleen wat de server zegt. Twee toestellen kunnen het dus niet oneens zijn over waar dezelfde duif is, en sluit je de app, dan vliegt hij door.

Coördinaten versleuteld in de database

Lengte- en breedtegraad gaan door een versleutelde cast, dus ze staan niet leesbaar in de tabel. Voor een spel dat om echte locaties draait is dat het verschil tussen een datalek met een kaart van waar mensen wonen en een kolom met ruis. Er is een endpoint waarmee een speler zijn account laat verwijderen, en de locaties van vrienden staan in een cache die apart wordt geleegd.

Van Niantic naar Mapbox, onder dwang

Het project ging niet meer open: Niantic haalde de Lightship-kaartpakketten offline en de packagemanager bleef hangen op een 404. Overgezet naar Mapbox v3 met vijf vectorlagen op de bestaande pixelart-materialen, een permanente tegelcache en wereldschaal 8. Onderweg kwamen er drie dingen mee die niets met kaarten te maken hadden: een verwijderde render-API in URP 17, een verkeerd geplaatste using en een dubbele Newtonsoft-dll.

Eén monoliet werd vijf assemblies

Alle C#-scripts zaten in Assembly-CSharp: elke wijziging hercompileerde alles en er was geen grens tussen lagen. Nu is er een kern zonder Unity-afhankelijkheid die in een tiende seconde test zonder dat er een scene laadt, met daarnaast de api-laag, de spellaag en de editorlaag. De compiler wees meteen verborgen afhankelijkheden aan en hield een Unity-logger tegen in de pure laag.

Een fout die eruitzag als een hang

Gooide er iets in een coroutine, dan stierf die stil: geen callback, geen melding, alleen een app die niets meer deed. Twee keer live gezien en met curl niet te reproduceren. De api-laag geeft nu een resultaattype terug dat niet leeg kan zijn, en een try/catch garandeert precies één callback. Daarbovenop een foutsoort die zegt of het zin heeft opnieuw te proberen en of de sessie verlopen is.

Versiecontrole die niet alles buitensluit

De app vergeleek zijn versie met die van de api en zou bij de eerstvolgende release iedereen buitensluiten. Nu geldt een ondergrens per platform, ingesteld via een omgevingsvariabele zonder deploy, met echte semver-vergelijking en een uitzondering voor reviewers. Een Android-hotfix sleurt iOS er dus niet in mee.

Wat erin zit

  • Berichten en reizen Een bericht krijgt een duif mee; de reis loopt door in echte tijd met een logboek per stap.
  • Vrienden Zoeken op afstand, verzoeken sturen, accepteren of weigeren.
  • Winkel en valuta Duiven met eigen basiswaarden, waaronder vliegsnelheid, af te rekenen met in-game transacties.
  • Beloningen en statistieken Voortgang per account, met beloningen die aan mijlpalen hangen.
  • Pushberichten Firebase Cloud Messaging met een apparaattoken per toestel, zodat aankomst binnenkomt als de app dicht is.
  • Beheerportaal Losse webomgeving voor het team, los van de spelaccounts.