Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b737dd43d0 | ||
|
|
888cf1ee7e |
@@ -0,0 +1,42 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
|
||||||
|
namespace NecromancerTome
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Утечка в самой игре, на которую наступала шкала некромантии в поясе (1.3.0+,
|
||||||
|
/// fill="{% cvar('necroNecromancyProgressCVar') / 20 }" в Config/XUi_InGame/windows.xml).
|
||||||
|
///
|
||||||
|
/// Найдено 28.09 замером (NecroProfiler): FPS 60 -> 30 за 10-15 минут в любом мире, в теле;
|
||||||
|
/// группа окон toolbelt росла 2 -> 23 мс/кадр при неизменных 573 элементах; в режиме змеи пояс
|
||||||
|
/// скрыт - и тормозов нет; перезаход в мир сбрасывает.
|
||||||
|
///
|
||||||
|
/// Механика (декомпиляция 3.3): BindingNcalcFunctions.cvar при каждом вычислении выражения
|
||||||
|
/// регистрирует НОВЫЙ VariableStateCVar, а BindingInfoNcalc.RegisterVariable добавляет его в
|
||||||
|
/// список без проверки. Новая переменная начинает с 0; если шкала не пуста, её RefreshValue в
|
||||||
|
/// следующем кадре видит «изменилось» -> выражение пересчитывается -> cvar() добавляет ещё одну.
|
||||||
|
/// Плюс одна переменная за кадр, пока CVar не 0, и каждый кадр обходится весь список.
|
||||||
|
///
|
||||||
|
/// Лечение: одну и ту же CVar в одной привязке регистрируем один раз. Значение cvar() берёт
|
||||||
|
/// прямо у игрока, так что отслеживающая переменная нужна только одна - для «изменилось».
|
||||||
|
/// </summary>
|
||||||
|
[HarmonyPatch(typeof(BindingInfoNcalc), nameof(BindingInfoNcalc.RegisterVariable))]
|
||||||
|
public static class Patch_BindingInfoNcalc_RegisterVariable_CVarLeak
|
||||||
|
{
|
||||||
|
public static bool Prefix(BindingInfoNcalc __instance, BindingInfoNcalc.VariableStateAbs _var, ref bool __result)
|
||||||
|
{
|
||||||
|
if (!(_var is BindingInfoNcalc.VariableStateCVar added))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foreach (BindingInfoNcalc.VariableStateAbs existing in __instance.variables)
|
||||||
|
{
|
||||||
|
if (existing is BindingInfoNcalc.VariableStateCVar known && known.cVarName == added.cVarName)
|
||||||
|
{
|
||||||
|
__result = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -269,7 +269,15 @@ namespace NecromancerTome
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ours.width != src.width || ours.height != src.height)
|
// Качество текстур ниже Full уменьшает атлас игры вдвое/вчетверо (Half: 256 вместо 512).
|
||||||
|
// Раньше тут был пропуск - и пирамида оставалась без текстуры (28.09, игра на Half).
|
||||||
|
// Наши уменьшенные копии уже лежат в мипах: при Half берём с мипа 1, при Quarter - с 2.
|
||||||
|
int mipOffset = 0;
|
||||||
|
while (mipOffset < ours.mipmapCount && (ours.width >> mipOffset) > src.width)
|
||||||
|
{
|
||||||
|
mipOffset++;
|
||||||
|
}
|
||||||
|
if ((ours.width >> mipOffset) != src.width || (ours.height >> mipOffset) != src.height)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[NecromancerTome] CustomBlockPaint: " + label + " size mismatch, " +
|
Debug.LogWarning("[NecromancerTome] CustomBlockPaint: " + label + " size mismatch, " +
|
||||||
"atlas is " + src.width + "x" + src.height + " but ours is " +
|
"atlas is " + src.width + "x" + src.height + " but ours is " +
|
||||||
@@ -283,11 +291,11 @@ namespace NecromancerTome
|
|||||||
" - skipped");
|
" - skipped");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (ours.mipmapCount != src.mipmapCount)
|
if (ours.mipmapCount - mipOffset < src.mipmapCount)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("[NecromancerTome] CustomBlockPaint: " + label + " mip mismatch, " +
|
Debug.LogWarning("[NecromancerTome] CustomBlockPaint: " + label + " mip mismatch, " +
|
||||||
"atlas has " + src.mipmapCount + " but ours has " + ours.mipmapCount +
|
"atlas has " + src.mipmapCount + " but ours has " + ours.mipmapCount +
|
||||||
" - skipped");
|
" (from mip " + mipOffset + ") - skipped");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,11 +311,14 @@ namespace NecromancerTome
|
|||||||
// GPU-side copy: the game's arrays are non-readable, so nothing can be pulled back
|
// GPU-side copy: the game's arrays are non-readable, so nothing can be pulled back
|
||||||
// to the CPU. CopyTexture moves whole slices with their mip chains.
|
// to the CPU. CopyTexture moves whole slices with their mip chains.
|
||||||
for (int i = 0; i < slice; i++) Graphics.CopyTexture(src, i, grown, i);
|
for (int i = 0; i < slice; i++) Graphics.CopyTexture(src, i, grown, i);
|
||||||
Graphics.CopyTexture(ours, 0, grown, slice);
|
for (int mip = 0; mip < src.mipmapCount; mip++)
|
||||||
|
{
|
||||||
|
Graphics.CopyTexture(ours, 0, mip + mipOffset, grown, slice, mip);
|
||||||
|
}
|
||||||
|
|
||||||
target = grown;
|
target = grown;
|
||||||
Debug.Log("[NecromancerTome] CustomBlockPaint: " + label + " grown from " + slice +
|
Debug.Log("[NecromancerTome] CustomBlockPaint: " + label + " grown from " + slice +
|
||||||
" to " + (slice + 1) + " slices");
|
" to " + (slice + 1) + " slices" + (mipOffset > 0 ? ", ours taken from mip " + mipOffset : ""));
|
||||||
return slice;
|
return slice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -271,8 +271,11 @@ namespace NecromancerTome
|
|||||||
{
|
{
|
||||||
player.emodel.DoRagdoll(EModelBase.RagdollMode.Default, 999999f, EnumBodyPartHit.None, Vector3.zero, Vector3.zero, false);
|
player.emodel.DoRagdoll(EModelBase.RagdollMode.Default, 999999f, EnumBodyPartHit.None, Vector3.zero, Vector3.zero, false);
|
||||||
}
|
}
|
||||||
|
// Выход по R - только когда тело уже лежит. В первые RagdollDelay секунд игра ещё
|
||||||
|
// обрабатывает ввод: можно взять ствол, и R разом перезарядило бы его и вывело из змеи.
|
||||||
PlayerActionsLocal input = player.playerInput;
|
PlayerActionsLocal input = player.playerInput;
|
||||||
if (input != null && (input.Reload.WasPressed || input.PermanentActions.Reload.WasPressed))
|
if (_ragdollAt <= 0f && player.emodel.IsRagdollActive && input != null &&
|
||||||
|
(input.Reload.WasPressed || input.PermanentActions.Reload.WasPressed))
|
||||||
{
|
{
|
||||||
Exit(player);
|
Exit(player);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user