diff --git a/TechbloxModdingAPI/Block.cs b/TechbloxModdingAPI/Block.cs
index 64b8231..e8626fc 100644
--- a/TechbloxModdingAPI/Block.cs
+++ b/TechbloxModdingAPI/Block.cs
@@ -39,45 +39,17 @@ namespace TechbloxModdingAPI
/// The placed block will be a complete block with a placement grid and collision which will be saved along with the game.
///
/// The block's type
- /// The block's color
- /// The block's material
/// The block's position - default block size is 0.2
- /// The block's rotation in degrees
- /// The block's uniform scale - default scale is 1 (with 0.2 width)
- /// The block's non-uniform scale - 0 means is used
- /// Whether the block should be flipped
/// Whether the block should be auto-wired (if functional)
/// The player who placed the block
/// The placed block or null if failed
public static Block PlaceNew(BlockIDs block, float3 position, bool autoWire = false, Player player = null)
- {
- return PlaceNew(block, position, autoWire, player);
- }
-
- ///
- /// Place a new block at the given position. If scaled, position means the center of the block. The default block size is 0.2 in terms of position.
- /// Place blocks next to each other to connect them.
- /// The placed block will be a complete block with a placement grid and collision which will be saved along with the game.
- ///
- /// The block's type
- /// The block's color
- /// The block's materialr
- /// The block's position - default block size is 0.2
- /// The block's rotation in degrees
- /// The block's uniform scale - default scale is 1 (with 0.2 width)
- /// The block's non-uniform scale - 0 means is used
- /// Whether the block should be flipped
- /// Whether the block should be auto-wired (if functional)
- /// The player who placed the block
- /// The placed block or null if failed
- public static T PlaceNew(BlockIDs block, float3 position, bool autoWire = false, Player player = null)
- where T : Block
{
if (PlacementEngine.IsInGame && GameState.IsBuildMode())
{
var initializer = PlacementEngine.PlaceBlock(block, position, player, autoWire);
var egid = initializer.EGID;
- var bl = New(egid.entityID, egid.groupID);
+ var bl = New(egid);
bl.InitData = initializer;
Placed += bl.OnPlacedInit;
return bl;
@@ -89,10 +61,11 @@ namespace TechbloxModdingAPI
///
/// Returns the most recently placed block.
///
- /// The block object
+ /// The block object or null if doesn't exist
public static Block GetLastPlacedBlock()
{
- return New(BlockIdentifiers.LatestBlockID);
+ EGID? egid = BlockEngine.FindBlockEGID(BlockIdentifiers.LatestBlockID);
+ return egid.HasValue ? New(egid.Value) : null;
}
///
@@ -113,108 +86,35 @@ namespace TechbloxModdingAPI
remove => BlockEventsEngine.Removed -= value;
}
- private static Dictionary> initializers = new Dictionary>();
-
- private static Dictionary typeToGroup =
- new Dictionary
+ private static readonly Dictionary> GroupToConstructor =
+ new Dictionary>
{
- {typeof(LogicGate), new [] {CommonExclusiveGroups.LOGIC_BLOCK_GROUP}},
- {typeof(Motor), new[] {CommonExclusiveGroups.MOTOR_BLOCK_GROUP}},
- {typeof(MusicBlock), new[] {CommonExclusiveGroups.MUSIC_BLOCK_GROUP}},
- {typeof(ObjectIdentifier), new[]{CommonExclusiveGroups.OBJID_BLOCK_GROUP}},
- {typeof(Piston), new[] {CommonExclusiveGroups.PISTON_BLOCK_GROUP}},
- {typeof(Servo), new[] {CommonExclusiveGroups.SERVO_BLOCK_GROUP}},
- {
- typeof(SpawnPoint),
- new[]
- {
- CommonExclusiveGroups.SPAWNPOINT_BLOCK_GROUP,
- CommonExclusiveGroups.BUILDINGSPAWN_BLOCK_GROUP
- }
- },
- {
- typeof(SfxBlock),
- new[]
- {
- CommonExclusiveGroups.SIMPLESFX_BLOCK_GROUP,
- CommonExclusiveGroups.LOOPEDSFX_BLOCK_GROUP
- }
- },
- {typeof(DampedSpring), new [] {CommonExclusiveGroups.DAMPEDSPRING_BLOCK_GROUP}},
- {typeof(TextBlock), new[] {CommonExclusiveGroups.TEXT_BLOCK_GROUP}},
- {typeof(Timer), new[] {CommonExclusiveGroups.TIMER_BLOCK_GROUP}}
- };
-
- ///
- /// Constructs a new instance of T with the given ID and group using dynamically created delegates.
- /// It's equivalent to new T(EGID) with a minimal overhead thanks to caching the created delegates.
- ///
- /// The block ID
- /// The block group
- /// The block's type or Block itself
- /// An instance of the provided type
- /// The block group doesn't match or cannot be found
- /// The block class doesn't have the needed constructor
- private static T New(uint id, ExclusiveGroupStruct? group = null) where T : Block
+ {CommonExclusiveGroups.LOGIC_BLOCK_GROUP, id => new LogicGate(id)},
+ {CommonExclusiveGroups.MOTOR_BLOCK_GROUP, id => new Motor(id)},
+ {CommonExclusiveGroups.MUSIC_BLOCK_GROUP, id => new MusicBlock(id)},
+ {CommonExclusiveGroups.OBJID_BLOCK_GROUP, id => new ObjectIdentifier(id)},
+ {CommonExclusiveGroups.PISTON_BLOCK_GROUP, id => new Piston(id)},
+ {CommonExclusiveGroups.SERVO_BLOCK_GROUP, id => new Servo(id)},
+ {CommonExclusiveGroups.SPAWNPOINT_BLOCK_GROUP, id => new SpawnPoint(id)},
+ {CommonExclusiveGroups.BUILDINGSPAWN_BLOCK_GROUP, id => new SpawnPoint(id)},
+ {CommonExclusiveGroups.SIMPLESFX_BLOCK_GROUP, id => new SfxBlock(id)},
+ {CommonExclusiveGroups.LOOPEDSFX_BLOCK_GROUP, id => new SfxBlock(id)},
+ {CommonExclusiveGroups.DAMPEDSPRING_BLOCK_GROUP, id => new DampedSpring(id)},
+ {CommonExclusiveGroups.TEXT_BLOCK_GROUP, id => new TextBlock(id)},
+ {CommonExclusiveGroups.TIMER_BLOCK_GROUP, id => new Timer(id)}
+ };/*.SelectMany(kv => kv.Value.Select(v => (Key: v, Value: kv.Key)))
+ .ToDictionary(kv => kv.Key, kv => kv.Value);*/
+
+ private static Block New(EGID egid)
{
- var type = typeof(T);
- EGID egid;
- if (!group.HasValue)
- {
- if (typeToGroup.TryGetValue(type, out var gr) && gr.Length == 1)
- egid = new EGID(id, gr[0]);
- else
- egid = BlockEngine.FindBlockEGID(id) ?? throw new BlockTypeException("Could not find block group!");
- }
- else
- {
- egid = new EGID(id, group.Value);
- if (typeToGroup.TryGetValue(type, out var gr)
- && gr.All(egs => egs != group.Value)) //If this subclass has a specific group, then use that - so Block should still work
- throw new BlockTypeException($"Incompatible block type! Type {type.Name} belongs to group {gr.Select(g => ((uint)g).ToString()).Aggregate((a, b) => a + ", " + b)} instead of {(uint)group.Value}");
- }
-
- if (initializers.TryGetValue(type, out var func))
- {
- var bl = (T) func(egid);
- return bl;
- }
-
- //https://stackoverflow.com/a/10593806/2703239
- var ctor = type.GetConstructor(new[] {typeof(EGID)});
- if (ctor == null)
- throw new MissingMethodException("There is no constructor with an EGID parameter for this object");
- DynamicMethod dynamic = new DynamicMethod(string.Empty,
- type,
- new[] {typeof(EGID)},
- type);
- ILGenerator il = dynamic.GetILGenerator();
-
- //il.DeclareLocal(type);
- il.Emit(OpCodes.Ldarg_0); //Load EGID and pass to constructor
- il.Emit(OpCodes.Newobj, ctor); //Call constructor
- //il.Emit(OpCodes.Stloc_0); - doesn't seem like we need these
- //il.Emit(OpCodes.Ldloc_0);
- il.Emit(OpCodes.Ret);
-
- func = (Func) dynamic.CreateDelegate(typeof(Func));
- initializers.Add(type, func);
- var block = (T) func(egid);
- return block;
+ return GroupToConstructor.ContainsKey(egid.groupID)
+ ? GroupToConstructor[egid.groupID](egid)
+ : new Block(egid);
}
public Block(EGID id)
{
- Id = id;
- var type = GetType();
- if (typeToGroup.TryGetValue(type, out var groups))
- {
- if (groups.All(gr => gr != id.groupID))
- throw new BlockTypeException("The block has the wrong group! The type is " + GetType() +
- " while the group is " + id.groupID);
- }
- else if (type != typeof(Block) && !typeof(CustomBlock).IsAssignableFrom(type))
- Logging.LogWarning($"Unknown block type! Add {type} to the dictionary.");
+ Id = id; //TODO: Check if block type is correct
}
///
@@ -224,7 +124,9 @@ namespace TechbloxModdingAPI
///
public Block(uint id)
{
- Id = BlockEngine.FindBlockEGID(id) ?? throw new BlockTypeException("Could not find the appropriate group for the block. The block probably doesn't exist or hasn't been submitted.");
+ Id = BlockEngine.FindBlockEGID(id)
+ ?? throw new BlockTypeException("Could not find the appropriate group for the block." +
+ " The block probably doesn't exist or hasn't been submitted.");
}
///
@@ -471,9 +373,9 @@ namespace TechbloxModdingAPI
/// Creates a copy of the block in the game with the same properties, stats and wires.
///
///
- public T Copy() where T : Block
+ public Block Copy()
{
- var block = PlaceNew(Type, Position);
+ var block = PlaceNew(Type, Position);
block.Rotation = Rotation;
block.Color = Color;
block.Material = Material;
@@ -535,38 +437,5 @@ namespace TechbloxModdingAPI
GameEngineManager.AddGameEngine(BlockCloneEngine);
Wire.signalEngine = SignalEngine; // requires same functionality, no need to duplicate the engine
}
-
- ///
- /// Convert the block to a specialised block class.
- ///
- /// The block.
- /// The specialised block type.
- public T Specialise() where T : Block
- {
- // What have I gotten myself into?
- // C# can't cast to a child of Block unless the object was originally that child type
- // And C# doesn't let me make implicit cast operators for child types
- // So thanks to Microsoft, we've got this horrible implementation using reflection
-
- //Lets improve that using delegates
- var block = New(Id.entityID, Id.groupID);
- if (this.InitData.Valid)
- {
- block.InitData = this.InitData;
- Placed += block.OnPlacedInit; //Reset InitData of new object
- }
-
- return block;
- }
-
-#if DEBUG
- public static EntitiesDB entitiesDB
- {
- get
- {
- return BlockEngine.GetEntitiesDB();
- }
- }
-#endif
}
}
\ No newline at end of file
diff --git a/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs b/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs
index 2274600..f794b4d 100644
--- a/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs
+++ b/TechbloxModdingAPI/Tests/TechbloxModdingAPIPluginTest.cs
@@ -313,7 +313,7 @@ namespace TechbloxModdingAPI.Tests
.Action((float x, float y, float z) =>
{
Logging.CommandLog("Block placed: " +
- Block.PlaceNew((BlockIDs) 500, new float3(0, 0, 0)));
+ Block.PlaceNew((BlockIDs) 500, new float3(0, 0, 0)));
}).Build();
GameClient.SetDebugInfo("InstalledMods", InstalledMods);