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

Add component metaclass / command metaclasses #1173

Merged
merged 11 commits into from
Sep 26, 2019
Merged
Show file tree
Hide file tree
Changes from 3 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
@@ -0,0 +1,29 @@
using System.Collections.Generic;
using Improbable.Gdk.CodeGeneration.Model.Details;

namespace Improbable.Gdk.CodeGenerator
{
public partial class MetaclassGenerator
{
private UnityComponentDetails details;
private string qualifiedNamespace;

public string Generate(UnityComponentDetails details, string package)
{
qualifiedNamespace = package;
this.details = details;

return TransformText();
}

private UnityComponentDetails GetComponentDetails()
{
return details;
}

private IReadOnlyList<UnityCommandDetails> GetCommandDetailsList()
{
return details.CommandDetails;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public SingleGenerationJob(string outputDir, IFileSystem fileSystem, DetailsStor
Path.ChangeExtension($"{componentName}ComponentReaderWriter", FileExtension)));
OutputFiles.Add(Path.Combine(relativeOutputPath,
Path.ChangeExtension($"{componentName}ViewStorage", FileExtension)));
OutputFiles.Add(Path.Combine(relativeOutputPath, Path.ChangeExtension($"{componentName}Metaclass", FileExtension)));
}

foreach (var enumTarget in enumsToGenerate)
Expand Down Expand Up @@ -128,6 +129,7 @@ protected override void RunImpl()
var commandDiffStorageGenerator = new CommandDiffStorageGenerator();
var viewStorageGenerator = new ViewStorageGenerator();
var commandMetaDataStorageGenerator = new CommandMetaDataStorageGenerator();
var metaclassGenerator = new MetaclassGenerator();

foreach (var enumTarget in enumsToGenerate)
{
Expand Down Expand Up @@ -248,6 +250,10 @@ protected override void RunImpl()
var viewStorageFileName = Path.ChangeExtension($"{componentName}ViewStorage", FileExtension);
var viewStorageCode = viewStorageGenerator.Generate(componentTarget.Content, package);
Content.Add(Path.Combine(relativeOutputPath, viewStorageFileName), viewStorageCode);

var metaclassFileName = Path.ChangeExtension($"{componentName}Metaclass", FileExtension);
var metaclassCode = metaclassGenerator.Generate(componentTarget.Content, package);
Content.Add(Path.Combine(relativeOutputPath, metaclassFileName), metaclassCode);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<#@ template language="C#" #>
<#@ output extension=".cs" #>
<#
var componentDetails = GetComponentDetails();
var generatedHeader = CommonGeneratorUtils.GetGeneratedHeader();
var commandDetailsList = GetCommandDetailsList();
var rootNamespace = $"global::{qualifiedNamespace}.{componentDetails.ComponentName}";
#>
<#= generatedHeader #>

using System;
using Improbable.Gdk.Core;
using Improbable.Gdk.Core.Commands;

namespace <#= qualifiedNamespace #>
{
public partial class <#= componentDetails.ComponentName #>
{
public class ComponentMetaclass : IComponentMetaclass
{
public uint ComponentId => <#= componentDetails.ComponentId #>;
public string Name => "<#= componentDetails.ComponentName #>";

public Type Data { get; } = typeof(<#= rootNamespace #>.Component);
public Type Snapshot { get; } = typeof(<#= rootNamespace #>.Snapshot);
public Type Update { get; } = typeof(<#= rootNamespace #>.Update);

public Type ReplicationHandler { get; } = typeof(<#= rootNamespace #>.ComponentReplicator);
public Type Serializer { get; } = typeof(<#= rootNamespace #>.ComponentSerializer);
public Type DiffDeserializer { get; } = typeof(<#= rootNamespace #>.DiffComponentDeserializer);

public Type DiffStorage { get; } = typeof(<#= rootNamespace #>.DiffComponentStorage);
public Type ViewStorage { get; } = typeof(<#= rootNamespace #>.<#= componentDetails.ComponentName #>ViewStorage);
public Type EcsViewManager { get; } = typeof(<#= rootNamespace #>.EcsViewManager);
public Type DynamicInvokable { get; } = typeof(<#= rootNamespace #>.<#= componentDetails.ComponentName #>Dynamic);

public ICommandMetaclass[] Commands { get; } = new ICommandMetaclass[]
{
<# foreach (var command in commandDetailsList) { #>
new <#= command.CommandName #>Metaclass(),
<# } #>
};
}
<# foreach (var command in commandDetailsList) { #>

public class <#= command.CommandName #>Metaclass : ICommandMetaclass
{
public uint CommandIndex => <#= command.CommandIndex #>;
public string Name => "<#= command.CommandName #>";

public Type DiffDeserializer { get; } = typeof(<#= rootNamespace #>.<#= command.CommandName #>DiffCommandDeserializer);
public Type Serializer { get; } = typeof(<#= rootNamespace #>.<#= command.CommandName #>CommandSerializer);

public Type MetaDataStorage { get; } = typeof(<#= rootNamespace #>.<#= command.CommandName #>CommandMetaDataStorage);
public Type SendStorage { get; } = typeof(<#= rootNamespace #>.<#= command.CommandName #>CommandsToSendStorage);
public Type DiffStorage { get; } = typeof(<#= rootNamespace #>.Diff<#= command.CommandName #>CommandStorage);
}
<# } #>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;

namespace Improbable.Gdk.Core.Commands
{
public interface ICommandMetaclass
{
uint CommandIndex { get; }
string Name { get; }

Type DiffDeserializer { get; }
Type Serializer { get; }

Type MetaDataStorage { get; }
Type SendStorage { get; }
Type DiffStorage { get; }
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Improbable.Gdk.Core.Commands;

namespace Improbable.Gdk.Core
{
public interface IComponentMetaclass
{
uint ComponentId { get; }
string Name { get; }

Type Data { get; }
Type Snapshot { get; }
Type Update { get; }

Type ReplicationHandler { get; }
Type Serializer { get; }
Type DiffDeserializer { get; }

Type DiffStorage { get; }
Type ViewStorage { get; }
Type EcsViewManager { get; }
Type DynamicInvokable { get; }

ICommandMetaclass[] Commands { get; }
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,43 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Improbable.Gdk.Core.Commands;

namespace Improbable.Gdk.Core
{
internal static class ComponentDatabase
public static class ComponentDatabase
{
public static Dictionary<uint, IDynamicInvokable> IdsToDynamicInvokers { get; }
internal static Dictionary<uint, IComponentMetaclass> Metaclasses { get; }

public static Dictionary<Type, uint> ComponentsToIds { get; }
private static Dictionary<Type, uint> ComponentsToIds { get; }

public static Dictionary<Type, uint> SnapshotsToIds { get; }
private static Dictionary<Type, uint> SnapshotsToIds { get; }

static ComponentDatabase()
jamiebrynes7 marked this conversation as resolved.
Show resolved Hide resolved
{
IdsToDynamicInvokers = new Dictionary<uint, IDynamicInvokable>();
ComponentsToIds = new Dictionary<Type, uint>();
SnapshotsToIds = new Dictionary<Type, uint>();
Metaclasses = ReflectionUtility.GetNonAbstractTypes(typeof(IComponentMetaclass))
.Select(type => (IComponentMetaclass) Activator.CreateInstance(type))
.ToDictionary(metaclass => metaclass.ComponentId, metaclass => metaclass);

var dynamicTypes = ReflectionUtility.GetNonAbstractTypes(typeof(IDynamicInvokable));
var componentTypes = ReflectionUtility.GetNonAbstractTypes(typeof(ISpatialComponentData));
var snapshotTypes = ReflectionUtility.GetNonAbstractTypes(typeof(ISpatialComponentSnapshot));
ComponentsToIds = Metaclasses.ToDictionary(pair => pair.Value.Data, pair => pair.Key);
SnapshotsToIds = Metaclasses.ToDictionary(pair => pair.Value.Snapshot, pair => pair.Key);
}

foreach (var type in dynamicTypes)
public static uint GetComponentId<T>() where T : ISpatialComponentData
{
if (!ComponentsToIds.TryGetValue(typeof(T), out var id))
{
var instance = (IDynamicInvokable) Activator.CreateInstance(type);
IdsToDynamicInvokers.Add(instance.ComponentId, instance);
throw new ArgumentException($"Can not find ID for unregistered SpatialOS component {nameof(T)}.");
}

foreach (var type in componentTypes)
{
var instance = (ISpatialComponentData) Activator.CreateInstance(type);
ComponentsToIds.Add(type, instance.ComponentId);
}
return id;
}

foreach (var type in snapshotTypes)
public static uint GetSnapshotComponentId<T>() where T : ISpatialComponentSnapshot
{
if (!SnapshotsToIds.TryGetValue(typeof(T), out var id))
{
var instance = (ISpatialComponentSnapshot) Activator.CreateInstance(type);
SnapshotsToIds.Add(type, instance.ComponentId);
throw new ArgumentException($"Can not find ID for unregistered SpatialOS component snapshot {nameof(T)}.");
}

return id;
}
}
}
35 changes: 13 additions & 22 deletions workers/unity/Packages/io.improbable.gdk.core/Dynamic/Dynamic.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Improbable.Worker.CInterop;

namespace Improbable.Gdk.Core
Expand All @@ -21,6 +23,15 @@ public delegate TUpdate SnapshotToUpdate<TSnapshot, out TUpdate>(in TSnapshot sn

public static class Dynamic
{
private static readonly Dictionary<uint, IDynamicInvokable> DynamicInvokers;

static Dynamic()
jamiebrynes7 marked this conversation as resolved.
Show resolved Hide resolved
{
DynamicInvokers = ComponentDatabase.Metaclasses.ToDictionary(
pair => pair.Key,
pair => (IDynamicInvokable) Activator.CreateInstance(pair.Value.DynamicInvokable));
}

public struct VTable<TUpdate, TSnapshot>
where TUpdate : struct, ISpatialComponentUpdate
where TSnapshot : struct, ISpatialComponentSnapshot
Expand All @@ -41,40 +52,20 @@ void Accept<TUpdate, TSnapshot>(uint componentId, VTable<TUpdate, TSnapshot> vta

public static void ForEachComponent(IHandler handler)
{
foreach (var component in ComponentDatabase.IdsToDynamicInvokers.Values)
foreach (var component in DynamicInvokers.Values)
{
component.InvokeHandler(handler);
}
}

public static void ForComponent(uint componentId, IHandler handler)
{
if (!ComponentDatabase.IdsToDynamicInvokers.TryGetValue(componentId, out var component))
if (!DynamicInvokers.TryGetValue(componentId, out var component))
{
throw new ArgumentException($"Unknown component ID {componentId}.");
}

component.InvokeHandler(handler);
}

public static uint GetComponentId<T>() where T : ISpatialComponentData
{
if (!ComponentDatabase.ComponentsToIds.TryGetValue(typeof(T), out var id))
{
throw new ArgumentException($"Can not find ID for unregistered SpatialOS component {nameof(T)}.");
}

return id;
}

public static uint GetSnapshotComponentId<T>() where T : ISpatialComponentSnapshot
{
if (!ComponentDatabase.SnapshotsToIds.TryGetValue(typeof(T), out var id))
{
throw new ArgumentException($"Can not find ID for unregistered SpatialOS component snapshot {nameof(T)}.");
}

return id;
}
}
}