using System.Collections.Generic; using UniLinq; using UnityEngine; namespace KFCommonUtilityLib.Scripts.StaticManagers { public static class AnimationRiggingManager { //public class FpvTransformRef //{ // public Animator fpvAnimator; // public RigTargets targets; // public ItemInventoryData invData; // //public Transform muzzle; // //public Transform muzzle2; // //public bool isDoubleBarrel; // public FpvTransformRef(RigTargets targets, ItemInventoryData invData) // { // this.targets = targets; // this.invData = invData; // //this.isDoubleBarrel = isDoubleBarrel; // fpvAnimator = targets.itemFpv.GetComponentInChildren(); // //if (isDoubleBarrel) // //{ // // muzzle = targets.itemFpv.transform.FindInChildren("Muzzle_L"); // // muzzle2 = targets.itemFpv.transform.FindInChildren("Muzzle_R"); // //} // //else // // muzzle = targets.itemFpv.transform.FindInChilds("Muzzle"); // } // public bool IsRanged(out ItemActionRanged.ItemActionDataRanged rangedData) // { // return (rangedData = invData.actionData[MultiActionManager.GetActionIndexForEntity(GameManager.Instance.World.GetPrimaryPlayer())] as ItemActionRanged.ItemActionDataRanged) != null; // } //} public static bool IsHoldingRiggedWeapon(EntityPlayer player) { AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); return targets && !targets.Destroyed; } //private static bool RigItemChangedThisFrame = false; //private static readonly HashSet hash_rig_items = new HashSet(); private static readonly HashSet hash_items_take_over_reload_time = new HashSet(); private static readonly HashSet hash_items_parse_later = new HashSet(); private static readonly HashSet hash_rig_names = new HashSet(); private static readonly HashSet hash_rig_changed_players = new HashSet(); //patched to item xml parsing //public static void AddRigItem(int itemId) => hash_rig_items.Add(itemId); public static void Clear() { //hash_rig_items.Clear(); //RigItemChangedThisFrame = false; hash_items_parse_later.Clear(); hash_items_take_over_reload_time.Clear(); hash_rig_names.Clear(); hash_rig_changed_players.Clear(); } public static void AddReloadTimeTakeOverItem(string name) { hash_items_parse_later.Add(name); } public static void AddRigExcludeName(string name) { hash_rig_names.Add(name); } public static void RemoveRigExcludeName(string name) { hash_rig_names.Remove(name); } public static bool ShouldExcludeRig(string name) { return hash_rig_names.Contains(name); } public static string[] GetExcludeRigs() { return hash_rig_names.ToArray(); } public static void ParseItemIDs() { foreach (var name in hash_items_parse_later) { hash_items_take_over_reload_time.Add(ItemClass.GetItemClass(name).Id); //Log.Out($"parse item id: {name} {ItemClass.GetItemClass(name).Id}"); } hash_items_parse_later.Clear(); } public static bool IsReloadTimeTakeOverItem(int id) { return hash_items_take_over_reload_time.Contains(id); } public static AnimationTargetsAbs GetRigTargetsFromPlayer(EntityAlive player) { if (player is not EntityPlayer) return null; Transform holdingItemTransform = player.inventory?.GetHoldingItemTransform(); if (holdingItemTransform) { return holdingItemTransform.GetComponent(); } return null; } public static AnimationTargetsAbs GetRigTargetsFromInventory(Inventory inventory) { Transform holdingItemTransform = inventory?.GetHoldingItemTransform(); if (holdingItemTransform) { return holdingItemTransform.GetComponent(); } return null; } //public static bool IsRigItem(int itemId) => hash_rig_items.Contains(itemId); public static void UpdatePlayerAvatar(AvatarController controller) { if (!controller?.Entity) { return; } AnimationTargetsAbs targets = GetRigTargetsFromPlayer(controller.Entity as EntityPlayer); bool RigItemChangedThisFrame = hash_rig_changed_players.Remove(controller.Entity.entityId); if (targets && !targets.Destroyed) { targets.UpdatePlayerAvatar(controller, RigItemChangedThisFrame); } controller.UpdateBool(AvatarController.isCrouchingHash, controller.entity.IsCrouching, true); //if ((controller.Entity as EntityPlayerLocal).bFirstPersonView && targets && !targets.Destroyed && targets.itemFpv) //{ // //workaround for animator bullshit // if (!targets.itemFpv.gameObject.activeSelf) // { // Log.Out("Rigged weapon not active, enabling it..."); // targets.SetEnabled(true); // } // //vroid workaround // //it seems to use a separate animator for vroid model and does not replace CharacterBody // //controller.UpdateInt(AvatarController.weaponHoldTypeHash, -1, false); // controller.FPSArms.Animator.Play("idle", 0, 0f); // foreach (var hash in resetHashes) // { // AnimationRiggingPatches.VanillaResetTrigger(controller, hash, false); // } // //controller.FPSArms?.Animator?.SetInteger(AvatarController.weaponHoldTypeHash, -1); // //controller.CharacterBody?.Animator?.SetInteger(AvatarController.weaponHoldTypeHash, -1); //} //if (RigItemChangedThisFrame) //{ // Log.Out("Rigged weapon changed, resetting animator..."); // Transform modelRoot = controller.GetActiveModelRoot(); // //if (modelRoot && (!targets || targets.Destroyed) && modelRoot.GetComponentInChildren().TryGetComponent(out var builder)) // //{ // // builder.DestroyGraph(!targets || targets.Destroyed); // //} // if (controller is AvatarLocalPlayerController localPlayerController && localPlayerController.isFPV && localPlayerController.FPSArms != null) // { // if (localPlayerController.FPSArms.Animator.TryGetComponent(out var builder)) // { // builder.VanillaWrapper.Play("idle", 0, 0f); // } // else // { // localPlayerController.FPSArms.Animator.Play("idle", 0, 0f); // } // } // controller.UpdateInt(AvatarController.weaponHoldTypeHash, -1, false); //} } public static void OnClearInventorySlot(Inventory inv, int slot) { if (inv == null) return; Transform transform = inv.models[slot]; if (transform && transform.TryGetComponent(out var targets) && !targets.Destroyed) { //RigItemChangedThisFrame = true; targets.Destroy(); if (slot == inv.holdingItemIdx && inv.entity is EntityPlayer) { hash_rig_changed_players.Add(inv.entity.entityId); } } } //patched to EntityPlayerLocal.OnHoldingItemChanged and EntityAlive.OnHoldingItemIndexChanged public static void OnHoldingItemIndexChanged(EntityPlayer player) { if (!player || player.inventory == null || player.inventory.m_LastDrawnHoldingItemIndex < 0 || player.inventory.m_LastDrawnHoldingItemIndex >= player.inventory.GetSlotCount()) return; if (player.inventory.m_LastDrawnHoldingItemIndex == player.inventory.holdingItemIdx) { hash_rig_changed_players.Add(player.entityId); return; } Transform lastHoldingTransform = player.inventory.models[player.inventory.m_LastDrawnHoldingItemIndex]; if (!lastHoldingTransform) { hash_rig_changed_players.Add(player.entityId); return; } AnimationTargetsAbs targets = lastHoldingTransform.GetComponent(); //if (targets && !targets.Destroyed && targets.IsAnimationSet) //{ // //RigItemChangedThisFrame = true; // hash_rig_changed_players.Add(player.entityId); // return; //} targets = GetRigTargetsFromPlayer(player); if (targets && !targets.Destroyed && targets.IsAnimationSet) { //RigItemChangedThisFrame = true; hash_rig_changed_players.Add(player.entityId); } } public static Transform GetAttachmentReferenceOverrideTransform(Transform transform, string transformPath, Entity entity) { if (transform == null || entity == null || !(entity is EntityAlive entityAlive) || entityAlive.inventory == null) return null; //Log.Out("TRYING TO REDIRECT TRANSFORM REFERENCE: " + transform.name + " CHILD: " + transformPath); var targets = entityAlive.inventory.GetHoldingItemTransform()?.GetComponent(); if (targets != null && targets.attachmentReference != null) { var redirected = GameUtils.FindDeepChild(targets.attachmentReference, transform.name) ?? targets.attachmentReference; //Log.Out("REDIRECTING TRANSFORM REFERENCE TO " + redirected.name); var find = GameUtils.FindDeepChild(redirected, transformPath); if (find != null) //Log.Out("FOUND REDIRECTED CHILD: " + find.name + " PARENT: " + find.parent.name); return find; } return GameUtils.FindDeepChild(transform, transformPath); } public static Transform GetAttachmentReferenceOverrideTransformActive(Transform transform, string transformPath, Entity entity) { if (transform == null || entity == null || !(entity is EntityAlive entityAlive) || entityAlive.inventory == null) return null; //Log.Out("TRYING TO REDIRECT TRANSFORM REFERENCE: " + transform.name + " CHILD: " + transformPath); var targets = entityAlive.inventory.GetHoldingItemTransform()?.GetComponent(); if (targets != null && targets.attachmentReference != null) { var redirected = GameUtils.FindDeepChildActive(targets.attachmentReference, transform.name) ?? targets.attachmentReference; //Log.Out("REDIRECTING TRANSFORM REFERENCE TO " + redirected.name); var find = GameUtils.FindDeepChildActive(redirected, transformPath); if (find != null) //Log.Out("FOUND REDIRECTED CHILD: " + find.name + " PARENT: " + find.parent.name); return find; } return GameUtils.FindDeepChildActive(transform, transformPath); } //public static Transform GetMuzzleOverrideFPV(Transform muzzle, bool isLocalFpv) //{ // if (!isLocalFpv || fpvTransformRef == null) // return muzzle; // if (fpvTransformRef.IsRanged(out var rangedData)) // { // return rangedData.muzzle; // } // return muzzle; //} //public static Transform GetMuzzle2OverrideFPV(Transform muzzle2, bool isLocalFpv) //{ // if (!isLocalFpv || fpvTransformRef == null) // return muzzle2; // if (fpvTransformRef.IsRanged(out var rangedData)) // { // return rangedData.muzzle2; // } // return muzzle2; //} public static Transform GetTransformOverrideByName(Transform itemModel, string name, bool onlyActive = true) { if (itemModel == null) return null; if (!itemModel.TryGetComponent(out var targets) || targets.Destroyed) { if (string.IsNullOrEmpty(name)) return itemModel; return onlyActive ? GameUtils.FindDeepChildActive(itemModel, name) : GameUtils.FindDeepChild(itemModel, name); } var attachmentOverride = targets.GetAttachmentPathOverride(name, onlyActive); if (attachmentOverride) { return attachmentOverride; } Transform targetRoot = targets.ItemCurrentOrDefault; if (string.IsNullOrEmpty(name)) return targetRoot; return onlyActive ? GameUtils.FindDeepChildActive(targetRoot, name) : GameUtils.FindDeepChild(targetRoot, name); } public static Transform GetAddPartTransformOverride(Transform itemModel, string name, bool onlyActive = true) { return GetTransformOverrideByName(itemModel, name, onlyActive) ?? itemModel; } //patched to ItemActionRanged.ItemActionEffect public static bool SpawnFpvParticles(bool isLocalFpv, ItemActionData _actionData, string particlesMuzzleFire, string particlesMuzzleFireFpv, string particlesMuzzleSmoke, string particlesMuzzleSmokeFpv) { if (!isLocalFpv || !GetRigTargetsFromInventory(_actionData.invData.holdingEntity.inventory)) return false; var itemActionDataRanged = _actionData as ItemActionRanged.ItemActionDataRanged; EntityPlayerLocal player = GameManager.Instance.World.GetPrimaryPlayer(); if (itemActionDataRanged.muzzle != null) { if (particlesMuzzleFire != null) { Transform fire = GameManager.Instance.SpawnParticleEffectClientForceCreation(new ParticleEffect(particlesMuzzleFireFpv != null ? particlesMuzzleFireFpv : particlesMuzzleFire, Vector3.zero, 1f, Color.clear, null, null, false), player.entityId, true); if (fire != null) { fire.transform.localPosition = Vector3.zero; //fire.transform.localEulerAngles = Vector3.zero; if (itemActionDataRanged.IsDoubleBarrel && itemActionDataRanged.invData.itemValue.Meta == 0) fire.transform.SetParent(itemActionDataRanged.muzzle2, false); else fire.transform.SetParent(itemActionDataRanged.muzzle, false); Utils.SetLayerRecursively(fire.gameObject, 10, null); //fire.transform.localPosition = Vector3.zero; //fire.transform.localEulerAngles = Vector3.zero; //fire.transform.localScale = Vector3.one; foreach (var particle in fire.GetComponentsInChildren()) { particle.gameObject.SetActive(true); particle.Clear(); particle.Play(); } var temp = fire.gameObject.GetOrAddComponent(); temp.life = 5; //temp.Restart(); if (fire.TryGetComponent(out var lod)) lod.enabled = false; //Log.Out($"barrel position: {fire.transform.parent.parent.position}/{fire.transform.parent.parent.localPosition}, muzzle position: {fire.transform.parent.position}/{fire.transform.parent.localPosition}, particle position: {fire.transform.position}"); //Log.Out($"particles: {string.Join("\n", fire.GetComponentsInChildren().Select(ps => ps.name + " active: " + ps.gameObject.activeInHierarchy + " layer: " + ps.gameObject.layer + " position: " + ps.transform.position))}"); } } if (particlesMuzzleSmoke != null && itemActionDataRanged.muzzle != null) { float num = GameManager.Instance.World.GetLightBrightness(World.worldToBlockPos(itemActionDataRanged.muzzle.transform.position)) / 2f; Color clear = Color.clear; Transform smoke = GameManager.Instance.SpawnParticleEffectClientForceCreation(new ParticleEffect(particlesMuzzleSmokeFpv != null ? particlesMuzzleSmokeFpv : particlesMuzzleSmoke, Vector3.zero, num, clear, null, null, false), player.entityId, true); if (smoke != null) { smoke.transform.localPosition = Vector3.zero; //smoke.transform.localEulerAngles = Vector3.zero; Utils.SetLayerRecursively(smoke.gameObject, 10, null); smoke.transform.SetParent(itemActionDataRanged.muzzle, false); //smoke.transform.localPosition = Vector3.zero; //smoke.transform.localEulerAngles = Vector3.zero; //smoke.transform.localScale = Vector3.one; foreach (var particle in smoke.GetComponentsInChildren()) { particle.gameObject.SetActive(true); particle.Clear(); particle.Play(); } var temp = smoke.gameObject.GetOrAddComponent(); temp.life = 5; //temp.Restart(); if (smoke.TryGetComponent(out var lod)) lod.enabled = false; } } } return true; } //public static void SetTrigger(int _pid, EntityPlayer player) //{ // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); // if (targets && !targets.Destroyed && targets.ItemAnimator) // { // targets.ItemAnimator.SetTrigger(_pid); // //Log.Out($"setting trigger {_pid}"); // } //} //public static void ResetTrigger(int _pid, EntityPlayer player) //{ // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); // if (targets && !targets.Destroyed && targets.ItemAnimator) // { // targets.ItemAnimator.ResetTrigger(_pid); // //Log.Out($"resetting trigger {_pid}"); // } //} //public static void SetFloat(int _pid, float _value, EntityPlayer player) //{ // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); // if (targets&& !targets.Destroyed && targets.ItemAnimator) // { // targets.ItemAnimator.SetFloat(_pid, _value); // //Log.Out($"setting float {_pid}"); // } //} //public static void SetBool(int _pid, bool _value, EntityPlayer player) //{ // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); // if (targets && !targets.Destroyed && targets.ItemAnimator) // { // targets.ItemAnimator.SetBool(_pid, _value); // //Log.Out($"setting bool {_pid}"); // } //} //public static void SetInt(int _pid, int _value, EntityPlayer player) //{ // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); // if (targets && !targets.Destroyed && targets.ItemAnimator) // { // targets.ItemAnimator.SetInteger(_pid, _value); // //Log.Out($"setting int {_pid}"); // } //} } }