Add some info and prev. value for setters

This commit is contained in:
Norbi Peti 2020-07-21 00:19:30 +02:00
parent 16521ab7eb
commit 3f2139d592
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
3 changed files with 25 additions and 4 deletions

View file

@ -137,6 +137,16 @@ namespace GamecraftModdingAPI
{typeof(Timer), new[] {CommonExclusiveGroups.BUILD_TIMER_BLOCK_GROUP}}
};
/// <summary>
/// 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.
/// </summary>
/// <param name="id">The block ID</param>
/// <param name="group">The block group</param>
/// <typeparam name="T">The block's type or Block itself</typeparam>
/// <returns>An instance of the provided type</returns>
/// <exception cref="BlockTypeException">The block group doesn't match or cannot be found</exception>
/// <exception cref="MissingMethodException">The block class doesn't have the needed constructor</exception>
private static T New<T>(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<EGID, T>) dynamic.CreateDelegate(typeof(Func<EGID, T>));
@ -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);
}
/// <summary>
@ -328,6 +341,7 @@ namespace GamecraftModdingAPI
/// <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);

View file

@ -85,10 +85,11 @@ namespace GamecraftModdingAPI.Blocks
{
if (entitiesDB.Exists<T>(block.Id))
setter(ref entitiesDB.QueryEntity<T>(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<T>() ? initializer.Get<T>() : default;
ref T structRef = ref component;
setter(ref structRef, value);
initializer.Init(structRef);
}

View file

@ -9,6 +9,9 @@ namespace GamecraftModdingAPI.Blocks
{
public partial class BlockEngine
{
/// <summary>
/// Holds information needed to construct a component initializer
/// </summary>
internal struct BlockInitData
{
public FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> Group;
@ -17,6 +20,9 @@ namespace GamecraftModdingAPI.Blocks
internal delegate FasterDictionary<RefWrapper<Type>, ITypeSafeDictionary> GetInitGroup(
EntityComponentInitializer initializer);
/// <summary>
/// Accesses the group field of the initializer
/// </summary>
internal GetInitGroup InitGroup = CreateAccessor<GetInitGroup>("_group");
//https://stackoverflow.com/questions/55878525/unit-testing-ref-structs-with-private-fields-via-reflection