Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add create entity execution options #72

Merged
merged 2 commits into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 7 additions & 4 deletions Runtime/DynamicEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ public class DynamicEntity : MonoBehaviour {
public void AddEcsactCompnent<C>(C component)
where C : Ecsact.Component {
if(Application.isPlaying) {
Ecsact.Defaults.Runner.executionOptions.AddComponent(entityId, component);
Ecsact.Defaults.Runner!.executionOptions.AddComponent(
entityId,
component
);
}

ecsactComponents.Add(new SerializableEcsactComponent {
Expand All @@ -74,7 +77,7 @@ public void AddEcsactComponent(
object componentData
) {
if(Application.isPlaying) {
Ecsact.Defaults.Runner.executionOptions
Ecsact.Defaults.Runner!.executionOptions
.AddComponent(entityId, componentId, componentData);
}

Expand Down Expand Up @@ -109,7 +112,7 @@ private void AddInitialEcsactComponents() {
}

foreach(var ecsactComponent in ecsactComponents) {
Ecsact.Defaults.Runner.executionOptions
Ecsact.Defaults.Runner!.executionOptions
.AddComponent(entityId, ecsactComponent.id, ecsactComponent.data!);
}
}
Expand All @@ -127,7 +130,7 @@ void OnDisable() {
var hasComponent =
Ecsact.Defaults.Registry.HasComponent(entityId, ecsactComponent.id);
if(hasComponent) {
Ecsact.Defaults.Runner.executionOptions.RemoveComponent(
Ecsact.Defaults.Runner!.executionOptions.RemoveComponent(
entityId,
ecsactComponent.id
);
Expand Down
108 changes: 108 additions & 0 deletions Runtime/EcsactExecutionOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@
namespace Ecsact {

public class ExecutionOptions {
public class BuilderEntity {
public BuilderEntity AddComponent<C>(C component)
where C : Ecsact.Component {
var componentId = Ecsact.Util.GetComponentID<C>();
components.Add(componentId, component);
return this;
}
public EcsactRuntime.EntityIdCallback callback;
internal Dictionary<Int32, object> components = new();
};

public EcsactRuntime.CExecutionOptions executionOptions;

private List<EcsactRuntime.EcsactAction> actions;
Expand All @@ -15,6 +26,14 @@ public class ExecutionOptions {
private List<EcsactRuntime.EcsactComponentId> removes;
private List<Int32> removes_entities;

public List<BuilderEntity> create_entities;
private List<List<EcsactRuntime.EcsactComponent>> create_entities_components;
public List<Int32> create_entities_placeholders;
private List<Int32> create_entities_components_length;
private List<GCHandle> create_entity_pins;

private List<EcsactRuntime.EcsactComponentId> destroy_entities;

internal ExecutionOptions() {
actions = new();
adds = new();
Expand All @@ -24,6 +43,12 @@ internal ExecutionOptions() {
removes = new();
removes_entities = new();
executionOptions = new();
create_entities = new();
create_entities_components = new();
create_entities_placeholders = new();
create_entities_components_length = new();
create_entity_pins = new();
destroy_entities = new();
}

public void AddComponent<C>(Int32 entityId, C component)
Expand Down Expand Up @@ -86,6 +111,14 @@ public void RemoveComponent(Int32 entityId, Int32 componentId) {
removes_entities.Add(entityId);
}

public BuilderEntity CreateEntity(EcsactRuntime.EntityIdCallback callback) {
BuilderEntity builder = new();
builder.callback = callback;

create_entities.Add(builder);
return builder;
}

public void Alloc() {
if(actions.Count > 0) {
var actionsArray = actions.ToArray();
Expand Down Expand Up @@ -119,6 +152,56 @@ public void Alloc() {
executionOptions.removeComponentsLength = removesArray.Length;
executionOptions.removeComponentsEntities = removesEntitiesArray;
}

if(create_entities.Count > 0) {
executionOptions.createEntitiesLength = create_entities.Count;
create_entities_placeholders = new List<Int32>(create_entities.Count);
executionOptions.createEntitiesComponentsLength =
new Int32[create_entities.Count];
executionOptions.createEntitiesComponents =
new IntPtr[create_entities.Count];

create_entities_components =
new List<List<EcsactRuntime.EcsactComponent>>(create_entities.Count);

for(int i = 0; i < create_entities.Count; i++) {
var builder = create_entities[i];

executionOptions.createEntitiesComponentsLength[i] =
builder.components.Count;

var compList = new List<EcsactRuntime.EcsactComponent>();
create_entities_components.Add(compList);

foreach(var component in builder.components) {
var componentPtr =
Marshal.AllocHGlobal(Marshal.SizeOf(component.Value));

Ecsact.Util
.ComponentToPtr(component.Value, component.Key, componentPtr);

EcsactRuntime.EcsactComponent ecsactComponent;
ecsactComponent.componentData = componentPtr;
ecsactComponent.componentId = component.Key;

compList.Add(ecsactComponent);
}

if(builder.components.Count > 0) {
var createPinned =
GCHandle.Alloc(compList.ToArray(), GCHandleType.Pinned);

create_entity_pins.Add(createPinned);

var createEntityComponentsPinned = createPinned.AddrOfPinnedObject();

executionOptions.createEntitiesComponents[i] =
createEntityComponentsPinned;
} else {
executionOptions.createEntitiesComponents[i] = IntPtr.Zero;
}
}
}
}

public int actionCount() {
Expand Down Expand Up @@ -161,6 +244,25 @@ public void Free() {

removes.Clear();
removes_entities.Clear();

create_entities_placeholders.Clear();

foreach(var componentList in create_entities_components) {
foreach(var ecsComponent in componentList) {
Marshal.FreeHGlobal(ecsComponent.componentData);
}
}
create_entities_components.Clear();

foreach(var pin in create_entity_pins) {
pin.Free();
}

create_entities_components_length.Clear();
create_entity_pins.Clear();
create_entities.Clear();

destroy_entities.Clear();
}

public bool isEmpty() {
Expand All @@ -176,6 +278,12 @@ public bool isEmpty() {
if(removes.Count > 0) {
return false;
}
if(create_entities.Count > 0) {
return false;
}
if(destroy_entities.Count > 0) {
return false;
}
return true;
}
}
Expand Down
23 changes: 23 additions & 0 deletions Runtime/EcsactRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ public class EcsactRunner : MonoBehaviour {
public int debugExecutionTimeMs = 0;
#endif

private Ecsact.Details.ExecutionEntityCallbacks entityCallbacks = new();

void Start() {
Ecsact.Defaults.Runtime.OnEntityCreated((entityId, placeholderId) => {
var callback = entityCallbacks.GetAndClearCallback(placeholderId);
callback(entityId);
});
}

public Ecsact.ExecutionOptions executionOptions = new();

internal static EcsactRunner CreateInstance<ComponentT>(
Expand Down Expand Up @@ -51,11 +60,16 @@ protected void Execute() {
}

try {
LoadEntityCallbacks();
// NOTE: Temporary, this should be abstracted out
executionOptions.executionOptions.createEntities =
executionOptions.create_entities_placeholders.ToArray();
Ecsact.Defaults.Registry.ExecuteSystems(executionOptions);
} finally {
executionOptions.Free();
#if UNITY_EDITOR
executionTimeWatch.Stop();
executionOptions.create_entities_placeholders = new();
debugExecutionTimeMs = (int)executionTimeWatch.ElapsedMilliseconds;
debugExecutionCountTotal += 1;
#endif
Expand All @@ -65,6 +79,15 @@ protected void Execute() {

Ecsact.Defaults.Runtime.wasm.PrintAndConsumeLogs();
}

protected void LoadEntityCallbacks() {
for(int i = 0; i < executionOptions.create_entities.Count; i++) {
var builder = executionOptions.create_entities[i];
var id = entityCallbacks.AddCallback(builder.callback);
// NOTE: Temporary, this should be abstracted out
executionOptions.create_entities_placeholders.Add(id);
}
}
}

} // namespace Ecsact
80 changes: 80 additions & 0 deletions Runtime/EcsactRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ public enum EcsactEvent : Int32 {
InitComponent = 0,
UpdateComponent = 1,
RemoveComponent = 2,
CreateEntity = 3,
}

public delegate void EachComponentCallback(
Expand All @@ -186,6 +187,13 @@ public delegate void ComponentEventCallback(
IntPtr callbackUserData
);

public delegate void EntityEventCallback(
EcsactEvent ev,
Int32 entityId,
Int32 placeholderId,
IntPtr callbackUserData
);

public struct EcsactAction {
public Int32 actionId;
public IntPtr actionData;
Expand Down Expand Up @@ -222,6 +230,18 @@ public struct CExecutionOptions {
public Int32 actionsLength;
[MarshalAs(UnmanagedType.LPArray)]
public EcsactAction[] actions;

public Int32 createEntitiesLength;
[MarshalAs(UnmanagedType.LPArray)]
public Int32[] createEntities;
[MarshalAs(UnmanagedType.LPArray)]
public Int32[] createEntitiesComponentsLength;
[MarshalAs(UnmanagedType.LPArray)]
public IntPtr[] createEntitiesComponents;

public Int32 destroyEntitiesLength;
[MarshalAs(UnmanagedType.LPArray)]
public EcsactComponentId[] destroyEntities;
};

public struct ExecutionEventsCollector {
Expand Down Expand Up @@ -261,6 +281,30 @@ public struct ExecutionEventsCollector {
/// <c>callbackUserData</c> passed to <c>removeCallback</c>
/// </summary>
public IntPtr removeCallbackUserData;

/// <summary>
/// invoked after system executions are finished for every created entity.
/// Invocation happens in the calling thread. <c>event</c> will
/// always be <c>EcsactEvent.CreateEntity</c>.
/// </summary>
public EntityEventCallback createEntityCallback;

/// <summary>
/// <c>callbackUserData</c> passed to <c>createEntityCallback</c>
/// </summary>
public IntPtr createEntityCallbackUserData;

/// <summary>
/// invoked after system executions are finished for every destroyed entity.
/// Invocation happens in the calling thread. <c>event</c> will
/// always be <c>EcsactEvent.DestroyEntity</c>.
/// </summary>
public EntityEventCallback destroyEntityCallback;

/// <summary>
/// <c>callbackUserData</c> passed to <c>destroyEntityCallback</c>
/// </summary>
public IntPtr destroyEntitycallbackUserData;
}

public struct StaticComponentInfo {
Expand Down Expand Up @@ -1418,6 +1462,7 @@ CExecutionOptions[] executionOptionsList
_owner._execEvs.initCallbackUserData = ownerIntPtr;
_owner._execEvs.updateCallbackUserData = ownerIntPtr;
_owner._execEvs.removeCallbackUserData = ownerIntPtr;
_owner._execEvs.createEntityCallbackUserData = ownerIntPtr;
var error = ecsact_execute_systems(
registryId,
executionCount,
Expand Down Expand Up @@ -2832,12 +2877,15 @@ public static void Free(EcsactRuntime runtime) {
/// <summary>Remove Component Untyped Callback</summary>
private delegate void RmvCompUtCb(Int32 entityId, object component);

public delegate void EntityIdCallback(Int32 entityId);

private List<InitComponentCallback> _initAnyCompCbs = new();
private List<UpdateComponentCallback> _updateAnyCompCbs = new();
private List<RemoveComponentCallback> _removeAnyCompCbs = new();
private Dictionary<Int32, List<InitCompUtCb>> _initCompCbs = new();
private Dictionary<Int32, List<UpCompUtCb>> _updateCompCbs = new();
private Dictionary<Int32, List<RmvCompUtCb>> _removeCompCbs = new();
private List<EntityCallback> _createEntityCbs = new();
internal ExecutionEventsCollector _execEvs;

private EcsactRuntime() {
Expand All @@ -2848,6 +2896,8 @@ private EcsactRuntime() {
updateCallbackUserData = IntPtr.Zero,
removeCallback = OnRemoveComponentHandler,
removeCallbackUserData = IntPtr.Zero,
createEntityCallback = OnEntityCreatedHandler,
createEntityCallbackUserData = IntPtr.Zero,
};
}

Expand Down Expand Up @@ -3085,4 +3135,34 @@ IntPtr callbackUserData
componentObject = Ecsact.Util.HandlePtrToComponent(ref componentObject);
self._TriggerRemoveComponentEvent(entityId, componentId, componentObject);
}

public delegate void EntityCallback(Int32 entityId, Int32 placeholderId);

public Action OnEntityCreated(EntityCallback callback) {
_createEntityCbs.Add(callback);
return () => { _createEntityCbs.Remove(callback); };
}

[AOT.MonoPInvokeCallback(typeof(EntityCallback))]
private static void OnEntityCreatedHandler(
EcsactEvent ev,
Int32 entityId,
Int32 placeholderId,
IntPtr callbackUserData
) {
AssertPlayMode();
UnityEngine.Debug.Assert(ev == EcsactEvent.CreateEntity);
UnityEngine.Debug.Log("Entity created");

try {
var self =
(GCHandle.FromIntPtr(callbackUserData).Target as EcsactRuntime)!;

foreach(var callback in self._createEntityCbs) {
callback(entityId, placeholderId);
}
} catch(Exception e) {
UnityEngine.Debug.LogException(e);
}
}
}
Loading