Pular para o conteúdo

Vindo de outro telefone

Uma cidade que já tem um telefone acumula anos de coisas nele: números que as pessoas decoraram, conversas, fotos, @handles. Perder tudo isso é o verdadeiro preço de trocar de telefone, e é a razão pela qual a maioria dos servidores nunca troca. Isto lê as tabelas do telefone antigo e escreve nas nossas.

É possível migrar de quatro telefones, e todos os quatro são testados da mesma maneira: suas próprias tabelas são criadas a partir do esquema que o instalador deles envia, uma pequena cidade é gravada nelas, a importação é executada de verdade e cada linha que ela afirma ter processado é verificada depois.

DeSuas tabelasPelo que ele indexa tudo
lb-phonephone_*o número de telefone, com phone_phones transformando um em dono
Quasar Smartphone Proqs_phone_*um scope_id — um telefone, não uma pessoa
NPWDnpwd_*o identificador da framework, e seus números já estão em users
qb-phoneplayer_contacts, phone_messages…citizenid, que é o dono deste telefone no QBCore

Ele nunca toca no telefone antigo. Nenhuma instrução sequer escreve em uma tabela que não seja nossa. Os dados do lb-phone ficam exatamente como estavam depois, o que torna o caminho de volta simples: apague as nossas linhas.

O ensaio é real. DryRun vem ativado por padrão. Ele lê tudo o que uma execução real lê, calcula cada linha que escreveria, não escreve nenhuma delas e imprime a contagem. É o mesmo código — um ensaio que pegasse atalhos seria um ensaio de nada.

Não pode acontecer duas vezes. Uma execução real deixa um recibo no banco de dados. A próxima inicialização o encontra e para, porque uma linha de configuração esquecida duplicaria todas as conversas da cidade.

-- 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
}

Reinicie uma vez e leia o console:

