Zum Inhalt springen

Wechsel von einem anderen Telefon

Eine Stadt, die bereits ein Telefon besitzt, birgt Jahre an Daten: Rufnummern, die man auswendig kennt, Konversationen, Fotos, @handles. Das alles zu verlieren, ist der eigentliche Preis eines Telefonwechsels und der Grund, warum die meisten Server davor zurückschrecken. Diese Funktion liest die Tabellen des alten Telefons ein und befüllt unsere.

Vier Telefone werden unterstützt, und alle vier werden nach demselben Prinzip getestet: Ihre Tabellen werden nach dem Schema ihres Installers angelegt, eine kleine Teststadt wird eingetragen, der Import wird real ausgeführt und jede importierte Zeile anschließend geprüft.

VonSeine TabellenWorüber alles zugeordnet wird
lb-phonephone_*die Rufnummer, wobei phone_phones die Nummer einem Besitzer zuweist
Quasar Smartphone Proqs_phone_*eine scope_id — ein einzelnes Telefon, keine Person
NPWDnpwd_*der Framework-Identifikator, und seine Nummern stehen bereits in users
qb-phoneplayer_contacts, phone_messages…citizenid, was unter QBCore der Besitzer dieses Telefons ist

Das alte Telefon wird niemals angerührt. Kein einziger Befehl schreibt in eine fremde Tabelle. Die Daten von lb-phone bleiben exakt so, wie sie waren; ein Zurückrollen ist daher denkbar einfach: Lösche unsere Zeilen.

Der Probelauf ist real. DryRun ist standardmäßig aktiv. Er liest alles, was ein echter Durchlauf liest, berechnet jede Zeile, die geschrieben werden würde, schreibt keine davon und gibt die Zähler aus. Es ist derselbe Code — ein Probelauf, der Abkürzungen nähme, wäre kein verlässlicher Test.

Es kann nicht versehentlich doppelt ausgeführt werden. Ein realer Durchlauf hinterlegt eine Quittung in der Datenbank. Der nächste Start findet diese und stoppt, da eine vergessene Config-Zeile sonst jede Konversation der Stadt duplizieren würde.

-- shared/config/import.lua
Config.Import = {
From = 'lb-phone', -- or false, which is where it starts
DryRun = true, -- read the count first
Numbers = 'keep', -- their old numbers move across
Crypto = 'cash', -- sell their coins at their own price
}

Starte den Server einmal neu und lies die Konsole:

[mic_phone import] lb-phone — REHEARSAL, nothing was written
[mic_phone import] contacts 482
[mic_phone import] messages 19104
[mic_phone import] numbers 137
[mic_phone import] photos 2210
[mic_phone import] social 96
[mic_phone import] · a phone whose owner is not in `users` any more was skipped (×8)
[mic_phone import] · lb-phone does not say whether an alarm repeats, so its alarms arrive as one-off alarms

Setze dann DryRun = false, starte ein weiteres Mal neu und setze From = false, sobald alles durchgelaufen ist.

Befinden sich die Tabellen nicht in dieser Datenbank, meldet das Skript dies und bricht ohne Änderungen ab. Die Angabe des falschen Telefons kostet dich also lediglich eine Zeile in der Konsole.

Alles Folgende bezieht sich auf lb-phone als das umfangreichste der vier Systeme. Die Besonderheiten der übrigen drei folgen weiter unten.

Aus lb-phoneWird zu
phone_phonesdie Rufnummer in users, der Akku, die Telefoneinstellungen
sein settings.appsder Startbildschirm — dasselbe Dock, dieselben Apps auf denselben Seiten
phone_phone_contactsKontakte, mit Favoriten und Bildern
phone_message_*Konversationen, Gruppen und ungelesene Nachrichten
phone_phone_callsAnrufliste, ein Eintrag pro Seite, verpasste Anrufe inklusive
phone_photosdie Mediathek, Fotos und Videos
phone_mail_*E-Mails, gelesen und ungelesen
phone_maps_locationsgespeicherte Orte
phone_marketplace_posts, phone_yellow_pages_postsKleinanzeigen
Instagram, Twitter, TikTok, TinderInstapic, Twixel, Klipz, Flinder — Handles, Namen, Bilder, Bios, Beiträge, Abonnements und Verifizierungs-Häkchen
phone_darkchat_*das Darknet: der Raum, wer anwesend war, was geschrieben wurde
phone_notes, phone_clock_alarmsNotizen und Wecker — da lb-phone nicht speichert, ob ein Wecker wiederholt wird, kommen sie als Einmal-Wecker an
phone_cryptosiehe Krypto weiter unten

