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¶
["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 в админ-панели — это минималистичная страница с тремя секциями:
- Local patch.zip — input file + кнопки [Anti-Dirty] [Force Apply].
- From catalog — dropdown с redux'ами из БД + version select + кнопка [Apply].
- Restore Clean — одна большая красная кнопка с confirm-dialog'ом.
В нижней части — лог: stream события из инжекта (start, decompress, replace, archivefix, done). Удобно для дебага.