From 1c6d2bda89729e16233ae5f12b60f072de838eda Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Wed, 29 Nov 2023 20:11:41 +0100 Subject: [PATCH] Generalized component access And other refactorings --- TechbloxModdingAPI/Block.cs | 101 ++++++++++-------- TechbloxModdingAPI/Blocks/BlockComplexity.cs | 2 +- .../Blocks/Engines/BlockCloneEngine.cs | 3 - .../Blocks/Engines/BlockEngine.cs | 59 +--------- .../Blocks/Engines/MovementEngine.cs | 68 ------------ .../Blocks/Engines/RotationEngine.cs | 75 ------------- .../Blocks/Engines/ScalingEngine.cs | 2 +- .../Editor}/Engines/PlacementEngine.cs | 17 ++- TechbloxModdingAPI/Common/EcsObjectBase.cs | 38 +++++++ .../Common/EcsObjectBaseEngine.cs | 45 ++++++++ .../Common/Traits/HasPhysics.cs | 20 ++++ TechbloxModdingAPI/TechbloxModdingAPI.csproj | 2 + 12 files changed, 178 insertions(+), 254 deletions(-) delete mode 100644 TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs delete mode 100644 TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs rename TechbloxModdingAPI/{Blocks => Client/Editor}/Engines/PlacementEngine.cs (90%) create mode 100644 TechbloxModdingAPI/Common/Traits/HasPhysics.cs diff --git a/TechbloxModdingAPI/Block.cs b/TechbloxModdingAPI/Block.cs index 7bfb6a9..44eb099 100644 --- a/TechbloxModdingAPI/Block.cs +++ b/TechbloxModdingAPI/Block.cs @@ -16,8 +16,11 @@ using TechbloxModdingAPI.Blocks.Engines; using TechbloxModdingAPI.Client.App; using TechbloxModdingAPI.Common; using TechbloxModdingAPI.Common.Engines; +using TechbloxModdingAPI.Common.Traits; using TechbloxModdingAPI.Tests; using TechbloxModdingAPI.Utility; +using Unity.Transforms; +using UnityEngine; namespace TechbloxModdingAPI { @@ -25,11 +28,9 @@ namespace TechbloxModdingAPI /// A single (perhaps scaled) block. Properties may return default values if the block is removed and then setting them is ignored. /// For specific block type operations, use the specialised block classes in the TechbloxModdingAPI.Blocks namespace. /// - public class Block : EcsObjectBase, IEquatable, IEquatable + public class Block : EcsObjectBase, IHasPhysics, IEquatable, IEquatable { protected static readonly PlacementEngine PlacementEngine = new(); - protected static readonly MovementEngine MovementEngine = new(); - protected static readonly RotationEngine RotationEngine = new(); protected static readonly RemovalEngine RemovalEngine = new(); protected static readonly SignalEngine SignalEngine = new(); protected static readonly BlockEventsEngine BlockEventsEngine = new(); @@ -163,13 +164,21 @@ namespace TechbloxModdingAPI /// public float3 Position { - get => MovementEngine.GetPosition(this); + get => GetComponent().position; set { - MovementEngine.MoveBlock(this, value); + // main (persistent) position + GetComponent().position = value; + // placement grid position + GetComponent().position = value; + // rendered position + GetComponent().position = value; + this.UpdatePhysicsUECSComponent(new Translation { Value = value }); + + GetComponent().areConnectionsAssigned = false; if (blockGroup != null) blockGroup.PosAndRotCalculated = false; - BlockEngine.UpdateDisplayedBlock(Id); + BlockEngine.UpdateDisplayData(Id); } } @@ -178,13 +187,24 @@ namespace TechbloxModdingAPI /// public float3 Rotation { - get => RotationEngine.GetRotation(this); + get => ((Quaternion)GetComponent().rotation).eulerAngles; set { - RotationEngine.RotateBlock(this, value); + // main (persistent) rotation + Quaternion newRotation = GetComponent().rotation; + newRotation.eulerAngles = value; + GetComponent().rotation = newRotation; + // placement grid rotation + GetComponent().rotation = newRotation; + // rendered rotation + GetComponent().rotation = newRotation; + this.UpdatePhysicsUECSComponent(new Rotation { Value = newRotation }); + + // They are assigned during machine processing anyway + GetComponent().areConnectionsAssigned = false; if (blockGroup != null) blockGroup.PosAndRotCalculated = false; - BlockEngine.UpdateDisplayedBlock(Id); + BlockEngine.UpdateDisplayData(Id); } } @@ -194,18 +214,19 @@ namespace TechbloxModdingAPI /// public float3 Scale { - get => BlockEngine.GetBlockInfo(this).scale; + get => GetComponent().scale; set { int uscale = UniformScale; if (value.x < 4e-5) value.x = uscale; if (value.y < 4e-5) value.y = uscale; if (value.z < 4e-5) value.z = uscale; - BlockEngine.GetBlockInfo(this).scale = value; + GetComponent().scale = value; + GetComponent().areConnectionsAssigned = false; //BlockEngine.GetBlockInfo(this).gridScale = value - (int3) value + 1; if (!Exists) return; //UpdateCollision needs the block to exist ScalingEngine.UpdateCollision(Id); - BlockEngine.UpdateDisplayedBlock(Id); + BlockEngine.UpdateDisplayData(Id); } } @@ -215,11 +236,12 @@ namespace TechbloxModdingAPI /// public int UniformScale { - get => BlockEngine.GetBlockInfo(this).scaleFactor; + get => GetComponent().scaleFactor; set { + //It appears that only the non-uniform scale has any visible effect so we'll set that as well if (value < 1) value = 1; - BlockEngine.GetBlockInfo(this).scaleFactor = value; + GetComponent().scaleFactor = value; Scale = new float3(value, value, value); } } @@ -229,12 +251,12 @@ namespace TechbloxModdingAPI */ public bool Flipped { - get => BlockEngine.GetBlockInfo(this).scale.x < 0; + get => GetComponent().scale.x < 0; set { - ref var st = ref BlockEngine.GetBlockInfo(this); + ref var st = ref GetComponent(); st.scale.x = math.abs(st.scale.x) * (value ? -1 : 1); - BlockEngine.UpdatePrefab(this, (byte) Material, value); + BlockEngine.UpdateDisplayedPrefab(this, (byte) Material, value); } } @@ -245,7 +267,7 @@ namespace TechbloxModdingAPI { get { - var opt = BlockEngine.GetBlockInfoOptional(this); + var opt = GetComponentOptional(); return opt ? (BlockIDs) opt.Get().DBID : BlockIDs.Invalid; } } @@ -257,16 +279,17 @@ namespace TechbloxModdingAPI { get { - var opt = BlockEngine.GetBlockInfoOptional(this); + var opt = GetComponentOptional(); return new BlockColor(opt ? opt.Get().indexInPalette : byte.MaxValue); } set { + // TODO: Expose CubeListData in the API if (value.Color == BlockColors.Default) value = new BlockColor(FullGameFields._dataDb.TryGetValue((int) Type, out CubeListData cld) ? cld.DefaultColour : throw new BlockTypeException("Unknown block type! Could not set default color.")); - ref var color = ref BlockEngine.GetBlockInfo(this); + ref var color = ref GetComponent(); color.indexInPalette = value.Index; color.hasNetworkChange = true; color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); //Setting to 255 results in black @@ -279,10 +302,10 @@ namespace TechbloxModdingAPI /// public float4 CustomColor { - get => BlockEngine.GetBlockInfo(this).paletteColour; + get => GetComponent().paletteColour; set { - ref var color = ref BlockEngine.GetBlockInfo(this); + ref var color = ref GetComponent(); color.paletteColour = value; color.hasNetworkChange = true; } @@ -295,7 +318,7 @@ namespace TechbloxModdingAPI { get { - var opt = BlockEngine.GetBlockInfoOptional(this); + var opt = GetComponentOptional(); return opt ? (BlockMaterial) opt.Get().materialId : BlockMaterial.Default; } set @@ -307,11 +330,11 @@ namespace TechbloxModdingAPI : throw new BlockTypeException("Unknown block type! Could not set default material."); if (!FullGameFields._dataDb.ContainsKey(val)) throw new BlockException($"Block material {value} does not exist!"); - ref var comp = ref BlockEngine.GetBlockInfo(this); + ref var comp = ref GetComponent(); if (comp.materialId == val) return; comp.materialId = val; - BlockEngine.UpdatePrefab(this, val, Flipped); //The default causes the screen to go black + BlockEngine.UpdateDisplayedPrefab(this, val, Flipped); //The default causes the screen to go black } } @@ -324,12 +347,12 @@ namespace TechbloxModdingAPI { get { - var opt = BlockEngine.GetBlockInfoOptional(this); + var opt = GetComponentOptional(); return opt ? FullGameFields._managers.blockLabelResourceManager.GetText(opt.Get().instanceID) : null; } set { - var opt = BlockEngine.GetBlockInfoOptional(this); + var opt = GetComponentOptional(); if (opt) FullGameFields._managers.blockLabelResourceManager.SetText(opt.Get().instanceID, value); } } @@ -349,7 +372,7 @@ namespace TechbloxModdingAPI { if (blockGroup != null) return blockGroup; if (!GameClient.IsBuildMode) return null; // Breaks in simulation - var bgec = BlockEngine.GetBlockInfo(this); + var bgec = GetComponent(); return blockGroup = bgec.currentBlockGroup == -1 ? null : GetInstance(new EGID((uint)bgec.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup), @@ -366,7 +389,7 @@ namespace TechbloxModdingAPI blockGroup?.RemoveInternal(this); if (!InitData.Valid) return; - BlockEngine.GetBlockInfo(this).currentBlockGroup = (int?) value?.Id.entityID ?? -1; + GetComponent().currentBlockGroup = (int?) value?.Id.entityID ?? -1; value?.AddInternal(this); blockGroup = value; } @@ -377,8 +400,8 @@ namespace TechbloxModdingAPI /// public bool Static { - get => BlockEngine.GetBlockInfo(this).isStatic; - set => BlockEngine.GetBlockInfo(this).isStatic = value; + get => GetComponent().isStatic; + set => GetComponent().isStatic = value; } /// @@ -386,7 +409,7 @@ namespace TechbloxModdingAPI /// public float Mass { - get => BlockEngine.GetBlockInfo(this).mass; + get => GetComponent().mass; } /// @@ -394,16 +417,10 @@ namespace TechbloxModdingAPI /// public BlockComplexity Complexity { - get => new(BlockEngine.GetBlockInfo(this)); - set => BlockEngine.GetBlockInfo(this) = value; + get => new(GetComponent()); + set => GetComponent() = value; } - /// - /// Whether the block exists. The other properties will return a default value if the block doesn't exist. - /// If the block was just placed, then this will also return false but the properties will work correctly. - /// - public bool Exists => BlockEngine.BlockExists(Id); - /// /// Returns an array of blocks that are connected to this one. Returns an empty array if the block doesn't exist. /// @@ -422,7 +439,7 @@ namespace TechbloxModdingAPI /// The SimBody of the chunk or null if the block doesn't exist or not in simulation mode. public SimBody GetSimBody() { - var st = BlockEngine.GetBlockInfo(this); + var st = GetComponent(); /*return st.machineRigidBodyId != uint.MaxValue ? new SimBody(st.machineRigidBodyId, st.clusterId) - TODO: : null;*/ @@ -487,8 +504,6 @@ namespace TechbloxModdingAPI public static void Init() { EngineManager.AddEngine(PlacementEngine, ApiEngineType.Build); - EngineManager.AddEngine(MovementEngine, ApiEngineType.Build); - EngineManager.AddEngine(RotationEngine, ApiEngineType.Build); EngineManager.AddEngine(RemovalEngine, ApiEngineType.Build); EngineManager.AddEngine(BlockEngine, ApiEngineType.Build, ApiEngineType.PlayServer, ApiEngineType.PlayClient); EngineManager.AddEngine(BlockEventsEngine, ApiEngineType.Build); diff --git a/TechbloxModdingAPI/Blocks/BlockComplexity.cs b/TechbloxModdingAPI/Blocks/BlockComplexity.cs index 9f32866..238bd42 100644 --- a/TechbloxModdingAPI/Blocks/BlockComplexity.cs +++ b/TechbloxModdingAPI/Blocks/BlockComplexity.cs @@ -2,7 +2,7 @@ using RobocraftX.Blocks; namespace TechbloxModdingAPI.Blocks { - public record BlockComplexity(int Cpu, int Power) + public readonly record struct BlockComplexity(int Cpu, int Power) { public BlockComplexity(BlockComplexityComponent component) : this(component.cpu, component.power) { diff --git a/TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs b/TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs index 86ccc96..157be7a 100644 --- a/TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/BlockCloneEngine.cs @@ -97,8 +97,5 @@ namespace TechbloxModdingAPI.Blocks.Engines }; } } - - public string Name { get; } = "TechbloxModdingAPIBlockCloneGameEngine"; - public bool isRemovable { get; } = false; } } \ No newline at end of file diff --git a/TechbloxModdingAPI/Blocks/Engines/BlockEngine.cs b/TechbloxModdingAPI/Blocks/Engines/BlockEngine.cs index c784fc2..9a47ced 100644 --- a/TechbloxModdingAPI/Blocks/Engines/BlockEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/BlockEngine.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; - using Gamecraft.ColourPalette; using Gamecraft.Wires; using RobocraftX.Blocks; @@ -14,13 +12,9 @@ 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 TechbloxModdingAPI.Common; using TechbloxModdingAPI.Common.Engines; using Unity.Mathematics; -using TechbloxModdingAPI.Utility; using TechbloxModdingAPI.Utility.ECS; using PrefabsID = RobocraftX.Common.PrefabsID; @@ -74,50 +68,7 @@ namespace TechbloxModdingAPI.Blocks.Engines : entitiesDB.QueryEntity(index, ColourPaletteExclusiveGroups.COLOUR_PALETTE_GROUP).Colour; - public OptionalRef GetBlockInfoOptional(Block block) where T : unmanaged, IEntityComponent - { - return entitiesDB.QueryEntityOptional(block); - } - - public ref T GetBlockInfo(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(block); - } - - internal ref T GetBlockInfo(EcsObjectBase obj) where T : unmanaged, IEntityComponent - { - return ref entitiesDB.QueryEntityOrDefault(obj); - } - - public ref T GetBlockInfoViewComponent(Block block) where T : struct, IEntityViewComponent - { - return ref entitiesDB.QueryEntityOrDefault(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) + public void UpdateDisplayData(EGID id) { if (!BlockExists(id)) return; var pos = entitiesDB.QueryEntity(id); @@ -129,7 +80,7 @@ namespace TechbloxModdingAPI.Blocks.Engines entitiesDB.PublishEntityChangeDelayed(id); // Signal a prefab change so it updates the render buffers } - internal void UpdatePrefab(Block block, byte material, bool flipped) + internal void UpdateDisplayedPrefab(Block block, byte material, bool flipped) { var prefabAssetIDOpt = entitiesDB.QueryEntityOptional(block); uint prefabAssetID = prefabAssetIDOpt @@ -150,12 +101,12 @@ namespace TechbloxModdingAPI.Blocks.Engines entitiesDB.PublishEntityChangeDelayed(block.Id); entitiesDB.PublishEntityChangeDelayed(block.Id); - ref BuildingActionComponent local = + /*ref BuildingActionComponent local = ref entitiesDB.QueryEntity(BuildingDroneUtility .GetLocalBuildingDrone(entitiesDB).ToEGID(entitiesDB)); local.buildAction = BuildAction.ChangeMaterial; - local.targetPosition = block.Position; - this.entitiesDB.PublishEntityChangeDelayed(local.ID); + local.targetPosition = block.Position; - TODO: This probably only plays the audio + this.entitiesDB.PublishEntityChangeDelayed(local.ID);*/ } //Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData } diff --git a/TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs b/TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs deleted file mode 100644 index 24bcd7d..0000000 --- a/TechbloxModdingAPI/Blocks/Engines/MovementEngine.cs +++ /dev/null @@ -1,68 +0,0 @@ -using RobocraftX.Common; -using RobocraftX.DOTS; -using Svelto.ECS; -using Svelto.ECS.EntityStructs; -using TechbloxModdingAPI.Common.Engines; -using Unity.Mathematics; -using Unity.Transforms; -using TechbloxModdingAPI.Utility; -using TechbloxModdingAPI.Utility.ECS; - -namespace TechbloxModdingAPI.Blocks.Engines -{ - /// - /// Engine which executes block movement actions - /// - public class MovementEngine : IApiEngine - { - public string Name { get; } = "TechbloxModdingAPIMovementGameEngine"; - - public EntitiesDB entitiesDB { set; private get; } - - public bool isRemovable => false; - - public bool IsInGame = false; - - public void Dispose() - { - IsInGame = false; - } - - public void Ready() - { - IsInGame = true; - } - - // implementations for Movement static class - - internal float3 MoveBlock(Block block, float3 vector) - { - ref PositionEntityStruct posStruct = ref this.entitiesDB.QueryEntityOrDefault(block); - ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault(block); - ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault(block); - var phyStruct = this.entitiesDB.QueryEntityOptional(block); - // main (persistent) position - posStruct.position = vector; - // placement grid position - gridStruct.position = vector; - // rendered position - transStruct.position = vector; - // collision position - if (phyStruct) - { //It exists - FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.Get().dotsEntity, new Translation - { - Value = posStruct.position - }); - } - - entitiesDB.QueryEntityOrDefault(block).areConnectionsAssigned = false; - return posStruct.position; - } - - internal float3 GetPosition(Block block) - { - return entitiesDB.QueryEntityOrDefault(block).position; - } - } -} diff --git a/TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs b/TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs deleted file mode 100644 index 8fae547..0000000 --- a/TechbloxModdingAPI/Blocks/Engines/RotationEngine.cs +++ /dev/null @@ -1,75 +0,0 @@ -using RobocraftX.Common; -using RobocraftX.DOTS; -using Svelto.ECS; -using Svelto.ECS.EntityStructs; -using TechbloxModdingAPI.Common.Engines; -using Unity.Mathematics; -using UnityEngine; -using TechbloxModdingAPI.Utility; -using TechbloxModdingAPI.Utility.ECS; - -namespace TechbloxModdingAPI.Blocks.Engines -{ - /// - /// Engine which executes block movement actions - /// - public class RotationEngine : IApiEngine - { - public string Name { get; } = "TechbloxModdingAPIRotationGameEngine"; - - public EntitiesDB entitiesDB { set; private get; } - - public bool isRemovable => false; - - public bool IsInGame = false; - - public void Dispose() - { - IsInGame = false; - } - - public void Ready() - { - IsInGame = true; - } - - // implementations for Rotation static class - - internal float3 RotateBlock(Block block, Vector3 vector) - { - ref RotationEntityStruct rotStruct = ref this.entitiesDB.QueryEntityOrDefault(block); - ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault(block); - ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault(block); - var phyStruct = this.entitiesDB.QueryEntityOptional(block); - // main (persistent) rotation - Quaternion newRotation = rotStruct.rotation; - newRotation.eulerAngles = vector; - rotStruct.rotation = newRotation; - // placement grid rotation - gridStruct.rotation = newRotation; - // rendered rotation - transStruct.rotation = newRotation; - // collision rotation - if (phyStruct) - { //It exists - FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.Get().dotsEntity, - new Unity.Transforms.Rotation - { - Value = rotStruct.rotation - }); - } - - // TODO: Connections probably need to be assigned (maybe) - // They are assigned during machine processing anyway - entitiesDB.QueryEntityOrDefault(block).areConnectionsAssigned = false; - return ((Quaternion)rotStruct.rotation).eulerAngles; - - } - - internal float3 GetRotation(Block block) - { - ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntityOrDefault(block); - return ((Quaternion) rotStruct.rotation).eulerAngles; - } - } -} diff --git a/TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs b/TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs index 41a96a6..dfab4e2 100644 --- a/TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs +++ b/TechbloxModdingAPI/Blocks/Engines/ScalingEngine.cs @@ -29,7 +29,7 @@ namespace TechbloxModdingAPI.Blocks.Engines private EntityManager _entityManager; //Unity entity manager public void UpdateCollision(EGID egid) - { + { // TODO: Move to BlockEngine/IHasPhysics if (_entityManager == default) _entityManager = FullGameFields._physicsWorld.EntityManager; //Assuming the block exists diff --git a/TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs b/TechbloxModdingAPI/Client/Editor/Engines/PlacementEngine.cs similarity index 90% rename from TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs rename to TechbloxModdingAPI/Client/Editor/Engines/PlacementEngine.cs index b340b63..4f43cda 100644 --- a/TechbloxModdingAPI/Blocks/Engines/PlacementEngine.cs +++ b/TechbloxModdingAPI/Client/Editor/Engines/PlacementEngine.cs @@ -41,7 +41,7 @@ namespace TechbloxModdingAPI.Blocks.Engines private static IEntityFactory _entityFactory; public EntityInitializer PlaceBlock(BlockIDs block, float3 position, Player player, bool autoWire) - { //It appears that only the non-uniform scale has any visible effect, but if that's not given here it will be set to the uniform one + { return BuildBlock((ushort) block, position, autoWire, (player ?? Player.LocalPlayer).Id); } @@ -52,15 +52,19 @@ namespace TechbloxModdingAPI.Blocks.Engines if(!FullGameFields._dataDb.ContainsKey(block)) throw new BlockException("Block with ID " + block + " not found!"); //RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine - DBEntityStruct dbEntity = new DBEntityStruct {DBID = block}; - EntityInitializer structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.blockIDGeneratorClient.Next(), block); //The ghost block index is only used for triggers + var structInitializer = _blockEntityFactory.Build(CommonExclusiveGroups.blockIDGeneratorClient.Next(), block); //The ghost block index is only used for triggers + + // Use the default steel material for the block until it's changed and set up the graphics for it uint prefabAssetID = structInitializer.Has() ? structInitializer.Get().prefabAssetID : throw new BlockException("Prefab asset ID not found!"); //Set by the game uint prefabId = PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, (byte) BlockMaterial.SteelBodywork, 1, false); structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId)); - structInitializer.Init(dbEntity); + structInitializer.Get().materialId = (byte) BlockMaterial.SteelBodywork; + + // The DBID is the block's type (cube, servo, seat etc.) + structInitializer.Init(new DBEntityStruct {DBID = block}); structInitializer.Init(new PositionEntityStruct {position = position}); structInitializer.Init(new RotationEntityStruct {rotation = quaternion.identity}); structInitializer.Init(new ScalingEntityStruct {scale = new float3(1, 1, 1)}); @@ -70,7 +74,6 @@ namespace TechbloxModdingAPI.Blocks.Engines rotation = quaternion.identity }); structInitializer.Init(new UniformBlockScaleEntityStruct {scaleFactor = 1}); - structInitializer.Get().materialId = (byte) BlockMaterial.SteelBodywork; var bssesopt = entitiesDB.QueryEntityOptional(new EGID(playerId, BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup)); if (!bssesopt) @@ -107,10 +110,6 @@ namespace TechbloxModdingAPI.Blocks.Engines return structInitializer; } - public string Name => "TechbloxModdingAPIPlacementGameEngine"; - - public bool isRemovable => false; - [HarmonyPatch] class FactoryObtainerPatch { diff --git a/TechbloxModdingAPI/Common/EcsObjectBase.cs b/TechbloxModdingAPI/Common/EcsObjectBase.cs index 1ee545c..01d6c10 100644 --- a/TechbloxModdingAPI/Common/EcsObjectBase.cs +++ b/TechbloxModdingAPI/Common/EcsObjectBase.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using Svelto.DataStructures; using Svelto.ECS; +using Svelto.ECS.Hybrid; using Svelto.ECS.Internal; using TechbloxModdingAPI.Common.Engines; using TechbloxModdingAPI.Common.Utils; @@ -17,6 +18,11 @@ public abstract class EcsObjectBase /// May be an invalid reference, in that case operations do not have any effect. /// public EntityReference Reference { get; } + + /// + /// Whether the entity reference is still valid. Returns false if this object no longer exists. + /// + public bool Exists => Id != default; // TODO: Might need extra code to support IDs during init private static readonly Dictionary> _instances = new(); private static readonly EcsObjectBaseEngine _engine = new(); @@ -57,6 +63,38 @@ public abstract class EcsObjectBase dict.Add(reference, this); Reference = reference; } + + + + protected internal OptionalRef GetComponentOptional() where T : unmanaged, IEntityComponent + { + return _engine.GetComponentOptional(this); + } + + protected internal ref T GetComponent() where T : unmanaged, IEntityComponent + { + return ref _engine.GetComponent(this); + } + + protected internal ref T GetViewComponent() where T : struct, IEntityViewComponent + { + return ref _engine.GetViewComponent(this); + } + + protected internal object GetComponent(Type type, string name) + { + return _engine.GetComponent(this, type, name); + } + + protected internal void SetComponent(Type type, string name, object value) + { + _engine.SetComponent(this, type, name, value); + } + + protected bool RemoveEntity() + { + // TODO: _entityFunctions.Remove...() + } #region ECS initializer stuff diff --git a/TechbloxModdingAPI/Common/EcsObjectBaseEngine.cs b/TechbloxModdingAPI/Common/EcsObjectBaseEngine.cs index 9e8667b..34a23e9 100644 --- a/TechbloxModdingAPI/Common/EcsObjectBaseEngine.cs +++ b/TechbloxModdingAPI/Common/EcsObjectBaseEngine.cs @@ -1,5 +1,11 @@ +using System; +using HarmonyLib; using Svelto.ECS; +using Svelto.ECS.Hybrid; +using TechbloxModdingAPI.Blocks.Engines; using TechbloxModdingAPI.Common.Engines; +using TechbloxModdingAPI.Utility; +using TechbloxModdingAPI.Utility.ECS; namespace TechbloxModdingAPI.Common; @@ -10,6 +16,7 @@ public class EcsObjectBaseEngine : IApiEngine } public EntitiesDB entitiesDB { get; set; } + public void Dispose() { } @@ -23,4 +30,42 @@ public class EcsObjectBaseEngine : IApiEngine { return entitiesDB is not null && reference.ToEGID(entitiesDB, out var egid) ? egid : default; } + + public OptionalRef GetComponentOptional(EcsObjectBase obj) where T : unmanaged, IEntityComponent + { + return entitiesDB.QueryEntityOptional(obj); + } + + public ref T GetComponent(EcsObjectBase obj) where T : unmanaged, IEntityComponent + { +#if DEBUG + if (entitiesDB.Exists(obj.Id) && obj.InitData.Valid) + throw new ArgumentException("The block exists but the init data has not been removed!"); +#endif + return ref entitiesDB.QueryEntityOrDefault(obj); + } + + public ref T GetViewComponent(EcsObjectBase obj) where T : struct, IEntityViewComponent + { + return ref entitiesDB.QueryEntityOrDefault(obj); + } + + public object GetComponent(EcsObjectBase obj, 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, obj, null }); + var str = AccessTools.Property(opt.GetType(), "Value").GetValue(opt); + return AccessTools.Field(str.GetType(), name).GetValue(str); + } + + public void SetComponent(EcsObjectBase obj, Type type, string name, object value) + { + var opt = AccessTools.Method(typeof(BlockEngine), "GetBlockInfoOptional", generics: new[] { type }) + .Invoke(this, new object[] { obj }); + var prop = AccessTools.Property(opt.GetType(), "Value"); + var str = prop.GetValue(opt); + AccessTools.Field(str.GetType(), name).SetValue(str, value); + prop.SetValue(opt, str); + } } \ No newline at end of file diff --git a/TechbloxModdingAPI/Common/Traits/HasPhysics.cs b/TechbloxModdingAPI/Common/Traits/HasPhysics.cs new file mode 100644 index 0000000..560d984 --- /dev/null +++ b/TechbloxModdingAPI/Common/Traits/HasPhysics.cs @@ -0,0 +1,20 @@ +using RobocraftX.DOTS; +using TechbloxModdingAPI.Utility; +using Unity.Entities; +using Unity.Transforms; + +namespace TechbloxModdingAPI.Common.Traits; + +public interface IHasPhysics +{ +} + +public static class HasPhysicsExtensions +{ + internal static void UpdatePhysicsUECSComponent(this O obj, T componentData) where O : EcsObjectBase, IHasPhysics where T : struct, IComponentData + { + var phyStruct = obj.GetComponentOptional(); + if (phyStruct) //It exists + FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.Get().dotsEntity, componentData); + } +} \ No newline at end of file diff --git a/TechbloxModdingAPI/TechbloxModdingAPI.csproj b/TechbloxModdingAPI/TechbloxModdingAPI.csproj index 5f6e410..a8f09f3 100644 --- a/TechbloxModdingAPI/TechbloxModdingAPI.csproj +++ b/TechbloxModdingAPI/TechbloxModdingAPI.csproj @@ -11,6 +11,8 @@ en-CA true latest + Debug;Release;Test + AnyCPU