Skip to content

Commit

Permalink
Fix incorrect component fetching for managed structs. Fixes #35, fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
BeanCheeseBurrito committed Sep 15, 2024
1 parent 92ca952 commit 98ea3b0
Show file tree
Hide file tree
Showing 58 changed files with 2,684 additions and 6,582 deletions.
42 changes: 10 additions & 32 deletions src/Flecs.NET.Codegen/Generators/Invoker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,12 @@ private static string GenerateEachIteratorInvokers(int i)
{{Generator.GetCallbackCountVariable(callback)}}
{{Generator.IterPointerVariables[i]}}
{{Generator.IterStepVariables[i]}}
Ecs.TableLock(it);
if (it.IsLinear())
{
for (int i = 0; i < count; i++)
callback({{Generator.GetCallbackArguments(i, callback)}});
}
else
{
{{Generator.IterStepVariables[i]}}
for (int i = 0; i < count; i++)
callback({{Generator.GetCallbackSteppedArguments(i, callback)}});
}
for (int i = 0; i < count; i++, {{Generator.IterPointerIncrements[i]}})
callback({{Generator.GetCallbackSteppedArguments(i, callback)}});
Ecs.TableUnlock(it);
}
Expand Down Expand Up @@ -121,33 +113,19 @@ private static string GenerateFindIteratorInvokers(int i)
{{Generator.GetCallbackCountVariable(callback)}}
{{Generator.IterPointerVariables[i]}}
{{Generator.IterStepVariables[i]}}
Ecs.TableLock(it);
Entity result = default;
if (it.IsLinear())
for (int i = 0; i < count; i++, {{Generator.IterPointerIncrements[i]}})
{
for (int i = 0; i < count; i++)
{
if (!callback({{Generator.GetCallbackArguments(i, callback)}}))
continue;
result = new Entity(it.Handle->world, it.Handle->entities[i]);
break;
}
}
else
{
{{Generator.IterStepVariables[i]}}
for (int i = 0; i < count; i++)
{
if (!callback({{Generator.GetCallbackSteppedArguments(i, callback)}}))
continue;
result = new Entity(it.Handle->world, it.Handle->entities[i]);
break;
}
if (!callback({{Generator.GetCallbackSteppedArguments(i, callback)}}))
continue;
result = new Entity(it.Handle->world, it.Handle->entities[i]);
break;
}
Ecs.TableUnlock(it);
Expand Down
18 changes: 17 additions & 1 deletion src/Flecs.NET.Codegen/Generators/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ namespace Flecs.NET.Core;
/// A type-safe wrapper around <see cref="Query"/> that takes {{i + 1}} type arguments.
/// </summary>
/// {{Generator.XmlTypeParameters[i]}}
public unsafe partial struct Query<{{Generator.TypeParameters[i]}}> : IDisposable, IEquatable<Query<{{Generator.TypeParameters[i]}}>>
public unsafe partial struct {{Generator.GetTypeName(Type.Query, i)}} : IDisposable, IEquatable<{{Generator.GetTypeName(Type.Query, i)}}>
{
private Query _query;

Expand Down Expand Up @@ -202,6 +202,22 @@ public override int GetHashCode()
}
}

// Flecs.NET Extensions
public unsafe partial struct {{Generator.GetTypeName(Type.Query, i)}}
{
/// <inheritdoc cref="Query.World()"/>
public World World()
{
return _query.World();
}

/// <inheritdoc cref="Query.RealWorld()"/>
public World RealWorld()
{
return _query.RealWorld();
}
}

