Browse Source

improve checks on entity componet fields

tags/2.7
sebas77 5 years ago
parent
commit
07a6d108d6
4 changed files with 144 additions and 99 deletions
  1. +3
    -2
      Svelto.ECS/EnginesRoot.Submission.cs
  2. +131
    -0
      Svelto.ECS/EntityBuilder.CheckFields.cs
  3. +9
    -96
      Svelto.ECS/EntityBuilder.cs
  4. +1
    -1
      Svelto.ECS/ExclusiveGroups.cs

+ 3
- 2
Svelto.ECS/EnginesRoot.Submission.cs View File

@@ -59,7 +59,8 @@ namespace Svelto.ECS
catch (Exception e)
{
#if DEBUG && !PROFILER
var str = "Entity Operation is ".FastConcat(entitiesOperations[i].type.ToString())
var str = "Crash while executing Entity Operation"
.FastConcat(entitiesOperations[i].type.ToString())
.FastConcat(" id: ")
.FastConcat(entitiesOperations[i].ID)
.FastConcat(" to id: ")
@@ -69,7 +70,7 @@ namespace Svelto.ECS
.FastConcat(" to groupid: ")
.FastConcat(entitiesOperations[i].toGroupID);
#if RELAXED_ECS
Console.LogException(str.FastConcat(" ").FastConcat(entitiesOperations[i].trace), e);
Console.LogException(str.FastConcat(" ", entitiesOperations[i].trace), e);
#else
throw new ECSException(str.FastConcat(" ").FastConcat(entitiesOperations[i].trace), e);
#endif


+ 131
- 0
Svelto.ECS/EntityBuilder.CheckFields.cs View File

@@ -0,0 +1,131 @@
#if !DEBUG || PROFILER
#define DISABLE_CHECKS
using System.Diagnostics;
#endif
using System;
using System.Reflection;
using Svelto.ECS.Internal;

namespace Svelto.ECS
{
public partial class EntityBuilder<T>
{
#if DISABLE_CHECKS
[Conditional("_CHECKS_DISABLED")]
#endif
static void CheckFields(Type type, bool needsReflection, bool isRoot)
{
if (ENTITY_VIEW_TYPE == typeof(EntityInfoView)) return;

if (type == EGIDType || type == ExclusiveGroupStructType) return;

{
var methods = type.GetMethods(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);

var properties = type.GetProperties(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);

if (isRoot)
{
if (properties.Length > 1)
ProcessError("EntityViews cannot have public methods or properties", type);
if (methods.Length > properties.Length + 1)
ProcessError("EntityViews cannot have public methods or properties", type);
}
else
{
if (properties.Length > 0)
ProcessError("Entity components fields cannot have public methods or properties", type);

if (methods.Length > 0)
ProcessError("Entity components fields cannot have public methods or properties", type);
}
}

if (needsReflection == false)
{
if (type.IsClass)
throw new ECSException("IEntityStructs must be structs - EntityView: ".FastConcat(ENTITY_VIEW_TYPE));

var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);

for (int i = fields.Length - 1; i >= 0; --i)
{
var field = fields[i];
var fieldFieldType = field.FieldType;

SubCheckFields(fieldFieldType);
}
}
else
{
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);

if (fields.Length < 1)
ProcessError("Entity View Structs must hold entity components interfaces", type);
for (int i = fields.Length - 1; i >= 0; --i)
{
var field = fields[i];
if (field.FieldType.IsInterfaceEx() == false)
ProcessError("Entity View Structs must hold entity components interfaces", type);
var properties = field.FieldType.GetProperties(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);

for (int j = properties.Length - 1; j >= 0; --j)
{
if (properties[j].PropertyType.IsGenericType == true)
{
var genericTypeDefinition = properties[j].PropertyType.GetGenericTypeDefinition();
if (genericTypeDefinition == typeof(DispatchOnSet<>) ||
genericTypeDefinition == typeof(DispatchOnChange<>)) continue;
}
SubCheckFields(properties[j].PropertyType);
}
}
}
}

static void SubCheckFields(Type fieldFieldType)
{
if (fieldFieldType.IsPrimitive == true || fieldFieldType.IsValueType == true)
{
if (fieldFieldType.IsValueType && !fieldFieldType.IsEnum && fieldFieldType.IsPrimitive == false)
{
CheckFields(fieldFieldType, false, false);
}

return;
}
ProcessError("Entity Structs field and Entity View Struct components must hold value types", fieldFieldType);
}
static void ProcessError(string message, Type type)
{
#if !RELAXED_ECS
throw new EntityStructException(message, ENTITY_VIEW_TYPE, type);
#else
Utilities.Console.LogError("Invalid entity view detected - EntityViews must handle only value types and have " +
"no public methods! EntityView ".FastConcat(ENTITY_VIEW_NAME).FastConcat(
" invalid field: ", type.ToString()));
#endif
}

static readonly Type EGIDType = typeof(EGID);
static readonly Type ExclusiveGroupStructType = typeof(ExclusiveGroup.ExclusiveGroupStruct);
}
public class EntityStructException : Exception
{
public EntityStructException(string message, Type entityViewType, Type type):
base(message.FastConcat(" entity view: ", entityViewType.ToString(), " field: ", type.ToString()))
{}
}
}

