Sonntag, 9. November 2014

Nachrichten asynchron anzeigen mit einer Messag-Queue

Voraussetzung: "Der Einstieg in lua“

Abbildung 1: Wenn die Nachricht unpassend ist, wird sie später angezeigt

In diesem Beitrag geht es um asynchrone Nachrichtenverarbeitung. Klingt komplizierter als es ist, deswegen will ich es mal an einem einfachen Beispiel erklären:

Stellt euch vor in eurem Wherigo-Spiel geschieht gerade ein längerer Dialog. Der Spieler muss 3-4 Fragen beantworten auf die er jeweils direkt eine Antwort bekommt.

Dazu habt ihr einen Timer der im Hintergrund einmal pro Minute etwas prüft und gegebenenfalls eine Nachricht anzeigt "Die Löwen sind wieder hungrig und möchten gefüttert werden"
Nicht nur dass die Nachricht Umlaute enthält, nein sie würde auch im aktuellen schwierigen Dialog stören bzw. wichtige Informationen überlagern.

Stellt euch vor, der Spieler erhält gerade die dringende Nachricht "Gehe schnell zum Affengehege" als der Timer anspringt und sofort mit der wenig dringenden Löwennachricht überlagert. Da wüsste der Spieler gar nicht, dass er zuerst du den Affen soll.

Um dass zu verhindern nutze ich eine Mesage-Queue in die ich Nachrichten einstelle (Zeile 174), wenn sie gerade unpassend sind. Wenn sie gerade nicht stören, also hideMessage auf false steht können sie auch direkt angezeigt werden.
Die msgQueue besteht aus einer Tabelle in die mit table.insert ein Text sowie ein Bild eingefügt wird, um später die Nachricht darzustellen.
Zusätzlich hält das Array-Objekt noch einen Pointer, der auf die nächste darzustellende Nachricht zeigt.

Wenn dann die kritische Situation vorbei ist (Der Dialog ist beendet, oder immer wenn der Spieler eine Zone verlässt) wird printMessageFromQueue aufgerufen. Diese Methode prüft ob neue Nachrichten vorhanden sind (dann wenn mehr Nachrichten im Array sind als der Pointer groß ist) und gibt die Nachricht aus auf die der Pointer zeigt.
Nach Drücken von "OK" durch den Spieler wird der Pointer einen weitergesetzt und printMessageFromQueue rekursiv aufgerufen. Solange bis alle Nachricht abgearbeitet, also angezeigt wurden.


Abbildung 2: Während der Dialog mit dem Spieler etwas länger dauert, springt der Timer an und schiebt die Nachricht in die Queue
Abb. 2 zeigt uns die Anwendung im Code. Die Methode doLongDialog soll den komplizierten Frage-Antwort-Dialog simulieren. Bevor der Dialog startet wird hideMessage auf true gesetzt. Ab jetzt gehen alle Nachrichten in die Queue.
Zeile 206 bis 208 zeigen uns den Timerfall. Während der Timer anspringt ist hideMessage positiv und die Nachricht wird eingereiht.

Nachdem der Dialog vorbei ist, wird (!!! Im Callback des letzten Dialogs / MessageBox !!!) hideMessage wieder auf false gesetzt, damit ab jetzt wieder live angezeigt werden kann, da die kritische Situation vorbei ist.

Wenn es in eurem Spiel keinen festdefinierten Zeitpunkt gibt, wann die Nachrichten nachgeholt werden können, könnt ihr mit einem weiteren Timer arbeiten, der alle 60 Sekunden prüft ob hideMessage auf false steht und dann printMessageFromQueue aufruft.


Abbildung 3: Egal ob direkt oder später, die Nachricht erscheint als MessageBox

Samstag, 8. November 2014

Doppelte Logeinträge mit GSAK finden

Wer kennt es nicht das Problem. Man hat 2-3 Wochen bzw. 50 Caches lang keine Statistik mehr generiert und dann nachdem man mal wieder die Graphiken aktualisert hat, kommt das Horrorszenario: 2047 Funde bei 2046 Caches.


Abbildung 1: Der Horror - Bei einem Cache hab ich aus versehen doppelt geloggt
OK, es müssen nicht genau 2047 Funde sein, aber das Problem hatten die meisten schonmal. Bei irgendeinem Cache ist doppelt geloggt wurden. Entweder hat der Groundspeak Server gehangen und man hat doppelt losgeschickt, man hat einmal vom Smartphone und einmal am PC geloggt oder beim nachträglichen Ändern des Logs (Text / Datum) ist was schiefgegangen.
Schlimmer als die Frage WARUM ist "WO habe ich doppelt geloggt?" Da kann es schon ein wenig mühselig sein die letzten 50 Caches durchzugehen. Vorallem wenn man zwischendurch ganz alte Einträge nachholt. "Ach ja, das Event von letztem Jahr muss ich auch noch nachloggen."

Abbildung 2: Sqlite Manager als Datenbank-Tool starten
Aber warum soll man selber suchen und nicht suchen lassen.