// IIterableBase Interface
public unsafe partial struct {{Generator.GetTypeName(Type.Query, i)}} : IIterableBase
{
Expand Down
13 changes: 8 additions & 5 deletions src/Flecs.NET.Codegen/Helpers/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -178,14 +178,17 @@ public static class Generator

#endregion

#region Invoker Variables
#region Invoker

// Generates "T0* pointer0 = it.GetPointer<T0>(0); T1* pointer1 = it.GetPointer<T1>(1);..."
public static readonly string[] IterPointerVariables = CacheJoinedStrings(Separator.Space, i => $"T{i}* pointer{i} = it.GetPointer<T{i}>({i});");
// Generates "byte* pointer0 = (byte*)it.GetPointer<T0>(0); byte* pointer1 = (byte*)it.GetPointer<T1>(1);..."
public static readonly string[] IterPointerVariables = CacheJoinedStrings(Separator.Space, i => $"byte* pointer{i} = (byte*)it.GetPointer<T{i}>({i});");

// Generates "int step0 = it.Step<T0>(0); int step1 = it.Step<T1>(1);..."
public static readonly string[] IterStepVariables = CacheJoinedStrings(Separator.Space, i => $"int step{i} = it.Step<T{i}>({i});");

// Generates "pointer0 = &pointer0[step0], pointer1 = &pointer1[step1]..."
public static readonly string[] IterPointerIncrements = CacheJoinedStrings(Separator.Comma, i => $"pointer{i} = &pointer{i}[step{i}]");

#endregion

#region Invoker Callback Arguments
Expand Down Expand Up @@ -218,7 +221,7 @@ public static class Generator
public static readonly string[] EachIterPointerArguments = CacheStrings(i => $"it, i, {EachPointerArguments[i]}");

// Generates "ref Managed.GetTypeRef<T0>(&pointer0[i * step0]), ref Managed.GetTypeRef<T1>(&pointer1[i * step1]), ref Managed.GetTypeRef<T2>(&pointer2[i * step2])..."
public static readonly string[] EachRefSteppedArguments = CacheJoinedStrings(Separator.Comma, i => $"ref Managed.GetTypeRef<T{i}>(&pointer{i}[i * step{i}])");
public static readonly string[] EachRefSteppedArguments = CacheJoinedStrings(Separator.Comma, i => $"ref Managed.GetTypeRef<T{i}>(pointer{i})");

// Generates "new Entity(it.Handle->world, it.Handle->entities[i]), ref Managed.GetTypeRef<T0>(&pointer0[i * step0]), ref Managed.GetTypeRef<T1>(&pointer1[i * step1]), ref Managed.GetTypeRef<T2>(&pointer2[i * step2])"
public static readonly string[] EachEntityRefSteppedArguments = CacheStrings(i => $"new Entity(it.Handle->world, it.Handle->entities[i]), {EachRefSteppedArguments[i]}");
Expand All @@ -227,7 +230,7 @@ public static class Generator
public static readonly string[] EachIterRefSteppedArguments = CacheStrings(i => $"it, i, {EachRefSteppedArguments[i]}");

// Generates "&pointer0[i * step0], &pointer1[i * step1], &pointer2[i * step2]..."
public static readonly string[] EachPointerSteppedArguments = CacheJoinedStrings(Separator.Comma, i => $"&pointer{i}[i * step{i}]");
public static readonly string[] EachPointerSteppedArguments = CacheJoinedStrings(Separator.Comma, i => $"(T{i}*)pointer{i}");

// Generates "new Entity(it.Handle->world, it.Handle->entities[i]), &pointer0[i * step0], &pointer1[i * step1], &pointer2[i * step2]..."
public static readonly string[] EachEntityPointerSteppedArguments = CacheStrings(i => $"new Entity(it.Handle->world, it.Handle->entities[i]), {EachPointerSteppedArguments[i]}");
Expand Down
39 changes: 31 additions & 8 deletions src/Flecs.NET.Tests/CSharp/Core/EntityTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,49 @@ namespace Flecs.NET.Tests.CSharp.Core
public class EntityTests
{
[Fact]
public void AddManaged()
public void AddManagedClass()
{
using World world = World.Create();
Entity entity = world.Entity();

entity.Add<string>();
Assert.True(entity.Has<string>());
entity.Add<ManagedClass>();
Assert.True(entity.Has<ManagedClass>());
}

[Fact]
public void SetManaged()
public void SetManagedClass()
{
using World world = World.Create();
Entity entity = world.Entity();

entity.Set<string>("Text");
Assert.True(entity.Has<string>());
entity.Set(new ManagedClass(10));
Assert.True(entity.Has<ManagedClass>());

ref readonly string str = ref entity.Get<string>();
Assert.True(str == "Text");
ref readonly ManagedClass component = ref entity.Get<ManagedClass>();
Assert.True(component.Value == 10);
}

[Fact]
public void AddManagedStruct()
{
using World world = World.Create();
Entity entity = world.Entity();

entity.Add<ManagedStruct>();
Assert.True(entity.Has<ManagedStruct>());
}

[Fact]
public void SetManagedStruct()
{
using World world = World.Create();
Entity entity = world.Entity();

entity.Set(new ManagedStruct(10));
Assert.True(entity.Has<ManagedStruct>());

ref readonly ManagedStruct component = ref entity.Get<ManagedStruct>();
Assert.True(component.Value == 10);
}
}
}
36 changes: 36 additions & 0 deletions src/Flecs.NET.Tests/CSharp/Core/QueryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -785,5 +785,41 @@ static void Callback(Iter it)
}
}
}

