using System; using NitroxClient.Communication.Packets.Processors.Abstract; using NitroxClient.GameLogic; using NitroxClient.MonoBehaviours; using NitroxModel.DataStructures.Util; using NitroxModel.Helper; using NitroxModel.Packets; using UnityEngine; namespace NitroxClient.Communication.Packets.Processors; public class PlayerHeldItemChangedProcessor : ClientPacketProcessor { private int defaultLayer; private int viewModelLayer; private readonly PlayerManager playerManager; public PlayerHeldItemChangedProcessor(PlayerManager playerManager) { this.playerManager = playerManager; if (NitroxEnvironment.IsNormal) { SetupLayers(); } } private void SetupLayers() { defaultLayer = LayerMask.NameToLayer("Default"); viewModelLayer = LayerMask.NameToLayer("Viewmodel"); } public override void Process(PlayerHeldItemChanged packet) { Optional opPlayer = playerManager.Find(packet.PlayerId); Validate.IsPresent(opPlayer); if (!NitroxEntity.TryGetObjectFrom(packet.ItemId, out GameObject item)) { return; // Item can be not spawned yet bc async. } Pickupable pickupable = item.GetComponent(); Validate.IsTrue(pickupable); Validate.NotNull(pickupable.inventoryItem); ItemsContainer inventory = opPlayer.Value.Inventory; PlayerTool tool = item.GetComponent(); // Copied from QuickSlots switch (packet.Type) { case PlayerHeldItemChanged.ChangeType.DRAW_AS_TOOL: Validate.IsTrue(tool); ModelPlug.PlugIntoSocket(tool, opPlayer.Value.ItemAttachPoint); Utils.SetLayerRecursively(item, viewModelLayer); foreach (Animator componentsInChild in tool.GetComponentsInChildren()) { componentsInChild.cullingMode = AnimatorCullingMode.AlwaysAnimate; } if (tool.mainCollider) { tool.mainCollider.enabled = false; } tool.GetComponent().isKinematic = true; item.SetActive(true); tool.SetHandIKTargetsEnabled(true); SafeAnimator.SetBool(opPlayer.Value.ArmsController.GetComponent(), $"holding_{tool.animToolName}", true); opPlayer.Value.AnimationController["using_tool_first"] = packet.IsFirstTime == null; if (item.TryGetComponent(out FPModel fpModelDraw)) //FPModel needs to be updated { fpModelDraw.OnEquip(null, null); } break; case PlayerHeldItemChanged.ChangeType.HOLSTER_AS_TOOL: Validate.IsTrue(tool); item.SetActive(false); Utils.SetLayerRecursively(item, defaultLayer); if (tool.mainCollider) { tool.mainCollider.enabled = true; } tool.GetComponent().isKinematic = false; pickupable.inventoryItem.item.Reparent(inventory.tr); foreach (Animator componentsInChild in tool.GetComponentsInChildren()) { componentsInChild.cullingMode = AnimatorCullingMode.CullUpdateTransforms; } SafeAnimator.SetBool(opPlayer.Value.ArmsController.GetComponent(), $"holding_{tool.animToolName}", false); opPlayer.Value.AnimationController["using_tool_first"] = false; if (item.TryGetComponent(out FPModel fpModelHolster)) //FPModel needs to be updated { fpModelHolster.OnUnequip(null, null); } break; case PlayerHeldItemChanged.ChangeType.DRAW_AS_ITEM: pickupable.inventoryItem.item.Reparent(opPlayer.Value.ItemAttachPoint); pickupable.inventoryItem.item.SetVisible(true); Utils.SetLayerRecursively(pickupable.inventoryItem.item.gameObject, viewModelLayer); break; case PlayerHeldItemChanged.ChangeType.HOLSTER_AS_ITEM: pickupable.inventoryItem.item.Reparent(inventory.tr); pickupable.inventoryItem.item.SetVisible(false); Utils.SetLayerRecursively(pickupable.inventoryItem.item.gameObject, defaultLayer); break; default: throw new ArgumentOutOfRangeException(nameof(packet.Type)); } } }