Skip to content
This repository has been archived by the owner on Jan 18, 2022. It is now read-only.

Commit

Permalink
Add rendering support for user-defined types (#1391)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamie Brynes committed Jun 11, 2020
1 parent 8330867 commit d60046b
Show file tree
Hide file tree
Showing 11 changed files with 372 additions and 161 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,25 @@ public ComponentVisualElementJob(CodegenJobOptions options, IFileSystem fileSyst
AddJobTarget(Path.Combine(relativeOutputPath, DebugAsmdefFileName), () => DebugAssemblyGenerator.Generate());

var componentsToGenerate = detailsStore.Components.Values.ToList();
AddGenerators(relativeOutputPath, componentsToGenerate, component => ($"{component.Name}Renderer.cs", ComponentVisualElementGenerator.Generate));
var componentGenerator = new ComponentVisualElementGenerator(detailsStore);
AddGenerators(relativeOutputPath, componentsToGenerate, component => ($"{component.Name}Renderer.cs", componentGenerator.Generate));
Logger.Trace($"Added job targets for {componentsToGenerate.Count} components");

// Types
Logger.Trace("Gathering nested types.");
var allNestedTypes = detailsStore.Types
.SelectMany(kv => detailsStore.GetNestedTypes(kv.Key))
.ToHashSet();

Logger.Trace("Gathering types details.");
var typesToGenerate = detailsStore.Types
.Where(kv => !allNestedTypes.Contains(kv.Key))
.Select(kv => kv.Value)
.ToList();

var typeGenerator = new TypeVisualElementGenerator(detailsStore);
AddGenerators(relativeOutputPath, typesToGenerate, type => ($"{type.Name}Renderer.cs", typeGenerator.Generate));
Logger.Trace($"Added job targets for {typesToGenerate.Count} types");
}
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Improbable.Gdk.CodeGeneration.CodeWriter;
using Improbable.Gdk.CodeGeneration.CodeWriter.Scopes;
using Improbable.Gdk.CodeGeneration.Model;
using Improbable.Gdk.CodeGeneration.Model.Details;
using Improbable.Gdk.CodeGeneration.Utils;
using ValueType = Improbable.Gdk.CodeGeneration.Model.ValueType;

namespace Improbable.Gdk.CodeGenerator
{
public static class ComponentVisualElementGenerator
public class ComponentVisualElementGenerator
{
public static CodeWriter Generate(UnityComponentDetails details)
private readonly FieldTypeHandler typeGenerator;

public ComponentVisualElementGenerator(DetailsStore detailsStore)
{
typeGenerator = new FieldTypeHandler(detailsStore);
}

public CodeWriter Generate(UnityComponentDetails details)
{
return CodeWriter.Populate(cgw =>
{
Expand All @@ -29,7 +31,7 @@ public static CodeWriter Generate(UnityComponentDetails details)
{
type.Line($"public override ComponentType ComponentType {{ get; }} = ComponentType.ReadOnly<{details.Name}.Component>();");
type.TextList(details.FieldDetails.Select(ToFieldDeclaration));
type.TextList(details.FieldDetails.Select(typeGenerator.ToFieldDeclaration));
GenerateConstructor(type, details);
GenerateUpdateMethod(type, details);
Expand All @@ -38,27 +40,7 @@ public static CodeWriter Generate(UnityComponentDetails details)
});
}

private static string ToFieldDeclaration(UnityFieldDetails fieldDetails)
{
switch (fieldDetails.FieldType)
{
case SingularFieldType singularFieldType:
var uiType = GetUiFieldType(singularFieldType.ContainedType);

if (uiType == "")
{
// TODO: Eliminate this case.
return "";
}

return $"private readonly {uiType} {fieldDetails.CamelCaseName}Field;";
default:
// TODO: Lists, maps, and options
return "";
}
}

private static void GenerateConstructor(TypeBlock typeBlock, UnityComponentDetails details)
private void GenerateConstructor(TypeBlock typeBlock, UnityComponentDetails details)
{
typeBlock.Method($"public {details.Name}Renderer() : base()", mb =>
{
Expand All @@ -67,146 +49,20 @@ private static void GenerateConstructor(TypeBlock typeBlock, UnityComponentDetai
foreach (var field in details.FieldDetails)
{
mb.TextList(ToFieldInitialisation(field));
mb.TextList(typeGenerator.ToFieldInitialisation(field, "ComponentFoldout"));
}
});
}

private static IEnumerable<string> ToFieldInitialisation(UnityFieldDetails fieldDetails)
{
switch (fieldDetails.FieldType)
{
case SingularFieldType singularFieldType:

var uiType = GetUiFieldType(singularFieldType.ContainedType);

if (uiType == "")
{
// TODO: Eliminate this case.
yield break;
}

var humanReadableName = Formatting.SnakeCaseToHumanReadable(fieldDetails.Name);
yield return $"{fieldDetails.CamelCaseName}Field = new {uiType}(\"{humanReadableName}\");";
yield return $"{fieldDetails.CamelCaseName}Field.SetEnabled(false);";

if (singularFieldType.ContainedType.Category == ValueType.Enum)
{
yield return $"{fieldDetails.CamelCaseName}Field.Init(default({fieldDetails.Type}));";
}

yield return $"ComponentFoldout.Add({fieldDetails.CamelCaseName}Field);";
break;
default:
// TODO: Lists, maps, and options
yield break;
}
}

private static void GenerateUpdateMethod(TypeBlock typeBlock, UnityComponentDetails details)
private void GenerateUpdateMethod(TypeBlock typeBlock, UnityComponentDetails details)
{
typeBlock.Method("public override void Update(EntityManager manager, Entity entity)", mb =>
{
mb.Line($"AuthoritativeToggle.value = manager.HasComponent<{details.Name}.HasAuthority>(entity);");
mb.Line($"var component = manager.GetComponentData<{details.Name}.Component>(entity);");
mb.TextList(TextList.New(details.FieldDetails.Select(ToUiFieldUpdate)));
mb.TextList(details.FieldDetails.Select(fd => typeGenerator.ToUiFieldUpdate(fd, "component")));
});
}

private static string ToUiFieldUpdate(UnityFieldDetails fieldDetails)
{
switch (fieldDetails.FieldType)
{
case SingularFieldType singularFieldType:
switch (singularFieldType.ContainedType.Category)
{
case ValueType.Enum:
return $"{fieldDetails.CamelCaseName}Field.value = component.{fieldDetails.PascalCaseName};";
case ValueType.Primitive:
var primitiveType = singularFieldType.ContainedType.PrimitiveType.Value;

switch (primitiveType)
{
case PrimitiveType.Int32:
case PrimitiveType.Int64:
case PrimitiveType.Uint32:
case PrimitiveType.Uint64:
case PrimitiveType.Sint32:
case PrimitiveType.Sint64:
case PrimitiveType.Fixed32:
case PrimitiveType.Fixed64:
case PrimitiveType.Sfixed32:
case PrimitiveType.Sfixed64:
case PrimitiveType.Float:
case PrimitiveType.Double:
case PrimitiveType.String:
case PrimitiveType.EntityId:
return $"{fieldDetails.CamelCaseName}Field.value = component.{fieldDetails.PascalCaseName}.ToString();";
case PrimitiveType.Bytes:
return $"{fieldDetails.CamelCaseName}Field.value = global::System.Text.Encoding.Default.GetString(component.{fieldDetails.PascalCaseName});";
case PrimitiveType.Bool:
return $"{fieldDetails.CamelCaseName}Field.value = component.{fieldDetails.PascalCaseName};";
break;
case PrimitiveType.Entity:
// TODO: Entity type.
return "";
case PrimitiveType.Invalid:
throw new ArgumentException("Unknown primitive type encountered");
default:
throw new ArgumentOutOfRangeException();
}
case ValueType.Type:
// TODO: User defined types.
return "";
default:
throw new ArgumentOutOfRangeException();
}
default:
// TODO: Lists, maps, and options
return "";
}
}

private static string GetUiFieldType(ContainedType type)
{
switch (type.Category)
{
case ValueType.Enum:
return "EnumField";
case ValueType.Primitive:
switch (type.PrimitiveType.Value)
{
case PrimitiveType.Int32:
case PrimitiveType.Int64:
case PrimitiveType.Uint32:
case PrimitiveType.Uint64:
case PrimitiveType.Sint32:
case PrimitiveType.Sint64:
case PrimitiveType.Fixed32:
case PrimitiveType.Fixed64:
case PrimitiveType.Sfixed32:
case PrimitiveType.Sfixed64:
case PrimitiveType.Float:
case PrimitiveType.Double:
case PrimitiveType.String:
case PrimitiveType.EntityId:
case PrimitiveType.Bytes:
return "TextField";
case PrimitiveType.Bool:
return "Toggle";
case PrimitiveType.Entity:
return "";
case PrimitiveType.Invalid:
throw new ArgumentException("Unknown primitive type encountered.");
default:
throw new ArgumentOutOfRangeException();
}
case ValueType.Type:
return "";
default:
throw new ArgumentOutOfRangeException();
}
}
}
}
Loading

0 comments on commit d60046b

Please sign in to comment.