[Fact]
private void EachManagedClass()
{
using World world = World.Create();
using Query<ManagedClass> query = world.Query<ManagedClass>();

for (int i = 0; i < 5; i ++)
world.Entity().Set(new ManagedClass(10));

Assert.True(query.IsTrue());
Assert.Equal(5, query.Count());

query.Each(static (Iter _, int i, ref ManagedClass component) =>
{
Assert.Equal(10, component.Value);
});
}

[Fact]
private void EachManagedStruct()
{
using World world = World.Create();
using Query<ManagedStruct> query = world.Query<ManagedStruct>();

for (int i = 0; i < 5; i ++)
world.Entity().Set(new ManagedStruct(10));

Assert.True(query.IsTrue());
Assert.Equal(5, query.Count());

query.Each(static (Iter it, int i, ref ManagedStruct component) =>
{
Assert.Equal(10, component.Value);
});
}
}
}
12 changes: 12 additions & 0 deletions src/Flecs.NET.Tests/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,24 @@ public record struct Other(int Value);
public record struct Singleton(int Value);
public record struct PositionInitialized(float X, float Y);

public record struct ManagedStruct(int Value)
{
public object Dummy = null!;
}

public class ManagedClass(int value)
{
public int Value = value;
public object Dummy = null!;
}

public class ManagedComponent
{
public string Value = null!;
public ManagedComponent Nested = null!;
}


public struct Base;
public struct Prefab;

Expand Down
6 changes: 4 additions & 2 deletions src/Flecs.NET/Core/BindingContext/QueryContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ internal struct QueryContext : IDisposable
{
public Callback OrderByAction;
public Callback GroupByAction;
public Callback ContextFree;
public Callback GroupByContextFree;
public Callback GroupCreateAction;
public Callback GroupDeleteAction;
public Callback ContextFree;

public NativeList<NativeString> Strings;

public void Dispose()
{
OrderByAction.Dispose();
GroupByAction.Dispose();
ContextFree.Dispose();
GroupByContextFree.Dispose();
GroupCreateAction.Dispose();
GroupDeleteAction.Dispose();
ContextFree.Dispose();

if (Strings == default)
return;
Expand Down
4 changes: 2 additions & 2 deletions src/Flecs.NET/Core/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3780,11 +3780,11 @@ private ref Entity SetInternal<T>(ulong id, T* component)
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>())
{
Managed.AllocGcHandle(component, out GCHandle handle);
ecs_set_id(World, Id, id, (IntPtr)sizeof(T), &handle);
ecs_set_id(World, Id, id, sizeof(GCHandle), &handle);
}
else
{
ecs_set_id(World, Id, id, (IntPtr)sizeof(T), component);
ecs_set_id(World, Id, id, sizeof(T), component);
}

return ref this;
Expand Down
2 changes: 1 addition & 1 deletion src/Flecs.NET/Core/Iter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ internal Span<T> GetSpan<T>(int index)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal int Step<T>(int index)
{
return (Handle->sources == null || Handle->sources[index] == 0) && (Handle->set_fields & (1 << index)) != 0 && !Type<T>.IsTag ? 1 : 0;
return (Handle->sources == null || Handle->sources[index] == 0) && (Handle->set_fields & (1 << index)) != 0 && !Type<T>.IsTag ? Type<T>.Size : 0;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
6 changes: 3 additions & 3 deletions src/Flecs.NET/Core/QueryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1715,7 +1715,7 @@ public ref QueryBuilder GroupBy(ulong component, Ecs.GroupByCallback callback)
"Cannot set .GroupBy callback if group_by_ctx is already occupied.");

Context.GroupByAction.Dispose();
Context.ContextFree.Dispose();
Context.GroupByContextFree.Dispose();

GroupByContext* context = Memory.AllocZeroed<GroupByContext>(1);
Callback.Set(ref context->GroupBy, callback);
Expand Down Expand Up @@ -1746,8 +1746,8 @@ public ref QueryBuilder GroupBy<T>(Ecs.GroupByCallback callback)
/// <returns></returns>
public ref QueryBuilder GroupByCtx(void* ctx, Ecs.ContextFree contextFree)
{
Callback.Set(ref Context.ContextFree, contextFree);
Desc.group_by_ctx_free = Context.ContextFree.Pointer;
Callback.Set(ref Context.GroupByContextFree, contextFree);
Desc.group_by_ctx_free = Context.GroupByContextFree.Pointer;
Desc.group_by_ctx = ctx;
return ref this;
}
Expand Down
Loading

0 comments on commit 98ea3b0

Please sign in to comment.