Перейти к содержанию

Injector — manual install

Injector — это «голый» инжект-инструмент в админ-панели. Не для каталога, а для отладки и manual operations. Админ может:

  • Залить локальный patch.zip напрямую в update.rpf (минуя весь catalog-flow).
  • Установить redux из каталога (как юзер, но с минимальным UI).
  • Restore'нуть update.rpf до чистого — adminRestoreCleanUpdate.

Use cases

  • Debugging. Админ собрал patch.zip локально, хочет проверить как он встаёт у себя в GTA, без promotion в catalog.
  • Testing новых redux'ов перед публикацией. Загрузить, прокликать в игре, при необходимости вернуть назад.
  • Emergency rollback. Юзер прислал бажный билд с неправильным update.rpf — админ кликает restore-clean и проверяет.

Handlers

HunterGraphics.Shell/Bridge/WebViewBridgeHost.cs
["adminInject"] = async payload =>
{
    var patchZipPath = payload?.GetProperty("patchZipPath").GetString()!;
    var bypassDirtyCheck = payload?.TryGetProperty("bypassDirty", out var b) == true && b.GetBoolean();
    return await _bridge.AdminInjectAsync(patchZipPath, bypassDirtyCheck);
},

["adminInjectFromCatalog"] = async payload =>
{
    var reduxId = payload?.GetProperty("reduxId").GetString()!;
    var versionId = payload?.TryGetProperty("versionId", out var v) == true ? v.GetString() : null;
    return await _bridge.AdminInjectFromCatalogAsync(reduxId, versionId);
},

["adminRestoreCleanUpdate"] = async _ => await _bridge.AdminRestoreCleanUpdateAsync(),

bypassDirty

Уникальная админская опция — bypassDirty: true. По обычному инжект-flow если update.rpf уже модифицирован неизвестно кем (isDirty == true), юзеру показывается confirm-modal «у вас уже стоит чужой мод, перезаписать?» — см. preflight.

В админ-injector'е этот гард можно пропустить — иногда админ намеренно хочет инжектить поверх существующего билда (например для теста conflict resolution'а или просто чтобы быстро проверить «накладывается ли наш patch на эту версию мода»).

public async Task<InjectResultDto> AdminInjectAsync(string patchZipPath, bool bypassDirtyCheck)
{
    using var _mtx = await UpdateRpfMutex.AcquireAsync("admin-inject");

    var preflight = await _preflight.AnalyzeAsync();
    if (preflight.IsDirty && !bypassDirtyCheck)
        return new InjectResultDto(false, "DIRTY_FILES_NEED_CONFIRM");

    return await _injector.ApplyPatchAsync(patchZipPath);
}

Restore Clean

AdminRestoreCleanUpdateAsync восстанавливает update.rpf из бэкапа в cache/clean/update.rpf. Это тот же clean-backup который юзеры используют через Settings → Reset GTA, но в админке выставлен прям отдельной кнопкой.

public async Task<RestoreResultDto> AdminRestoreCleanUpdateAsync()
{
    using var _mtx = await UpdateRpfMutex.AcquireAsync("admin-restore-clean");

    var cleanPath = Path.Combine(_paths.CacheDir, "clean", "update.rpf");
    if (!File.Exists(cleanPath))
        return new RestoreResultDto(false, "Чистого update.rpf нет в кеше — сделайте backup сначала");

    var dest = Path.Combine(_paths.GtaPath, "update", "update.rpf");
    AtomicCopy(cleanPath, dest);

    _stateService.ResetInstallState();
    return new RestoreResultDto(true, null);
}

После restore — _stateService.ResetInstallState() стирает install-state.json, чтобы next-install-pipeline считал matchesClean = true (бы preflight).

UI

Injector в админ-панели — это минималистичная страница с тремя секциями:

  1. Local patch.zip — input file + кнопки [Anti-Dirty] [Force Apply].
  2. From catalog — dropdown с redux'ами из БД + version select + кнопка [Apply].
  3. Restore Clean — одна большая красная кнопка с confirm-dialog'ом.

В нижней части — лог: stream события из инжекта (start, decompress, replace, archivefix, done). Удобно для дебага.

Дальше: Database →