|
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using HarmonyLib;
-
- using Gamecraft.ColourPalette;
- using Gamecraft.Wires;
- using RobocraftX.Blocks;
- using RobocraftX.Common;
- using RobocraftX.Physics;
- using RobocraftX.Rendering;
- using RobocraftX.Rendering.GPUI;
- using Svelto.DataStructures;
- using Svelto.ECS;
- using Svelto.ECS.EntityStructs;
- using Svelto.ECS.Experimental;
- using Svelto.ECS.Hybrid;
- using Techblox.BuildingDrone;
- using Techblox.ObjectIDBlockServer;
- using Unity.Mathematics;
-
- using TechbloxModdingAPI.Engines;
- using TechbloxModdingAPI.Utility;
-
- namespace TechbloxModdingAPI.Blocks.Engines
- {
- /// <summary>
- /// Engine for executing general block actions
- /// </summary>
- public partial class BlockEngine : IApiEngine
- {
- public string Name { get; } = "TechbloxModdingAPIBlockGameEngine";
-
- 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 Array.Empty<Block>();
- Stack<EGID> cubeStack = new Stack<EGID>();
- FasterList<EGID> cubes = new FasterList<EGID>(10);
- var coll = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
- foreach (var ((ecoll, count), _) in coll)
- {
- for(int i = 0; i < count; i++)
- {
- ecoll[i].isProcessed = false;
- }
- }
-
- //TODO: GetConnectedCubesUtility
- ConnectedCubesUtility.TreeTraversal.GetConnectedCubes(entitiesDB, blockID, cubeStack, cubes,
- (in GridConnectionsEntityStruct _) => false);
-
- var ret = new Block[cubes.count];
- for (int i = 0; i < cubes.count; i++)
- ret[i] = Block.New(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 OptionalRef<T> GetBlockInfoOptional<T>(Block block) where T : unmanaged, IEntityComponent
- {
- return entitiesDB.QueryEntityOptional<T>(block);
- }
-
- public ref T GetBlockInfo<T>(Block block) where T : unmanaged, IEntityComponent
- {
- #if DEBUG
- if (!typeof(BlockTagEntityStruct).IsAssignableFrom(typeof(T)) && block.Exists && block.InitData.Valid)
- throw new ArgumentException("The block exists but the init data has not been removed!");
- #endif
- return ref entitiesDB.QueryEntityOrDefault<T>(block);
- }
-
- internal ref T GetBlockInfo<T>(EcsObjectBase obj) where T : unmanaged, IEntityComponent
- {
- return ref entitiesDB.QueryEntityOrDefault<T>(obj);
- }
-
- public ref T GetBlockInfoViewComponent<T>(Block block) where T : struct, IEntityViewComponent
- {
- return ref entitiesDB.QueryEntityOrDefault<T>(block);
- }
-
- internal object GetBlockInfo(Block block, Type type, string name)
- {
- var opt = AccessTools.Method(typeof(NativeApiExtensions), "QueryEntityOptional",
- new[] { typeof(EntitiesDB), typeof(EcsObjectBase), typeof(ExclusiveGroupStruct) }, new[] { type })
- .Invoke(null, new object[] { entitiesDB, block, null });
- var str = AccessTools.Property(opt.GetType(), "Value").GetValue(opt);
- return AccessTools.Field(str.GetType(), name).GetValue(str);
- }
-
- internal void SetBlockInfo(Block block, Type type, string name, object value)
- {
- var opt = AccessTools.Method(typeof(BlockEngine), "GetBlockInfoOptional", generics: new[] { type })
- .Invoke(this, new object[] { block });
- var prop = AccessTools.Property(opt.GetType(), "Value");
- var str = prop.GetValue(opt);
- AccessTools.Field(str.GetType(), name).SetValue(str, value);
- prop.SetValue(opt, str);
- }
-
- 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);
- var skew = entitiesDB.QueryEntity<SkewComponent>(id);
- entitiesDB.QueryEntity<RenderingDataStruct>(id).matrix =
- math.mul(float4x4.TRS(pos.position, rot.rotation, scale.scale), skew.skewMatrix);
- entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(id); // Signal a prefab change so it updates the render buffers
- }
-
- internal void UpdatePrefab(Block block, byte material, bool flipped)
- {
- var prefabAssetIDOpt = entitiesDB.QueryEntityOptional<PrefabAssetIDComponent>(block);
- uint prefabAssetID = prefabAssetIDOpt
- ? prefabAssetIDOpt.Get().prefabAssetID
- : uint.MaxValue;
- if (prefabAssetID == uint.MaxValue)
- {
- if (entitiesDB.QueryEntityOptional<BlockTagEntityStruct>(block)) //The block exists
- throw new BlockException("Prefab asset ID not found for block " + block); //Set by the game
- return;
- }
-
- uint prefabId =
- PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, material, 1, flipped);
- entitiesDB.QueryEntityOrDefault<GFXPrefabEntityStructGPUI>(block).prefabID = prefabId;
- if (block.Exists)
- {
- entitiesDB.PublishEntityChangeDelayed<CubeMaterialStruct>(block.Id);
- entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(block.Id);
-
- ref BuildingActionComponent local =
- ref entitiesDB.QueryEntity<BuildingActionComponent>(BuildingDroneUtility
- .GetLocalBuildingDrone(entitiesDB).ToEGID(entitiesDB));
- local.buildAction = BuildAction.ChangeMaterial;
- local.targetPosition = block.Position;
- this.entitiesDB.PublishEntityChangeDelayed<BuildingActionComponent>(local.ID);
- }
- //Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData
- }
-
- public void UpdateBlockColor(EGID id)
- {
- entitiesDB.PublishEntityChange<ColourParameterEntityStruct>(id);
- }
-
- public bool BlockExists(EGID blockID)
- {
- return entitiesDB.Exists<BlockTagEntityStruct>(blockID);
- }
-
- public SimBody[] GetSimBodiesFromID(byte id)
- {
- var ret = new FasterList<SimBody>(4);
- var (oids, tags, count) = entitiesDB.QueryEntities<ObjectIdEntityStruct, BlockTagEntityStruct>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP);
- EGIDMapper<GridConnectionsEntityStruct>? connections = null;
- for (int i = 0; i < count; i++)
- {
- if (oids[i].objectId != id) continue;
- var tag = tags[i];
- if (!connections.HasValue) //Would need reflection to get the group from the build group otherwise
- connections = entitiesDB.QueryMappedEntities<GridConnectionsEntityStruct>(tag.ID.groupID);
- var rid = connections.Value.Entity(tag.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 SimBody[] GetConnectedSimBodies(uint id)
- {
- var (joints, count) = entitiesDB.QueryEntities<JointEntityStruct>(MachineSimulationGroups.JOINTS_GROUP);
- var list = new FasterList<SimBody>(4);
- for (int i = 0; i < count; i++)
- {
- ref var joint = ref joints[i];
- if (joint.isBroken) 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, count), _) in groups)
- {
- for (var index = 0; index < count; index++)
- {
- var conn = coll[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<BlockTagEntityStruct>();
- foreach (ExclusiveGroupStruct group in groups)
- {
- if (entitiesDB.Exists<BlockTagEntityStruct>(id, group))
- return new EGID(id, group);
- }
-
- return null;
- }
-
- public Cluster GetCluster(uint sbid)
- {
- var groups = entitiesDB.QueryEntities<GridConnectionsEntityStruct>();
- foreach (var ((coll, count), _) in groups)
- {
- for (var index = 0; index < count; index++)
- {
- var conn = coll[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.FindGroups<GridConnectionsEntityStruct>();
- groups = new QueryGroups(groups).Except(CommonExclusiveGroups.DISABLED_JOINTS_IN_SIM_GROUP).Evaluate().result;
- var set = new HashSet<Block>();
- foreach (var ((coll, tags, count), _) in entitiesDB.QueryEntities<GridConnectionsEntityStruct, BlockTagEntityStruct>(groups))
- {
- for (var index = 0; index < count; index++)
- {
- var conn = coll[index];
- if (conn.machineRigidBodyId == sbid)
- set.Add(Block.New(tags[index].ID));
- }
- }
-
- return set.ToArray();
- }
-
- public ObjectID[] GetObjectIDsFromID(byte id)
- {
- if (!entitiesDB.HasAny<ObjectIDTweakableComponent>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP))
- return Array.Empty<ObjectID>();
-
- var ret = new FasterList<ObjectID>(4);
- var (oids, tags, count) = entitiesDB.QueryEntities<ObjectIDTweakableComponent, BlockTagEntityStruct>(ObjectIDBlockExclusiveGroups.OBJECT_ID_BLOCK_GROUP);
- for (var index = 0; index < count; index++)
- {
- if (oids[index].objectIDToTrigger == id)
- ret.Add(new ObjectID(tags[index].ID));
- }
-
- return ret.ToArray();
- }
- }
- }
|