TechbloxModdingAPI/GamecraftModdingAPI/Blocks/BlockEngine.cs
Norbi Peti 680721256c Add support for copying wires, some fixes and additions
Removing blocks from groups when they are removed from the game
Attempted to update graphics when changing blocks
Disallowing changing the block group after creation, now that we can copy blocks
2020-11-13 23:59:37 +01:00

305 lines
9.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Gamecraft.ColourPalette;
using Gamecraft.TimeRunning;
using Gamecraft.Wires;
using RobocraftX.Blocks;
using RobocraftX.Common;
using RobocraftX.Physics;
using RobocraftX.Rendering;
using Svelto.ECS.EntityStructs;
using Svelto.DataStructures;
using Svelto.ECS;
using Svelto.ECS.Hybrid;
using Unity.Mathematics;
using GamecraftModdingAPI.Engines;
namespace GamecraftModdingAPI.Blocks
{
/// <summary>
/// Engine for executing general block actions
/// </summary>
public partial class BlockEngine : IApiEngine
{
public string Name { get; } = "GamecraftModdingAPIBlockGameEngine";
public EntitiesDB entitiesDB { set; private get; }
public bool isRemovable => false;
public void Dispose()
{
}
public void Ready()
{
}
public Block[] GetConnectedBlocks(EGID blockID)
{
if (!BlockExists(blockID)) return new Block[0];
Stack<EGID> cubeStack = new Stack<EGID>();
FasterList<EGID> cubes = new FasterList<EGID>(10);
var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
foreach (var (ecoll, _) in coll)
{
var ecollB = ecoll.ToBuffer();
for(int i = 0; i < ecoll.count; i++)
{
ref var conn = ref ecollB.buffer[i];
conn.isProcessed = false;
}
}
ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes,
(in GridConnectionsEntityStruct g) => { return false; });
var ret = new Block[cubes.count];
for (int i = 0; i < cubes.count; i++)
ret[i] = new Block(cubes[i]);
return ret;
}
public float4 ConvertBlockColor(byte index) => index == byte.MaxValue
? new float4(-1f, -1f, -1f, -1f)
: entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index,
CommonExclusiveGroups.COLOUR_PALETTE_GROUP).Colour;
public ref T GetBlockInfo<T>(EGID blockID) where T : unmanaged, IEntityComponent
{
if (entitiesDB.Exists<T>(blockID))
return ref entitiesDB.QueryEntity<T>(blockID);
T[] structHolder = new T[1]; //Create something that can be referenced
return ref structHolder[0]; //Gets a default value automatically
}
public ref T GetBlockInfoViewStruct<T>(EGID blockID) where T : struct, INeedEGID, IEntityViewComponent
{
if (entitiesDB.Exists<T>(blockID))
{
// TODO: optimize by using EntitiesDB internal calls instead of iterating over everything
BT<MB<T>> entities = entitiesDB.QueryEntities<T>(blockID.groupID).ToBuffer();
for (int i = 0; i < entities.count; i++)
{
if (entities.buffer[i].ID == blockID)
{
return ref entities.buffer[i];
}
}
}
T[] structHolder = new T[1]; //Create something that can be referenced
return ref structHolder[0]; //Gets a default value automatically
}
public U GetBlockInfo<T, U>(Block block, Func<T, U> getter,
U def = default) where T : unmanaged, IEntityComponent
{
if (entitiesDB.Exists<T>(block.Id))
return getter(entitiesDB.QueryEntity<T>(block.Id));
return GetBlockInitInfo(block, getter, def);
}
public U GetBlockInfoViewStruct<T, U>(Block block, Func<T, U> getter,
U def = default) where T : struct, IEntityViewComponent
{
if (entitiesDB.Exists<T>(block.Id))
return getter(entitiesDB.QueryEntity<T>(block.Id));
return GetBlockInitInfo(block, getter, def);
}
private U GetBlockInitInfo<T, U>(Block block, Func<T, U> getter, U def) where T : struct, IEntityComponent
{
if (block.InitData.Group == null) return def;
var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group);
if (initializer.Has<T>())
return getter(initializer.Get<T>());
return def;
}
public delegate void Setter<T, U>(ref T component, U value) where T : struct, IEntityComponent;
public void SetBlockInfoViewStruct<T, U>(Block block, Setter<T, U> setter, U value) where T : struct, IEntityViewComponent
{
if (entitiesDB.Exists<T>(block.Id))
setter(ref entitiesDB.QueryEntity<T>(block.Id), value);
else
SetBlockInitInfo(block, setter, value);
}
public void SetBlockInfo<T, U>(Block block, Setter<T, U> setter, U value) where T : unmanaged, IEntityComponent
{
if (entitiesDB.Exists<T>(block.Id))
setter(ref entitiesDB.QueryEntity<T>(block.Id), value);
else
SetBlockInitInfo(block, setter, value);
}
private void SetBlockInitInfo<T, U>(Block block, Setter<T, U> setter, U value)
where T : struct, IEntityComponent
{
if (block.InitData.Group != null)
{
var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group);
T component = initializer.Has<T>() ? initializer.Get<T>() : default;
ref T structRef = ref component;
setter(ref structRef, value);
initializer.Init(structRef);
}
}
public void UpdateDisplayedBlock(EGID id)
{
if (!BlockExists(id)) return;
var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id);
var rot = entitiesDB.QueryEntity<RotationEntityStruct>(id);
var scale = entitiesDB.QueryEntity<ScalingEntityStruct>(id);
entitiesDB.QueryEntity<RenderingDataStruct>(id).matrix = float4x4.TRS(pos.position, rot.rotation, scale.scale);
}
public bool BlockExists(EGID blockID)
{
return entitiesDB.Exists<DBEntityStruct>(blockID);
}
public bool GetBlockInfoExists<T>(Block block) where T : struct, IEntityComponent
{
if (entitiesDB.Exists<T>(block.Id))
return true;
if (block.InitData.Group == null)
return false;
var init = new EntityComponentInitializer(block.Id, block.InitData.Group);
return init.Has<T>();
}
public SimBody[] GetSimBodiesFromID(byte id)
{
var ret = new FasterList<SimBody>(4);
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.OBJID_BLOCK_GROUP))
return new SimBody[0];
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.OBJID_BLOCK_GROUP).ToBuffer();
var connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(CommonExclusiveGroups.OBJID_BLOCK_GROUP);
for (int i = 0; i < oids.count; i++)
{
ref ObjectIdEntityStruct oid = ref oids.buffer[i];
if (oid.objectId != id) continue;
var rid = connections.Entity(oid.ID.entityID).machineRigidBodyId;
foreach (var rb in ret)
{
if (rb.Id.entityID == rid)
goto DUPLICATE; //Multiple Object Identifiers on one rigid body
}
ret.Add(new SimBody(rid));
DUPLICATE: ;
}
return ret.ToArray();
}
public ObjectIdentifier[] GetObjectIDsFromID(byte id, bool sim)
{
var ret = new FasterList<ObjectIdentifier>(4);
if (!entitiesDB.HasAny<ObjectIdEntityStruct>(CommonExclusiveGroups.OBJID_BLOCK_GROUP))
return new ObjectIdentifier[0];
var oids = entitiesDB.QueryEntities<ObjectIdEntityStruct>(CommonExclusiveGroups.OBJID_BLOCK_GROUP).ToBuffer();
for (int i = 0; i < oids.count; i++)
{
ref ObjectIdEntityStruct oid = ref oids.buffer[i];
if (sim ? oid.simObjectId == id : oid.objectId == id)
ret.Add(new ObjectIdentifier(oid.ID));
}
return ret.ToArray();
}
public SimBody[] GetConnectedSimBodies(uint id)
{
var joints = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP).ToBuffer();
var list = new FasterList<SimBody>(4);
for (int i = 0; i < joints.count; i++)
{
ref var joint = ref joints.buffer[i];
if (joint.jointState == JointState.Broken) continue;
if (joint.connectedEntityA == id) list.Add(new SimBody(joint.connectedEntityB));
else if (joint.connectedEntityB == id) list.Add(new SimBody(joint.connectedEntityA));
}
return list.ToArray();
}
public SimBody[] GetClusterBodies(uint cid)
{
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
var bodies = new HashSet<uint>();
foreach (var (coll, _) in groups)
{
var array = coll.ToBuffer().buffer;
for (var index = 0; index < array.capacity; index++)
{
var conn = array[index];
if (conn.clusterId == cid)
bodies.Add(conn.machineRigidBodyId);
}
}
return bodies.Select(id => new SimBody(id, cid)).ToArray();
}
public EGID? FindBlockEGID(uint id)
{
var groups = entitiesDB.FindGroups<DBEntityStruct>();
foreach (ExclusiveGroupStruct group in groups)
{
if (entitiesDB.Exists<DBEntityStruct>(id, group))
return new EGID(id, group);
}
return null;
}
public Cluster GetCluster(uint sbid)
{
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
foreach (var (coll, _) in groups)
{
var array = coll.ToBuffer().buffer;
for (var index = 0; index < array.capacity; index++)
{
var conn = array[index];
//Static blocks don't have a cluster ID but the cluster destruction manager should have one
if (conn.machineRigidBodyId == sbid && conn.clusterId != uint.MaxValue)
return new Cluster(conn.clusterId);
}
}
return null;
}
public Block[] GetBodyBlocks(uint sbid)
{
var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
var set = new HashSet<Block>();
foreach (var (coll, _) in groups)
{
var array = coll.ToBuffer().buffer;
for (var index = 0; index < array.capacity; index++)
{
var conn = array[index];
if (conn.machineRigidBodyId == sbid)
set.Add(new Block(conn.ID));
}
}
return set.ToArray();
}
#if DEBUG
public EntitiesDB GetEntitiesDB()
{
return entitiesDB;
}
#endif
}
}