- Пирамида: StreamModeWrite/Read теперь глобальные перечисления (в 3.2 были внутри TileEntity). - Хранилище: Bag поверх ItemStackGrid (конструктор с местом хранения, Resize, ItemGrid), запись и чтение через PooledBinaryWriter/Reader. Формат хранилища 2; формат 1 из сейвов 3.2 читается. Незнакомый номер формата больше не считается «хранилища нет» - байты сохраняются. - Сфера на браслете: ModificationCount/GetModification/SetModification. - Непустой сундук: TEFeatureStorage.IsEmpty (ITileEntityLootable в 3.3 нет). - Поиск ножа в инвентаре через ItemGrid. - GameVersionGuard пускает только 3.3. Проверено в игре на V 3.3.0 b14: хранилище из сейва 3.2 (24 стопки) прочиталось, сохранилось и перечиталось; Пирамида включается; «Жертва», обыск трупа и мешки работают. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
152 lines
6.6 KiB
C#
152 lines
6.6 KiB
C#
using System;
|
||
using System.IO;
|
||
using HarmonyLib;
|
||
using UnityEngine;
|
||
|
||
namespace NecromancerTome
|
||
{
|
||
/// <summary>
|
||
/// ПРОВЕРКА ВЕРСИИ ИГРЫ, 1.4.2 (2026-09-24). Повод: 1.4.1 на игре 3.3.0 experimental молча
|
||
/// потеряла содержимое Пространственного хранилища - разбор в BACKLOG.md, «Игра 3.3.0
|
||
/// experimental». Решение пользователя: при несовместимой версии мод показывает в главном меню
|
||
/// окно «мод несовместим, обновите» с ЕДИНСТВЕННОЙ кнопкой «Выйти из игры» - без «играть всё
|
||
/// равно».
|
||
///
|
||
/// ПОЧЕМУ ЧИТАЕТСЯ cVersionInformation, А НЕ cVersionMinor. cVersionMinor - const, компилятор
|
||
/// вписывает её значение (20) прямо в нашу DLL, и на 3.3 она всё равно «видела» бы 20.
|
||
/// cVersionInformation - static readonly, её значение берётся из игры при запуске.
|
||
///
|
||
/// ПОЧЕМУ Minor / 10. Игра хранит версию двузначным числом: 3.2.0 = 20, 3.2.1 = 21, 3.3.0 = 30
|
||
/// (VersionInformation печатает его как {Minor/10}.{Minor%10}). Проверка по десяткам пропускает
|
||
/// любые хотфиксы 3.3.x и не пропускает ни 3.2, ни 3.4 и всё, что будет после.
|
||
///
|
||
/// ВСЁ, ЧЕМ ПОЛЬЗУЕТСЯ ЭТОТ ФАЙЛ, СВЕРЕНО С ДЕКОМПИЛЯЦИЕЙ 3.3.0 (build 25485021): Constants,
|
||
/// VersionInformation, XUiC_MainMenu.OnOpen, XUiC_MessageBoxWindowGroup (класс совпадает целиком),
|
||
/// Mod.VersionString. Иначе сборка под 3.2 упала бы на 3.3 раньше, чем показала окно.
|
||
///
|
||
/// ОТЛАДКА НА 3.2: если в папке мода лежит файл FORCE_VERSION_GUARD, мод ведёт себя так, будто
|
||
/// версия несовместима. В релизный архив он не попадает - состав архива задан явным списком.
|
||
/// </summary>
|
||
public static class GameVersionGuard
|
||
{
|
||
/// <summary>Под какую версию собран мод: Major и десяток Minor (3.3.x = 3 и 3; сборка 1.4.x была под 3.2).</summary>
|
||
public const int SupportedMajor = 3;
|
||
public const int SupportedMinorTens = 3;
|
||
public const string SupportedText = "3.3";
|
||
|
||
private static bool? supported;
|
||
|
||
public static bool IsSupported
|
||
{
|
||
get
|
||
{
|
||
if (supported == null)
|
||
{
|
||
supported = Check();
|
||
}
|
||
return supported.Value;
|
||
}
|
||
}
|
||
|
||
public static string GameVersionText
|
||
{
|
||
get
|
||
{
|
||
VersionInformation v = Constants.cVersionInformation;
|
||
return v != null ? v.LongStringNoBuild : "?";
|
||
}
|
||
}
|
||
|
||
private static bool Check()
|
||
{
|
||
if (ForcedByFile())
|
||
{
|
||
Debug.LogWarning("[NecromancerTome] GameVersionGuard: FORCE_VERSION_GUARD file present - acting as if the game version were unsupported");
|
||
return false;
|
||
}
|
||
VersionInformation v = Constants.cVersionInformation;
|
||
bool ok = v != null && v.Major == SupportedMajor && v.Minor / 10 == SupportedMinorTens;
|
||
Debug.Log("[NecromancerTome] GameVersionGuard: game " + GameVersionText + " (Major " + (v != null ? v.Major : -1) +
|
||
", Minor " + (v != null ? v.Minor : -1) + "), mod built for " + SupportedText + " -> " +
|
||
(ok ? "supported" : "NOT SUPPORTED"));
|
||
return ok;
|
||
}
|
||
|
||
private static bool ForcedByFile()
|
||
{
|
||
return DebugFileExists("FORCE_VERSION_GUARD");
|
||
}
|
||
|
||
/// <summary>Отладка сохранения хранилища байт в байт на 3.2: при файле FORCE_VAULT_UNREAD
|
||
/// в папке мода хранилище из сейва не разбирается, а проходит всю цепочку сохранения
|
||
/// нетронутым - ровно как на несовместимой версии, но без окна с выходом, так что в мир
|
||
/// можно зайти и сохраниться.</summary>
|
||
public static bool ForceVaultUnread
|
||
{
|
||
get { return DebugFileExists("FORCE_VAULT_UNREAD"); }
|
||
}
|
||
|
||
private static bool DebugFileExists(string _name)
|
||
{
|
||
try
|
||
{
|
||
string folder = ModEntry.Instance != null ? ModEntry.Instance.Path : null;
|
||
return folder != null && File.Exists(Path.Combine(folder, _name));
|
||
}
|
||
catch (Exception)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
public static void ShowIncompatibleWindow(XUi _xui)
|
||
{
|
||
string modVersion = ModEntry.Instance != null ? ModEntry.Instance.VersionString : "?";
|
||
string text = string.Format(Localization.Get("necroVersionGuardText"), modVersion, SupportedText, GameVersionText);
|
||
XUiC_MessageBoxWindowGroup.ShowCustom(_xui,
|
||
Localization.Get("necroVersionGuardTitle"),
|
||
text,
|
||
"",
|
||
delegate(XUiC_MessageBoxWindowGroup _box)
|
||
{
|
||
_box.buttons[0].DefaultConfirm("necroVersionGuardQuit", delegate
|
||
{
|
||
Debug.Log("[NecromancerTome] GameVersionGuard: player pressed Quit");
|
||
Application.Quit();
|
||
});
|
||
},
|
||
_openMainMenuOnClose: false,
|
||
_modal: true,
|
||
_buttonOnOutsideClick: -1,
|
||
// Проверено в игре 2026-09-25: Esc модальное окно не закрывает - оно остаётся на
|
||
// экране, и уйти можно только кнопкой. Это и нужно. _buttonOnExternalClose: 0 - на
|
||
// случай, если игра всё же закроет окно извне: тогда это тоже выход.
|
||
_buttonOnExternalClose: 0);
|
||
Debug.LogWarning("[NecromancerTome] GameVersionGuard: incompatible game version, quit window shown");
|
||
}
|
||
}
|
||
|
||
/// <summary>Главное меню: здесь показывается окно, и здесь же сбрасываются непрочитанные байты
|
||
/// хранилища - возврат в меню значит, что прежний мир закрыт, и его данные не должны перейти к
|
||
/// персонажу следующего.</summary>
|
||
[HarmonyPatch(typeof(XUiC_MainMenu), "OnOpen")]
|
||
public static class Patch_XUiC_MainMenu_OnOpen_VersionGuard
|
||
{
|
||
public static void Postfix(XUiC_MainMenu __instance)
|
||
{
|
||
try
|
||
{
|
||
SpatialVaultPersistence.UnreadableByEntity.Clear();
|
||
if (!GameVersionGuard.IsSupported)
|
||
{
|
||
GameVersionGuard.ShowIncompatibleWindow(__instance.xui);
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError("[NecromancerTome] GameVersionGuard: main menu postfix failed: " + e);
|
||
}
|
||
}
|
||
}
|
||
}
|