using System; using System.Collections; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using BITFALL.Cosmetic; using BITKit; using BITKit.Entities; using BITKit.Entities.Physics; using Cysharp.Threading.Tasks; using UnityEngine; namespace BITFALL.Entities { [CustomType(typeof(IEntityPhysics))] public class EntityPhysics : EntityBehavior,IEntityPhysics { [SerializeField] private Animator animator; private Rigidbody[] rigidbodies=Array.Empty(); private Collider[] colliders=Array.Empty(); private Joint[] joints=Array.Empty(); private new Rigidbody rigidbody; [Inject(true)] private IHealth _health; [Inject(true)] private IEntityOverride _override; [Inject(true)] private ICosmeticService _cosmeticService; private readonly Dictionary _jointXMotions=new(); private readonly Dictionary _jointYMotions=new(); private readonly Dictionary _jointZMotions=new(); private readonly Dictionary _jointAngularXMotions=new(); private readonly Dictionary _jointAngularYMotions=new(); private readonly Dictionary _jointAngularZMotions=new(); private readonly IntervalUpdate _intervalUpdate=new(0.01f); private bool isDirty = false; private readonly ValidHandle allowUpdate = new(); public override void OnAwake() { OnCosmeticsChanged(); if (_health is not null) _health.OnSetAlive += SetDirty; if (_override is not null) _override.OnOverride += SetDirty; if (_cosmeticService is not null) _cosmeticService.OnCosmeticsChanged += OnCosmeticsChanged; destroyCancellationToken.Register(() => { if (_cosmeticService is not null) _cosmeticService.OnCosmeticsChanged -= OnCosmeticsChanged; }); allowUpdate.AddElement(this); } public override void OnLateUpdate(float deltaTime) { base.OnLateUpdate(deltaTime); if ( destroyCancellationToken.IsCancellationRequested || !isDirty || !_intervalUpdate.AllowUpdateWithoutReset || allowUpdate.Allow is false ) return; isDirty = false; EnsureConf(); } [BIT] private void OnCosmeticsChanged() { allowUpdate.SetDisableElements(this); colliders = Array.Empty(); rigidbodies = Array.Empty(); joints = Array.Empty(); var rigidbodyList = new List(); var collidersList = new List(); var jointList = new List(); foreach (var physicsComponent in GetComponentsInChildren(true)) { if (physicsComponent.Rigidbody) rigidbodyList.Add(physicsComponent.Rigidbody); if (physicsComponent.Collider) collidersList.Add(physicsComponent.Collider); if (physicsComponent.Joint) jointList.Add(physicsComponent.Joint); } colliders = collidersList.ToArray(); rigidbodies = rigidbodyList.ToArray(); joints = jointList.ToArray(); _jointXMotions.Clear(); _jointYMotions.Clear(); _jointZMotions.Clear(); _jointAngularXMotions.Clear(); _jointAngularYMotions.Clear(); _jointAngularZMotions.Clear(); foreach (var x in joints) { switch (x) { case ConfigurableJoint configurableJoint: _jointXMotions.Add(configurableJoint, configurableJoint.xMotion); _jointYMotions.Add(configurableJoint, configurableJoint.yMotion); _jointZMotions.Add(configurableJoint, configurableJoint.zMotion); _jointAngularXMotions.Add(configurableJoint, configurableJoint.angularXMotion); _jointAngularYMotions.Add(configurableJoint, configurableJoint.angularYMotion); _jointAngularZMotions.Add(configurableJoint, configurableJoint.angularZMotion); break; } } if (animator) rigidbody = animator.GetBoneTransform(HumanBodyBones.Hips)?.GetComponent(); EnsureConf(); isDirty = false; allowUpdate.RemoveDisableElements(this); } private void SetDirty(bool any) => SetDirty(); private void SetDirty() { _intervalUpdate.Reset(); isDirty = true; } private void EnsureConf() { var allow = (_health, _override) switch { (not null,not null)=>_health.IsAlive || _override.IsOvering, (not null,null)=>_health.IsAlive, (null,not null)=>_override.IsOvering, _=>true, }; if (animator) { animator.enabled = allow; } try { foreach (var x in rigidbodies) { try { x.isKinematic= allow; x.gameObject.SetActive(!allow); } catch (Exception e) { BIT4Log.LogException(e); } } foreach (var x in colliders) { x.enabled = !allow; } OnSetPhysics?.Invoke(!allow); } catch (OperationCanceledException) { return; } catch (Exception e) { BIT4Log.LogException(e); return; } foreach (var joint in joints) { switch (joint) { case ConfigurableJoint configurableJoint: configurableJoint.xMotion = allow ? _jointXMotions[joint] : ConfigurableJointMotion.Free; configurableJoint.yMotion = allow ? _jointYMotions[joint] : ConfigurableJointMotion.Free; configurableJoint.zMotion = allow ? _jointZMotions[joint] : ConfigurableJointMotion.Free; configurableJoint.angularXMotion = allow ? _jointAngularXMotions[joint] : ConfigurableJointMotion.Free; configurableJoint.angularYMotion = allow ? _jointAngularYMotions[joint] : ConfigurableJointMotion.Free; configurableJoint.angularZMotion = allow ? _jointAngularZMotions[joint] : ConfigurableJointMotion.Free; break; } } } public Vector3 Center => rigidbody.worldCenterOfMass; public bool IsPhysics { get; private set; } public Vector3 Velocity { get => rigidbody ? rigidbody.velocity : default; set { foreach (var x in rigidbodies) { x.velocity = value; } } } public Action OnSetPhysics { get; set; } public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force) { foreach (var x in rigidbodies) { x.AddForce(force, mode); } } public void AddTorque(Vector3 torque, ForceMode mode = ForceMode.Force) { foreach (var x in rigidbodies) { x.AddTorque(torque, mode); } } } }