Переход с другого телефона
В городе, где уже есть телефон, за годы накопилось множество вещей: номера, которые люди выучили наизусть, переписки, фотографии, @handles. Потерять всё это — настоящая цена смены телефона, и именно поэтому большинство серверов её никогда не меняют. Этот инструмент читает таблицы старого телефона и записывает наши.
Перейти можно с четырёх телефонов, и все четыре проверяются одинаково: их таблицы создаются по схеме, которую поставляет их установщик, в них записывается небольшой город, импорт запускается по-настоящему, а затем проверяется каждая строка, на которую он претендует.
| Откуда | Его таблицы | По чему он индексирует всё |
|---|---|---|
| lb-phone | phone_* | по номеру телефона, а phone_phones превращает его во владельца |
| Quasar Smartphone Pro | qs_phone_* | по scope_id — один телефон, а не один человек |
| NPWD | npwd_* | по идентификатору фреймворка, а его номера уже лежат в users |
| qb-phone | player_contacts, phone_messages… | по citizenid, который на QBCore является владельцем этого телефона |
Три обещания
Заголовок раздела «Три обещания»Старый телефон он никогда не трогает. Ни один оператор не пишет в таблицу, которая не наша. Данные lb-phone после этого остаются ровно такими, какими были, и именно поэтому путь назад прост: удалите наши строки.
Репетиция настоящая. DryRun включён по умолчанию. Он читает всё то же, что читает настоящий запуск, вычисляет каждую строку, которую записал бы, не записывает ни одной и выводит количество. Это тот же код — репетиция, которая пошла бы коротким путём, была бы репетицией ничего.
Это не может произойти дважды. Настоящий запуск оставляет в базе данных квитанцию. Следующая загрузка находит её и останавливается, потому что одна забытая строка конфига иначе продублировала бы каждую переписку в городе.
Как это сделать
Заголовок раздела «Как это сделать»-- shared/config/import.luaConfig.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}Перезапустите один раз и прочитайте консоль:
[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Затем DryRun = false, перезапустите ещё раз, а потом установите From = false.
Если этих таблиц нет в этой базе данных, он так и говорит и ничего не делает, так что указание неверного телефона стоит вам одной строки в консоли.
Что переносится
Заголовок раздела «Что переносится»Всё ниже — про lb-phone, самый полный из четырёх. Чем отличается каждый из остальных, описано дальше.
| Из lb-phone | Становится |
|---|---|
phone_phones | номер в users, батарея, настройки телефона |
его settings.apps | главный экран — тот же док, те же приложения на тех же страницах |
phone_phone_contacts | контакты, с избранным и картинками |
phone_message_* | переписки, группы и счётчики непрочитанных |
phone_phone_calls | недавние, по строке на каждую сторону, включая пропущенные |
phone_photos | библиотека, фото и видео |
phone_mail_* | почта, прочитанная и непрочитанная |
phone_maps_locations | сохранённые места |
phone_marketplace_posts, phone_yellow_pages_posts | объявления |
| Instagram, Twitter, TikTok, Tinder | Instapic, Twixel, Klipz, Flinder — handle’ы, имена, картинки, био, посты, подписки и галочка верификации |
phone_darkchat_* | даркнет: комната, кто в ней был, что было сказано |
phone_notes, phone_clock_alarms | заметки и будильники — в будильниках lb-phone не указано, повторяются ли они, поэтому они приходят как разовые |
phone_crypto | см. Крипто ниже |
На обоих телефонах картинки — это URL, поэтому ничего не скачивается и не загружается заново. Фотографии игрока продолжают работать в первый же день, потому что они никогда не принадлежали ни одному из телефонов.
Что не переносится и почему
Заголовок раздела «Что не переносится и почему»Отчёт говорит о каждом из этих пунктов вслух, а не оставляет кому-то замечать это самому.
- Обои и рингтоны. Их файлы называются по-своему, а наши — по-своему. Неверная картинка хуже, чем картинка по умолчанию.
- Пароли социальных сетей. См. ниже — аккаунты переносятся, пароли — нет.
- Режим полёта, намеренно. Импортировать переключатель, который кто-то оставил включённым, — значит импортировать телефон, который не работает, и игрока, который не понимает почему.
- Фотоальбомы. Все картинки лежат в библиотеке; альбомы не восстанавливаются.
Остальные три и чем каждый отличается
Заголовок раздела «Остальные три и чем каждый отличается»Quasar Smartphone Pro
Заголовок раздела «Quasar Smartphone Pro»Лучше всех сделан из четырёх, и соответствие в трёх местах точное, а не приблизительное:
- Счётчики непрочитанных пересчитываются, а не копируются. Quasar хранит
last_read_message_id; наш хранит число. Поэтому число вычисляется — сколько сообщений в этой переписке пришло после последнего прочитанного, — и оно верно, даже если собственный счётчик успел разойтись. - В недавних уже указано
incoming,outgoingиmissed, а это наши три слова. - Фото знает, что оно видео, с его длиной и постером, поэтому приходит как видео.
Заметки (закреплённые остаются закреплёнными), будильники, записи календаря и напоминания тоже переносятся: открытое напоминание со сроком становится записью календаря, напоминание без даты сохраняет свои слова как заметка, а завершённое остаётся позади. Quasar умеет повторять будильник только по выходным, чего этот телефон не умеет, поэтому такие приходят как разовые.
Закреплённые и отключённые переписки сохраняют оба признака. Почта приходит вместе с папкой, в которой лежала, — черновики и корзина остаются позади, потому что неотправленный черновик не стоит переноса. Что не переносится: их настройки и главный экран, которые лежат в JSON-блобе собственной формы Quasar, и их id из App Store, которые не наши.
Одну вещь стоит знать: Quasar позволяет персонажу держать больше одного телефона, а этот хранит один номер на персонажа. Первый перенесённый номер становится его; любой другой упоминается в отчёте, и ничего не перезаписывается.
Самый простой — по причине, которую стоит назвать вслух: NPWD уже хранит номер в users.phone_number, а это та же колонка, которую читает этот телефон. На стандартном сервере NPWD переносить нечего, и отчёт так и говорит, а не притворяется, что работает.
Его переписки называются строкой из входящих в них номеров, а не id, поэтому соединение идёт по этой строке. Имя профиля в его Twitter становится @handle; в Match имени пользователя нет вообще, поэтому аккаунт Flinder индексируется по номеру персонажа. У фотографий нет собственной даты, поэтому библиотека датируется по порядку, в котором они были сделаны. Заметки переносятся так же, датируясь по порядку написания. В объявлениях нет цены, и они приходят с нулём.
qb-phone
Заголовок раздела «qb-phone»Самый старый и меньше всех похожий на нас — но личность достаётся бесплатно, потому что на QBCore этот телефон уже использует citizenid, по которому qb-phone индексирует всё.
Основная работа — его переписки. В qb-phone переписок нет: phone_messages — это одна строка на человека на номер, где весь разговор лежит как JSON-массив, записываемый отдельно с каждой стороны. Поэтому одна и та же переписка существует дважды, и две копии не обязаны совпадать. Каждая пара номеров поэтому строится один раз, с той стороны, где в ней больше сообщений, — слияние придумало бы порядок, а импорт обоих дал бы каждому каждое сообщение дважды. Переписка без временных меток сохраняет свой порядок и раскладывается с интервалом в минуту.
Номера лежат в players.charinfo в виде JSON, а не в колонке, поэтому их считывают оттуда и записывают туда, где их хранит этот телефон. Его твиты содержат имя, а не аккаунт, поэтому для каждого персонажа создаётся один аккаунт Twixel по его имени.
Numbers = 'keep' — это смысл всей затеи: номер на визитке и в контактах у всех остальных по-прежнему до человека дозванивается.
Номер всегда записывается только в пустую колонку. Если у персонажа здесь уже есть номер и он другой, это конфликт: он подсчитывается, называется в отчёте, и ничего не перезаписывается. Старые номера также сохраняют свой прежний вид — 1234567890, а не 555-###-#### этого телефона, — это косметика, и она влияет только на номера, которые будут выданы позже.
Numbers = 'ours' оставляет их в покое и позволяет этому телефону выдавать свои. Старые контакты будут указывать в никуда, поэтому это только для города, который начинает заново.
Социальные аккаунты
Заголовок раздела «Социальные аккаунты»Их пароли хранятся открытым текстом в колонке. Наши — это хеш PBKDF2, созданный в браузере игрока, и одно не вычисляется из другого, поэтому пароль — единственное, что не переносится, и нигде по пути не сохраняется.
Аккаунт приходит с пометкой «импортирован». Когда его владелец впервые открывает приложение, телефон сообщает Этот аккаунт перешёл со старого телефона. Выберите для него пароль, и это становится новым паролем.
Это безопасно по причине лучше, чем была бы у пароля: строка указывает владельца, а сервер знает, кто спрашивает, без подсказок. Пароль, который никогда не был нашим, ничего не доказывает.
Между двумя выдуманными рынками нет честного обменного курса, поэтому выберите, что произойдёт, а не позволяйте это угадывать:
'cash'— продать по собственной цене старого телефона и записать в кошелёк как движение средств. Никто ничего не выигрывает и не теряет, и ни о чём не нужно договариваться.'skip'— оставить как есть. Их накопления остаются в их таблицах, и с ними можно разобраться вручную.- таблица — ваше собственное соответствие, когда накопления должны сохраниться как монеты:
Crypto = { qbit = 'santo', lifeinvader = 'vine' },Если что-то пошло не так
Заголовок раздела «Если что-то пошло не так»Ничего старого телефона не затронуто, поэтому:
- Удалите наши строки для того шага, который оказался неверным, — отчёт называет их.
- Удалите квитанцию:
DELETE FROM mic_phone_json WHERE owner = '@import'. Config.Import.Again = true— и запустите снова.
Skip пропускает отдельные шаги по именам, которые выводит отчёт:
Skip = { 'photos', 'crypto' },