@@ -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. | |||
/// </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 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 | |||
/// </summary> | |||
public float3 Position | |||
{ | |||
get => MovementEngine.GetPosition(this); | |||
get => GetComponent<PositionEntityStruct>().position; | |||
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) | |||
blockGroup.PosAndRotCalculated = false; | |||
BlockEngine.UpdateDisplayedBlock(Id); | |||
BlockEngine.UpdateDisplayData(Id); | |||
} | |||
} | |||
@@ -178,13 +187,24 @@ namespace TechbloxModdingAPI | |||
/// </summary> | |||
public float3 Rotation | |||
{ | |||
get => RotationEngine.GetRotation(this); | |||
get => ((Quaternion)GetComponent<RotationEntityStruct>().rotation).eulerAngles; | |||
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) | |||
blockGroup.PosAndRotCalculated = false; | |||
BlockEngine.UpdateDisplayedBlock(Id); | |||
BlockEngine.UpdateDisplayData(Id); | |||
} | |||
} | |||
@@ -194,18 +214,19 @@ namespace TechbloxModdingAPI | |||
/// </summary> | |||
public float3 Scale | |||
{ | |||
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale; | |||
get => GetComponent<ScalingEntityStruct>().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<ScalingEntityStruct>(this).scale = value; | |||
GetComponent<ScalingEntityStruct>().scale = value; | |||
GetComponent<GridConnectionsEntityStruct>().areConnectionsAssigned = false; | |||
//BlockEngine.GetBlockInfo<GridScaleStruct>(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 | |||
/// </summary> | |||
public int UniformScale | |||
{ | |||
get => BlockEngine.GetBlockInfo<UniformBlockScaleEntityStruct>(this).scaleFactor; | |||
get => GetComponent<UniformBlockScaleEntityStruct>().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<UniformBlockScaleEntityStruct>(this).scaleFactor = value; | |||
GetComponent<UniformBlockScaleEntityStruct>().scaleFactor = value; | |||
Scale = new float3(value, value, value); | |||
} | |||
} | |||
@@ -229,12 +251,12 @@ namespace TechbloxModdingAPI | |||
*/ | |||
public bool Flipped | |||
{ | |||
get => BlockEngine.GetBlockInfo<ScalingEntityStruct>(this).scale.x < 0; | |||
get => GetComponent<ScalingEntityStruct>().scale.x < 0; | |||
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); | |||
BlockEngine.UpdatePrefab(this, (byte) Material, value); | |||
BlockEngine.UpdateDisplayedPrefab(this, (byte) Material, value); | |||
} | |||
} | |||
@@ -245,7 +267,7 @@ namespace TechbloxModdingAPI | |||
{ | |||
get | |||
{ | |||
var opt = BlockEngine.GetBlockInfoOptional<DBEntityStruct>(this); | |||
var opt = GetComponentOptional<DBEntityStruct>(); | |||
return opt ? (BlockIDs) opt.Get().DBID : BlockIDs.Invalid; | |||
} | |||
} | |||
@@ -257,16 +279,17 @@ namespace TechbloxModdingAPI | |||
{ | |||
get | |||
{ | |||
var opt = BlockEngine.GetBlockInfoOptional<ColourParameterEntityStruct>(this); | |||
var opt = GetComponentOptional<ColourParameterEntityStruct>(); | |||
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<ColourParameterEntityStruct>(this); | |||
ref var color = ref GetComponent<ColourParameterEntityStruct>(); | |||
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 | |||
/// </summary> | |||
public float4 CustomColor | |||
{ | |||
get => BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this).paletteColour; | |||
get => GetComponent<ColourParameterEntityStruct>().paletteColour; | |||
set | |||
{ | |||
ref var color = ref BlockEngine.GetBlockInfo<ColourParameterEntityStruct>(this); | |||
ref var color = ref GetComponent<ColourParameterEntityStruct>(); | |||
color.paletteColour = value; | |||
color.hasNetworkChange = true; | |||
} | |||
@@ -295,7 +318,7 @@ namespace TechbloxModdingAPI | |||
{ | |||
get | |||
{ | |||
var opt = BlockEngine.GetBlockInfoOptional<CubeMaterialStruct>(this); | |||
var opt = GetComponentOptional<CubeMaterialStruct>(); | |||
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<MaterialPropertiesData>(val)) | |||
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) | |||
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<LabelResourceIDComponent>(this); | |||
var opt = GetComponentOptional<LabelResourceIDComponent>(); | |||
return opt ? FullGameFields._managers.blockLabelResourceManager.GetText(opt.Get().instanceID) : null; | |||
} | |||
set | |||
{ | |||
var opt = BlockEngine.GetBlockInfoOptional<LabelResourceIDComponent>(this); | |||
var opt = GetComponentOptional<LabelResourceIDComponent>(); | |||
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<BlockGroupEntityComponent>(this); | |||
var bgec = GetComponent<BlockGroupEntityComponent>(); | |||
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<BlockGroupEntityComponent>(this).currentBlockGroup = (int?) value?.Id.entityID ?? -1; | |||
GetComponent<BlockGroupEntityComponent>().currentBlockGroup = (int?) value?.Id.entityID ?? -1; | |||
value?.AddInternal(this); | |||
blockGroup = value; | |||
} | |||
@@ -377,8 +400,8 @@ namespace TechbloxModdingAPI | |||
/// </summary> | |||
public bool Static | |||
{ | |||
get => BlockEngine.GetBlockInfo<BlockStaticComponent>(this).isStatic; | |||
set => BlockEngine.GetBlockInfo<BlockStaticComponent>(this).isStatic = value; | |||
get => GetComponent<BlockStaticComponent>().isStatic; | |||
set => GetComponent<BlockStaticComponent>().isStatic = value; | |||
} | |||
/// <summary> | |||
@@ -386,7 +409,7 @@ namespace TechbloxModdingAPI | |||
/// </summary> | |||
public float Mass | |||
{ | |||
get => BlockEngine.GetBlockInfo<MassStruct>(this).mass; | |||
get => GetComponent<MassStruct>().mass; | |||
} | |||
/// <summary> | |||
@@ -394,16 +417,10 @@ namespace TechbloxModdingAPI | |||
/// </summary> | |||
public BlockComplexity Complexity | |||
{ | |||
get => new(BlockEngine.GetBlockInfo<BlockComplexityComponent>(this)); | |||
set => BlockEngine.GetBlockInfo<BlockComplexityComponent>(this) = value; | |||
get => new(GetComponent<BlockComplexityComponent>()); | |||
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> | |||
/// Returns an array of blocks that are connected to this one. Returns an empty array if the block doesn't exist. | |||
/// </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> | |||
public SimBody GetSimBody() | |||
{ | |||
var st = BlockEngine.GetBlockInfo<GridConnectionsEntityStruct>(this); | |||
var st = GetComponent<GridConnectionsEntityStruct>(); | |||
/*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); | |||
@@ -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) | |||
{ | |||
@@ -97,8 +97,5 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
}; | |||
} | |||
} | |||
public string Name { get; } = "TechbloxModdingAPIBlockCloneGameEngine"; | |||
public bool isRemovable { get; } = false; | |||
} | |||
} |
@@ -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<PaletteEntryEntityStruct>(index, | |||
ColourPaletteExclusiveGroups.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) | |||
public void UpdateDisplayData(EGID id) | |||
{ | |||
if (!BlockExists(id)) return; | |||
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 | |||
} | |||
internal void UpdatePrefab(Block block, byte material, bool flipped) | |||
internal void UpdateDisplayedPrefab(Block block, byte material, bool flipped) | |||
{ | |||
var prefabAssetIDOpt = entitiesDB.QueryEntityOptional<PrefabAssetIDComponent>(block); | |||
uint prefabAssetID = prefabAssetIDOpt | |||
@@ -150,12 +101,12 @@ namespace TechbloxModdingAPI.Blocks.Engines | |||
entitiesDB.PublishEntityChangeDelayed<CubeMaterialStruct>(block.Id); | |||
entitiesDB.PublishEntityChangeDelayed<GFXPrefabEntityStructGPUI>(block.Id); | |||
ref BuildingActionComponent local = | |||
/*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); | |||
local.targetPosition = block.Position; - TODO: This probably only plays the audio | |||
this.entitiesDB.PublishEntityChangeDelayed<BuildingActionComponent>(local.ID);*/ | |||
} | |||
//Phyiscs prefab: prefabAssetID, set on block creation from the CubeListData | |||
} | |||
@@ -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; | |||
} | |||
} | |||
} |
@@ -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; | |||
} | |||
} | |||
} |
@@ -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 | |||
@@ -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<CubeListData>(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<PrefabAssetIDComponent>() | |||
? structInitializer.Get<PrefabAssetIDComponent>().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<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 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<CubeMaterialStruct>().materialId = (byte) BlockMaterial.SteelBodywork; | |||
var bssesopt = entitiesDB.QueryEntityOptional<BoxSelectStateEntityStruct>(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 | |||
{ |
@@ -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. | |||
/// </summary> | |||
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 EcsObjectBaseEngine _engine = new(); | |||
@@ -57,6 +63,38 @@ public abstract class EcsObjectBase | |||
dict.Add(reference, this); | |||
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 | |||
@@ -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<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); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -11,6 +11,8 @@ | |||
<NeutralLanguage>en-CA</NeutralLanguage> | |||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> | |||
<LangVersion>latest</LangVersion> | |||
<Configurations>Debug;Release;Test</Configurations> | |||
<Platforms>AnyCPU</Platforms> | |||
</PropertyGroup> | |||
<ItemGroup> | |||