Files
necromants-tome-7d2d-3-2/HarmonySrc/FpArms.cs
T
AlexCubeandClaude Opus 5.5 f5f4d92cef Одержимость от первого лица: руки как у игрока, серые, только у гуманоидов обычной комплекции
FpArms собирает руки для первого лица по шагам игры (baseRigFPPrefab + голая кожа basePartsFP, аниматор FPPlayerController), пол по зомби (BaseMale/BaseFemale), кожа серая через _Tint, без одежды. ~/ё работает только у списка гуманоидов; подсказка - только им. Коллайдеры рук выключены. Ударов пока нет.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 15:32:33 +03:00

143 lines
6.0 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 UnityEngine;
namespace NecromancerTome
{
/// <summary>
/// Руки одержимого в виде от первого лица (указание 13.10: «делаем так, как у игрока»). У персонажа игры две
/// модели: полное тело (его видят другие и он сам со стороны) и отдельные руки для первого лица (baseRigFP,
/// SDCSUtils.CreateVizFP) - рисуются только у себя. Здесь собираем такие же руки по тем же шагам игры:
/// скелет baseRigFPPrefab с аниматором FPPlayerController, голая кожа (basePartsFP), без одежды и волос
/// (указание: «одежду пока не показываем»). Пол - по зомби (IsMale): BaseMale или BaseFemale из
/// archetypes.xml. Кожа серая (указание: «руки вообще серые - типа зомби их так видит») - цвет _Tint у
/// материала кожи, как игра красит тон кожи.
///
/// Руки - под UFPSRoot камеры игрока, как у персонажа; камеру одержимости мы ставим в голову зомби, руки
/// едут вместе с ней. Слой HoldingItem - его камера игрока рисует только при ShowHoldingItemLayer(true).
///
/// Только гуманоиды обычной комплекции (Allows), указание 13.10.
///
/// ПАМЯТЬ. Одна модель рук на время вида от первого лица; Hide выгружает её (SDCSUtils.UnloadViz - материалы
/// и ссылки на ассеты освобождаются) - на переключении вида и на выходе из одержимости.
/// </summary>
public static class FpArms
{
/// <summary>Начала имён классов, у кого вид от первого лица (варианты Feral/Radiated/Charged/Infernal - тоже).</summary>
static readonly string[] Allowed =
{
"zombieArlene", "zombieBiker", "zombieBoe", "zombieBowler", "zombieBurnt", "zombieBusinessMan", "zombieDarlene",
"zombieInmate", "zombieJanitor", "zombieJoe", "zombieLab", "zombieLumberjack", "zombieMaleHazmat", "zombieMarlene",
"zombieMoe", "zombieNurse", "zombiePartyGirl", "zombieSkateboarder", "zombieSoldier", "zombieSteve", "zombieTomClark",
"zombieUtilityWorker", "zombieYo",
};
public static readonly Color Tint = new Color(0.55f, 0.56f, 0.55f, 1f);
static GameObject _rig;
static SDCSUtils.TransformCatalog _bones;
static bool _layerWasShown;
public static bool Active => _rig != null;
public static bool Allows(EntityAlive _z)
{
if (_z == null || !EntityClass.list.TryGetValue(_z.entityClass, out EntityClass cls) || cls?.entityClassName == null)
{
return false;
}
string name = cls.entityClassName;
if (name.Contains("Crawler"))
{
return false;
}
foreach (string a in Allowed)
{
if (name.StartsWith(a))
{
return true;
}
}
return false;
}
public static void Show(EntityPlayerLocal _player, EntityAlive _z)
{
if (_rig != null || _player == null || _z == null)
{
return;
}
Archetype arch = Archetype.GetArchetype(_z.IsMale ? "BaseMale" : "BaseFemale");
Transform cam = _player.cameraTransform;
if (arch == null || cam == null)
{
Debug.LogWarning("[NecromancerTome] FpArms: нет архетипа или камеры - рук не будет");
return;
}
Transform parent = cam.FindInChildren("UFPSRoot") ?? cam;
Archetype wasArch = SDCSUtils.tmpArchetype;
SDCSUtils.AssetRefs wasOwner = SDCSUtils.tmpAssetsOwner;
try
{
SDCSUtils.tmpArchetype = arch;
SDCSUtils.setupRig(ref _rig, ref _bones, SDCSUtils.baseRigFPPrefab, parent, SDCSUtils.FPAnimController);
SDCSUtils.tmpAssetsOwner = SDCSUtils.GetAssetOwnerForRig(_rig);
SDCSUtils.setupBase(_rig, _bones, SDCSUtils.basePartsFP, true);
}
finally
{
SDCSUtils.tmpArchetype = wasArch;
SDCSUtils.tmpAssetsOwner = wasOwner;
}
_rig.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
_rig.name = "necroZombieArmsFP";
int layer = LayerMask.NameToLayer("HoldingItem");
int tinted = 0;
foreach (SkinnedMeshRenderer smr in _rig.GetComponentsInChildren<SkinnedMeshRenderer>(true))
{
smr.gameObject.layer = layer;
// Материалы с _Tint игра уже размножила для этой модели (SDCSUtils.Stitch) - красим свои копии.
foreach (Material m in smr.sharedMaterials)
{
if (m != null && m.HasColor("_Tint"))
{
m.SetColor("_Tint", Tint);
tinted++;
}
}
}
// Коллайдеры рук (у женского скелета игра вешает капсулу на таз) - выключены: руки в голове зомби ловили бы
// луч прицела и толкали бы предметы.
foreach (Collider c in _rig.GetComponentsInChildren<Collider>(true))
{
c.enabled = false;
}
foreach (HingeJoint j in _rig.GetComponentsInChildren<HingeJoint>(true))
{
if (j.connectedBody == null)
{
j.gameObject.SetActive(false);
}
}
_layerWasShown = _player.playerCamera != null && (_player.playerCamera.cullingMask & (1 << layer)) != 0;
_player.ShowHoldingItemLayer(true);
Debug.Log("[NecromancerTome] FpArms: руки " + arch.Name + " для " + _z.EntityName + ", серых материалов " + tinted +
", родитель " + parent.name);
}
public static void Hide(EntityPlayerLocal _player)
{
if (_rig == null)
{
return;
}
if (!_layerWasShown)
{
_player?.ShowHoldingItemLayer(false);
}
SDCSUtils.UnloadViz(_rig);
_rig = null;
_bones = null;
Debug.Log("[NecromancerTome] FpArms: руки убраны");
}
}
}