Generalized component access

And other refactorings
This commit is contained in:
Norbi Peti 2023-11-29 20:11:41 +01:00
parent bf08b61788
commit 1c6d2bda89
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
12 changed files with 178 additions and 254 deletions

View file

@ -16,8 +16,11 @@ using TechbloxModdingAPI.Blocks.Engines;
using TechbloxModdingAPI.Client.App; using TechbloxModdingAPI.Client.App;
using TechbloxModdingAPI.Common; using TechbloxModdingAPI.Common;
using TechbloxModdingAPI.Common.Engines; using TechbloxModdingAPI.Common.Engines;
using TechbloxModdingAPI.Common.Traits;
using TechbloxModdingAPI.Tests; using TechbloxModdingAPI.Tests;
using TechbloxModdingAPI.Utility; using TechbloxModdingAPI.Utility;
using Unity.Transforms;
using UnityEngine;
namespace TechbloxModdingAPI 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. /// 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. /// For specific block type operations, use the specialised block classes in the TechbloxModdingAPI.Blocks namespace.
/// </summary> /// </summary>
public class Block : EcsObjectBase, IEquatable<Block>, IEquatable<EGID> public class Block : EcsObjectBase, IHasPhysics, IEquatable<Block>, IEquatable<EGID>
{ {
protected static readonly PlacementEngine PlacementEngine = new(); 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 RemovalEngine RemovalEngine = new();
protected static readonly SignalEngine SignalEngine = new(); protected static readonly SignalEngine SignalEngine = new();
protected static readonly BlockEventsEngine BlockEventsEngine = new(); protected static readonly BlockEventsEngine BlockEventsEngine = new();
@ -163,13 +164,21 @@ namespace TechbloxModdingAPI
/// </summary> /// </summary>
public float3 Position public float3 Position
{ {
get => MovementEngine.GetPosition(this); get => GetComponent<PositionEntityStruct>().position;
set set
{ {
MovementEngine.MoveBlock(this, value); // main (persistent) position
GetComponent<PositionEntityStruct>().position = value;
// placement grid position
GetComponent<GridRotationStruct>().position = value;
// rendered position
GetComponent<LocalTransformEntityStruct>().position = value;
this.UpdatePhysicsUECSComponent(new Translation { Value = value });
GetComponent<GridConnectionsEntityStruct>().areConnectionsAssigned = false;
if (blockGroup != null) if (blockGroup != null)
blockGroup.PosAndRotCalculated = false; blockGroup.PosAndRotCalculated = false;
BlockEngine.UpdateDisplayedBlock(Id); BlockEngine.UpdateDisplayData(Id);
} }
} }
@ -178,13 +187,24 @@ namespace TechbloxModdingAPI
/// </summary> /// </summary>
public float3 Rotation public float3 Rotation
{ {
get => RotationEngine.GetRotation(this); get => ((Quaternion)GetComponent<RotationEntityStruct>().rotation).eulerAngles;
set set
{ {
RotationEngine.RotateBlock(this, value); // main (persistent) rotation
Quaternion newRotation = GetComponent<RotationEntityStruct>().rotation;
newRotation.eulerAngles = value;
GetComponent<RotationEntityStruct>().rotation = newRotation;
// placement grid rotation
GetComponent<GridRotationStruct>().rotation = newRotation;
// rendered rotation
GetComponent<LocalTransformEntityStruct>().rotation = newRotation;
this.UpdatePhysicsUECSComponent(new Rotation { Value = newRotation });
// They are assigned during machine processing anyway
GetComponent<GridConnectionsEntityStruct>().areConnectionsAssigned = false;
if (blockGroup != null) if (blockGroup != null)
blockGroup.PosAndRotCalculated = false; blockGroup.PosAndRotCalculated = false;
BlockEngine.UpdateDisplayedBlock(Id); BlockEngine.UpdateDisplayData(Id);
} }
} }
@ -194,18 +214,19 @@ namespace TechbloxModdingAPI
/// </summary> /// </summary>
public float3 Scale public float3 Scale
{ {
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale; get => GetComponent<ScalingEntityStruct>().scale;
set set
{ {
int uscale = UniformScale; int uscale = UniformScale;
if (value.x < 4e-5) value.x = uscale; if (value.x < 4e-5) value.x = uscale;
if (value.y < 4e-5) value.y = uscale; if (value.y < 4e-5) value.y = uscale;
if (value.z < 4e-5) value.z = uscale; if (value.z < 4e-5) value.z = uscale;
BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale = value; GetComponent<ScalingEntityStruct>().scale = value;
GetComponent<GridConnectionsEntityStruct>().areConnectionsAssigned = false;
//BlockEngine.GetBlockInfo<GridScaleStruct>(this).gridScale = value - (int3) value + 1; //BlockEngine.GetBlockInfo<GridScaleStruct>(this).gridScale = value - (int3) value + 1;
if (!Exists) return; //UpdateCollision needs the block to exist if (!Exists) return; //UpdateCollision needs the block to exist
ScalingEngine.UpdateCollision(Id); ScalingEngine.UpdateCollision(Id);
BlockEngine.UpdateDisplayedBlock(Id); BlockEngine.UpdateDisplayData(Id);
} }
} }
@ -215,11 +236,12 @@ namespace TechbloxModdingAPI
/// </summary> /// </summary>
public int UniformScale public int UniformScale
{ {
get => BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(this).scaleFactor; get => GetComponent<UniformBlockScaleEntityStruct>().scaleFactor;
set 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; if (value < 1) value = 1;
BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(this).scaleFactor = value; GetComponent<UniformBlockScaleEntityStruct>().scaleFactor = value;
Scale = new float3(value, value, value); Scale = new float3(value, value, value);
} }
} }
@ -229,12 +251,12 @@ namespace TechbloxModdingAPI
*/ */
public bool Flipped public bool Flipped
{ {
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale.x < 0; get => GetComponent<ScalingEntityStruct>().scale.x < 0;
set set
{ {
ref var st = ref BlockEngine.GetBlockInfo<ScalingEntityStruct>(this); ref var st = ref GetComponent<ScalingEntityStruct>();
st.scale.x = math.abs(st.scale.x) * (value ? -1 : 1); 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 get
{ {
var opt = BlockEngine.GetBlockInfoOptional<DBEntityStruct>(this); var opt = GetComponentOptional<DBEntityStruct>();
return opt ? (BlockIDs) opt.Get().DBID : BlockIDs.Invalid; return opt ? (BlockIDs) opt.Get().DBID : BlockIDs.Invalid;
} }
} }
@ -257,16 +279,17 @@ namespace TechbloxModdingAPI
{ {
get get
{ {
var opt = BlockEngine.GetBlockInfoOptional<ColourParameterEntityStruct>(this); var opt = GetComponentOptional<ColourParameterEntityStruct>();
return new BlockColor(opt ? opt.Get().indexInPalette : byte.MaxValue); return new BlockColor(opt ? opt.Get().indexInPalette : byte.MaxValue);
} }
set set
{ {
// TODO: Expose CubeListData in the API
if (value.Color == BlockColors.Default) if (value.Color == BlockColors.Default)
value = new BlockColor(FullGameFields._dataDb.TryGetValue((int) Type, out CubeListData cld) value = new BlockColor(FullGameFields._dataDb.TryGetValue((int) Type, out CubeListData cld)
? cld.DefaultColour ? cld.DefaultColour
: throw new BlockTypeException("Unknown block type! Could not set default color.")); : throw new BlockTypeException("Unknown block type! Could not set default color."));
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this); ref var color = ref GetComponent<ColourParameterEntityStruct>();
color.indexInPalette = value.Index; color.indexInPalette = value.Index;
color.hasNetworkChange = true; color.hasNetworkChange = true;
color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); //Setting to 255 results in black color.paletteColour = BlockEngine.ConvertBlockColor(color.indexInPalette); //Setting to 255 results in black
@ -279,10 +302,10 @@ namespace TechbloxModdingAPI
/// </summary> /// </summary>
public float4 CustomColor public float4 CustomColor
{ {
get => BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this).paletteColour; get => GetComponent<ColourParameterEntityStruct>().paletteColour;
set set
{ {
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this); ref var color = ref GetComponent<ColourParameterEntityStruct>();
color.paletteColour = value; color.paletteColour = value;
color.hasNetworkChange = true; color.hasNetworkChange = true;
} }
@ -295,7 +318,7 @@ namespace TechbloxModdingAPI
{ {
get get
{ {
var opt = BlockEngine.GetBlockInfoOptional<CubeMaterialStruct>(this); var opt = GetComponentOptional<CubeMaterialStruct>();
return opt ? (BlockMaterial) opt.Get().materialId : BlockMaterial.Default; return opt ? (BlockMaterial) opt.Get().materialId : BlockMaterial.Default;
} }
set set
@ -307,11 +330,11 @@ namespace TechbloxModdingAPI
: throw new BlockTypeException("Unknown block type! Could not set default material."); : throw new BlockTypeException("Unknown block type! Could not set default material.");
if (!FullGameFields._dataDb.ContainsKey<MaterialPropertiesData>(val)) if (!FullGameFields._dataDb.ContainsKey<MaterialPropertiesData>(val))
throw new BlockException($"Block material {value} does not exist!"); throw new BlockException($"Block material {value} does not exist!");
ref var comp = ref BlockEngine.GetBlockInfo<CubeMaterialStruct>(this); ref var comp = ref GetComponent<CubeMaterialStruct>();
if (comp.materialId == val) if (comp.materialId == val)
return; return;
comp.materialId = val; 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 get
{ {
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this); var opt = GetComponentOptional<LabelResourceIDComponent>();
return opt ? FullGameFields._managers.blockLabelResourceManager.GetText(opt.Get().instanceID) : null; return opt ? FullGameFields._managers.blockLabelResourceManager.GetText(opt.Get().instanceID) : null;
} }
set set
{ {
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this); var opt = GetComponentOptional<LabelResourceIDComponent>();
if (opt) FullGameFields._managers.blockLabelResourceManager.SetText(opt.Get().instanceID, value); if (opt) FullGameFields._managers.blockLabelResourceManager.SetText(opt.Get().instanceID, value);
} }
} }
@ -349,7 +372,7 @@ namespace TechbloxModdingAPI
{ {
if (blockGroup != null) return blockGroup; if (blockGroup != null) return blockGroup;
if (!GameClient.IsBuildMode) return null; // Breaks in simulation if (!GameClient.IsBuildMode) return null; // Breaks in simulation
var bgec = BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this); var bgec = GetComponent<BlockGroupEntityComponent>();
return blockGroup = bgec.currentBlockGroup == -1 return blockGroup = bgec.currentBlockGroup == -1
? null ? null
: GetInstance(new EGID((uint)bgec.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup), : GetInstance(new EGID((uint)bgec.currentBlockGroup, BlockGroupExclusiveGroups.BlockGroupEntityGroup),
@ -366,7 +389,7 @@ namespace TechbloxModdingAPI
blockGroup?.RemoveInternal(this); blockGroup?.RemoveInternal(this);
if (!InitData.Valid) if (!InitData.Valid)
return; return;
BlockEngine.GetBlockInfo<BlockGroupEntityComponent>(this).currentBlockGroup = (int?) value?.Id.entityID ?? -1; GetComponent<BlockGroupEntityComponent>().currentBlockGroup = (int?) value?.Id.entityID ?? -1;
value?.AddInternal(this); value?.AddInternal(this);
blockGroup = value; blockGroup = value;
} }
@ -377,8 +400,8 @@ namespace TechbloxModdingAPI
/// </summary> /// </summary>
public bool Static public bool Static
{ {
get => BlockEngine.GetBlockInfo<BlockStaticComponent>(this).isStatic; get => GetComponent<BlockStaticComponent>().isStatic;
set => BlockEngine.GetBlockInfo<BlockStaticComponent>(this).isStatic = value; set => GetComponent<BlockStaticComponent>().isStatic = value;
} }
/// <summary> /// <summary>
@ -386,7 +409,7 @@ namespace TechbloxModdingAPI
/// </summary> /// </summary>
public float Mass public float Mass
{ {
get => BlockEngine.GetBlockInfo<MassStruct>(this).mass; get => GetComponent<MassStruct>().mass;
} }
/// <summary> /// <summary>
@ -394,16 +417,10 @@ namespace TechbloxModdingAPI
/// </summary> /// </summary>
public BlockComplexity Complexity public BlockComplexity Complexity
{ {
get => new(BlockEngine.GetBlockInfo<BlockComplexityComponent>(this)); get => new(GetComponent<BlockComplexityComponent>());
set => BlockEngine.GetBlockInfo<BlockComplexityComponent>(this) = value; set => GetComponent<BlockComplexityComponent>() = value;
} }
/// <summary>
/// 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.
/// </summary>
public bool Exists => BlockEngine.BlockExists(Id);
/// <summary> /// <summary>
/// Returns an array of blocks that are connected to this one. Returns an empty array if the block doesn't exist. /// Returns an array of blocks that are connected to this one. Returns an empty array if the block doesn't exist.
/// </summary> /// </summary>
@ -422,7 +439,7 @@ namespace TechbloxModdingAPI
/// <returns>The SimBody of the chunk or null if the block doesn't exist or not in simulation mode.</returns> /// <returns>The SimBody of the chunk or null if the block doesn't exist or not in simulation mode.</returns>
public SimBody GetSimBody() public SimBody GetSimBody()
{ {
var st = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(this); var st = GetComponent<GridConnectionsEntityStruct>();
/*return st.machineRigidBodyId != uint.MaxValue /*return st.machineRigidBodyId != uint.MaxValue
? new SimBody(st.machineRigidBodyId, st.clusterId) - TODO: ? new SimBody(st.machineRigidBodyId, st.clusterId) - TODO:
: null;*/ : null;*/
@ -487,8 +504,6 @@ namespace TechbloxModdingAPI
public static void Init() public static void Init()
{ {
EngineManager.AddEngine(PlacementEngine, ApiEngineType.Build); EngineManager.AddEngine(PlacementEngine, ApiEngineType.Build);
EngineManager.AddEngine(MovementEngine, ApiEngineType.Build);
EngineManager.AddEngine(RotationEngine, ApiEngineType.Build);
EngineManager.AddEngine(RemovalEngine, ApiEngineType.Build); EngineManager.AddEngine(RemovalEngine, ApiEngineType.Build);
EngineManager.AddEngine(BlockEngine, ApiEngineType.Build, ApiEngineType.PlayServer, ApiEngineType.PlayClient); EngineManager.AddEngine(BlockEngine, ApiEngineType.Build, ApiEngineType.PlayServer, ApiEngineType.PlayClient);
EngineManager.AddEngine(BlockEventsEngine, ApiEngineType.Build); EngineManager.AddEngine(BlockEventsEngine, ApiEngineType.Build);

View file

@ -2,7 +2,7 @@ using RobocraftX.Blocks;
namespace TechbloxModdingAPI.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) public BlockComplexity(BlockComplexityComponent component) : this(component.cpu, component.power)
{ {

View file

@ -97,8 +97,5 @@ namespace TechbloxModdingAPI.Blocks.Engines
}; };
} }
} }
public string Name { get; } = "TechbloxModdingAPIBlockCloneGameEngine";
public bool isRemovable { get; } = false;
} }
} }