[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

Depois defina DryRun = false, reinicie mais uma vez e defina From = false em seguida.

Se as tabelas não estiverem neste banco de dados, ele avisa e não faz nada, então colocar o nome do telefone errado só lhe custa uma linha no console.

Tudo abaixo refere-se ao lb-phone, que é o mais completo dos quatro. O que cada um dos outros faz de diferente está mais abaixo.

Do lb-phoneTorna-se
phone_phoneso número em users, a bateria, as configurações do telefone
seu settings.appsa Tela de Início — o mesmo dock, os mesmos aplicativos nas mesmas páginas
phone_phone_contactscontatos, com favoritos e fotos
phone_message_*conversas, grupos e a contagem de não lidas
phone_phone_callsrecentes, uma linha para cada lado, incluindo chamadas perdidas
phone_photosa biblioteca, fotos e vídeos
phone_mail_*e-mails, lidos e não lidos
phone_maps_locationslugares salvos
phone_marketplace_posts, phone_yellow_pages_postsanúncios
Instagram, Twitter, TikTok, TinderInstapic, Twixel, Klipz, Flinder — arrobas, nomes, fotos, bios, publicações, seguidores e o selo de verificado
phone_darkchat_*a darknet: a sala, quem estava nela, o que foi dito
phone_notes, phone_clock_alarmsnotas e alarmes — os alarmes do lb-phone não dizem se são repetidos, então chegam como alarmes únicos
phone_cryptoveja Cripto abaixo

As imagens são URLs em ambos os telefones, portanto nada é baixado ou enviado novamente. As fotos de um jogador continuam funcionando no primeiro dia porque, para começo de conversa, nunca pertenceram a nenhum dos dois telefones.

O relatório diz cada um destes itens em voz alta, em vez de deixar que alguém descubra sozinho.

  • Papéis de parede e toques. Os deles apontam para os arquivos deles; os nossos, para os nossos. Uma imagem quebrada é pior do que a padrão.
  • Senhas de redes sociais. Veja abaixo — as contas vêm, as senhas não podem vir.
  • Modo avião, deliberadamente. Importar uma chave que alguém deixou ligada é importar um telefone que não funciona e um jogador que não sabe dizer o porquê.
  • Álbuns de fotos. Todas as imagens estão na biblioteca; os álbuns não são reconstruídos.

Os outros três, e o que há de diferente em cada um

Seção intitulada “Os outros três, e o que há de diferente em cada um”

O mais bem construído dos quatro, e o mapeamento é exato em vez de aproximado em três pontos:

  • As contagens de mensagens não lidas são recontadas, não copiadas. O Quasar armazena last_read_message_id; o nosso armazena um número. Assim, o número é calculado — quantas mensagens naquela conversa chegaram depois da última lida —, o que fica correto mesmo que o contador deles tivesse saído de sincronia.
  • As chamadas recentes já dizem incoming, outgoing e missed, que são as nossas três palavras.
  • Uma foto sabe que é um vídeo, com sua duração e sua capa, então chega como vídeo.

Notas (as fixadas continuam fixadas), alarmes, entradas de calendário e lembretes também vêm: um lembrete aberto com data de vencimento vira uma entrada no calendário, um sem data mantém seu texto como uma nota, e um concluído fica para trás. O Quasar pode repetir um alarme apenas nos fins de semana, o que este telefone não faz, então eles chegam como alarmes únicos.

Conversas fixadas e silenciadas mantêm ambos os estados. Os e-mails vêm com a pasta em que estavam — rascunhos e lixeira ficam para trás, porque um rascunho que ninguém enviou não vale a pena mover. O que não vem: as configurações e a tela de início deles, que vivem em um bloco JSON no formato próprio do Quasar, e os IDs da App Store deles, que não são os nossos.

Uma coisa importante: o Quasar permite que um personagem tenha mais de um telefone, enquanto este mantém um número por personagem. O primeiro número encontrado passa a ser o dele; qualquer outro é citado no relatório e nada é sobrescrito.

O mais fácil, por um motivo que vale a pena destacar: o NPWD já guarda o número em users.phone_number, que é a mesma coluna que este telefone lê. Em um servidor NPWD padrão não há nada para mover, e o relatório avisa isso em vez de fingir que trabalhou.

Suas conversas são identificadas por uma string com os números presentes nelas, em vez de um ID, então a junção é feita por essa string. O nome de perfil do Twitter vira o @handle; o Match não tem nome de usuário, então a conta do Flinder é indexada pelo número do personagem. As fotos não têm data própria, então a biblioteca recebe datas na ordem em que foram tiradas. Suas notas vêm da mesma maneira, datadas pela ordem em que foram escritas. Os anúncios não têm preço e chegam gratuitos.

O mais antigo e o menos parecido conosco — mas a identidade sai de graça, porque no QBCore este telefone já usa o citizenid pelo qual o qb-phone indexa tudo.

Suas conversas dão o verdadeiro trabalho. O qb-phone não tem conversas propriamente ditas: phone_messages é uma linha por pessoa e por número, com toda a troca de mensagens em um array JSON gravado separadamente de cada lado. Portanto, a mesma conversa existe duas vezes e as duas cópias não precisam concordar entre si. Cada par de números é, portanto, construído uma única vez, a partir do lado que tiver mais mensagens — mesclá-los inventaria uma ordem, e importar ambos daria a todo mundo cada mensagem duplicada. Uma conversa sem carimbos de data/hora mantém sua ordem e é distribuída com um minuto de intervalo entre as mensagens.

Os números vivem em players.charinfo como JSON em vez de em uma coluna própria, então são lidos de lá e gravados onde este telefone os guarda. Seus tweets carregam um nome em vez de uma conta, portanto é criada uma conta no Twixel por personagem a partir do nome.

Numbers = 'keep' é o objetivo de todo este processo: o número no cartão de visitas de alguém, e nos contatos de todos os outros, continua alcançando essa pessoa.

Um número só é gravado em uma coluna vazia. Se um personagem já tiver um número aqui e for diferente, isso é um conflito: ele é contabilizado, citado no relatório e nada é sobrescrito. Os números antigos também mantêm seu formato antigo — 1234567890 em vez do padrão 555-###-#### deste telefone —, o que é apenas estético e só difere dos números novos distribuídos dali em diante.

Numbers = 'ours' deixa os números antigos de lado e permite que este telefone distribua os seus próprios. Os contatos antigos apontarão para ninguém, então isso serve apenas para uma cidade que está recomeçando do zero.

As senhas deles ficam em texto puro em uma coluna. As nossas são um hash PBKDF2 gerado no navegador do jogador, e não é possível calcular uma a partir da outra — portanto, a senha é a única coisa que não atravessa a migração e não fica armazenada em lugar nenhum pelo caminho.

A conta chega marcada como importada. Na primeira vez que o dono abre o aplicativo, o telefone diz Esta conta veio do seu telefone antigo. Escolha uma senha para ela, e essa passa a ser a nova senha.

Isso é seguro por um motivo melhor do que qualquer senha seria: a linha no banco de dados especifica o dono, e o servidor sabe quem está pedindo sem precisar que lhe digam. Nada está sendo provado por uma senha que nunca foi nossa.

Não existe taxa de câmbio honesta entre dois mercados inventados, então escolha o que acontece em vez de deixar que o sistema tente adivinhar:

  • 'cash' — vende pelo próprio preço do telefone antigo e registra na carteira como uma movimentação. Ninguém ganha, ninguém perde e nada precisa ser negociado.
  • 'skip' — ignora. O saldo deles permanece nas tabelas antigas e pode ser tratado manualmente.
  • uma tabela — o seu próprio mapeamento, quando o saldo deve sobreviver na forma de moedas:
Crypto = { qbit = 'santo', lifeinvader = 'vine' },

Nada do telefone antigo foi tocado, portanto:

  1. Apague as nossas linhas referentes a qualquer etapa que tenha dado errado — o relatório diz os nomes delas.
  2. Apague o recibo: DELETE FROM mic_phone_json WHERE owner = '@import'.
  3. Defina Config.Import.Again = true e execute novamente.

Skip deixa etapas individuais de fora usando os nomes que o relatório imprime:

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