using System; using Svelto.ECS; using Unity.Mathematics; using UnityEngine; using Gamecraft.Damage; using RobocraftX.Common; using RobocraftX.Physics; using Techblox.TimeRunning.Clusters; namespace TechbloxModdingAPI { /// /// A rigid body (like a chunk of connected blocks) during simulation. /// public class SimBody : EcsObjectBase, IEquatable, IEquatable { /// /// The cluster this chunk belongs to, or null if no cluster destruction manager present or the chunk doesn't exist. /// Get the SimBody from a Block if possible for good performance here. /// public Cluster Cluster => cluster ??= clusterId == uint.MaxValue // Return cluster or if it's null then set it ? Block.BlockEngine.GetCluster(Id.entityID) // If we don't have a clusterId set then get it from the game : GetInstance(new EGID(clusterId, ClustersExclusiveGroups.SIMULATION_CLUSTERS_GROUP), egid => new Cluster(egid)); // Otherwise get the cluster from the ID private Cluster cluster; private readonly uint clusterId = uint.MaxValue; public SimBody(EGID id) : base(id) { } public SimBody(uint id) : this(new EGID(id, CommonExclusiveGroups.SIMULATION_BODIES_GROUP)) { } internal SimBody(uint id, uint clusterID) : this(id) { clusterId = clusterID; } /// /// The position of this body. When setting the position, update the position of the connected bodies as well, /// otherwise unexpected forces may arise. /// public float3 Position { get => GetStruct().position; set => GetStruct().position = value; } public float3 Velocity { get => GetStruct().velocity; set => GetStruct().velocity = value; } public float3 AngularVelocity { get => GetStruct().angularVelocity; set => GetStruct().angularVelocity = value; } //Delta versions are used internally, can't be set or get public float3 Rotation { get => ((Quaternion) GetStruct().rotation).eulerAngles; set { ref var str = ref GetStruct(); Quaternion quaternion = str.rotation; quaternion.eulerAngles = value; str.rotation = quaternion; } } [Obsolete] //Cannot get mass even from UECS public float Mass { get => 0f; //set => GetStruct().physicsMass.InverseMass = math.rcp(value); } public float3 CenterOfMass { get => 0f; //TODO //set => GetStruct().physicsMass.CenterOfMass = value; } public float Volume { get => GetStruct().volume; } public float InitialHealth { get => 0f; set { } } public float CurrentHealth { get => 0f; set { } } public float HealthMultiplier { get => 0f; set { } } /// /// Whether the body can be moved or static. /// public bool Static => Block.BlockEngine.GetBlockInfo(this).isStatic; //Setting it doesn't have any effect /// /// The rigid bodies connected to this one via functional joints (broken ones don't count). /// public SimBody[] GetConnectedBodies() { return Block.BlockEngine.GetConnectedSimBodies(Id.entityID); } /// /// The blocks that form this rigid body. /// /// public Block[] GetBlocks() { return Block.BlockEngine.GetBodyBlocks(Id.entityID); } private ref RigidBodyEntityStruct GetStruct() { return ref Block.BlockEngine.GetBlockInfo(this); } public override string ToString() { return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Mass)}: {Mass}, {nameof(Static)}: {Static}"; } public bool Equals(SimBody other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Id.Equals(other.Id); } public bool Equals(EGID other) { return Id.Equals(other); } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != this.GetType()) return false; return Equals((SimBody) obj); } public override int GetHashCode() { return Id.GetHashCode(); } /// /// Returns the object identified by the given ID (A-Z). /// This has the same result as calling ObjectIdentifier.GetByID(id) and then GetRigidBody() with the duplicates filtered out. /// /// The alphabetical ID /// An array that may be empty public static SimBody[] GetFromObjectID(char id) => Block.BlockEngine.GetSimBodiesFromID((byte) (id - 'A')); } }