diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index 673ef49..c3e0393 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -55,13 +55,7 @@ namespace GamecraftModdingAPI float3 rotation = default, BlockColors color = BlockColors.Default, byte darkness = 0, int uscale = 1, float3 scale = default, Player player = null) { - if (PlacementEngine.IsInGame && GameState.IsBuildMode()) - { - return new Block(PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation)); - } - - return null; + return PlaceNew(block, position, rotation, color, darkness, uscale, scale, player); } /// @@ -85,8 +79,10 @@ namespace GamecraftModdingAPI if (PlacementEngine.IsInGame && GameState.IsBuildMode()) { var egid = PlacementEngine.PlaceBlock(block, color, darkness, - position, uscale, scale, player, rotation); - return New(egid.entityID, egid.groupID); + position, uscale, scale, player, rotation, out var initializer); + var bl = New(egid.entityID, egid.groupID); + bl.InitData.Group = BlockEngine.InitGroup(initializer); + return bl; } return null; @@ -205,6 +201,8 @@ namespace GamecraftModdingAPI public EGID Id { get; } + internal BlockEngine.BlockInitData InitData; + /// /// The block's current position or zero if the block no longer exists. /// A block is 0.2 wide by default in terms of position. @@ -236,12 +234,11 @@ namespace GamecraftModdingAPI /// public float3 Scale { - get => BlockEngine.GetBlockInfo(Id).scale; + get => BlockEngine.GetBlockInfo(this, (ScalingEntityStruct st) => st.scale); set { + BlockEngine.SetBlockInfo(this, (ref ScalingEntityStruct st, float3 val) => st.scale = val, value); if (!Exists) return; //UpdateCollision needs the block to exist - ref var scaling = ref BlockEngine.GetBlockInfo(Id); - scaling.scale = value; ScalingEngine.UpdateCollision(Id); } } @@ -252,11 +249,11 @@ namespace GamecraftModdingAPI /// public int UniformScale { - get => BlockEngine.GetBlockInfo(Id).scaleFactor; + get => BlockEngine.GetBlockInfo(this, (UniformBlockScaleEntityStruct st) => st.scaleFactor); set { - ref var scaleStruct = ref BlockEngine.GetBlockInfo(Id); - scaleStruct.scaleFactor = value; + BlockEngine.SetBlockInfo(this, (ref UniformBlockScaleEntityStruct st, int val) => st.scaleFactor = val, + value); Scale = new float3(value, value, value); } } @@ -268,8 +265,7 @@ namespace GamecraftModdingAPI { get { - var id = (BlockIDs) BlockEngine.GetBlockInfo(Id, out var exists).DBID; - return exists ? id : BlockIDs.Invalid; + return BlockEngine.GetBlockInfo(this, (DBEntityStruct st) => (BlockIDs) st.DBID, BlockIDs.Invalid); } } @@ -280,17 +276,19 @@ namespace GamecraftModdingAPI { get { - byte index = BlockEngine.GetBlockInfo(Id, out var exists).indexInPalette; - if (!exists) index = byte.MaxValue; + byte index = BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.indexInPalette, + byte.MaxValue); return new BlockColor(index); } set { - ref var color = ref BlockEngine.GetBlockInfo(Id); - color.indexInPalette = (byte)(value.Color + value.Darkness * 10); - color.overridePaletteColour = false; - color.needsUpdate = true; - BlockEngine.SetBlockColorFromPalette(ref color); + BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, BlockColor val) => + { + color.indexInPalette = (byte) (val.Color + val.Darkness * 10); + color.overridePaletteColour = false; + color.needsUpdate = true; + BlockEngine.SetBlockColorFromPalette(ref color); + }, value); } } @@ -299,27 +297,31 @@ namespace GamecraftModdingAPI /// public float4 CustomColor { - get => BlockEngine.GetBlockInfo(Id).overriddenColour; + get => BlockEngine.GetBlockInfo(this, (ColourParameterEntityStruct st) => st.overriddenColour); set { - ref var color = ref BlockEngine.GetBlockInfo(Id); - color.overriddenColour = value; - color.overridePaletteColour = true; - color.needsUpdate = true; + BlockEngine.SetBlockInfo(this, (ref ColourParameterEntityStruct color, float4 val) => + { + color.overriddenColour = val; + color.overridePaletteColour = true; + color.needsUpdate = true; + }, value); } } /// - /// The short text displayed on the block if applicable, or null. + /// The text displayed on the block if applicable, or null. /// Setting it is temporary to the session, it won't be saved. /// public string Label { - get => BlockEngine.GetBlockInfo(Id).textLabelComponent?.text; + get => BlockEngine.GetBlockInfo(this, (TextLabelEntityViewStruct st) => st.textLabelComponent?.text); set { - ref var text = ref BlockEngine.GetBlockInfo(Id); - if (text.textLabelComponent != null) text.textLabelComponent.text = value; + BlockEngine.SetBlockInfo(this, (ref TextLabelEntityViewStruct text, string val) => + { + if (text.textLabelComponent != null) text.textLabelComponent.text = val; + }, value); } } @@ -346,8 +348,8 @@ namespace GamecraftModdingAPI /// The SimBody of the cluster or null if the block doesn't exist. public SimBody GetSimBody() { - uint id = BlockEngine.GetBlockInfo(Id, out var exists).machineRigidBodyId; - return exists ? new SimBody(id) : null; + return BlockEngine.GetBlockInfo(this, + (GridConnectionsEntityStruct st) => new SimBody(st.machineRigidBodyId)); } public override string ToString() @@ -404,7 +406,9 @@ namespace GamecraftModdingAPI // So thanks to Microsoft, we've got this horrible implementation using reflection //Lets improve that using delegates - return New(Id.entityID, Id.groupID); + var block = New(Id.entityID, Id.groupID); + block.InitData = this.InitData; + return block; } #if DEBUG diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 81a1630..d6f4907 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Gamecraft.Wires; @@ -10,14 +11,13 @@ using Svelto.DataStructures; using Svelto.ECS; using GamecraftModdingAPI.Engines; -using GamecraftModdingAPI.Utility; namespace GamecraftModdingAPI.Blocks { /// /// Engine for executing general block actions /// - public class BlockEngine : IApiEngine + public partial class BlockEngine : IApiEngine { public string Name { get; } = "GamecraftModdingAPIBlockGameEngine"; @@ -61,66 +61,54 @@ namespace GamecraftModdingAPI.Blocks color.paletteColour = paletteEntry.Colour; } - /// - /// Get a struct of a block. Can be used to set properties. - /// Returns a default value if not found. - /// - /// The block's ID - /// The struct to query - /// An editable reference to the struct public ref T GetBlockInfo(EGID blockID) where T : struct, IEntityComponent { - if (!Synced) - { - Sync(); - Synced = true; - } if (entitiesDB.Exists(blockID)) return ref entitiesDB.QueryEntity(blockID); T[] structHolder = new T[1]; //Create something that can be referenced return ref structHolder[0]; //Gets a default value automatically } - /// - /// Get a struct of a block. Can be used to set properties. - /// Returns a default value if not found. - /// - /// The block's ID - /// Whether the specified struct exists for the block - /// The struct to query - /// An editable reference to the struct - public ref T GetBlockInfo(EGID blockID, out bool exists) where T : struct, IEntityComponent + public U GetBlockInfo(Block block, Func getter, + U def = default) where T : struct, IEntityComponent { - if (!Synced) + if (entitiesDB.Exists(block.Id)) + return getter(entitiesDB.QueryEntity(block.Id)); + if (block.InitData.Group == null) return def; + var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); + if (initializer.Has()) + return getter(initializer.Get()); + return def; + } + + public delegate void Setter(ref T component, U value) where T : struct, IEntityComponent; + + public void SetBlockInfo(Block block, Setter setter, U value) where T : struct, IEntityComponent + { + if (entitiesDB.Exists(block.Id)) + setter(ref entitiesDB.QueryEntity(block.Id), value); + if (block.InitData.Group != null) { - Sync(); - Synced = true; + var initializer = new EntityComponentInitializer(block.Id, block.InitData.Group); + ref T structRef = ref (new T[1])[0]; //A reference for a default value for struct + setter(ref structRef, value); + initializer.Init(structRef); } - exists = entitiesDB.Exists(blockID); - if (exists) - return ref entitiesDB.QueryEntity(blockID); - T[] structHolder = new T[1]; - return ref structHolder[0]; } - public bool BlockExists(EGID id) + public bool BlockExists(EGID blockID) { - if (!Synced) - { - Sync(); - Synced = true; - } - return entitiesDB.Exists(id); + return entitiesDB.Exists(blockID); } - public bool GetBlockInfoExists(EGID blockID) where T : struct, IEntityComponent + public bool GetBlockInfoExists(Block block) where T : struct, IEntityComponent { - if (!Synced) - { - Sync(); - Synced = true; - } - return entitiesDB.Exists(blockID); + if (entitiesDB.Exists(block.Id)) + return true; + if (block.InitData.Group == null) + return false; + var init = new EntityComponentInitializer(block.Id, block.InitData.Group); + return init.Has(); } public SimBody[] GetSimBodiesFromID(byte id) @@ -183,17 +171,6 @@ namespace GamecraftModdingAPI.Blocks return null; } - /// - /// Synchronize newly created entity components with entities DB. - /// This forces a partial game tick, so it may be slow. - /// This also has the potential to make Gamecraft unstable. - /// Use this sparingly. - /// - private static void Sync() - { - DeterministicStepCompositionRootPatch.SubmitEntitiesNow(); - } - #if DEBUG public EntitiesDB GetEntitiesDB() { diff --git a/GamecraftModdingAPI/Blocks/BlockEngineInit.cs b/GamecraftModdingAPI/Blocks/BlockEngineInit.cs new file mode 100644 index 0000000..4be9a98 --- /dev/null +++ b/GamecraftModdingAPI/Blocks/BlockEngineInit.cs @@ -0,0 +1,46 @@ +using System; +using System.Linq.Expressions; + +using Svelto.DataStructures; +using Svelto.ECS; +using Svelto.ECS.Internal; + +namespace GamecraftModdingAPI.Blocks +{ + public partial class BlockEngine + { + internal struct BlockInitData + { + public FasterDictionary, ITypeSafeDictionary> Group; + } + + internal delegate FasterDictionary, ITypeSafeDictionary> GetInitGroup( + EntityComponentInitializer initializer); + + internal GetInitGroup InitGroup = CreateAccessor("_group"); + + //https://stackoverflow.com/questions/55878525/unit-testing-ref-structs-with-private-fields-via-reflection + internal static TDelegate CreateAccessor(string memberName) where TDelegate : Delegate + { + var invokeMethod = typeof(TDelegate).GetMethod("Invoke"); + if (invokeMethod == null) + throw new InvalidOperationException($"{typeof(TDelegate)} signature could not be determined."); + + var delegateParameters = invokeMethod.GetParameters(); + if (delegateParameters.Length != 1) + throw new InvalidOperationException("Delegate must have a single parameter."); + + var paramType = delegateParameters[0].ParameterType; + + var objParam = Expression.Parameter(paramType, "obj"); + var memberExpr = Expression.PropertyOrField(objParam, memberName); + Expression returnExpr = memberExpr; + if (invokeMethod.ReturnType != memberExpr.Type) + returnExpr = Expression.ConvertChecked(memberExpr, invokeMethod.ReturnType); + + var lambda = + Expression.Lambda(returnExpr, $"Access{paramType.Name}_{memberName}", new[] {objParam}); + return lambda.Compile(); + } + } +} \ No newline at end of file diff --git a/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs b/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs index 3c34b65..0a205f0 100644 --- a/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEventsEngine.cs @@ -1,9 +1,11 @@ using System; -using GamecraftModdingAPI.Engines; -using GamecraftModdingAPI.Utility; + using RobocraftX.Common; using Svelto.ECS; +using GamecraftModdingAPI.Engines; +using GamecraftModdingAPI.Utility; + namespace GamecraftModdingAPI.Blocks { public class BlockEventsEngine : IReactionaryEngine @@ -11,11 +13,18 @@ namespace GamecraftModdingAPI.Blocks public event EventHandler Placed; public event EventHandler Removed; + public BlockEventsEngine() + { + //Console.WriteLine("Creating BlockEventsEngine\n" + Environment.StackTrace); + } + public void Ready() { + //Console.WriteLine("BlockEventsEngine registered"); } public EntitiesDB entitiesDB { get; set; } + public void Dispose() { } @@ -23,17 +32,52 @@ namespace GamecraftModdingAPI.Blocks public string Name { get; } = "GamecraftModdingAPIBlockEventsEngine"; public bool isRemovable { get; } = false; + private bool shouldAddRemove; public void Add(ref DBEntityStruct entityComponent, EGID egid) { - ExceptionUtil.InvokeEvent(Placed, this, new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); + if (!(shouldAddRemove = !shouldAddRemove)) + return; + ExceptionUtil.InvokeEvent(Placed, this, + new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); } public void Remove(ref DBEntityStruct entityComponent, EGID egid) { - ExceptionUtil.InvokeEvent(Removed, this, new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); + if (!(shouldAddRemove = !shouldAddRemove)) + return; + ExceptionUtil.InvokeEvent(Removed, this, + new BlockPlacedRemovedEventArgs {ID = egid, Type = (BlockIDs) entityComponent.DBID}); } } + /*[HarmonyPatch] + public static class TestPatch + { + public static void Postfix(FasterDictionary, FasterList> engines, + ExclusiveGroupStruct? previousGroup, in PlatformProfiler profiler, EGID egid) + { + if (!engines.TryGetValue(new RefWrapper(TypeSafeDictionary._type), out result)) + return; + } + public static MethodBase TargetMethod() + { + return AccessTools.Method("Svelto.ECS.Internal.TypeSafeDictionary:AddEntityComponentToEngines"); + } + }*/ + + /*[HarmonyPatch] + public static class TestPatch + { + public static void Postfix(EGID basePartEGID) + { + Console.WriteLine("Patched Add method: " + basePartEGID); + } + public static MethodBase TargetMethod() + { + return AccessTools.Method("RobocraftX.CR.MachineEditing.BuildBlockAdditionalPartEngine:Add"); + } + }*/ + public struct BlockPlacedRemovedEventArgs { public EGID ID; diff --git a/GamecraftModdingAPI/Blocks/BlockIDs.cs b/GamecraftModdingAPI/Blocks/BlockIDs.cs index b0eca31..596fb38 100644 --- a/GamecraftModdingAPI/Blocks/BlockIDs.cs +++ b/GamecraftModdingAPI/Blocks/BlockIDs.cs @@ -6,7 +6,7 @@ namespace GamecraftModdingAPI.Blocks public enum BlockIDs : ushort { /// - /// A custom value for the API. Doesn't exist for Gamecraft. + /// Called "nothing" in Gamecraft. (DBID.NOTHING) /// Invalid = ushort.MaxValue, AluminiumCube = 0, diff --git a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs index e132029..4425a1e 100644 --- a/GamecraftModdingAPI/Blocks/ConsoleBlock.cs +++ b/GamecraftModdingAPI/Blocks/ConsoleBlock.cs @@ -14,18 +14,10 @@ namespace GamecraftModdingAPI.Blocks { public ConsoleBlock(EGID id): base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public ConsoleBlock(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_CONSOLE_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom console block properties @@ -34,43 +26,47 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).commandName; + return BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.commandName); } set { - BlockEngine.GetBlockInfo(Id).commandName.Set(value); + BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.commandName.Set(val), + value); } } public string Arg1 { - get => BlockEngine.GetBlockInfo(Id).arg1; + get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg1); set { - BlockEngine.GetBlockInfo(Id).arg1.Set(value); + BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg1.Set(val), + value); } } public string Arg2 { - get => BlockEngine.GetBlockInfo(Id).arg2; + get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg2); - set - { - BlockEngine.GetBlockInfo(Id).arg2.Set(value); - } + set + { + BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg2.Set(val), + value); + } } public string Arg3 { - get => BlockEngine.GetBlockInfo(Id).arg3; + get => BlockEngine.GetBlockInfo(this, (ConsoleBlockEntityStruct st) => st.arg3); - set - { - BlockEngine.GetBlockInfo(Id).arg3.Set(value); - } + set + { + BlockEngine.SetBlockInfo(this, (ref ConsoleBlockEntityStruct st, string val) => st.arg3.Set(val), + value); + } } } } diff --git a/GamecraftModdingAPI/Blocks/Motor.cs b/GamecraftModdingAPI/Blocks/Motor.cs index fde2920..fdadd26 100644 --- a/GamecraftModdingAPI/Blocks/Motor.cs +++ b/GamecraftModdingAPI/Blocks/Motor.cs @@ -13,18 +13,10 @@ namespace GamecraftModdingAPI.Blocks { public Motor(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public Motor(uint id): base(new EGID(id, CommonExclusiveGroups.BUILD_MOTOR_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom motor properties @@ -36,13 +28,12 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).maxVelocity; + return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.maxVelocity); } set { - ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo(Id); - motor.maxVelocity = value; + BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, float val) => st.maxVelocity = val, value); } } @@ -53,13 +44,12 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).maxForce; + return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.maxForce); } set { - ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo(Id); - motor.maxForce = value; + BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, float val) => st.maxForce = val, value); } } @@ -70,13 +60,12 @@ namespace GamecraftModdingAPI.Blocks { get { - return BlockEngine.GetBlockInfo(Id).reverse; + return BlockEngine.GetBlockInfo(this, (MotorReadOnlyStruct st) => st.reverse); } set { - ref MotorReadOnlyStruct motor = ref BlockEngine.GetBlockInfo(Id); - motor.reverse = value; + BlockEngine.SetBlockInfo(this, (ref MotorReadOnlyStruct st, bool val) => st.reverse = val, value); } } } diff --git a/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs b/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs index 9af96c2..0dc835a 100644 --- a/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs +++ b/GamecraftModdingAPI/Blocks/ObjectIdentifier.cs @@ -8,27 +8,22 @@ namespace GamecraftModdingAPI.Blocks { public ObjectIdentifier(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(Id)) - { - throw new BlockTypeException($"Block is not a {GetType().Name} block"); - } } public ObjectIdentifier(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_OBJID_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(Id)) - { - throw new BlockTypeException($"Block is not a {GetType().Name} block"); - } } public char Identifier { - get => (char) (BlockEngine.GetBlockInfo(Id).objectId + 'A'); + get => (char) BlockEngine.GetBlockInfo(this, (ObjectIdEntityStruct st) => st.objectId + 'A'); set { - BlockEngine.GetBlockInfo(Id).objectId = (byte) (value - 'A'); - Label = value + ""; //The label isn't updated automatically + BlockEngine.SetBlockInfo(this, (ref ObjectIdEntityStruct st, char val) => + { + st.objectId = (byte) (val - 'A'); + Label = val + ""; //The label isn't updated automatically + }, value); } } @@ -37,7 +32,7 @@ namespace GamecraftModdingAPI.Blocks /// public byte SimID { - get => BlockEngine.GetBlockInfo(Id).simObjectId; + get => BlockEngine.GetBlockInfo(this, (ObjectIdEntityStruct st) => st.simObjectId); } /// diff --git a/GamecraftModdingAPI/Blocks/Piston.cs b/GamecraftModdingAPI/Blocks/Piston.cs index 2586b60..aed8c33 100644 --- a/GamecraftModdingAPI/Blocks/Piston.cs +++ b/GamecraftModdingAPI/Blocks/Piston.cs @@ -13,18 +13,10 @@ namespace GamecraftModdingAPI.Blocks { public Piston(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public Piston(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_PISTON_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom piston properties @@ -33,13 +25,13 @@ namespace GamecraftModdingAPI.Blocks /// The piston's max extension distance. /// public float MaximumExtension - { - get => BlockEngine.GetBlockInfo(Id).maxDeviation; + { + get => BlockEngine.GetBlockInfo(this, (PistonReadOnlyStruct st) => st.maxDeviation); set { - ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo(Id); - piston.maxDeviation = value; + BlockEngine.SetBlockInfo(this, (ref PistonReadOnlyStruct st, float val) => st.maxDeviation = val, + value); } } @@ -47,13 +39,12 @@ namespace GamecraftModdingAPI.Blocks /// The piston's max extension force. /// public float MaximumForce - { - get => BlockEngine.GetBlockInfo(Id).maxForce; + { + get => BlockEngine.GetBlockInfo(this, (PistonReadOnlyStruct st) => st.maxForce); set { - ref PistonReadOnlyStruct piston = ref BlockEngine.GetBlockInfo(Id); - piston.maxForce = value; + BlockEngine.SetBlockInfo(this, (ref PistonReadOnlyStruct st, float val) => st.maxForce = val, value); } } } diff --git a/GamecraftModdingAPI/Blocks/PlacementEngine.cs b/GamecraftModdingAPI/Blocks/PlacementEngine.cs index 2297d90..61834b0 100644 --- a/GamecraftModdingAPI/Blocks/PlacementEngine.cs +++ b/GamecraftModdingAPI/Blocks/PlacementEngine.cs @@ -40,15 +40,16 @@ namespace GamecraftModdingAPI.Blocks private static BlockEntityFactory _blockEntityFactory; //Injected from PlaceBlockEngine public EGID PlaceBlock(BlockIDs block, BlockColors color, byte darkness, float3 position, int uscale, - float3 scale, Player player, float3 rotation) + float3 scale, Player player, float3 rotation, out EntityComponentInitializer initializer) { //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 if (darkness > 9) throw new Exception("That is too dark. Make sure to use 0-9 as darkness. (0 is default.)"); - return BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation, + initializer = BuildBlock((ushort) block, (byte) (color + darkness * 10), position, uscale, scale, rotation, (player ?? new Player(PlayerType.Local)).Id); + return initializer.EGID; } - private EGID BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId) + private EntityComponentInitializer BuildBlock(ushort block, byte color, float3 position, int uscale, float3 scale, float3 rot, uint playerId) { if (_blockEntityFactory == null) throw new Exception("The factory is null."); @@ -107,7 +108,7 @@ namespace GamecraftModdingAPI.Blocks pickedBlock.placedBlockEntityID = structInitializer.EGID; pickedBlock.placedBlockWasAPickedBlock = false; Block.BlockEngine.Synced = false; // Block entities will need to be submitted before properties can be used - return structInitializer.EGID; + return structInitializer; } public string Name { get; } = "GamecraftModdingAPIPlacementGameEngine"; diff --git a/GamecraftModdingAPI/Blocks/Servo.cs b/GamecraftModdingAPI/Blocks/Servo.cs index c4b57fb..730749a 100644 --- a/GamecraftModdingAPI/Blocks/Servo.cs +++ b/GamecraftModdingAPI/Blocks/Servo.cs @@ -13,18 +13,10 @@ namespace GamecraftModdingAPI.Blocks { public Servo(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public Servo(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SERVO_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom servo properties @@ -33,13 +25,12 @@ namespace GamecraftModdingAPI.Blocks /// The servo's minimum angle. /// public float MinimumAngle - { - get => BlockEngine.GetBlockInfo(Id).minDeviation; + { + get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.minDeviation); set { - ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo(Id); - servo.minDeviation = value; + BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.minDeviation = val, value); } } @@ -48,13 +39,12 @@ namespace GamecraftModdingAPI.Blocks /// public float MaximumAngle { - get => BlockEngine.GetBlockInfo(Id).maxDeviation; + get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.maxDeviation); - set - { - ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo(Id); - servo.maxDeviation = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.maxDeviation = val, value); + } } /// @@ -62,13 +52,12 @@ namespace GamecraftModdingAPI.Blocks /// public float MaximumForce { - get => BlockEngine.GetBlockInfo(Id).maxForce; + get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.maxForce); - set - { - ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo(Id); - servo.maxForce = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, float val) => st.maxForce = val, value); + } } /// @@ -76,13 +65,12 @@ namespace GamecraftModdingAPI.Blocks /// public bool Reverse { - get => BlockEngine.GetBlockInfo(Id).reverse; + get => BlockEngine.GetBlockInfo(this, (ServoReadOnlyStruct st) => st.reverse); - set - { - ref ServoReadOnlyStruct servo = ref BlockEngine.GetBlockInfo(Id); - servo.reverse = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref ServoReadOnlyStruct st, bool val) => st.reverse = val, value); + } } } } diff --git a/GamecraftModdingAPI/Blocks/SignalingBlock.cs b/GamecraftModdingAPI/Blocks/SignalingBlock.cs index 8a62d64..149e450 100644 --- a/GamecraftModdingAPI/Blocks/SignalingBlock.cs +++ b/GamecraftModdingAPI/Blocks/SignalingBlock.cs @@ -16,7 +16,7 @@ namespace GamecraftModdingAPI.Blocks { public SignalingBlock(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) + if (!BlockEngine.GetBlockInfoExists(this)) { throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); } @@ -24,17 +24,12 @@ namespace GamecraftModdingAPI.Blocks public SignalingBlock(uint id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) + if (!BlockEngine.GetBlockInfoExists(this)) { throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); } } - protected ref BlockPortsStruct GetBlockPortsStruct() - { - return ref BlockEngine.GetBlockInfo(Id); - } - /// /// Generates the input port identifiers. /// @@ -53,16 +48,6 @@ namespace GamecraftModdingAPI.Blocks return SignalEngine.GetSignalOutputs(Id); } - /// - /// Gets the port struct. - /// - /// The port struct. - /// Port identifier. - protected ref PortEntityStruct GetPortStruct(EGID portId) - { - return ref BlockEngine.GetBlockInfo(portId); - } - /// /// Gets the connected wire. /// @@ -89,16 +74,16 @@ namespace GamecraftModdingAPI.Blocks /// The input port count. /// public uint InputCount - { - get => GetBlockPortsStruct().inputCount; - } + { + get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.inputCount); + } /// /// The output port count. /// public uint OutputCount { - get => GetBlockPortsStruct().outputCount; + get => BlockEngine.GetBlockInfo(this, (BlockPortsStruct st) => st.outputCount); } } } diff --git a/GamecraftModdingAPI/Blocks/SpawnPoint.cs b/GamecraftModdingAPI/Blocks/SpawnPoint.cs index 4419e38..7616acb 100644 --- a/GamecraftModdingAPI/Blocks/SpawnPoint.cs +++ b/GamecraftModdingAPI/Blocks/SpawnPoint.cs @@ -15,18 +15,10 @@ namespace GamecraftModdingAPI.Blocks { public SpawnPoint(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public SpawnPoint(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_SPAWNPOINT_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom spawn point properties @@ -36,16 +28,12 @@ namespace GamecraftModdingAPI.Blocks /// public uint Lives { - get - { - return BlockEngine.GetBlockInfo(Id).lives; - } + get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.lives); - set - { - ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo(Id); - spses.lives = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, uint val) => st.lives = val, value); + } } /// @@ -53,16 +41,12 @@ namespace GamecraftModdingAPI.Blocks /// public bool Damageable { - get - { - return BlockEngine.GetBlockInfo(Id).canTakeDamage; - } + get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.canTakeDamage); - set - { - ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo(Id); - spses.canTakeDamage = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, bool val) => st.canTakeDamage = val, value); + } } /// @@ -70,16 +54,12 @@ namespace GamecraftModdingAPI.Blocks /// public bool GameOverEnabled { - get - { - return BlockEngine.GetBlockInfo(Id).gameOverScreen; - } + get => BlockEngine.GetBlockInfo(this, (SpawnPointStatsEntityStruct st) => st.gameOverScreen); - set - { - ref SpawnPointStatsEntityStruct spses = ref BlockEngine.GetBlockInfo(Id); - spses.gameOverScreen = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref SpawnPointStatsEntityStruct st, bool val) => st.gameOverScreen = val, value); + } } /// @@ -87,16 +67,12 @@ namespace GamecraftModdingAPI.Blocks /// public byte Team { - get - { - return BlockEngine.GetBlockInfo(Id).teamId; - } + get => BlockEngine.GetBlockInfo(this, (SpawnPointIdsEntityStruct st) => st.teamId); - set - { - ref SpawnPointIdsEntityStruct spses = ref BlockEngine.GetBlockInfo(Id); - spses.teamId = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref SpawnPointIdsEntityStruct st, byte val) => st.teamId = val, value); + } } } } diff --git a/GamecraftModdingAPI/Blocks/TextBlock.cs b/GamecraftModdingAPI/Blocks/TextBlock.cs index 94cf212..6096dd4 100644 --- a/GamecraftModdingAPI/Blocks/TextBlock.cs +++ b/GamecraftModdingAPI/Blocks/TextBlock.cs @@ -14,18 +14,10 @@ namespace GamecraftModdingAPI.Blocks { public TextBlock(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public TextBlock(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TEXT_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom text block properties @@ -35,35 +27,34 @@ namespace GamecraftModdingAPI.Blocks /// public string Text { - get - { - return BlockEngine.GetBlockInfo(Id).textCurrent; - } + get => BlockEngine.GetBlockInfo(this, (TextBlockDataStruct st) => st.textCurrent); - set - { - ref TextBlockDataStruct tbds = ref BlockEngine.GetBlockInfo(Id); - tbds.textCurrent.Set(value); - tbds.textStored.Set(value); - BlockEngine.GetBlockInfo(Id).newTextBlockStringContent.Set(value); - } - } + set + { + BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) => + { + tbds.textCurrent.Set(val); + tbds.textStored.Set(val); + }, value); + BlockEngine.SetBlockInfo(this, + (ref TextBlockNetworkDataStruct st, string val) => st.newTextBlockStringContent.Set(val), value); + } + } /// - /// The text block's current text block ID (used in ChangeTextBlockCommand). + /// The text block's current text block ID (used in ChangeTextBlockCommand). /// - public string TextBlockId + public string TextBlockId { - get - { - return BlockEngine.GetBlockInfo(Id).textBlockID; - } + get => BlockEngine.GetBlockInfo(this, (TextBlockDataStruct st) => st.textBlockID); - set - { - BlockEngine.GetBlockInfo(Id).textBlockID.Set(value); - BlockEngine.GetBlockInfo(Id).newTextBlockID.Set(value); - } + set + { + BlockEngine.SetBlockInfo(this, (ref TextBlockDataStruct tbds, string val) => + tbds.textBlockID.Set(val), value); + BlockEngine.SetBlockInfo(this, + (ref TextBlockNetworkDataStruct st, string val) => st.newTextBlockID.Set(val), value); + } } } } diff --git a/GamecraftModdingAPI/Blocks/Timer.cs b/GamecraftModdingAPI/Blocks/Timer.cs index 2acab5b..5766a41 100644 --- a/GamecraftModdingAPI/Blocks/Timer.cs +++ b/GamecraftModdingAPI/Blocks/Timer.cs @@ -15,18 +15,10 @@ namespace GamecraftModdingAPI.Blocks { public Timer(EGID id) : base(id) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } public Timer(uint id) : base(new EGID(id, CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP)) { - if (!BlockEngine.GetBlockInfoExists(this.Id)) - { - throw new BlockTypeException($"Block is not a {this.GetType().Name} block"); - } } // custom timer properties @@ -36,16 +28,13 @@ namespace GamecraftModdingAPI.Blocks /// public float Start { - get - { - return BlockEngine.GetBlockInfo(Id).startTime; - } + get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.startTime); - set - { - ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo(Id); - tbds.startTime = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, float val) => tbds.startTime = val, + value); + } } /// @@ -53,16 +42,13 @@ namespace GamecraftModdingAPI.Blocks /// public float End { - get - { - return BlockEngine.GetBlockInfo(Id).endTime; - } + get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.endTime); - set - { - ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo(Id); - tbds.endTime = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, float val) => tbds.endTime = val, + value); + } } /// @@ -70,16 +56,13 @@ namespace GamecraftModdingAPI.Blocks /// public bool DisplayMilliseconds { - get - { - return BlockEngine.GetBlockInfo(Id).outputFormatHasMS; - } + get => BlockEngine.GetBlockInfo(this, (TimerBlockDataStruct st) => st.outputFormatHasMS); - set - { - ref TimerBlockDataStruct tbds = ref BlockEngine.GetBlockInfo(Id); - tbds.outputFormatHasMS = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref TimerBlockDataStruct tbds, bool val) => tbds.outputFormatHasMS = val, + value); + } } /// @@ -87,16 +70,13 @@ namespace GamecraftModdingAPI.Blocks /// public int CurrentTime { - get - { - return BlockEngine.GetBlockInfo(Id).timeLastRenderFrameMS; - } + get => BlockEngine.GetBlockInfo(this, (TimerBlockLabelCacheEntityStruct st) => st.timeLastRenderFrameMS); - set - { - ref TimerBlockLabelCacheEntityStruct tblces = ref BlockEngine.GetBlockInfo(Id); - tblces.timeLastRenderFrameMS = value; - } + set + { + BlockEngine.SetBlockInfo(this, (ref TimerBlockLabelCacheEntityStruct tbds, int val) => tbds.timeLastRenderFrameMS = val, + value); + } } } }