View file

@ -1,8 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using HarmonyLib;
using Gamecraft.ColourPalette; using Gamecraft.ColourPalette;
using Gamecraft.Wires; using Gamecraft.Wires;
using RobocraftX.Blocks; using RobocraftX.Blocks;
@ -14,13 +12,9 @@ using Svelto.DataStructures;
using Svelto.ECS; using Svelto.ECS;
using Svelto.ECS.EntityStructs; using Svelto.ECS.EntityStructs;
using Svelto.ECS.Experimental; using Svelto.ECS.Experimental;
using Svelto.ECS.Hybrid;
using Techblox.BuildingDrone;
using Techblox.ObjectIDBlockServer; using Techblox.ObjectIDBlockServer;
using TechbloxModdingAPI.Common;
using TechbloxModdingAPI.Common.Engines; using TechbloxModdingAPI.Common.Engines;
using Unity.Mathematics; using Unity.Mathematics;
using TechbloxModdingAPI.Utility;
using TechbloxModdingAPI.Utility.ECS; using TechbloxModdingAPI.Utility.ECS;
using PrefabsID = RobocraftX.Common.PrefabsID; using PrefabsID = RobocraftX.Common.PrefabsID;
@ -74,50 +68,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
: entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index, : entitiesDB.QueryEntity<PaletteEntryEntityStruct>(index,
ColourPaletteExclusiveGroups.COLOUR_PALETTE_GROUP).Colour; ColourPaletteExclusiveGroups.COLOUR_PALETTE_GROUP).Colour;
public OptionalRef<T> GetBlockInfoOptional<T>(Block block) where T : unmanaged, IEntityComponent public void UpdateDisplayData(EGID id)
{
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; if (!BlockExists(id)) return;
var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id); var pos = entitiesDB.QueryEntity<PositionEntityStruct>(id);
@ -129,7 +80,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(id); // Signal a prefab change so it updates the render buffers entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(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<PrefabAssetIDComponent>(block); var prefabAssetIDOpt = entitiesDB.QueryEntityOptional<PrefabAssetIDComponent>(block);
uint prefabAssetID = prefabAssetIDOpt uint prefabAssetID = prefabAssetIDOpt
@ -150,12 +101,12 @@ namespace TechbloxModdingAPI.Blocks.Engines
entitiesDB.PublishEntityChangeDelayed<CubeMaterialStruct>(block.Id); entitiesDB.PublishEntityChangeDelayed<CubeMaterialStruct>(block.Id);
entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(block.Id); entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(block.Id);
ref BuildingActionComponent local = /*ref BuildingActionComponent local =
ref entitiesDB.QueryEntity<BuildingActionComponent>(BuildingDroneUtility ref entitiesDB.QueryEntity<BuildingActionComponent>(BuildingDroneUtility
.GetLocalBuildingDrone(entitiesDB).ToEGID(entitiesDB)); .GetLocalBuildingDrone(entitiesDB).ToEGID(entitiesDB));
local.buildAction = BuildAction.ChangeMaterial; local.buildAction = BuildAction.ChangeMaterial;
local.targetPosition = block.Position; local.targetPosition = block.Position; - TODO: This probably only plays the audio
this.entitiesDB.PublishEntityChangeDelayed<BuildingActionComponent>(local.ID); this.entitiesDB.PublishEntityChangeDelayed<BuildingActionComponent>(local.ID);*/
} }
//Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData //Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData
} }

