using System; using System.Collections.Generic; using System.Linq; using Gamecraft.Wires; using RobocraftX.Blocks; using RobocraftX.Common; using RobocraftX.GUI.Hotbar.Colours; using RobocraftX.Physics; using RobocraftX.Scene.Simulation; using Svelto.DataStructures; using Svelto.ECS; using Svelto.ECS.Hybrid; using GamecraftModdingAPI.Engines; using Unity.Mathematics; namespace GamecraftModdingAPI.Blocks { /// /// Engine for executing general block actions /// 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 cubeStack = new Stack(); FasterList cubes = new FasterList(10); var coll = entitiesDB.QueryEntities(); foreach (var (ecoll, _) in coll) foreach (ref var conn in ecoll) 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(index, CommonExclusiveGroups.COLOUR_PALETTE_GROUP).Colour; public ref T GetBlockInfo(EGID blockID) where T : unmanaged, IEntityComponent { if (entitiesDB.Exists(blockID)) return ref entitiesDB.QueryEntity(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(EGID blockID) where T : struct, INeedEGID, IEntityComponent { if (entitiesDB.Exists(blockID)) { // TODO: optimize by using EntitiesDB internal calls instead of iterating over everything EntityCollection entities = entitiesDB.QueryEntities(blockID.groupID); for (int i = 0; i < entities.count; i++) { if (entities[i].ID == blockID) { return ref entities[i]; } } } T[] structHolder = new T[1]; //Create something that can be referenced return ref structHolder[0]; //Gets a default value automatically } public U GetBlockInfo(Block block, Func getter, U def = default) where T : unmanaged, IEntityComponent { if (entitiesDB.Exists(block.Id)) return getter(entitiesDB.QueryEntity(block.Id)); return GetBlockInitInfo(block, getter, def); } public U GetBlockInfoViewStruct(Block block, Func getter, U def = default) where T : struct, IEntityViewComponent { if (entitiesDB.Exists(block.Id)) return getter(entitiesDB.QueryEntity(block.Id)); return GetBlockInitInfo(block, getter, def); } private U GetBlockInitInfo(Block block, Func 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()) return getter(initializer.Get()); return def; } public delegate void Setter(ref T component, U value) where T : struct, IEntityComponent; public void SetBlockInfoViewStruct(Block block, Setter setter, U value) where T : struct, IEntityViewComponent { if (entitiesDB.Exists(block.Id)) setter(ref entitiesDB.QueryEntity(block.Id), value); else SetBlockInitInfo(block, setter, value); } public void SetBlockInfo(Block block, Setter setter, U value) where T : unmanaged, IEntityComponent { if (entitiesDB.Exists(block.Id)) setter(ref entitiesDB.QueryEntity(block.Id), value); else SetBlockInitInfo(block, setter, value); } private void SetBlockInitInfo(Block block, Setter 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() ? initializer.Get() : default; ref T structRef = ref component; setter(ref structRef, value); initializer.Init(structRef); } } public bool BlockExists(EGID blockID) { return entitiesDB.Exists(blockID); } public bool GetBlockInfoExists(Block block) where T : struct, IEntityComponent { if (entitiesDB.Exists(block.Id)) return true; if (block.InitData.Group == null) return false; var init = new EntityComponentInitializer(block.Id, block.InitData.Group); return init.Has(); } public SimBody[] GetSimBodiesFromID(byte id) { var ret = new FasterList(4); if (!entitiesDB.HasAny(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) return new SimBody[0]; var oids = entitiesDB.QueryEntities(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); var connections = entitiesDB.QueryMappedEntities(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); foreach (ref ObjectIdEntityStruct oid in oids) { 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(4); if (!entitiesDB.HasAny(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) return new ObjectIdentifier[0]; var oids = entitiesDB.QueryEntities(CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP); foreach (ref ObjectIdEntityStruct oid in oids) 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(MachineSimulationGroups.JOINTS_GROUP); var list = new FasterList(4); foreach (var joint in joints) { 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(); var bodies = new HashSet(); foreach (var (coll, _) in groups) { foreach (var conn in coll) { if (conn.clusterId == cid) bodies.Add(conn.machineRigidBodyId); } } return bodies.Select(id => new SimBody(id)).ToArray(); } public EGID? FindBlockEGID(uint id) { var groups = entitiesDB.FindGroups(); foreach (ExclusiveGroupStruct group in groups) { if (entitiesDB.Exists(id, group)) return new EGID(id, group); } return null; } public Cluster GetCluster(uint sbid) { var groups = entitiesDB.QueryEntities(); foreach (var (coll, _) in groups) { foreach (var conn in coll) { if (conn.machineRigidBodyId == sbid) return new Cluster(conn.clusterId); } } return null; } #if DEBUG public EntitiesDB GetEntitiesDB() { return entitiesDB; } #endif } }