diff --git a/HarmonySrc/BloodTide.cs b/HarmonySrc/BloodTide.cs
index ecc23a3..3a03ec4 100644
--- a/HarmonySrc/BloodTide.cs
+++ b/HarmonySrc/BloodTide.cs
@@ -60,6 +60,7 @@ namespace NecromancerTome
_origHoldType = -1;
Heart(false);
Patch_XUiC_HUDStatBar_Update_BloodTide.Forget();
+ Patch_Stat_Tick_BloodTide.Next = null; // не держать стат (а через него игрока) после выхода из мира
return;
}
bool tide = SnakeMode.IsBloodTide();
@@ -293,7 +294,11 @@ namespace NecromancerTome
{
return;
}
- if (!_bars.TryGetValue(__instance, out var e))
+ if (_bars.TryGetValue(__instance, out var e) && e.bar.UiTransform == null)
+ {
+ _bars.Remove(__instance); // окно пересобрано - старая полоса удалена
+ }
+ if (!_bars.TryGetValue(__instance, out e))
{
if (!BloodTide.Armed || !(__instance.GetChildById("BarContent")?.ViewComponent is XUiV_Sprite s))
{
diff --git a/HarmonySrc/NecroTome.cs b/HarmonySrc/NecroTome.cs
index 7d50a40..64732f3 100644
--- a/HarmonySrc/NecroTome.cs
+++ b/HarmonySrc/NecroTome.cs
@@ -281,6 +281,24 @@ namespace NecromancerTome
/// Показать картинку или видео справа (или убрать обе). Видео задаётся только здесь,
/// а не в вёрстке: XUiV_Video сам запускает ролик при открытии окна, и в оглавлении он играл
/// бы невидимым. Пустой uri - XUiV_Video.startVideo сам освобождает свою текстуру.
+ /// Путь загруженной картинки (null - не загружена). Свой, а не _img.Path - см. ниже.
+ string _imgPath;
+
+ void ReleaseImage()
+ {
+ if (_img == null || _imgPath == null)
+ {
+ return;
+ }
+ Texture t = _img.Texture;
+ _img.Path = null; // TextureUris = пусто, Texture = null - без выгрузки (autounload выключен)
+ if (t != null)
+ {
+ UnityEngine.Object.Destroy(t);
+ }
+ _imgPath = null;
+ }
+
void SetMedia(string _image, string _video, bool _top = false)
{
bool img = !string.IsNullOrEmpty(_image), vid = !img && !string.IsNullOrEmpty(_video);
@@ -289,9 +307,18 @@ namespace NecromancerTome
// Без чтения _img.Path: у пустой картинки (в вёрстке texture не задан) его геттер берёт
// textureUris[0] из пустого массива - IndexOutOfRange (тест 09.10). Сеттер сам сравнивает
// с текущим путём и не перезагружает тот же файл.
- if (img)
+ // Утечка (проверка 10.10): картинка из файла мода - новая текстура (XUiV_Texture.FetchWwwTexture, клон),
+ // и при смене пути старая сама не удаляется (autounload в вёрстке не включён - в этом режиме игра на
+ // загрузке стирает путь новой картинки). Каждая смена главы оставляла ~2 МБ. Удаляем сами: при смене
+ // картинки, у главы без картинки и при закрытии окна (SetMedia(null, null)).
+ if (_imgPath != _image)
+ {
+ ReleaseImage();
+ }
+ if (img && _imgPath == null)
{
_img.Path = _image;
+ _imgPath = _image;
}
_img.IsVisible = img;
}
diff --git a/HarmonySrc/PyramidWardPatch.cs b/HarmonySrc/PyramidWardPatch.cs
index 4e8f2f4..a8b7c80 100644
--- a/HarmonySrc/PyramidWardPatch.cs
+++ b/HarmonySrc/PyramidWardPatch.cs
@@ -319,6 +319,7 @@ namespace NecromancerTome
// светящееся фиолетовое кольцо по земле - LineRenderer, точки опущены на рельеф лучом.
// Дочерний объект модели блока - поэтому сдвиги Origin и выгрузка чанка его не теряют.
GameObject ring;
+ static Material _ringMat;
public void SpawnZoneRing()
{
@@ -332,8 +333,13 @@ namespace NecromancerTome
const int n = 96;
lr.positionCount = n;
lr.widthMultiplier = 0.14f;
- var mat = new Material(Shader.Find("Sprites/Default"));
- lr.material = mat;
+ // Один материал на все кольца (проверка утечек 10.10): материал - ассет и с объектом кольца не удаляется,
+ // а кольцо пересоздаётся при каждой перезагрузке чанка (модель блока - новая). Цвет - вершинный (startColor).
+ if (_ringMat == null)
+ {
+ _ringMat = new Material(Shader.Find("Sprites/Default")) { name = "NecroWardRing" };
+ }
+ lr.sharedMaterial = _ringMat;
Color col = new Color(0.75f, 0.25f, 1f, 0.85f);
lr.startColor = col; lr.endColor = col;
lr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; lr.receiveShadows = false;
diff --git a/HarmonySrc/SpatialVaultPatch.cs b/HarmonySrc/SpatialVaultPatch.cs
index 20fd7bf..b3de406 100644
--- a/HarmonySrc/SpatialVaultPatch.cs
+++ b/HarmonySrc/SpatialVaultPatch.cs
@@ -68,8 +68,10 @@ namespace NecromancerTome
public const float ShoveDistance = 6f;
/// Session cache only - the durable copy lives on disk, see
- /// SpatialVaultPersistence.cs. Cleared on WorldShuttingDown so a different save loaded
- /// afterwards cannot inherit this world's vault through a recycled entityId.
+ /// SpatialVaultPersistence.cs. NOT cleared on WorldShuttingDown any more (that event fires before
+ /// the final player save and wiped vaults - see SpatialVaultPersistence.cs); a different save cannot
+ /// inherit this world's vault because ToPlayer overwrites or removes the entry on load. Leftover entries
+ /// are at most one per world loaded in a session - not a growing leak (checked 10.10).
public static readonly Dictionary PlayerVaults = new Dictionary();
public static bool Prefix(ItemActionData _actionData, bool _bReleased)
diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll
index 9538040..40b13d0 100644
Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ
diff --git a/NecromancerHarmony.pdb b/NecromancerHarmony.pdb
index be5e3a2..e81133e 100644
Binary files a/NecromancerHarmony.pdb and b/NecromancerHarmony.pdb differ