View file

@ -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
{
/// <summary>
/// Engine which executes block movement actions
/// </summary>
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<PositionEntityStruct>(block);
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
var phyStruct = this.entitiesDB.QueryEntityOptional<DOTSPhysicsEntityStruct>(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<GridConnectionsEntityStruct>(block).areConnectionsAssigned = false;
return posStruct.position;
}
internal float3 GetPosition(Block block)
{
return entitiesDB.QueryEntityOrDefault<PositionEntityStruct>(block).position;
}
}
}

View file

@ -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
{
/// <summary>
/// Engine which executes block movement actions
/// </summary>
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<RotationEntityStruct>(block);
ref GridRotationStruct gridStruct = ref this.entitiesDB.QueryEntityOrDefault<GridRotationStruct>(block);
ref LocalTransformEntityStruct transStruct = ref this.entitiesDB.QueryEntityOrDefault<LocalTransformEntityStruct>(block);
var phyStruct = this.entitiesDB.QueryEntityOptional<DOTSPhysicsEntityStruct>(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<GridConnectionsEntityStruct>(block).areConnectionsAssigned = false;
return ((Quaternion)rotStruct.rotation).eulerAngles;
}
internal float3 GetRotation(Block block)
{
ref RotationEntityStruct rotStruct = ref entitiesDB.QueryEntityOrDefault<RotationEntityStruct>(block);
return ((Quaternion) rotStruct.rotation).eulerAngles;
}
}
}