Bilder sind auf beiden Telefonen URLs, daher wird nichts heruntergeladen oder erneut hochgeladen. Die Fotos der Spieler funktionieren ab dem ersten Tag nahtlos weiter, da sie nie auf einem der beiden Telefone physisch lagen.

Der Importbericht spricht jeden dieser Punkte offen an, anstatt dich im Unklaren zu lassen.

  • Hintergrundbilder und Klingeltöne. Die alten Systeme referenzieren eigene Dateien, wir unsere. Ein fehlerhaftes Bild ist störender als das Standardbild.
  • Passwörter für soziale Netzwerke. Siehe unten — die Accounts ziehen um, Passwörter können es technisch nicht.
  • Flugmodus, ganz bewusst. Einen Schalter zu importieren, den jemand angelassen hat, bedeutet ein defektes Telefon und einen Spieler, der den Grund nicht versteht.
  • Fotoalben. Jedes Bild landet in der Mediathek; Alben werden nicht rekonstruiert.

Das am saubersten aufgebaute der vier Systeme; an drei Stellen ist das Mapping exakt statt angenähert:

  • Ungelesene Nachrichten werden neu berechnet, nicht kopiert. Quasar speichert last_read_message_id; wir eine Gesamtzahl. Die Zahl wird also exakt ermittelt — wie viele Nachrichten in diesem Chat folgten auf die zuletzt gelesene —, was selbst dann stimmt, wenn der alte Zähler asynchron war.
  • Anruflisten nutzen bereits incoming, outgoing und missed, was exakt unseren drei Werten entspricht.
  • Ein Foto weiß, dass es ein Video ist, mitsamt Laufzeit und Poster, und kommt somit als solches an.

Notizen (angepinnte bleiben angepinnt), Wecker, Kalendereinträge und Erinnerungen ziehen ebenfalls mit um: Eine offene Erinnerung mit Fälligkeitsdatum wird zum Kalendereintrag, eine ohne Datum bleibt als Notiz erhalten, erledigte werden verworfen. Quasar kann Wecker nur am Wochenende wiederholen, was dieses Telefon nicht anbietet; diese Wecker werden zu Einmal-Weckern.

Gepinnte und stummgeschaltete Chats behalten beide Status. E-Mails behalten ihren Ordner — Entwürfe und Papierkorb bleiben zurück, da sich der Umzug eines nie gesendeten Entwurfs nicht lohnt. Was nicht mitkommt: Einstellungen und Startbildschirm (liegen in einem Quasar-spezifischen JSON-Blob) sowie deren App-Store-IDs.

Wichtig zu wissen: Quasar erlaubt mehrere Telefone pro Charakter, während dieses Modell eine Nummer pro Charakter führt. Die erste verarbeitete Nummer wird übernommen; weitere werden im Bericht aufgeführt und überschreiben nichts.

Das unkomplizierteste System aus einem erfreulichen Grund: NPWD speichert die Nummer bereits in users.phone_number, genau in der Spalte, die auch dieses Telefon liest. Auf einem Standard-NPWD-Server muss nichts verschoben werden, und der Bericht bestätigt dies ehrlich.

Konversationen sind nach einer Zeichenkette der beteiligten Rufnummern statt nach einer ID benannt, die Verknüpfung erfolgt also über diesen String. Der Twitter-Profilname wird zum @handle; Match besitzt überhaupt keine Nutzernamen, weshalb ein Flinder-Account über die Nummer des Charakters zugeordnet wird. Fotos haben keinen eigenen Zeitstempel, daher wird die Mediathek nach der Aufnahmereihenfolge datiert. Notizen ziehen analog nach Erstellungsreihenfolge um. Inserate tragen keinen Preis und werden auf null gesetzt.