+ 9
- 96
Svelto.ECS/EntityBuilder.cs View File

@@ -1,9 +1,4 @@
#if !DEBUG || PROFILER
#define DISABLE_CHECKS
using System.Diagnostics;
#endif
using System.Reflection;
using System;
using System;
using System.Collections.Generic;
using Svelto.DataStructures;
using Svelto.ECS.Internal;
@@ -11,93 +6,18 @@ using Svelto.Utilities;

namespace Svelto.ECS
{
public class EntityBuilder<T> : IEntityBuilder where T : IEntityStruct, new()
public partial class EntityBuilder<T> : IEntityBuilder where T : IEntityStruct, new()
{
public EntityBuilder()
{
_initializer = defaultIt;
_initializer = DEFAULT_IT;

CheckFields(ENTITY_VIEW_TYPE);
CheckFields(ENTITY_VIEW_TYPE, NEEDS_REFLECTION, true);

if (needsReflection == true)
if (NEEDS_REFLECTION == true)
EntityView<T>.InitCache();
}

#if DISABLE_CHECKS
[Conditional("_CHECKS_DISABLED")]
#endif
static void CheckFields(Type type)
{
if (ENTITY_VIEW_TYPE == typeof(EntityInfoView)) return;

if (needsReflection == false )
{
if (type.IsClass)
throw new ECSException("IEntityStructs must be structs - EntityView:".FastConcat(typeof(T)));

var fields = type.GetFields(BindingFlags.Public |
BindingFlags.Instance);

for (int i = fields.Length - 1; i >= 0; --i)
{
var field = fields[i];

var fieldFieldType = field.FieldType;

SubCheckFields(fieldFieldType);
}

if (type.Assembly == Assembly.GetCallingAssembly() && type != EGIDType)
{
var methods = type.GetMethods(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);

var properties = type.GetProperties(BindingFlags.Public |
BindingFlags.Instance | BindingFlags.DeclaredOnly);

if (methods.Length > properties.Length + 1)
throw new EntityStructException(type);

for (int i = properties.Length - 1; i >= 0; --i)
{
var propertyInfo = properties[i];

var fieldFieldType = propertyInfo.PropertyType;
SubCheckFields(fieldFieldType);
}
}
}
else
{
var fields = type.GetFields(BindingFlags.Public |
BindingFlags.Instance);

if (fields.Length < 1)
#if !RELAXED_ECS
throw new ECSException("Invalid entity view struct detected - EntityView:".FastConcat(typeof(T)));
#else
Svelto.Utilities.Console.LogError("Invalid entity view struct detected - EntityView:".FastConcat(typeof(T)));
#endif
}
}

static void SubCheckFields(Type fieldFieldType)
{
if (fieldFieldType.IsPrimitive == true || fieldFieldType.IsValueType == true)
{
if (fieldFieldType.IsValueType && !fieldFieldType.IsEnum && fieldFieldType.IsPrimitive == false)
{
CheckFields(fieldFieldType);
}

return;
}

throw new EntityStructException(fieldFieldType);
}

public void BuildEntityAndAddToList(ref ITypeSafeDictionary dictionary, EGID entityID, object[] implementors)
{
if (dictionary == null)
@@ -105,7 +25,7 @@ namespace Svelto.ECS

var castedDic = dictionary as TypeSafeDictionary<T>;

if (needsReflection == true)
if (NEEDS_REFLECTION == true)
{
DBC.ECS.Check.Require(implementors != null, "Implementors not found while building an EntityView");
DBC.ECS.Check.Require(castedDic.ContainsKey(entityID.entityID) == false,
@@ -154,18 +74,11 @@ namespace Svelto.ECS
}
static readonly Type ENTITY_VIEW_TYPE = typeof(T);
static readonly T DEFAULT_IT = default(T);
static readonly bool NEEDS_REFLECTION = typeof(IEntityViewStruct).IsAssignableFrom(typeof(T));
static readonly string ENTITY_VIEW_NAME = ENTITY_VIEW_TYPE.ToString();
static readonly bool needsReflection = typeof(IEntityViewStruct).IsAssignableFrom(typeof(T));
static readonly T defaultIt = default(T);
static readonly Type EGIDType = typeof(EGID);

internal T _initializer;
}

public class EntityStructException : Exception
{
public EntityStructException(Type fieldType) :
base("EntityStruct must contains only value types and no public methods! " + fieldType.ToString())
{}
}
}

+ 1
- 1
Svelto.ECS/ExclusiveGroups.cs View File

@@ -93,7 +93,7 @@ namespace Svelto.ECS
/// <summary>
/// Use this constructor to reserve N groups
/// </summary>
public ExclusiveGroupStruct(ushort range)
internal ExclusiveGroupStruct(ushort range)
{
_id = (int) _globalId;
DBC.ECS.Check.Require(_globalId + range < ushort.MaxValue, "too many exclusive groups created");


Loading…
Cancel
Save