2020-06-04 22:20:35 +00:00
|
|
|
|
using System;
|
2020-05-22 22:06:49 +00:00
|
|
|
|
using Svelto.ECS;
|
|
|
|
|
using Unity.Mathematics;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
2020-08-13 14:59:13 +00:00
|
|
|
|
using Gamecraft.Damage;
|
2020-06-04 22:20:35 +00:00
|
|
|
|
using RobocraftX.Common;
|
|
|
|
|
using RobocraftX.Physics;
|
|
|
|
|
|
2020-05-22 22:06:49 +00:00
|
|
|
|
namespace GamecraftModdingAPI
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
2020-07-18 23:13:39 +00:00
|
|
|
|
/// A rigid body (like a chunk of connected blocks) during simulation.
|
2020-05-22 22:06:49 +00:00
|
|
|
|
/// </summary>
|
2020-06-04 22:20:35 +00:00
|
|
|
|
public class SimBody : IEquatable<SimBody>, IEquatable<EGID>
|
2020-05-22 22:06:49 +00:00
|
|
|
|
{
|
|
|
|
|
public EGID Id { get; }
|
|
|
|
|
|
2020-08-13 14:59:13 +00:00
|
|
|
|
/// <summary>
|
2020-10-02 14:40:06 +00:00
|
|
|
|
/// 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.
|
2020-08-13 14:59:13 +00:00
|
|
|
|
/// </summary>
|
|
|
|
|
public Cluster Cluster => cluster ?? (cluster = clusterId == uint.MaxValue ? Block.BlockEngine.GetCluster(Id.entityID) : new Cluster(clusterId));
|
|
|
|
|
|
|
|
|
|
private Cluster cluster;
|
2020-10-02 14:40:06 +00:00
|
|
|
|
private readonly uint clusterId = uint.MaxValue;
|
2020-08-13 14:59:13 +00:00
|
|
|
|
|
2020-05-22 22:06:49 +00:00
|
|
|
|
public SimBody(EGID id)
|
|
|
|
|
{
|
|
|
|
|
Id = id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public SimBody(uint id) : this(new EGID(id, CommonExclusiveGroups.SIMULATION_BODIES_GROUP))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-13 14:59:13 +00:00
|
|
|
|
internal SimBody(uint id, uint clusterID) : this(id)
|
|
|
|
|
{
|
|
|
|
|
clusterId = clusterID;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-24 19:55:49 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The position of this body. When setting the position, update the position of the connected bodies as well,
|
|
|
|
|
/// otherwise unexpected forces may arise.
|
|
|
|
|
/// </summary>
|
2020-05-22 22:06:49 +00:00
|
|
|
|
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;
|
2020-05-24 19:55:49 +00:00
|
|
|
|
} //Delta versions are used internally, can't be set or get
|
2020-05-22 22:06:49 +00:00
|
|
|
|
|
|
|
|
|
public float3 Rotation
|
|
|
|
|
{
|
|
|
|
|
get => ((Quaternion) GetStruct().rotation).eulerAngles;
|
|
|
|
|
set
|
|
|
|
|
{
|
|
|
|
|
ref var str = ref GetStruct();
|
|
|
|
|
Quaternion quaternion = str.rotation;
|
|
|
|
|
quaternion.eulerAngles = value;
|
|
|
|
|
str.rotation = quaternion;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float Mass
|
|
|
|
|
{
|
|
|
|
|
get => math.rcp(GetStruct().physicsMass.InverseMass);
|
2020-05-24 19:55:49 +00:00
|
|
|
|
//set => GetStruct().physicsMass.InverseMass = math.rcp(value);
|
2020-05-22 22:06:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-24 19:55:49 +00:00
|
|
|
|
public float3 CenterOfMass
|
|
|
|
|
{
|
|
|
|
|
get => GetStruct().physicsMass.CenterOfMass;
|
|
|
|
|
//set => GetStruct().physicsMass.CenterOfMass = value;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-13 14:59:13 +00:00
|
|
|
|
public float Volume
|
|
|
|
|
{
|
|
|
|
|
get => GetStruct().volume;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float InitialHealth
|
|
|
|
|
{
|
|
|
|
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth;
|
|
|
|
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).initialHealth = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float CurrentHealth
|
|
|
|
|
{
|
|
|
|
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth;
|
|
|
|
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).currentHealth = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public float HealthMultiplier
|
|
|
|
|
{
|
|
|
|
|
get => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier;
|
|
|
|
|
set => Block.BlockEngine.GetBlockInfo<HealthEntityComponent>(Id).healthMultiplier = value;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-24 19:55:49 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Whether the body can be moved or static.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public bool Static => Block.BlockEngine.GetBlockInfo<MassEntityStruct>(Id).isStatic; //Setting it doesn't have any effect
|
|
|
|
|
|
2020-05-22 22:06:49 +00:00
|
|
|
|
/// <summary>
|
2020-05-24 19:55:49 +00:00
|
|
|
|
/// The rigid bodies connected to this one via functional joints (broken ones don't count).
|
2020-05-22 22:06:49 +00:00
|
|
|
|
/// </summary>
|
2020-05-24 19:55:49 +00:00
|
|
|
|
public SimBody[] GetConnectedBodies()
|
|
|
|
|
{
|
|
|
|
|
return Block.BlockEngine.GetConnectedSimBodies(Id.entityID);
|
|
|
|
|
}
|
2020-05-22 22:06:49 +00:00
|
|
|
|
|
2020-10-02 14:40:06 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// The blocks that form this rigid body.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public Block[] GetBlocks()
|
|
|
|
|
{
|
|
|
|
|
return Block.BlockEngine.GetBodyBlocks(Id.entityID);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 22:06:49 +00:00
|
|
|
|
private ref RigidBodyEntityStruct GetStruct()
|
|
|
|
|
{
|
|
|
|
|
return ref Block.BlockEngine.GetBlockInfo<RigidBodyEntityStruct>(Id);
|
|
|
|
|
}
|
2020-05-24 17:29:02 +00:00
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return $"{nameof(Id)}: {Id}, {nameof(Position)}: {Position}, {nameof(Mass)}: {Mass}, {nameof(Static)}: {Static}";
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-04 22:20:35 +00:00
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-24 17:29:02 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 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.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="id">The alphabetical ID</param>
|
|
|
|
|
/// <returns>An array that may be empty</returns>
|
|
|
|
|
public static SimBody[] GetFromObjectID(char id) => Block.BlockEngine.GetSimBodiesFromID((byte) (id - 'A'));
|
2020-05-22 22:06:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|