Das älteste und uns am unähnlichsten — die Identität ist jedoch geschenkt, da dieses Telefon auf QBCore ohnehin die citizenid nutzt, über die qb-phone alles steuert.

Die Konversationen machen die Arbeit. qb-phone kennt keine Chats im klassischen Sinn: phone_messages ist eine Zeile pro Person und Rufnummer mit dem gesamten Verlauf als JSON-Array, getrennt von beiden Seiten geschrieben. Dieselbe Konversation existiert also doppelt und weicht oft voneinander ab. Jedes Nummernpaar wird daher ein einziges Mal aufgebaut, und zwar von der Seite mit den meisten Einträgen — ein Zusammenführen würde eine falsche Reihenfolge erfinden, und der Import beider Seiten gäbe jedem Spieler jede Nachricht doppelt. Chats ohne Zeitstempel behalten ihre Reihenfolge und werden im Minutentakt angeordnet.

Rufnummern liegen in players.charinfo als JSON statt in einer Spalte; sie werden dort ausgelesen und an unserem Speicherort abgelegt. Tweets tragen einen Anzeigenamen statt eines Accounts, weshalb pro Charakter ein Twixel-Account aus dessen Namen erzeugt wird.

Numbers = 'keep' ist der eigentliche Kern des gesamten Vorgangs: Die Nummer auf der Visitenkarte und in den Telefonbüchern aller anderen erreicht weiterhin dieselbe Person.

Eine Nummer wird grundsätzlich nur in eine leere Spalte geschrieben. Hat ein Charakter hier bereits eine abweichende Nummer, liegt ein Konflikt vor: Er wird gezählt, im Bericht genannt und nichts wird überschrieben. Alte Nummern behalten ihr gewohntes Format — 1234567890 statt des hiesigen 555-###-#### —, was rein kosmetisch ist und nur künftig neu vergebene Nummern betrifft.

Numbers = 'ours' belässt bestehende Felder unberührt und lässt dieses Telefon eigene Nummern verteilen. Alte Kontakte laufen dann ins Leere — nur sinnvoll für Städte, die bei null anfangen.

Deren Passwörter stehen im Klartext in einer Datenbankspalte. Unsere sind ein PBKDF2-Hash, der im Browser des Spielers erzeugt wird. Das eine lässt sich nicht aus dem anderen errechnen — das Passwort ist daher das Einzige, was nicht mitwandert und unterwegs nirgends zwischengespeichert wird.

Der Account kommt als importiert markiert an. Beim ersten Öffnen der App meldet das Telefon: Dieser Account stammt von deinem alten Telefon. Wähle ein Passwort dafür, und das wird das neue Passwort.

Das ist sicherer als jedes Passwort: Die Zeile nennt einen Besitzer, und der Server weiß ohne Nachfrage, wer anfragt. Ein Passwort, das nie unseres war, würde ohnehin nichts beweisen.

Zwischen zwei erfundenen Märkten gibt es keinen fairen Wechselkurs. Entscheide daher selbst, was geschehen soll, anstatt es raten zu lassen:

  • 'cash' — zu den Kursen des alten Telefons verkaufen und dem Wallet als Buchung gutschreiben. Niemand gewinnt, niemand verliert und es muss nichts ausgehandelt werden.
  • 'skip' — unverändert belassen. Die Bestände verbleiben in ihren Tabellen und können manuell geregelt werden.
  • eine Tabelle — deine eigene Umrechnungstabelle, falls Bestände als Coins überleben sollen:
Crypto = { qbit = 'santo', lifeinvader = 'vine' },

Am alten Telefon wurde nichts verändert, daher:

  1. Lösche unsere Zeilen für den fehlerhaften Schritt — der Bericht benennt sie.
  2. Lösche die Quittung: DELETE FROM mic_phone_json WHERE owner = '@import'.
  3. Setze Config.Import.Again = true und starte den Vorgang erneut.

Über Skip lassen sich einzelne Schritte anhand der Namen im Bericht überspringen:

Skip = { 'photos', 'crypto' },