Files
necromants-tome-7d2d-3-2/HarmonySrc/ModEntry.cs
T

125 lines
6.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Reflection;
using HarmonyLib;
using UnityEngine;
namespace NecromancerTome
{
/// <summary>
/// Mod entry point. The game finds this by scanning every assembly dropped in a
/// Mods/&lt;ModFolder&gt;/ directory for a type implementing IModApi.
/// </summary>
public class ModEntry : IModApi
{
/// <summary>The mod's own folder, kept from InitMod so patches can find files we ship
/// (currently Resources/necroatlas for the custom block paint). Nothing else knows where
/// the mod lives - the game hands it over exactly once, right here.</summary>
public static Mod Instance;
public void InitMod(Mod _modInstance)
{
Instance = _modInstance;
var harmony = new Harmony("necromancertome.harmony");
// НЕСОВМЕСТИМАЯ ВЕРСИЯ ИГРЫ (1.4.2, см. GameVersionGuard.cs): ставятся только окно в
// главном меню и сохранение хранилища байт в байт - каждое отдельно, чтобы отказ одного
// не помешал другим. Остальной код мода, написанный под другую версию, не запускается
// вовсе: игра всё равно закроется из главного меню.
if (!GameVersionGuard.IsSupported)
{
System.Type[] safetyPatches =
{
typeof(Patch_XUiC_MainMenu_OnOpen_VersionGuard),
typeof(Patch_PlayerDataFile_Read_SpatialVault),
typeof(Patch_PlayerDataFile_ToPlayer_SpatialVault),
typeof(Patch_PlayerDataFile_FromPlayer_SpatialVault),
typeof(Patch_PlayerDataFile_Write_SpatialVault),
};
foreach (System.Type patch in safetyPatches)
{
try
{
harmony.CreateClassProcessor(patch).Patch();
Debug.Log("[NecromancerTome] ModEntry: unsupported game version - safety patch " + patch.Name + " applied");
}
catch (System.Exception e)
{
Debug.LogError("[NecromancerTome] ModEntry: safety patch " + patch.Name + " failed: " + e);
}
}
return;
}
harmony.PatchAll(Assembly.GetExecutingAssembly());
PetFollowPatch.Init();
// SpatialVaultPersistence needs NO Init(): it is four Harmony postfixes that PatchAll
// above already attached. It used to register a WorldShuttingDown handler to clear its
// cache - that handler is exactly what wiped the vault on every clean exit, because
// that event fires BEFORE the final player save (GameManager.SaveAndCleanupWorld:
// event at IL_0026, SaveLocalPlayerData at IL_00c4). Freshness is decided by what was
// read instead; see that file.
// Traders rendered as washed-out ghosts (request 2026-09-13). Polls rather than
// hooks a spawn event - see that file for why the SDCS-built trader forces it.
GhostTraderPatch.Init();
SnakeMode.Init();
MindPalace.Init();
HandPose.Init();
NecroMailbox.Init();
Possession.Init();
BloodTide.Init();
RemainsDecay.Init();
// PyramidWardPatch.cs's TEFeaturePyramidWard needs no Init() call - it's discovered
// automatically by the engine's own TileEntityCompositeData reflection scan (see that
// file's class doc comment), not registered here like PetFollowPatch's UnityUpdate hook.
// Diagnostic-only, added 2026-08-28 while chasing "VictimPatch never logs anything at
// all for dropItemOnDeath, even though decompiling EntityAlive.OnEntityDeath()
// confirms it's called unconditionally right after the 'killed by' line seen in the
// log". This checks, at load time, whether Harmony actually attached our Prefix to
// that method at all - rules "patch never applied" in or out without waiting on
// another in-game death.
VerifyPrefixAttached(typeof(EntityAlive), "dropItemOnDeath");
// Патч на Entity.DropBagServer снят 2026-09-18 вместе с переделкой мешка «Жертвы»:
// он подменял собой ОБЫЧНЫЙ мешок, а тот теперь должен доставаться игроку как есть.
// Проверять нечего - см. VictimPatch.cs.
// Добавлено 2026-09-17 вместе с правкой "подчинённые не дерутся между собой"
// (CharmPatch.cs). Метод EAITarget.check в исходнике protected и назван со строчной
// буквы - если он когда-нибудь переименуется или сменит сигнатуру, PatchAll упадёт
// ещё на загрузке, но эта строка отвечает на тот же вопрос в логе явно и без
// раскопок: резолвится ли метод и висит ли на нём наш постфикс.
VerifyPatchAttached(typeof(EAITarget), "check");
}
/// <summary>То же, что VerifyPrefixAttached, но печатает и префиксы, и постфиксы - для
/// заплаток, которые стоят постфиксом (у VerifyPrefixAttached постфикс всегда выглядел бы
/// как "0 prefix patch(es)", то есть как ненайденная заплатка).</summary>
public static void VerifyPatchAttached(System.Type type, string methodName)
{
MethodBase method = AccessTools.Method(type, methodName);
if (method == null)
{
Debug.LogWarning("[NecromancerTome] ModEntry: could not resolve " + type.Name + "." + methodName + " via AccessTools - method not found");
return;
}
Patches info = Harmony.GetPatchInfo(method);
int prefixCount = info != null && info.Prefixes != null ? info.Prefixes.Count : 0;
int postfixCount = info != null && info.Postfixes != null ? info.Postfixes.Count : 0;
Debug.Log("[NecromancerTome] ModEntry: " + type.Name + "." + methodName + " resolved, has " +
prefixCount + " prefix and " + postfixCount + " postfix patch(es) attached after PatchAll");
}
public static void VerifyPrefixAttached(System.Type type, string methodName)
{
MethodBase method = AccessTools.Method(type, methodName);
if (method == null)
{
Debug.LogWarning("[NecromancerTome] ModEntry: could not resolve " + type.Name + "." + methodName + " via AccessTools - method not found");
return;
}
Patches info = Harmony.GetPatchInfo(method);
int prefixCount = info != null && info.Prefixes != null ? info.Prefixes.Count : 0;
Debug.Log("[NecromancerTome] ModEntry: " + type.Name + "." + methodName + " resolved, has " + prefixCount + " prefix patch(es) attached after PatchAll");
}
}
}