using UnityEngine; namespace NecromancerTome { /// /// Руки одержимого в виде от первого лица (указание 13.10: «делаем так, как у игрока»). У персонажа игры две /// модели: полное тело (его видят другие и он сам со стороны) и отдельные руки для первого лица (baseRigFP, /// SDCSUtils.CreateVizFP) - рисуются только у себя. Здесь собираем такие же руки по тем же шагам игры: /// скелет baseRigFPPrefab с аниматором FPPlayerController, голая кожа (basePartsFP), без одежды и волос /// (указание: «одежду пока не показываем»). Пол - по зомби (IsMale): BaseMale или BaseFemale из /// archetypes.xml. Кожа серая (указание: «руки вообще серые - типа зомби их так видит») - цвет _Tint у /// материала кожи, как игра красит тон кожи. /// /// Руки - под UFPSRoot камеры игрока, как у персонажа; камеру одержимости мы ставим в голову зомби, руки /// едут вместе с ней. Слой HoldingItem - его камера игрока рисует только при ShowHoldingItemLayer(true). /// /// Только гуманоиды обычной комплекции (Allows), указание 13.10. /// /// ПАМЯТЬ. Одна модель рук на время вида от первого лица; Hide выгружает её (SDCSUtils.UnloadViz - материалы /// и ссылки на ассеты освобождаются) - на переключении вида и на выходе из одержимости. /// public static class FpArms { /// Начала имён классов, у кого вид от первого лица (варианты Feral/Radiated/Charged/Infernal - тоже). 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(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(true)) { c.enabled = false; } foreach (HingeJoint j in _rig.GetComponentsInChildren(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: руки убраны"); } } }