Anmerkung: Nach Veröffentlichung des Posts wurde ich durch Kommentare aufmerksamer Leser darauf hingewiesen, dass man das Problem mittlerweile durch GSAK-Bordmittel lösen kann. (Siehe Kommentare). Hier erfolgt der Ansatz über die Datenbank, der für das Doppelte-Logs-Problem etwas komplizierter ist, dafür aber einen guten Einstieg gibt, wie man Infos aus der zugrunde liegenden Datenbank sqlite ziehen kann
Wir werfen dazu einen Blick auf die Datenbank, genau genommen der Datenbestand, der alle Founds enthält und von wo aus die Statistik generiert wird.
Um einen direkten Datenbankzugriff zu bekommen nutzen wir das von GSAK mitgelieferte Tool Sqlite Manager. Dies ist über Tools in der Menüleiste zu erreichen.
Wer mit alternativem Tools wie z.B. DBVisualizer unterwegs ist kann auch direkt die Sqlite Datei .db3 öffnen aber das GSAK integrierte Tool tut es hier vollkommen.


Abbildung 3: Die richtige Datenbank auswählen
Wichtig ist, dass ihr die richtige Datenbank auswählt. Bei mir heißt die Datenbank für die Funde foundDB, folglich liegt die Datenbankdatei unter data/foundDB/sqlite.db3


Abbildung 4: Durch geschickten Select auf die Logs Tabelle bekommt man alle doppelten Einträge heraus
Sobald die richtige Datenbank geöffnet ist, geht es los.
Zuerst selektiert man alle Zeilen deren Log-Type Found it und deren Finder man selbst ist. Krolock müsst ihr natürlich durch Euren Nickname ersetzen, ansonsten sehr ihr nur, ob ich doppelt geloggt haben
Um nicht mit unnötig vielen Daten weiterzuarbeiten wird nur die Spalte lParent geladen. Dies ist der GCCode des Caches den ihr gefunden habt. Der SQL-Befehl lautet bisher
SELECT lParent FROM Logs where lType = 'Found it' and lBy = 'Krolock'
Es müssten nach unserem Beispiel 2047 Zeilen ausgegeben werden.
Jetzt kommt der entscheidene Schritt, die Gruppierung. Dazu ergänzen wir im select Part ein Count(*) und gruppiern auf lParent
SELECT count(*) c, lParent FROM Logs where lType = 'Found it' and lBy = 'Krolock' group by lParent liefert nun 2046 Zeilen bei dem überall die Zählspalte c den Wert 1 besitzt.
"Ganz Gallien?" - Nein in einer Zeile steht ein 2, das ist die gesuchte Zeile. Um die Einserwerte zu eleminieren bauen wir noch ein Select um das Zwischergebnis herum, indem wir mit where c > 1 nur die Mehrfachnennungen aufzeigen und -falls ihr so richtig Mist beim Loggen hinbekommen habt- sortieren wir noch nach c absteigend

Zu kompliziert?

Solltest du jetzt denken " .... HÄ ???? .... ", so kann ich dich beruhigen.
Nimm einfach folgenden Code und ersetzte Krolock durch deinen Nickname.
Drücke dann auf F9 und schon siehst du den GCCode der Caches bei denen du doppelt geloggt hast.
select * from (SELECT count(*) c, lParent FROM Logs where lType = 'Found it' and lBy = 'Krolock' group by lParent) where c > 1 order by c desc

Dienstag, 4. November 2014

Wegführung zu lang, so was geht aber nun wirklich nicht

Ich wußte gar nicht, dass man bei einer Mystery-Serie die Dosen immer so anlegen muss, dass man eine schöne Wegführung hat. In den 6 Jahren in denen ich nun cache und auch eigene Caches veröffentliche, dachte ich immer es ging beim Cachen darum raus zu kommen, tolle Locations zu entdecken und gerade bei Mysteries lustige Suche zu entdecken bzw. was zu lernen.
So hab ich dann letztes Jahr auch gutgläubig 12 lustige Rätsel zum Thema Fußballerzitate veröffentlicht. Olli Kahn und Poldi lassen grüßen. Nach gut anderthalb Jahren hab ich aufgehört zu zählen wie viele Logs ich von der Art bekommen habe, wie ich euch mal exemplarisch mal einen hier zeigen möchte. Er stammt von Fußballerzitate #01

Ja hätte ich das gewußt. Da wäre mir natürlich Naturverträglichkeit und Sinnhaftigkeit von Locations egal gewesen und bei der Abstandregel zu bestehenden Caches hätte ich ein wenig gefuscht.
Aber wenigstens hätte ich dann einen Rundweg gebaut, bei dem alle 161 Meter eine Dose liegt, die von weitem sichtbar ist und auch ohne Schlamm erreichbar wäre.
Ich glaube, um sicher zu gehen, werde ich bei der nächsten Runde einfach vorher alle Interessenten fragen, ob sie mir der geplanten Tour zufrieden sind. Kann ja nicht sein, dass Leute extra aus Hessen anreisen und dann am Ende des Tages 500 Meter zu viel gelaufen sind. Am Besten ich hänge alles an Straßenschilder, dann kann man auch direkt im Auto bleiben.
Oder Plan B: Ich leg einfach keine Dosen mehr. Dann muss auch niemand zu viel laufen oder sich ärgern, dass er keinen Rundweg hat.