From 15485481a2e4529b9c99d07e116910a39c136521 Mon Sep 17 00:00:00 2001 From: NorbiPeti Date: Tue, 21 Jul 2020 00:19:30 +0200 Subject: [PATCH] Add some info and prev. value for setters --- GamecraftModdingAPI/Block.cs | 18 ++++++++++++++++-- GamecraftModdingAPI/Blocks/BlockEngine.cs | 5 +++-- GamecraftModdingAPI/Blocks/BlockEngineInit.cs | 6 ++++++ 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/GamecraftModdingAPI/Block.cs b/GamecraftModdingAPI/Block.cs index dc3fe19..5f30a64 100644 --- a/GamecraftModdingAPI/Block.cs +++ b/GamecraftModdingAPI/Block.cs @@ -137,6 +137,16 @@ namespace GamecraftModdingAPI {typeof(Timer), new[] {CommonExclusiveGroups.BUILD_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 { var type = typeof(T); @@ -175,8 +185,8 @@ namespace GamecraftModdingAPI 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); - il.Emit(OpCodes.Ldloc_0); + //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)); @@ -188,6 +198,9 @@ namespace GamecraftModdingAPI public Block(EGID id) { Id = id; + if (typeToGroup.TryGetValue(GetType(), out var groups) && 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); } /// @@ -328,6 +341,7 @@ namespace GamecraftModdingAPI /// /// Whether the block exists. The other properties will return a default value if the block doesn't exist. + /// If the block was just placed, then this will also return false but the properties will work correctly. /// public bool Exists => BlockEngine.BlockExists(Id); diff --git a/GamecraftModdingAPI/Blocks/BlockEngine.cs b/GamecraftModdingAPI/Blocks/BlockEngine.cs index 375620e..f97e405 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngine.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngine.cs @@ -85,10 +85,11 @@ namespace GamecraftModdingAPI.Blocks { if (entitiesDB.Exists(block.Id)) setter(ref entitiesDB.QueryEntity(block.Id), value); - if (block.InitData.Group != null) + else if (block.InitData.Group != null) { 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 + T component = initializer.Has() ? initializer.Get() : default; + ref T structRef = ref component; setter(ref structRef, value); initializer.Init(structRef); } diff --git a/GamecraftModdingAPI/Blocks/BlockEngineInit.cs b/GamecraftModdingAPI/Blocks/BlockEngineInit.cs index 4be9a98..70f713a 100644 --- a/GamecraftModdingAPI/Blocks/BlockEngineInit.cs +++ b/GamecraftModdingAPI/Blocks/BlockEngineInit.cs @@ -9,6 +9,9 @@ namespace GamecraftModdingAPI.Blocks { public partial class BlockEngine { + /// + /// Holds information needed to construct a component initializer + /// internal struct BlockInitData { public FasterDictionary, ITypeSafeDictionary> Group; @@ -17,6 +20,9 @@ namespace GamecraftModdingAPI.Blocks internal delegate FasterDictionary, ITypeSafeDictionary> GetInitGroup( EntityComponentInitializer initializer); + /// + /// Accesses the group field of the initializer + /// internal GetInitGroup InitGroup = CreateAccessor("_group"); //https://stackoverflow.com/questions/55878525/unit-testing-ref-structs-with-private-fields-via-reflection