imperfect-space/scripts/GameObject.cs

295 lines
7.8 KiB
C#

using System;
using Godot;
public abstract class GameObject
{
[Flags]
public enum DirtyFlags : ulong
{
None = 0,
UUID = 1UL << 0,
Sector = 1UL << 1,
LocalCoordinates = 1UL << 2,
Rotation = 1UL << 3,
Velocity = 1UL << 4,
AngularVelocity = 1UL << 5
}
public DirtyFlags DirtyBits { get; protected set; } = DirtyFlags.None;
protected Guid _uuid;
public Guid UUID
{
get => _uuid;
set
{
if (_uuid != value)
{
_uuid = value;
DirtyBits |= DirtyFlags.UUID;
}
}
}
protected Vector3I _currentSectorCoordinates;
protected Sector _currentSector;
public Sector CurrentSector
{
get => _currentSector;
protected set
{
if (_currentSector != value)
{
_currentSector = value;
_currentSectorCoordinates = value.Coordinates;
DirtyBits |= DirtyFlags.Sector;
}
}
}
protected Vector3 _localCoordinates;
public Vector3 LocalCoordinates
{
get => _localCoordinates;
protected set
{
if (_localCoordinates != value)
{
_localCoordinates = value;
DirtyBits |= DirtyFlags.LocalCoordinates;
}
}
}
protected Vector3 _rotation;
public Vector3 Rotation
{
get => _rotation;
protected set
{
if (_rotation != value)
{
_rotation = value;
DirtyBits |= DirtyFlags.Rotation;
}
}
}
protected Vector3 _velocity;
public Vector3 Velocity
{
get => _velocity;
protected set
{
if (_velocity != value)
{
_velocity = value;
DirtyBits |= DirtyFlags.Velocity;
}
}
}
protected Vector3 _angularVelocity;
public Vector3 AngularVelocity
{
get => _angularVelocity;
protected set
{
if (_angularVelocity != value)
{
_angularVelocity = value;
DirtyBits |= DirtyFlags.AngularVelocity;
}
}
}
public Vector3 SectorOffset { get; protected set; }
protected bool reassigning = false;
public GameObject(Sector sector, Vector3 localCoordinates)
{
UUID = Guid.NewGuid();
CurrentSector = sector;
LocalCoordinates = localCoordinates;
Velocity = new(0, 0, 1);
AngularVelocity = Vector3.Zero;
Rotation = Vector3.Zero;
}
public void ApplyVelocity(double delta)
{
SetCoordinates(LocalCoordinates + Velocity * delta);
Rotation += AngularVelocity * delta;
}
public bool IsInCurrentSector()
{
return Helpers.IsInsideArea(GameManager.Generator.GetSectorSize() / 2, LocalCoordinates);
}
public void UpdateSector()
{
if (!GameManager.GameUniverse.IsInside(CurrentSector.Coordinates, LocalCoordinates))
{
return;
}
Vector3 sectorSize = GameManager.Generator.GetSectorSize() / 2;
bool? x = null;
bool? y = null;
bool? z = null;
if (LocalCoordinates.X > sectorSize.X) x = true;
else if (LocalCoordinates.X < -sectorSize.X) x = false;
if (LocalCoordinates.Y > sectorSize.Y) y = true;
else if (LocalCoordinates.Y < -sectorSize.Y) y = false;
if (LocalCoordinates.Z > sectorSize.Z) z = true;
else if (LocalCoordinates.Z < -sectorSize.Z) z = false;
Sector sector = GameManager.GameUniverse.GetNeighbouringSector(CurrentSector, x, y, z);
if (sector != null)
{
reassigning = true;
sector.AssignObject(this);
}
}
public virtual void AssignSector(Sector sector)
{
Vector3 sectorOffset = GetSectorOffset(sector);
CurrentSector = sector;
LocalCoordinates += sectorOffset;
UpdateSectorOffsetToMainPlayer();
reassigning = false;
}
public Vector3 GetSectorOffset(Sector sector)
{
Vector3I relative = CurrentSector.Coordinates - sector.Coordinates;
return relative * GameManager.Generator.GetSectorSize();
}
public void UpdateSectorOffset(Sector sector)
{
SectorOffset = GetSectorOffset(sector);
}
public void UpdateSectorOffsetToMainPlayer()
{
UpdateSectorOffset(GameManager.Instance.GetCurrentSector());
}
public void SetCoordinates(Vector3 localCoordinates)
{
LocalCoordinates = localCoordinates;
UpdateNodePosition();
}
public double GetDistanceToObject(GameObject gameObject)
{
Sector sector = gameObject.CurrentSector;
Vector3 sectorOffset = GetSectorOffset(sector);
Vector3 position1 = LocalCoordinates;
Vector3 position2 = gameObject.LocalCoordinates - sectorOffset;
return Helpers.GetDistance(position1, position2);
}
public virtual void UpdateNodePosition() { }
public virtual void Simulate(double delta)
{
ApplyVelocity(delta);
if (!reassigning && !IsInCurrentSector())
{
UpdateSector();
}
}
public virtual Node3D Instantiate(Sector sector)
{
PackedScene modulePrefab = ResourceLoader.Load<PackedScene>("res://prefabs/gameObjects/node.tscn");
Node3D instance = modulePrefab.Instantiate<Node3D>();
instance.Name = $"GameObject-{UUID}";
return instance;
}
public virtual Godot.Collections.Dictionary NetworkWrite(long id, bool full)
{
Godot.Collections.Dictionary gameObjectData = [];
if (full)
gameObjectData.Add("type", GetType().ToString());
if (DirtyBits.HasFlag(DirtyFlags.Sector) || full)
gameObjectData.Add("sectorCoordinates", _currentSectorCoordinates);
if (DirtyBits.HasFlag(DirtyFlags.LocalCoordinates) || full)
gameObjectData.Add("localCoordinates", _localCoordinates);
if (DirtyBits.HasFlag(DirtyFlags.Rotation) || full)
gameObjectData.Add("rotation", _rotation);
if (DirtyBits.HasFlag(DirtyFlags.Velocity) || full)
gameObjectData.Add("velocity", _velocity);
if (DirtyBits.HasFlag(DirtyFlags.AngularVelocity) || full)
gameObjectData.Add("angularVelocity", _angularVelocity);
if (gameObjectData.Count > 0)
{
gameObjectData.Add("uuid", UUID.ToString());
return gameObjectData;
}
return null;
}
public virtual void NetworkRead(Godot.Collections.Dictionary gameObjectData)
{
if (gameObjectData.TryGetValue("sectorCoordinates", out var sectorCoordinatesData))
{
Sector newSector = GameManager.GameUniverse.GetSector((Vector3I)sectorCoordinatesData);
CurrentSector.GameObjects.Remove(this);
newSector.GameObjects.Add(this);
AssignSector(newSector);
}
if (gameObjectData.TryGetValue("localCoordinates", out var localCoordinatesData))
LocalCoordinates = (Vector3)localCoordinatesData;
if (gameObjectData.TryGetValue("rotation", out var rotationData))
Rotation = (Vector3)rotationData;
if (gameObjectData.TryGetValue("velocity", out var velocityData))
Velocity = (Vector3)velocityData;
if (gameObjectData.TryGetValue("angularVelocity", out var angularVelocityData))
AngularVelocity = (Vector3)angularVelocityData;
}
public override bool Equals(object obj)
{
GameObject gameObj = (GameObject)obj;
return gameObj.UUID == UUID;
}
public override int GetHashCode()
{
return UUID.GetHashCode();
}
}