static string addGetMethods(ComponentInfo componentInfo) { var getMethod = componentInfo.isSingletonComponent ? "\n static readonly $Type $nameComponent = new $Type();\n" : "\n public $Type $name { get { return ($Type)GetComponent($Ids.$Name); } }\n"; return buildString(componentInfo, getMethod); }
static string generateIndicesLookup(string lookupTag, ComponentInfo[] componentInfos) { return addClassHeader(lookupTag) + addIndices(componentInfos) + addComponentNames(componentInfos) + addComponentTypes(componentInfos) + addCloseClass(); }
/// <summary> /// Generates the contents of the source code files to write. /// </summary> /// <param name="componentInfos">Data about all available entity components.</param> /// <returns>Contents and names of the source code files to write.</returns> public CodeGenFile[] Generate(ComponentInfo[] componentInfos) { // Generate methods for initializing components from dictionaries. var codeGenFiles = componentInfos.Where(info => info.generateMethods && !info.isSingletonComponent) .Select( info => new CodeGenFile { fileName = info.fullTypeName + ClassFileNameSuffix, fileContent = AddDefaultPoolCode(info).ToUnixLineEndings() }) .ToList(); // Generate methods for creating entities and adding components from blueprints. codeGenFiles.Add( new CodeGenFile { fileName = "BlueprintPoolExtensions", fileContent = AddBlueprintPoolCode(componentInfos.Where(info => info.generateMethods)).ToUnixLineEndings() }); return codeGenFiles.ToArray(); }
static string addHasMethods(ComponentInfo componentInfo) { var hasMethod = componentInfo.isSingletonComponent ? @" public bool $prefix$Name { get { return HasComponent($Ids.$Name); } set { if (value != $prefix$Name) { if (value) { AddComponent($Ids.$Name, $nameComponent); } else { RemoveComponent($Ids.$Name); } } } } public Entity $Prefix$Name(bool value) { $prefix$Name = value; return this; } " : @" public bool has$Name { get { return HasComponent($Ids.$Name); } } "; return buildString(componentInfo, hasMethod); }
public CodeGenFile[] Generate(ComponentInfo[] componentInfos) { return componentInfos .Where(info => info.generateMethods) .Select(info => new CodeGenFile { fileName = info.fullTypeName + CLASS_SUFFIX, fileContent = generateComponentExtension(info).ToUnixLineEndings() }).ToArray(); }
// Important: This method should be called after Generate(poolNames) // This will overwrite the empty lookups with the actual content. public CodeGenFile[] Generate(ComponentInfo[] componentInfos) { var orderedComponentInfos = componentInfos.OrderBy(info => info.typeName).ToArray(); var lookupTagToComponentInfosMap = getLookupTagToComponentInfosMap(orderedComponentInfos); return lookupTagToComponentInfosMap .Select(kv => new CodeGenFile { fileName = kv.Key, fileContent = generateIndicesLookup(kv.Key, kv.Value.ToArray()).ToUnixLineEndings() }).ToArray(); }
/* * * ENTITY METHODS * */ static string addEntityMethods(ComponentInfo componentInfo) { return addEntityClassHeader() + addGetMethods(componentInfo) + addHasMethods(componentInfo) + addAddMethods(componentInfo) + addReplaceMethods(componentInfo) + addRemoveMethods(componentInfo) + addCloseClass(); }
static string addAddMethods(ComponentInfo componentInfo) { return componentInfo.isSingletonComponent ? string.Empty : buildString(componentInfo, @" public Entity Add$Name($typedArgs) { var component = CreateComponent<$Type>($Ids.$Name); $assign return AddComponent($Ids.$Name, component); } "); }
static string addContextGetMethods(ComponentInfo componentInfo) { var getMehod = componentInfo.isSingletonComponent ? @" public Entity $nameEntity { get { return GetGroup($TagMatcher.$Name).GetSingleEntity(); } } " : @" public Entity $nameEntity { get { return GetGroup($TagMatcher.$Name).GetSingleEntity(); } } public $Type $name { get { return $nameEntity.$name; } } "; return buildString(componentInfo, getMehod); }
static string addDefaultPoolCode(ComponentInfo componentInfo) { var code = addNamespace(); code += addEntityMethods(componentInfo); if (componentInfo.isSingleEntity) { code += addPoolMethods(componentInfo); } code += addMatcher(componentInfo); code += closeNamespace(); return code; }
public CodeGenFile[] Generate(ComponentInfo[] componentInfos) { var generatorName = GetType().FullName; return componentInfos .Where(info => info.generateMethods) .Select(info => new CodeGenFile( info.fullTypeName + "GeneratedExtension", generateComponentExtension(info), generatorName )).ToArray(); }
static string addAddMethods(ComponentInfo componentInfo) { return componentInfo.isSingletonComponent ? string.Empty : buildString(componentInfo, @" public Entity Add$Name($typedArgs) { var componentPool = GetComponentPool($Ids.$Name); var component = ($Type)(componentPool.Count > 0 ? componentPool.Pop() : new $Type()); $assign return AddComponent($Ids.$Name, component); } "); }
// Important: This method should be called before Generate(componentInfos) // This will generate empty lookups for all contexts. public CodeGenFile[] Generate(string[] contextNames) { var emptyInfos = new ComponentInfo[0]; var generatorName = GetType().FullName; return contextNames .Select(contextName => contextName.ContextPrefix() + CodeGenerator.DEFAULT_COMPONENT_LOOKUP_TAG) .Select(lookupTag => new CodeGenFile( lookupTag, generateIndicesLookup(lookupTag, emptyInfos), generatorName )).ToArray(); }
// Important: This method should be called after Generate(contextNames) // This will overwrite the empty lookups with the actual content. public CodeGenFile[] Generate(ComponentInfo[] componentInfos) { var orderedComponentInfos = componentInfos.OrderBy(info => info.typeName).ToArray(); var lookupTagToComponentInfosMap = getLookupTagToComponentInfosMap(orderedComponentInfos); var generatorName = GetType().FullName; return lookupTagToComponentInfosMap .Select(kv => new CodeGenFile( kv.Key, generateIndicesLookup(kv.Key, kv.Value.ToArray()), generatorName )).ToArray(); }
// Important: This method should be called before Generate(componentInfos) // This will generate empty lookups for all pools. public CodeGenFile[] Generate(string[] poolNames) { var emptyInfos = new ComponentInfo[0]; if (poolNames.Length == 0) { poolNames = new [] { string.Empty }; } return poolNames .Select(poolName => poolName + CodeGenerator.DEFAULT_COMPONENT_LOOKUP_TAG) .Select(lookupTag => new CodeGenFile { fileName = lookupTag, fileContent = generateIndicesLookup(lookupTag, emptyInfos).ToUnixLineEndings() }).ToArray(); }
// Important: This method should be called before Generate(componentInfos) // This will generate empty lookups for all pools. public CodeGenFile[] Generate(string[] poolNames) { var emptyInfos = new ComponentInfo[0]; var generatorName = GetType().FullName; return(poolNames .Select(poolName => poolName.PoolPrefix() + CodeGenerator.DEFAULT_COMPONENT_LOOKUP_TAG) .Select(lookupTag => new CodeGenFile( lookupTag, generateIndicesLookup(lookupTag, emptyInfos), generatorName )).ToArray()); }
static string addDefaultPoolCode(ComponentInfo componentInfo) { var code = addNamespace(); code += addEntityMethods(componentInfo); if (componentInfo.isSingleEntity) { code += addPoolMethods(componentInfo); } code += addMatcher(componentInfo); code += closeNamespace(); return(code); }
/* * * MATCHER * */ static string addMatcher(ComponentInfo componentInfo, bool onlyDefault = false) { const string matcherFormat = @" public partial class $TagMatcher { static IMatcher _matcher$Name; public static IMatcher $Name { get { if(_matcher$Name == null) { var matcher = (Matcher)Matcher.AllOf($Ids.$Name); matcher.componentNames = $Ids.componentNames; _matcher$Name = matcher; } return _matcher$Name; } } } "; if (onlyDefault) { if (componentInfo.contexts.Contains(CodeGenerator.DEFAULT_CONTEXT_NAME)) { return(buildString(componentInfo, matcherFormat)); } else { return(string.Empty); } } else { var contextIndex = 0; var matchers = componentInfo.contexts.Aggregate(string.Empty, (acc, contextName) => { if (!contextName.IsDefaultContextName()) { return(acc + buildString(componentInfo, matcherFormat, contextIndex++)); } else { contextIndex += 1; return(acc); } }); return(buildString(componentInfo, matchers)); } }
static object addPoolAddMethods(ComponentInfo componentInfo) { return(componentInfo.isSingletonComponent ? string.Empty : buildString(componentInfo, @" public Entity Set$Name($typedArgs) { if (has$Name) { throw new EntitasException(""Could not set $name!\n"" + this + "" already has an entity with $Type!"", ""You should check if the pool already has a $nameEntity before setting it or use pool.Replace$Name().""); } var entity = CreateEntity(); entity.Add$Name($args); return entity; } ")); }
static string addIndices(ComponentInfo[] componentInfos) { const string fieldFormat = " public const int {0} = {1};\n"; const string totalFormat = " public const int TotalComponents = {0};"; var code = string.Empty; for (int i = 0; i < componentInfos.Length; i++) { var info = componentInfos[i]; if (info != null) { code += string.Format(fieldFormat, info.typeName.RemoveComponentSuffix(), i); } } var totalComponents = string.Format(totalFormat, componentInfos.Count(info => info != null)); return code + "\n" + totalComponents; }
static object addContextAddMethods(ComponentInfo componentInfo) { return componentInfo.isSingletonComponent ? string.Empty : buildString(componentInfo, @" public Entity Set$Name($typedArgs) { if(has$Name) { throw new EntitasException(""Could not set $name!\n"" + this + "" already has an entity with $Type!"", ""You should check if the context already has a $nameEntity before setting it or use context.Replace$Name().""); } var entity = CreateEntity(); entity.Add$Name($args); return entity; } "); }
static string addPoolReplaceMethods(ComponentInfo componentInfo) { return(componentInfo.isSingletonComponent ? string.Empty : buildString(componentInfo, @" public Entity Replace$Name($typedArgs) { var entity = $nameEntity; if (entity == null) { entity = Set$Name($args); } else { entity.Replace$Name($args); } return entity; } ")); }
// Important: This method should be called before Generate(componentInfos) // This will generate empty lookups for all pools. public CodeGenFile[] Generate(string[] poolNames) { var emptyInfos = new ComponentInfo[0]; if (poolNames.Length == 0) { poolNames = new [] { string.Empty }; } return(poolNames .Select(poolName => poolName + CodeGenerator.DEFAULT_COMPONENT_LOOKUP_TAG) .Select(lookupTag => new CodeGenFile { fileName = lookupTag, fileContent = generateIndicesLookup(lookupTag, emptyInfos).ToUnixLineEndings() }).ToArray()); }
static string generateComponent(ComponentInfo componentInfo) { const string hideInBlueprintInspector = "[Entitas.Serialization.Blueprints.HideInBlueprintInspectorAttribute]\n"; const string componentFormat = @"public class {0} : IComponent {{ public {1} {2}; }} "; var memberInfo = componentInfo.memberInfos[0]; var code = string.Format(componentFormat, componentInfo.fullTypeName, memberInfo.type, memberInfo.name); return(componentInfo.hideInBlueprintInspector ? hideInBlueprintInspector + code : code); }
static string addComponentNames(ComponentInfo[] componentInfos) { const string format = " \"{1}\",\n"; var code = string.Empty; for (int i = 0; i < componentInfos.Length; i++) { var info = componentInfos[i]; if (info != null) { code += string.Format(format, i, info.typeName.RemoveComponentSuffix()); } } if (code.EndsWith(",\n")) { code = code.Remove(code.Length - 2) + "\n"; } return string.Format(@" public static readonly string[] componentNames = {{ {0} }};", code); }
static string addComponentTypes(ComponentInfo[] componentInfos) { const string format = " typeof({1}),\n"; var code = string.Empty; for (int i = 0; i < componentInfos.Length; i++) { var info = componentInfos[i]; if (info != null) { code += string.Format(format, i, info.fullTypeName); } } if (code.EndsWith(",\n")) { code = code.Remove(code.Length - 2) + "\n"; } return string.Format(@" public static readonly System.Type[] componentTypes = {{ {0} }};", code); }
static string addContextHasMethods(ComponentInfo componentInfo) { var hasMethod = componentInfo.isSingletonComponent ? @" public bool $prefix$Name { get { return $nameEntity != null; } set { var entity = $nameEntity; if(value != (entity != null)) { if(value) { CreateEntity().$prefix$Name = true; } else { DestroyEntity(entity); } } } } " : @" public bool has$Name { get { return $nameEntity != null; } } "; return buildString(componentInfo, hasMethod); }
static string addContextHasMethods(ComponentInfo componentInfo) { var hasMethod = componentInfo.isSingletonComponent ? @" public bool $prefix$Name { get { return $nameEntity != null; } set { var entity = $nameEntity; if(value != (entity != null)) { if(value) { CreateEntity().$prefix$Name = true; } else { DestroyEntity(entity); } } } } " : @" public bool has$Name { get { return $nameEntity != null; } } "; return(buildString(componentInfo, hasMethod)); }
/* * * HELPERS * */ static string buildString(ComponentInfo componentInfo, string format) { format = createFormatString(format); var a0_type = componentInfo.fullTypeName; var a1_name = componentInfo.typeName.RemoveComponentSuffix(); var a2_lowercaseName = a1_name.LowercaseFirst(); var poolNames = componentInfo.pools; var a3_tag = poolNames.Length == 0 ? string.Empty : poolNames[0]; var lookupTags = componentInfo.ComponentLookupTags(); var a4_ids = lookupTags.Length == 0 ? string.Empty : lookupTags[0]; var fieldInfos = componentInfo.fieldInfos; var a5_fieldNamesWithType = fieldNamesWithType(fieldInfos); var a6_fieldAssigns = fieldAssignments(fieldInfos); var a7_fieldNames = fieldNames(fieldInfos); var prefix = componentInfo.singleComponentPrefix; var a8_prefix = prefix.UppercaseFirst(); var a9_lowercasePrefix = prefix.LowercaseFirst(); return(string.Format(format, a0_type, a1_name, a2_lowercaseName, a3_tag, a4_ids, a5_fieldNamesWithType, a6_fieldAssigns, a7_fieldNames, a8_prefix, a9_lowercasePrefix)); }
/* * * HELPERS * */ static string buildString(ComponentInfo componentInfo, string format, int contextIndex = 0) { format = createFormatString(format); var a0_type = componentInfo.fullTypeName; var a1_name = componentInfo.typeName.RemoveComponentSuffix(); var a2_lowercaseName = a1_name.LowercaseFirst(); var contextNames = componentInfo.contexts; var a3_tag = contextNames[contextIndex].ContextPrefix(); var lookupTags = componentInfo.ComponentLookupTags(); var a4_ids = lookupTags.Length == 0 ? string.Empty : lookupTags[contextIndex]; var memberInfos = componentInfo.memberInfos; var a5_memberNamesWithType = memberNamesWithType(memberInfos); var a6_memberAssigns = memberAssignments(memberInfos); var a7_memberNames = memberNames(memberInfos); var prefix = componentInfo.singleComponentPrefix; var a8_prefix = prefix.UppercaseFirst(); var a9_lowercasePrefix = prefix.LowercaseFirst(); return(string.Format(format, a0_type, a1_name, a2_lowercaseName, a3_tag, a4_ids, a5_memberNamesWithType, a6_memberAssigns, a7_memberNames, a8_prefix, a9_lowercasePrefix)); }
static string generateComponentExtension(ComponentInfo componentInfo) { var code = addNamespace(); code += addEntityMethods(componentInfo); if (componentInfo.isSingleEntity) { code += addPoolMethods(componentInfo); } if (componentInfo.generateComponent) { // Add default matcher code += addMatcher(componentInfo, true); code += closeNamespace(); // Add custom matchers code += addMatcher(componentInfo); return(addUsings("Entitas") + generateComponent(componentInfo) + code); } if (componentInfo.pools.Length == 0) { code += addMatcher(componentInfo); code += closeNamespace(); } else { // Add default matcher code += addMatcher(componentInfo, true); code += closeNamespace(); // Add custom matchers code += addMatcher(componentInfo); code = addUsings("Entitas") + code; } return(code); }
static Dictionary<string, ComponentInfo[]> getLookupTagToComponentInfosMap(ComponentInfo[] componentInfos) { var currentIndex = 0; var orderedComponentInfoToLookupTagsMap = componentInfos .Where(info => info.generateIndex) .ToDictionary(info => info, info => info.ComponentLookupTags()) .OrderByDescending(kv => kv.Value.Length); return orderedComponentInfoToLookupTagsMap .Aggregate(new Dictionary<string, ComponentInfo[]>(), (map, kv) => { var info = kv.Key; var lookupTags = kv.Value; var incrementIndex = false; foreach (var lookupTag in lookupTags) { if (!map.ContainsKey(lookupTag)) { map.Add(lookupTag, new ComponentInfo[componentInfos.Length]); } var infos = map[lookupTag]; if (lookupTags.Length == 1) { // Component has only one lookupTag. Insert at next free slot. for (int i = 0; i < infos.Length; i++) { if (infos[i] == null) { infos[i] = info; break; } } } else { // Component has multiple lookupTags. Set at current index in all lookups. infos[currentIndex] = info; incrementIndex = true; } } if (incrementIndex) { currentIndex++; } return map; }); }
public static string[] ComponentLookupTags(this ComponentInfo componentInfo) { return(componentInfo.pools .Select(poolName => poolName.PoolPrefix() + CodeGenerator.DEFAULT_COMPONENT_LOOKUP_TAG) .ToArray()); }
public static string[] ComponentLookupTags(this ComponentInfo componentInfo) { return(componentInfo.contexts .Select(contextName => contextName.ContextPrefix() + CodeGenerator.DEFAULT_COMPONENT_LOOKUP_TAG) .ToArray()); }
static string generateComponentExtension(ComponentInfo componentInfo) { return(componentInfo.pools.Length == 0 ? addDefaultPoolCode(componentInfo) : addCustomPoolCode(componentInfo)); }
static string generateComponent(ComponentInfo componentInfo) { const string componentFormat = @"public class {0} : IComponent {{ public {1} {2}; }} "; var memberInfo = componentInfo.memberInfos[0]; return string.Format(componentFormat, componentInfo.fullTypeName, memberInfo.type, memberInfo.name); }
static string generateComponentExtension(ComponentInfo componentInfo) { var code = addNamespace(); code += addEntityMethods(componentInfo); if (componentInfo.isSingleEntity) { code += addPoolMethods(componentInfo); } if (componentInfo.generateComponent) { // Add default matcher code += addMatcher(componentInfo, true); code += closeNamespace(); // Add custom matchers code += addMatcher(componentInfo); return addUsings("Entitas") + generateComponent(componentInfo) + code; } if (componentInfo.pools.Length == 0) { code += addMatcher(componentInfo); code += closeNamespace(); } else { // Add default matcher code += addMatcher(componentInfo, true); code += closeNamespace(); // Add custom matchers code += addMatcher(componentInfo); code = addUsings("Entitas") + code; } return code; }
static string generateComponentExtension(ComponentInfo componentInfo) { return componentInfo.pools.Length == 0 ? addDefaultPoolCode(componentInfo) : addCustomPoolCode(componentInfo); }
/* * * MATCHER * */ static string addMatcher(ComponentInfo componentInfo) { const string matcherFormat = @" public partial class $TagMatcher { static IMatcher _matcher$Name; public static IMatcher $Name { get { if (_matcher$Name == null) { var matcher = (Matcher)Matcher.AllOf($Ids.$Name); matcher.componentNames = $Ids.componentNames; _matcher$Name = matcher; } return _matcher$Name; } } } "; if (componentInfo.pools.Length == 0) { return buildString(componentInfo, matcherFormat); } var poolIndex = 0; var matchers = componentInfo.pools.Aggregate(string.Empty, (acc, poolName) => { return acc + buildString(componentInfo, matcherFormat, poolIndex++); }); return buildString(componentInfo, matchers); }
/* * * HELPERS * */ static string buildString(ComponentInfo componentInfo, string format, int poolIndex = 0) { format = createFormatString(format); var a0_type = componentInfo.fullTypeName; var a1_name = componentInfo.typeName.RemoveComponentSuffix(); var a2_lowercaseName = a1_name.LowercaseFirst(); var poolNames = componentInfo.pools; var a3_tag = poolNames.Length == 0 ? string.Empty : poolNames[poolIndex]; var lookupTags = componentInfo.ComponentLookupTags(); var a4_ids = lookupTags.Length == 0 ? string.Empty : lookupTags[poolIndex]; var memberInfos = componentInfo.memberInfos; var a5_memberNamesWithType = memberNamesWithType(memberInfos); var a6_memberAssigns = memberAssignments(memberInfos); var a7_memberNames = memberNames(memberInfos); var prefix = componentInfo.singleComponentPrefix; var a8_prefix = prefix.UppercaseFirst(); var a9_lowercasePrefix = prefix.LowercaseFirst(); return string.Format(format, a0_type, a1_name, a2_lowercaseName, a3_tag, a4_ids, a5_memberNamesWithType, a6_memberAssigns, a7_memberNames, a8_prefix, a9_lowercasePrefix); }
/* * * POOL METHODS * */ static string addPoolMethods(ComponentInfo componentInfo) { return addPoolClassHeader() + addPoolGetMethods(componentInfo) + addPoolHasMethods(componentInfo) + addPoolAddMethods(componentInfo) + addPoolReplaceMethods(componentInfo) + addPoolRemoveMethods(componentInfo) + addCloseClass(); }
static string addRemoveMethods(ComponentInfo componentInfo) { return componentInfo.isSingletonComponent ? string.Empty : buildString(componentInfo, @" public Entity Remove$Name() { return RemoveComponent($Ids.$Name); } "); }
static string addPoolReplaceMethods(ComponentInfo componentInfo) { return componentInfo.isSingletonComponent ? string.Empty : buildString(componentInfo, @" public Entity Replace$Name($typedArgs) { var entity = $nameEntity; if (entity == null) { entity = Set$Name($args); } else { entity.Replace$Name($args); } return entity; } "); }
static string addPoolRemoveMethods(ComponentInfo componentInfo) { return componentInfo.isSingletonComponent ? string.Empty : buildString(componentInfo, @" public void Remove$Name() { DestroyEntity($nameEntity); } "); }