View file

@ -29,7 +29,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
private EntityManager _entityManager; //Unity entity manager private EntityManager _entityManager; //Unity entity manager
public void UpdateCollision(EGID egid) public void UpdateCollision(EGID egid)
{ { // TODO: Move to BlockEngine/IHasPhysics
if (_entityManager == default) if (_entityManager == default)
_entityManager = FullGameFields._physicsWorld.EntityManager; _entityManager = FullGameFields._physicsWorld.EntityManager;
//Assuming the block exists //Assuming the block exists

View file

@ -41,7 +41,7 @@ namespace TechbloxModdingAPI.Blocks.Engines
private static IEntityFactory _entityFactory; private static IEntityFactory _entityFactory;
public EntityInitializer PlaceBlock(BlockIDs block, float3 position, Player player, bool autoWire) 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); return BuildBlock((ushort) block, position, autoWire, (player ?? Player.LocalPlayer).Id);
} }
@ -52,15 +52,19 @@ namespace TechbloxModdingAPI.Blocks.Engines
if(!FullGameFields._dataDb.ContainsKey<CubeListData>(block)) if(!FullGameFields._dataDb.ContainsKey<CubeListData>(block))
throw new BlockException("Block with ID " + block + " not found!"); throw new BlockException("Block with ID " + block + " not found!");
//RobocraftX.CR.MachineEditing.PlaceSingleBlockEngine //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<PrefabAssetIDComponent>() uint prefabAssetID = structInitializer.Has<PrefabAssetIDComponent>()
? structInitializer.Get<PrefabAssetIDComponent>().prefabAssetID ? structInitializer.Get<PrefabAssetIDComponent>().prefabAssetID
: throw new BlockException("Prefab asset ID not found!"); //Set by the game : throw new BlockException("Prefab asset ID not found!"); //Set by the game
uint prefabId = PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, (byte) BlockMaterial.SteelBodywork, 1, false); uint prefabId = PrefabsID.GetOrAddPrefabID((ushort) prefabAssetID, (byte) BlockMaterial.SteelBodywork, 1, false);
structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId)); structInitializer.Init(new GFXPrefabEntityStructGPUI(prefabId));
structInitializer.Init(dbEntity); structInitializer.Get<CubeMaterialStruct>().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 PositionEntityStruct {position = position});
structInitializer.Init(new RotationEntityStruct {rotation = quaternion.identity}); structInitializer.Init(new RotationEntityStruct {rotation = quaternion.identity});
structInitializer.Init(new ScalingEntityStruct {scale = new float3(1, 1, 1)}); structInitializer.Init(new ScalingEntityStruct {scale = new float3(1, 1, 1)});
@ -70,7 +74,6 @@ namespace TechbloxModdingAPI.Blocks.Engines
rotation = quaternion.identity rotation = quaternion.identity
}); });
structInitializer.Init(new UniformBlockScaleEntityStruct {scaleFactor = 1}); structInitializer.Init(new UniformBlockScaleEntityStruct {scaleFactor = 1});
structInitializer.Get<CubeMaterialStruct>().materialId = (byte) BlockMaterial.SteelBodywork;
var bssesopt = entitiesDB.QueryEntityOptional<BoxSelectStateEntityStruct>(new EGID(playerId, var bssesopt = entitiesDB.QueryEntityOptional<BoxSelectStateEntityStruct>(new EGID(playerId,
BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup)); BoxSelectExclusiveGroups.BoxSelectVolumeExclusiveGroup));
if (!bssesopt) if (!bssesopt)
@ -107,10 +110,6 @@ namespace TechbloxModdingAPI.Blocks.Engines
return structInitializer; return structInitializer;
} }
public string Name => "TechbloxModdingAPIPlacementGameEngine";
public bool isRemovable => false;
[HarmonyPatch] [HarmonyPatch]
class FactoryObtainerPatch class FactoryObtainerPatch
{ {

View file

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using Svelto.DataStructures; using Svelto.DataStructures;
using Svelto.ECS; using Svelto.ECS;
using Svelto.ECS.Hybrid;
using Svelto.ECS.Internal; using Svelto.ECS.Internal;
using TechbloxModdingAPI.Common.Engines; using TechbloxModdingAPI.Common.Engines;
using TechbloxModdingAPI.Common.Utils; using TechbloxModdingAPI.Common.Utils;
@ -18,6 +19,11 @@ public abstract class EcsObjectBase
/// </summary> /// </summary>
public EntityReference Reference { get; } public EntityReference Reference { get; }
/// <summary>
/// Whether the entity reference is still valid. Returns false if this object no longer exists.
/// </summary>
public bool Exists => Id != default; // TODO: Might need extra code to support IDs during init
private static readonly Dictionary<Type, WeakDictionary<EntityReference, EcsObjectBase>> _instances = new(); private static readonly Dictionary<Type, WeakDictionary<EntityReference, EcsObjectBase>> _instances = new();
private static readonly EcsObjectBaseEngine _engine = new(); private static readonly EcsObjectBaseEngine _engine = new();
@ -58,6 +64,38 @@ public abstract class EcsObjectBase
Reference = reference; Reference = reference;
} }
protected internal OptionalRef<T> GetComponentOptional<T>() where T : unmanaged, IEntityComponent
{
return _engine.GetComponentOptional<T>(this);
}
protected internal ref T GetComponent<T>() where T : unmanaged, IEntityComponent
{
return ref _engine.GetComponent<T>(this);
}
protected internal ref T GetViewComponent<T>() where T : struct, IEntityViewComponent
{
return ref _engine.GetViewComponent<T>(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 #region ECS initializer stuff
protected internal EcsInitData InitData; protected internal EcsInitData InitData;

View file

@ -1,5 +1,11 @@
using System;
using HarmonyLib;
using Svelto.ECS; using Svelto.ECS;
using Svelto.ECS.Hybrid;
using TechbloxModdingAPI.Blocks.Engines;
using TechbloxModdingAPI.Common.Engines; using TechbloxModdingAPI.Common.Engines;
using TechbloxModdingAPI.Utility;
using TechbloxModdingAPI.Utility.ECS;
namespace TechbloxModdingAPI.Common; namespace TechbloxModdingAPI.Common;
@ -10,6 +16,7 @@ public class EcsObjectBaseEngine : IApiEngine
} }
public EntitiesDB entitiesDB { get; set; } public EntitiesDB entitiesDB { get; set; }
public void Dispose() public void Dispose()
{ {
} }
@ -23,4 +30,42 @@ public class EcsObjectBaseEngine : IApiEngine
{ {
return entitiesDB is not null && reference.ToEGID(entitiesDB, out var egid) ? egid : default; return entitiesDB is not null && reference.ToEGID(entitiesDB, out var egid) ? egid : default;
} }
public OptionalRef<T> GetComponentOptional<T>(EcsObjectBase obj) where T : unmanaged, IEntityComponent
{
return entitiesDB.QueryEntityOptional<T>(obj);
}
public ref T GetComponent<T>(EcsObjectBase obj) where T : unmanaged, IEntityComponent
{
#if DEBUG
if (entitiesDB.Exists<T>(obj.Id) && obj.InitData.Valid)
throw new ArgumentException("The block exists but the init data has not been removed!");
#endif
return ref entitiesDB.QueryEntityOrDefault<T>(obj);
}
public ref T GetViewComponent<T>(EcsObjectBase obj) where T : struct, IEntityViewComponent
{
return ref entitiesDB.QueryEntityOrDefault<T>(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);
}
} }

View file

@ -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<T, O>(this O obj, T componentData) where O : EcsObjectBase, IHasPhysics where T : struct, IComponentData
{
var phyStruct = obj.GetComponentOptional<DOTSPhysicsEntityStruct>();
if (phyStruct) //It exists
FullGameFields._physicsWorld.EntityManager.SetComponentData(phyStruct.Get().dotsEntity, componentData);
}
}

View file

@ -11,6 +11,8 @@
<NeutralLanguage>en-CA</NeutralLanguage> <NeutralLanguage>en-CA</NeutralLanguage>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Configurations>Debug;Release;Test</Configurations>
<Platforms>AnyCPU</Platforms>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>