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

Add rendering support for user-defined types #1391

Merged
merged 6 commits into from
Jun 11, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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