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

Simplify components, step 1 #1290

Merged
merged 10 commits into from
Feb 20, 2020
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
Expand Up @@ -18,10 +18,8 @@ public static CodeWriter Generate(UnityComponentDetails componentDetails)
return CodeWriter.Populate(cgw =>
{
cgw.UsingDirectives(
"System.Collections.Generic",
"System",
"Improbable.Gdk.Core",
"Improbable.Worker.CInterop"
"Improbable.Gdk.Core"
);

cgw.Namespace(componentDetails.Namespace, ns =>
Expand All @@ -30,7 +28,7 @@ public static CodeWriter Generate(UnityComponentDetails componentDetails)
{
Logger.Trace($"Generating {componentDetails.Namespace}.{componentDetails.Name}.DiffComponentStorage class.");

var classDefinition = new StringBuilder("public class DiffComponentStorage : IDiffUpdateStorage<Update>, IDiffComponentAddedStorage<Update>, IDiffAuthorityStorage");
var classDefinition = new StringBuilder("public class DiffComponentStorage : DiffComponentStorage<Update>");

foreach (var ev in eventDetailsList)
{
Expand All @@ -39,31 +37,6 @@ public static CodeWriter Generate(UnityComponentDetails componentDetails)

partial.Type(classDefinition.ToString(), storage =>
{
storage.Line(@"
private readonly HashSet<EntityId> entitiesUpdated = new HashSet<EntityId>();

private List<EntityId> componentsAdded = new List<EntityId>();
private List<EntityId> componentsRemoved = new List<EntityId>();

private readonly AuthorityComparer authorityComparer = new AuthorityComparer();
private readonly UpdateComparer<Update> updateComparer = new UpdateComparer<Update>();

// Used to represent a state machine of authority changes. Valid state changes are:
// authority lost -> authority lost temporarily
// authority lost temporarily -> authority lost
// authority gained -> authority gained
// Creating the authority lost temporarily set is the aim as it signifies authority epoch changes
private readonly HashSet<EntityId> authorityLost = new HashSet<EntityId>();
private readonly HashSet<EntityId> authorityGained = new HashSet<EntityId>();
private readonly HashSet<EntityId> authorityLostTemporary = new HashSet<EntityId>();

private MessageList<ComponentUpdateReceived<Update>> updateStorage =
new MessageList<ComponentUpdateReceived<Update>>();

private MessageList<AuthorityChangeReceived> authorityChanges =
new MessageList<AuthorityChangeReceived>();
");

foreach (var ev in eventDetailsList)
{
var eventType = $"{ev.PascalCaseName}.Event";
Expand All @@ -76,143 +49,37 @@ public static CodeWriter Generate(UnityComponentDetails componentDetails)
");
}

storage.Method("public Type[] GetEventTypes()", m =>
storage.Method("public override Type[] GetEventTypes()", m =>
{
m.Initializer("return new Type[]", () =>
{
return eventDetailsList.Select(ev => $"typeof({ev.PascalCaseName}.Event)");
});
});

storage.Method("public Type GetUpdateType()", m =>
{
m.Return("typeof(Update)");
});

storage.Method("public uint GetComponentId()", m =>
{
m.Return("ComponentId");
});

storage.Method("public void Clear()", m =>
if (eventDetailsList.Count > 0)
{
m.Line(new[]
storage.Method("public override void Clear()", m =>
{
"entitiesUpdated.Clear();",
"updateStorage.Clear();",
"authorityChanges.Clear();",
"componentsAdded.Clear();",
"componentsRemoved.Clear();"
m.Line("base.Clear();");
m.Line(eventDetailsList
.Select(ev => $"{ev.CamelCaseName}EventStorage.Clear();").ToList());
});
}

m.Line(eventDetailsList.Select(ev => $"{ev.CamelCaseName}EventStorage.Clear();").ToList());
});

storage.Method("public void RemoveEntityComponent(long entityId)", m =>
storage.Method("protected override void ClearEventStorage(long entityId)", m =>
{
m.Line("var id = new EntityId(entityId);");

m.Line("// Adding a component always updates it, so this will catch the case where the component was just added");
m.If("entitiesUpdated.Remove(id)", then =>
{
then.Line(new[]
{
"updateStorage.RemoveAll(update => update.EntityId.Id == entityId);",
"authorityChanges.RemoveAll(change => change.EntityId.Id == entityId);"
});

then.Line(eventDetailsList.Select(ev =>
$"{ev.CamelCaseName}EventStorage.RemoveAll(change => change.EntityId.Id == entityId);").ToList());
});

m.If("!componentsAdded.Remove(id)", () => new[]
{
"componentsRemoved.Add(id);"
});
m.Line(eventDetailsList.Select(ev => $"{ev.CamelCaseName}EventStorage.RemoveAll(change => change.EntityId.Id == entityId);").ToList());
});

storage.Line(@"
public void AddEntityComponent(long entityId, Update component)
{
var id = new EntityId(entityId);
if (!componentsRemoved.Remove(id))
{
componentsAdded.Add(id);
}

AddUpdate(new ComponentUpdateReceived<Update>(component, id, 0));
}

public void AddUpdate(ComponentUpdateReceived<Update> update)
{
entitiesUpdated.Add(update.EntityId);
updateStorage.InsertSorted(update, updateComparer);
}

public void AddAuthorityChange(AuthorityChangeReceived authorityChange)
{
if (authorityChange.Authority == Authority.NotAuthoritative)
{
if (authorityLostTemporary.Remove(authorityChange.EntityId) || !authorityGained.Contains(authorityChange.EntityId))
{
authorityLost.Add(authorityChange.EntityId);
}
}
else if (authorityChange.Authority == Authority.Authoritative)
{
if (authorityLost.Remove(authorityChange.EntityId))
{
authorityLostTemporary.Add(authorityChange.EntityId);
}
else
{
authorityGained.Add(authorityChange.EntityId);
}
}

authorityChanges.InsertSorted(authorityChange, authorityComparer);
}

public List<EntityId> GetComponentsAdded()
{
return componentsAdded;
}

public List<EntityId> GetComponentsRemoved()
{
return componentsRemoved;
}

public MessagesSpan<ComponentUpdateReceived<Update>> GetUpdates()
{
return updateStorage.Slice();
}

public MessagesSpan<ComponentUpdateReceived<Update>> GetUpdates(EntityId entityId)
{
var range = updateStorage.GetEntityRange(entityId);
return updateStorage.Slice(range.FirstIndex, range.Count);
}

public MessagesSpan<AuthorityChangeReceived> GetAuthorityChanges()
{
return authorityChanges.Slice();
}

public MessagesSpan<AuthorityChangeReceived> GetAuthorityChanges(EntityId entityId)
{
var range = authorityChanges.GetEntityRange(entityId);
return authorityChanges.Slice(range.FirstIndex, range.Count);
}
");
foreach (var ev in eventDetailsList)
{
var eventType = $"{ev.PascalCaseName}.Event";

storage.Method($"MessagesSpan<ComponentEventReceived<{eventType}>> IDiffEventStorage<{eventType}>.GetEvents(EntityId entityId)", () => new[]
{
$"var range = {ev.CamelCaseName}EventStorage.GetEntityRange(entityId);",
$"return {ev.CamelCaseName}EventStorage.Slice(range.FirstIndex, range.Count);"
$"var (firstIndex, count) = {ev.CamelCaseName}EventStorage.GetEntityRange(entityId);",
$"return {ev.CamelCaseName}EventStorage.Slice(firstIndex, count);"
});

storage.Method($"MessagesSpan<ComponentEventReceived<{eventType}>> IDiffEventStorage<{eventType}>.GetEvents()", () => new[]
Expand Down
2 changes: 1 addition & 1 deletion workers/unity/Packages/io.improbable.gdk.core/EntityId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Improbable.Gdk.Core
/// Instances of this type should be treated as transient identifiers that will not be
/// consistent between different runs of the same simulation.
/// </remarks>
public struct EntityId : IEquatable<EntityId>
public readonly struct EntityId : IEquatable<EntityId>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth noting this in the changelog :)

{
/// <summary>
/// The value of the EntityId.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
using System;
using System.Collections.Generic;
using Improbable.Worker.CInterop;

namespace Improbable.Gdk.Core
{
public abstract class DiffComponentStorage<TUpdate> : IDiffUpdateStorage<TUpdate>, IDiffComponentAddedStorage<TUpdate>, IDiffAuthorityStorage
where TUpdate : ISpatialComponentUpdate
{
private readonly HashSet<EntityId> entitiesUpdated = new HashSet<EntityId>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this protected since I'll need that in #1298 ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

private readonly uint componentId;

private readonly List<EntityId> componentsAdded = new List<EntityId>();
private readonly List<EntityId> componentsRemoved = new List<EntityId>();

private readonly AuthorityComparer authorityComparer = new AuthorityComparer();
private readonly UpdateComparer<TUpdate> updateComparer = new UpdateComparer<TUpdate>();

// Used to represent a state machine of authority changes. Valid state changes are:
// authority lost -> authority lost temporarily
// authority lost temporarily -> authority lost
// authority gained -> authority gained
// Creating the authority lost temporarily set is the aim as it signifies authority epoch changes
private readonly HashSet<EntityId> authorityLost = new HashSet<EntityId>();
private readonly HashSet<EntityId> authorityGained = new HashSet<EntityId>();
private readonly HashSet<EntityId> authorityLostTemporary = new HashSet<EntityId>();

private readonly MessageList<ComponentUpdateReceived<TUpdate>> updateStorage =
new MessageList<ComponentUpdateReceived<TUpdate>>();

private readonly MessageList<AuthorityChangeReceived> authorityChanges =
new MessageList<AuthorityChangeReceived>();

public abstract Type[] GetEventTypes();

public Type GetUpdateType() => typeof(TUpdate);

public virtual void Clear()
{
entitiesUpdated.Clear();
updateStorage.Clear();
authorityChanges.Clear();
componentsAdded.Clear();
componentsRemoved.Clear();
}

public void RemoveEntityComponent(long entityId)
{
var id = new EntityId(entityId);

// Adding a component always updates it, so this will catch the case where the component was just added
if (entitiesUpdated.Remove(id))
{
updateStorage.RemoveAll(update => update.EntityId.Id == entityId);
authorityChanges.RemoveAll(change => change.EntityId.Id == entityId);

//playerCollidedEventStorage.RemoveAll(change => change.EntityId.Id == entityId);
zeroZshadow marked this conversation as resolved.
Show resolved Hide resolved
ClearEventStorage(entityId);
}

if (!componentsAdded.Remove(id))
{
componentsRemoved.Add(id);
}
}

protected abstract void ClearEventStorage(long entityId);


zeroZshadow marked this conversation as resolved.
Show resolved Hide resolved
public void AddEntityComponent(long entityId, TUpdate component)
{
var id = new EntityId(entityId);
if (!componentsRemoved.Remove(id))
{
componentsAdded.Add(id);
}

AddUpdate(new ComponentUpdateReceived<TUpdate>(component, id, 0));
}

public void AddUpdate(ComponentUpdateReceived<TUpdate> update)
{
entitiesUpdated.Add(update.EntityId);
updateStorage.InsertSorted(update, updateComparer);
}

public void AddAuthorityChange(AuthorityChangeReceived authorityChange)
{
if (authorityChange.Authority == Authority.NotAuthoritative)
{
if (authorityLostTemporary.Remove(authorityChange.EntityId) || !authorityGained.Contains(authorityChange.EntityId))
{
authorityLost.Add(authorityChange.EntityId);
}
}
else if (authorityChange.Authority == Authority.Authoritative)
{
if (authorityLost.Remove(authorityChange.EntityId))
{
authorityLostTemporary.Add(authorityChange.EntityId);
}
else
{
authorityGained.Add(authorityChange.EntityId);
}
}

authorityChanges.InsertSorted(authorityChange, authorityComparer);
}

public List<EntityId> GetComponentsAdded()
{
return componentsAdded;
}

public List<EntityId> GetComponentsRemoved()
{
return componentsRemoved;
}

public MessagesSpan<ComponentUpdateReceived<TUpdate>> GetUpdates()
{
return updateStorage.Slice();
}

public MessagesSpan<ComponentUpdateReceived<TUpdate>> GetUpdates(EntityId entityId)
{
var (firstIndex, count) = updateStorage.GetEntityRange(entityId);
return updateStorage.Slice(firstIndex, count);
}

public MessagesSpan<AuthorityChangeReceived> GetAuthorityChanges()
{
return authorityChanges.Slice();
}

public MessagesSpan<AuthorityChangeReceived> GetAuthorityChanges(EntityId entityId)
{
var (firstIndex, count) = authorityChanges.GetEntityRange(entityId);
return authorityChanges.Slice(firstIndex, count);
}
}
}

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
Expand Up @@ -8,7 +8,6 @@ public interface IComponentDiffStorage
{
Type[] GetEventTypes();
Type GetUpdateType();
uint GetComponentId();

void Clear();
void RemoveEntityComponent(long entityId);
Expand Down
Loading