ECS refactor: new ComponentSet, serialization, generators

Major ECS API overhaul: added ComponentSet, refactored ComponentRegistry, and updated all entity/component creation methods. Introduced robust custom serialization infrastructure and per-component source generators for registration and (de)serialization. Updated editor, engine, and test code to use new APIs. Improved code quality, naming, and performance throughout. Removed obsolete code and updated dependencies.
This commit is contained in:
2025-12-20 20:41:40 +09:00
parent 3118021272
commit 00b4e82ded
60 changed files with 1216 additions and 814 deletions

View File

@@ -2,5 +2,6 @@ using Ghost.Core.Attributes;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Ghost.Graphics")] [assembly: InternalsVisibleTo("Ghost.Graphics")]
[assembly: InternalsVisibleTo("Ghost.Engine")]
[assembly: EngineAssembly] [assembly: EngineAssembly]

View File

@@ -23,9 +23,9 @@
<PackageReference Include="Misaki.HighPerformance" Version="1.0.2" /> <PackageReference Include="Misaki.HighPerformance" Version="1.0.2" />
<PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.2.1" /> <PackageReference Include="Misaki.HighPerformance.Jobs" Version="1.2.1" />
<PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.3.2" /> <PackageReference Include="Misaki.HighPerformance.LowLevel" Version="1.3.2" />
<PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.2.6" /> <PackageReference Include="Misaki.HighPerformance.Mathematics" Version="1.3.0" />
<PackageReference Include="System.IO.Hashing" Version="10.0.0" /> <PackageReference Include="System.IO.Hashing" Version="10.0.1" />
<PackageReference Include="TerraFX.Interop.Windows" Version="10.0.26100.5" /> <PackageReference Include="TerraFX.Interop.Windows" Version="10.0.26100.6" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -68,7 +68,7 @@ public readonly struct Identifier<T> : IEquatable<Identifier<T>>
public static Identifier<T> Invalid => new(-1); public static Identifier<T> Invalid => new(-1);
public readonly bool IsValid => this != Invalid; public readonly bool IsValid => this != Invalid;
public readonly bool IsNotValid => this == Invalid; public readonly bool IsInvalid => this == Invalid;
public readonly override int GetHashCode() public readonly override int GetHashCode()
{ {

View File

@@ -11,7 +11,7 @@ public static partial class AssetDatabase
private static void InitializeMetaData() private static void InitializeMetaData()
{ {
if (_watcher == null) if (s_watcher == null)
{ {
throw new InvalidOperationException("AssetDatabase is not initialized. Ensure that Initialize() is called before registering asset importers."); throw new InvalidOperationException("AssetDatabase is not initialized. Ensure that Initialize() is called before registering asset importers.");
} }
@@ -26,24 +26,24 @@ public static partial class AssetDatabase
} }
} }
_watcher.Created += OnAssetCreated; s_watcher.Created += OnAssetCreated;
_watcher.Deleted += OnAssetDeleted; s_watcher.Deleted += OnAssetDeleted;
_watcher.Renamed += OnAssetRenamed; s_watcher.Renamed += OnAssetRenamed;
} }
private static Result<string> GetMetaFilePath(string assetPath) private static Result<string, ErrorStatus> GetMetaFilePath(string assetPath)
{ {
if (Directory.Exists(assetPath)) if (Directory.Exists(assetPath))
{ {
return Result<string>.Failure("Folder does not have meta data"); return ErrorStatus.NotFound;
} }
if (Path.GetExtension(assetPath).Equals(".meta", StringComparison.OrdinalIgnoreCase)) if (Path.GetExtension(assetPath).Equals(".meta", StringComparison.OrdinalIgnoreCase))
{ {
return Result<string>.Failure("Asset path cannot be a meta file"); return ErrorStatus.InvalidState;
} }
return Result<string>.Success(assetPath + ".meta"); return assetPath + ".meta";
} }
private static ImporterSettings? GetDefaultSettingsForAsset(string assetPath) private static ImporterSettings? GetDefaultSettingsForAsset(string assetPath)
@@ -83,7 +83,7 @@ public static partial class AssetDatabase
var metaFileResult = GetMetaFilePath(assetPath); var metaFileResult = GetMetaFilePath(assetPath);
if (!metaFileResult.IsSuccess) if (!metaFileResult.IsSuccess)
{ {
return Result.Failure(metaFileResult.Message); return Result.Failure(metaFileResult.Error.ToString());
} }
if (File.Exists(metaFileResult.Value)) if (File.Exists(metaFileResult.Value))

View File

@@ -1,3 +1,4 @@
using Ghost.Editor.Core.Utilities;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
@@ -9,8 +10,7 @@ public static partial class AssetDatabase
private static void InitializeAssetHandle() private static void InitializeAssetHandle()
{ {
var methods = AppDomain.CurrentDomain.GetAssemblies() var methods = TypeCache.GetTypes()
.SelectMany(a => a.GetTypes())
.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) .SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
.Where(m => m.GetCustomAttribute<AssetOpenHandlerAttribute>() != null && .Where(m => m.GetCustomAttribute<AssetOpenHandlerAttribute>() != null &&
m.GetParameters().Length == 1 && m.GetParameters().Length == 1 &&

View File

@@ -4,7 +4,7 @@ namespace Ghost.Editor.Core.AssetHandle;
public static partial class AssetDatabase public static partial class AssetDatabase
{ {
private static FileSystemWatcher? _watcher; private static FileSystemWatcher? s_watcher;
private static readonly Dictionary<Guid, string> s_assetPathLookup = new(); private static readonly Dictionary<Guid, string> s_assetPathLookup = new();
@@ -22,7 +22,7 @@ public static partial class AssetDatabase
} }
AssetsDirectory = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(ProjectService.CurrentProject.Path)!, ProjectService.ASSETS_FOLDER)); AssetsDirectory = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(ProjectService.CurrentProject.Path)!, ProjectService.ASSETS_FOLDER));
_watcher = new FileSystemWatcher s_watcher = new FileSystemWatcher
{ {
Path = AssetsDirectory.FullName, Path = AssetsDirectory.FullName,
IncludeSubdirectories = true, IncludeSubdirectories = true,

View File

@@ -19,12 +19,14 @@ public sealed partial class PropertyField : ContentControl
{ typeof(RangeBase), RangeBase.ValueProperty }, { typeof(RangeBase), RangeBase.ValueProperty },
}; };
private object? sourceObject; private object? _sourceObject;
private FieldInfo? propertyInfo; internal FieldInfo? _propertyInfo;
private Type? _fieldType; internal Type? _fieldType;
private object? _lastValue; private object? _lastValue;
public event Action<PropertyField>? OnValueChanged;
public string Label public string Label
{ {
get => (string)GetValue(LabelProperty); get => (string)GetValue(LabelProperty);
@@ -59,8 +61,8 @@ public sealed partial class PropertyField : ContentControl
private static TField ConfigureField<TField>(PropertyField propertyField, FieldInfo fieldInfo, object sourceObject, Func<TField> factory) private static TField ConfigureField<TField>(PropertyField propertyField, FieldInfo fieldInfo, object sourceObject, Func<TField> factory)
where TField : FrameworkElement where TField : FrameworkElement
{ {
propertyField.sourceObject = sourceObject; propertyField._sourceObject = sourceObject;
propertyField.propertyInfo = fieldInfo; propertyField._propertyInfo = fieldInfo;
propertyField._fieldType = typeof(TField); propertyField._fieldType = typeof(TField);
var field = factory(); var field = factory();
@@ -72,6 +74,12 @@ public sealed partial class PropertyField : ContentControl
Path = new PropertyPath(fieldInfo.Name), Path = new PropertyPath(fieldInfo.Name),
Mode = BindingMode.TwoWay, Mode = BindingMode.TwoWay,
}); });
field.RegisterPropertyChangedCallback(dp, (s, e) =>
{
propertyField.OnValueChanged?.Invoke(propertyField);
});
return field; return field;
} }
@@ -82,14 +90,10 @@ public sealed partial class PropertyField : ContentControl
Label = label Label = label
}; };
FrameworkElement content; FrameworkElement content = fieldInfo.FieldType switch
switch (fieldInfo.FieldType)
{ {
case Type t when t == typeof(string): Type t when t == typeof(string) => ConfigureField(propertyField, fieldInfo, sourceObject, () => new TextBox()),
content = ConfigureField(propertyField, fieldInfo, sourceObject, () => new TextBox()); Type t when t == typeof(int) || t == typeof(float) || t == typeof(double) => ConfigureField(propertyField, fieldInfo, sourceObject, () => new NumberBox
break;
case Type t when t == typeof(int) || t == typeof(float) || t == typeof(double):
content = ConfigureField(propertyField, fieldInfo, sourceObject, () => new NumberBox
{ {
SpinButtonPlacementMode = NumberBoxSpinButtonPlacementMode.Hidden, SpinButtonPlacementMode = NumberBoxSpinButtonPlacementMode.Hidden,
AcceptsExpression = true, AcceptsExpression = true,
@@ -97,27 +101,20 @@ public sealed partial class PropertyField : ContentControl
{ {
FractionDigits = t == typeof(int) ? 0 : 9, FractionDigits = t == typeof(int) ? 0 : 9,
} }
}); }),
break; Type t when t == typeof(bool) => ConfigureField(propertyField, fieldInfo, sourceObject, () => new ToggleSwitch()),
case Type t when t == typeof(bool): Type t when t == typeof(Enum) => ConfigureField(propertyField, fieldInfo, sourceObject, () => new ComboBox
content = ConfigureField(propertyField, fieldInfo, sourceObject, () => new ToggleSwitch());
break;
case Type t when t == typeof(Enum):
content = ConfigureField(propertyField, fieldInfo, sourceObject, () => new ComboBox
{ {
ItemsSource = Enum.GetValues(t), ItemsSource = Enum.GetValues(t),
SelectedValuePath = "Value", SelectedValuePath = "Value",
}); }),
break; _ => new TextBlock
default:
content = new TextBlock
{ {
Text = $"Unsupported type: {fieldInfo.FieldType.Name}", Text = $"Unsupported type: {fieldInfo.FieldType.Name}",
VerticalAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Center,
Foreground = new Microsoft.UI.Xaml.Media.SolidColorBrush(Microsoft.UI.Colors.Red) Foreground = new Microsoft.UI.Xaml.Media.SolidColorBrush(Microsoft.UI.Colors.Red)
},
}; };
break;
}
propertyField.Content = content; propertyField.Content = content;
return propertyField; return propertyField;
@@ -125,12 +122,12 @@ public sealed partial class PropertyField : ContentControl
public void UpdateValue() public void UpdateValue()
{ {
if (sourceObject == null || propertyInfo == null || _fieldType == null) if (_sourceObject == null || _propertyInfo == null || _fieldType == null)
{ {
return; return;
} }
var currentValue = propertyInfo.GetValue(sourceObject); var currentValue = _propertyInfo.GetValue(_sourceObject);
if (Equals(currentValue, _lastValue)) if (Equals(currentValue, _lastValue))
{ {
return; return;
@@ -139,7 +136,7 @@ public sealed partial class PropertyField : ContentControl
var dp = GetValueProperty(_fieldType); var dp = GetValueProperty(_fieldType);
if (dp != null) if (dp != null)
{ {
SetValue(dp, propertyInfo.GetValue(sourceObject)); SetValue(dp, _propertyInfo.GetValue(_sourceObject));
_lastValue = currentValue; _lastValue = currentValue;
} }
} }

View File

@@ -4,10 +4,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Ghost.Editor.Core.Controls.Internal"> xmlns:local="using:Ghost.Editor.Core.Controls.Internal">
<Style TargetType="local:ComponentDataView"> <Style TargetType="local:ComponentView">
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="local:ComponentDataView"> <ControlTemplate TargetType="local:ComponentView">
<StackPanel Margin="0,0,0,16"> <StackPanel Margin="0,0,0,16">
<Border <Border
Padding="8" Padding="8"

View File

@@ -1,15 +1,15 @@
using Ghost.Core;
using Ghost.Editor.Core.Inspector; using Ghost.Editor.Core.Inspector;
using Ghost.Editor.Core.Resources; using Ghost.Editor.Core.Resources;
using Ghost.Editor.Core.Utilities; using Ghost.Editor.Core.Utilities;
using Ghost.SparseEntities; using Ghost.Entities;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
namespace Ghost.Editor.Core.Controls.Internal; namespace Ghost.Editor.Core.Controls.Internal;
internal unsafe sealed partial class ComponentDataView : Control internal sealed unsafe partial class ComponentView : Control
{ {
private delegate void EditorUpdate(); private delegate void EditorUpdate();
@@ -18,6 +18,10 @@ internal unsafe sealed partial class ComponentDataView : Control
private readonly World? _world; private readonly World? _world;
private readonly Entity _entity = Entity.Invalid; private readonly Entity _entity = Entity.Invalid;
private readonly Type? _componentType; private readonly Type? _componentType;
private readonly ComponentInfo _componentInfo;
private object? _managedInstance;
private void* _pComponentData;
private ComponentEditor? _customEditor; private ComponentEditor? _customEditor;
private PropertyField[]? _propertyFields; private PropertyField[]? _propertyFields;
@@ -30,11 +34,11 @@ internal unsafe sealed partial class ComponentDataView : Control
} }
public static readonly DependencyProperty HeaderTextProperty = public static readonly DependencyProperty HeaderTextProperty =
DependencyProperty.Register(nameof(HeaderText), typeof(string), typeof(ComponentDataView), new PropertyMetadata(string.Empty)); DependencyProperty.Register(nameof(HeaderText), typeof(string), typeof(ComponentView), new PropertyMetadata(string.Empty));
internal ComponentDataView() internal ComponentView()
{ {
DefaultStyleKey = typeof(ComponentDataView); DefaultStyleKey = typeof(ComponentView);
Unloaded += (s, e) => Unloaded += (s, e) =>
{ {
@@ -46,12 +50,14 @@ internal unsafe sealed partial class ComponentDataView : Control
}; };
} }
public ComponentDataView(string header, World world, Entity entity, Type componentType) : this() public ComponentView(string header, World world, Entity entity, Type componentType) : this()
{ {
HeaderText = header; HeaderText = header;
_world = world; _world = world;
_entity = entity; _entity = entity;
_componentType = componentType; _componentType = componentType;
_componentInfo = ComponentRegistry.GetComponentInfo(componentType);
} }
protected override void OnApplyTemplate() protected override void OnApplyTemplate()
@@ -77,7 +83,7 @@ internal unsafe sealed partial class ComponentDataView : Control
private void CustomEditorUpdate() private void CustomEditorUpdate()
{ {
_customEditor!.Update(); _customEditor?.Update();
} }
public void ReBuild() public void ReBuild()
@@ -93,6 +99,14 @@ internal unsafe sealed partial class ComponentDataView : Control
return; return;
} }
if (_propertyFields != null)
{
foreach (var propertyField in _propertyFields)
{
propertyField.OnValueChanged -= OnPropertyValueChanged;
}
}
var componentObject = new ComponentObject(_world, _entity); var componentObject = new ComponentObject(_world, _entity);
var editorType = TypeCache.GetTypes().FirstOrDefault(t => var editorType = TypeCache.GetTypes().FirstOrDefault(t =>
typeof(ComponentEditor).IsAssignableFrom(t) && typeof(ComponentEditor).IsAssignableFrom(t) &&
@@ -106,18 +120,21 @@ internal unsafe sealed partial class ComponentDataView : Control
} }
else else
{ {
var fields = _componentType.GetFields(StaticResource.componentPropertyBindingFlags); var fields = _componentType.GetFields(StaticResource.ComponentPropertyBindingFlags);
_propertyFields = new PropertyField[fields.Length]; _propertyFields = new PropertyField[fields.Length];
_pComponentData = _world.EntityManager.GetComponent(_entity, _componentInfo.id);
_managedInstance = Marshal.PtrToStructure((nint)_pComponentData, _componentType);
if (_managedInstance == null)
{
return;
}
for (var i = 0; i < fields.Length; i++) for (var i = 0; i < fields.Length; i++)
{ {
var field = fields[i]; var field = fields[i];
if (!_world.ComponentStorage.TryGetPool(TypeHandle.Get(_componentType), out var pool)) var propertyField = PropertyField.Create(field.Name, field, _managedInstance);
{ propertyField.OnValueChanged += OnPropertyValueChanged;
continue;
}
var component = pool.Get(_entity);
var propertyField = PropertyField.Create(field.Name, field, component);
_propertyFields[i] = propertyField; _propertyFields[i] = propertyField;
_contentContainer.Children.Add(propertyField); _contentContainer.Children.Add(propertyField);
@@ -126,19 +143,15 @@ internal unsafe sealed partial class ComponentDataView : Control
_editorUpdate = _customEditor == null ? ReflectionUpdate : CustomEditorUpdate; _editorUpdate = _customEditor == null ? ReflectionUpdate : CustomEditorUpdate;
_editorUpdate(); _editorUpdate();
_world.ComponentChanged += OnComponentChanged;
} }
private void OnComponentChanged(World world, Entity entity, Type type) private void OnPropertyValueChanged(PropertyField field)
{ {
if (world != _world if (_managedInstance == null || _pComponentData == null)
|| entity != _entity
|| type != _componentType)
{ {
return; return;
} }
_editorUpdate?.Invoke(); Marshal.StructureToPtr(_managedInstance, (nint)_pComponentData, false);
} }
} }

View File

@@ -41,8 +41,4 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Data\" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,10 +1,8 @@
using Ghost.SparseEntities; using Ghost.Entities;
using Ghost.SparseEntities.Components;
using Ghost.SparseEntities.Query;
namespace Ghost.Editor.Core.Inspector; namespace Ghost.Editor.Core.Inspector;
public unsafe readonly struct ComponentObject public readonly struct ComponentObject
{ {
private readonly World _world; private readonly World _world;
private readonly Entity _entity; private readonly Entity _entity;
@@ -15,15 +13,15 @@ public unsafe readonly struct ComponentObject
_entity = entity; _entity = entity;
} }
public CompRef<T> GetData<T>() public ref T GetData<T>()
where T : unmanaged, IComponentData where T : unmanaged, IComponent
{ {
return _world.EntityManager.GetComponent<T>(_entity); return ref _world.EntityManager.GetComponent<T>(_entity);
} }
public void SetData<T>(in T data) public void SetData<T>(in T data)
where T : unmanaged, IComponentData where T : unmanaged, IComponent
{ {
_world.EntityManager.SetComponent(_entity, in data); _world.EntityManager.SetComponent(_entity, data);
} }
} }

View File

@@ -4,5 +4,5 @@ namespace Ghost.Editor.Core.Resources;
internal static class StaticResource internal static class StaticResource
{ {
public static readonly BindingFlags componentPropertyBindingFlags = BindingFlags.Public | BindingFlags.Instance; public static readonly BindingFlags ComponentPropertyBindingFlags = BindingFlags.Public | BindingFlags.Instance;
} }

View File

@@ -15,15 +15,15 @@ public enum OpenWorldMode
public static class EditorWorldManager public static class EditorWorldManager
{ {
// TODO: Use guid keys instead of string paths for better performance and uniqueness // TODO: Use guid keys instead of string paths for better performance and uniqueness
private static readonly Dictionary<string, WorldNode> _loadedWorlds = new(); private static readonly Dictionary<string, WorldNode> s_loadedWorlds = new();
public static IEnumerable<WorldNode> LoadedWorlds => _loadedWorlds.Values; public static IEnumerable<WorldNode> LoadedWorlds => s_loadedWorlds.Values;
public static event Action<WorldNode>? OnWorldLoaded; public static event Action<WorldNode>? OnWorldLoaded;
public static event Action<WorldNode>? OnWorldUnloaded; public static event Action<WorldNode>? OnWorldUnloaded;
public static async Task LoadWorld(string worldPath) public static async Task LoadWorld(string worldPath)
{ {
if (_loadedWorlds.ContainsKey(worldPath) if (s_loadedWorlds.ContainsKey(worldPath)
|| !File.Exists(worldPath) || !File.Exists(worldPath)
|| Path.GetExtension(worldPath) != FileExtensions.SCENE_FILE_EXTENSION) || Path.GetExtension(worldPath) != FileExtensions.SCENE_FILE_EXTENSION)
{ {
@@ -33,18 +33,18 @@ public static class EditorWorldManager
var progressService = EditorApplication.GetService<IProgressService>(); var progressService = EditorApplication.GetService<IProgressService>();
progressService.ShowIndeterminateProgress("Loading world..."); progressService.ShowIndeterminateProgress("Loading world...");
foreach (var world in _loadedWorlds) foreach (var world in s_loadedWorlds)
{ {
world.Value.Unload(); world.Value.Unload();
OnWorldUnloaded?.Invoke(world.Value); OnWorldUnloaded?.Invoke(world.Value);
} }
await using var readStream = new FileStream(worldPath, FileMode.Open, FileAccess.Read, FileShare.Read); await using var readStream = new FileStream(worldPath, FileMode.Open, FileAccess.Read, FileShare.Read);
var deserializedScene = await JsonSerializer.DeserializeAsync<WorldNode>(readStream, Engine.Resources.StaticResource.defaultSerializerOptions) ?? throw new Exception("Deserialization failed."); var deserializedScene = await JsonSerializer.DeserializeAsync<WorldNode>(readStream, Engine.Resources.EngineResource.defaultSerializerOptions) ?? throw new Exception("Deserialization failed.");
_loadedWorlds.Clear(); s_loadedWorlds.Clear();
_loadedWorlds[worldPath] = deserializedScene; s_loadedWorlds[worldPath] = deserializedScene;
await deserializedScene.LoadAsync(); await deserializedScene.LoadAsync();
progressService.HideProgress(); progressService.HideProgress();

View File

@@ -2,7 +2,7 @@ using Ghost.Editor.Core.Controls.Internal;
using Ghost.Editor.Core.Inspector; using Ghost.Editor.Core.Inspector;
using Ghost.Editor.Core.Resources; using Ghost.Editor.Core.Resources;
using Ghost.Engine.Editor; using Ghost.Engine.Editor;
using Ghost.SparseEntities; using Ghost.Entities;
using Microsoft.UI.Text; using Microsoft.UI.Text;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
@@ -76,31 +76,46 @@ public partial class EntityNode : IInspectable
} }
} }
public UIElement? InspectorContent public unsafe UIElement? InspectorContent
{ {
get get
{ {
var r = Owner.World.EntityManager.GetEntityLocation(Entity);
if (!r)
{
return null;
}
var root = new StackPanel() var root = new StackPanel()
{ {
HorizontalAlignment = HorizontalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Top VerticalAlignment = VerticalAlignment.Top
}; };
foreach (var (typeHandle, componentPtr) in Owner.World.EntityManager.GetComponentsUnsafe(Entity)) var location = r.Value;
ref var archetype = ref Owner.World.GetArchetypeReference(location.archetypeID);
var it = archetype._signature.GetIterator();
while (it.Next(out var typeID))
{ {
if (componentPtr == IntPtr.Zero) var pComponent = archetype.GetComponentData(location.chunkIndex, location.rowIndex, typeID);
if (pComponent == null)
{ {
continue; continue;
} }
var type = typeHandle.ToType(); if (!ComponentRegistry.s_runtimeIDToType.TryGetValue(typeID, out var t))
if (type == null || type.GetCustomAttribute<HideEditorAttribute>() != null)
{ {
continue; continue;
} }
var dataView = new ComponentDataView(type.Name, Owner.World, Entity, type); if (t.GetCustomAttribute<HideEditorAttribute>() != null)
root.Children.Add(dataView); {
continue;
}
var componentView = new ComponentView(t.Name, Owner.World, Entity, t);
root.Children.Add(componentView);
} }
return root; return root;

View File

@@ -1,5 +1,5 @@
using Ghost.Engine.Components; using Ghost.Engine.Components;
using Ghost.SparseEntities; using Ghost.Entities;
namespace Ghost.Editor.Core.SceneGraph; namespace Ghost.Editor.Core.SceneGraph;
@@ -37,23 +37,23 @@ public class SceneGraphHelpers
{ {
// 1) If the child already has a parent, detach it first // 1) If the child already has a parent, detach it first
var childHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(childNode.Entity); var childHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(childNode.Entity);
if (childHierarchy.ValueRO.parent != Entity.Invalid) if (childHierarchy.parent != Entity.Invalid)
{ {
DetachFromParent(scene, childNode); DetachFromParent(scene, childNode);
} }
// 2) Link child to new parent // 2) Link child to new parent
childHierarchy.ValueRW.parent = parentNode.Entity; childHierarchy.parent = parentNode.Entity;
// 3) Insert child at the head of parent's child list // 3) Insert child at the head of parent's child list
var parentHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(parentNode.Entity); var parentHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(parentNode.Entity);
childHierarchy.ValueRW.nextSibling = parentHierarchy.ValueRO.firstChild; childHierarchy.nextSibling = parentHierarchy.firstChild;
parentHierarchy.ValueRW.firstChild = childNode.Entity; parentHierarchy.firstChild = childNode.Entity;
// 4) Write back // 4) Write back
scene.World.EntityManager.SetComponent(parentNode.Entity, in parentHierarchy.ValueRO); scene.World.EntityManager.SetComponent(parentNode.Entity, parentHierarchy);
scene.World.EntityManager.SetComponent(childNode.Entity, in childHierarchy.ValueRO); scene.World.EntityManager.SetComponent(childNode.Entity, childHierarchy);
// 5) Update children list in parent node // 5) Update children list in parent node
parentNode.AddChild(childNode); parentNode.AddChild(childNode);
@@ -67,7 +67,7 @@ public class SceneGraphHelpers
public static void DetachFromParent(WorldNode scene, EntityNode node) public static void DetachFromParent(WorldNode scene, EntityNode node)
{ {
var hierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(node.Entity); var hierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(node.Entity);
var parent = hierarchy.ValueRO.parent; var parent = hierarchy.parent;
if (parent == Entity.Invalid) if (parent == Entity.Invalid)
{ {
return; // already root return; // already root
@@ -76,35 +76,35 @@ public class SceneGraphHelpers
var parentHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(parent); var parentHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(parent);
// If entity is the first child, simply move head // If entity is the first child, simply move head
if (parentHierarchy.ValueRO.firstChild == node.Entity) if (parentHierarchy.firstChild == node.Entity)
{ {
parentHierarchy.ValueRW.firstChild = hierarchy.ValueRO.nextSibling; parentHierarchy.firstChild = hierarchy.nextSibling;
} }
else else
{ {
// Otherwise, find the previous sibling in the linked list // Otherwise, find the previous sibling in the linked list
var prevSibling = parentHierarchy.ValueRO.firstChild; var prevSibling = parentHierarchy.firstChild;
while (prevSibling != Entity.Invalid) while (prevSibling != Entity.Invalid)
{ {
var prevHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(prevSibling); var prevHierarchy = scene.World.EntityManager.GetComponent<Hierarchy>(prevSibling);
if (prevHierarchy.ValueRW.nextSibling == node.Entity) if (prevHierarchy.nextSibling == node.Entity)
{ {
prevHierarchy.ValueRW.nextSibling = hierarchy.ValueRO.nextSibling; prevHierarchy.nextSibling = hierarchy.nextSibling;
scene.World.EntityManager.SetComponent(prevSibling, in prevHierarchy.ValueRO); scene.World.EntityManager.SetComponent(prevSibling, prevHierarchy);
break; break;
} }
prevSibling = prevHierarchy.ValueRO.nextSibling; prevSibling = prevHierarchy.nextSibling;
} }
} }
// Clear child's references // Clear child's references
hierarchy.ValueRW.parent = Entity.Invalid; hierarchy.parent = Entity.Invalid;
hierarchy.ValueRW.nextSibling = Entity.Invalid; hierarchy.nextSibling = Entity.Invalid;
// Write back // Write back
scene.World.EntityManager.SetComponent(parent, in parentHierarchy.ValueRO); scene.World.EntityManager.SetComponent(parent, parentHierarchy);
scene.World.EntityManager.SetComponent(node.Entity, in hierarchy.ValueRO); scene.World.EntityManager.SetComponent(node.Entity, hierarchy);
// Remove from parent's children list // Remove from parent's children list
scene.EntityNodeLookup[parent].RemoveChild(node); scene.EntityNodeLookup[parent].RemoveChild(node);

View File

@@ -3,14 +3,14 @@ using Ghost.Editor.Core.Inspector;
using Ghost.Editor.Core.Resources; using Ghost.Editor.Core.Resources;
using Ghost.Editor.Core.Serializer; using Ghost.Editor.Core.Serializer;
using Ghost.Engine.Components; using Ghost.Engine.Components;
using Ghost.SparseEntities; using Ghost.Engine.IO;
using Ghost.Entities;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using System.Text.Json.Serialization;
namespace Ghost.Editor.Core.SceneGraph; namespace Ghost.Editor.Core.SceneGraph;
[JsonConverter(typeof(WorldNodeSerializer))] [CustomSerializer(typeof(WorldNodeSerializer))]
public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode> public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
{ {
private World _world; private World _world;
@@ -27,11 +27,6 @@ public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
Name = name; Name = name;
} }
internal WorldNode()
{
_world = World.Create();
}
private void UpdateLookup(Entity key, EntityNode value) private void UpdateLookup(Entity key, EntityNode value)
{ {
_entityNodeLookup[key] = value; _entityNodeLookup[key] = value;
@@ -85,13 +80,13 @@ public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
} }
var hc = _world.EntityManager.GetComponent<Hierarchy>(entity); var hc = _world.EntityManager.GetComponent<Hierarchy>(entity);
var child = hc.ValueRO.firstChild; var child = hc.firstChild;
while (child != Entity.Invalid) while (child != Entity.Invalid)
{ {
node.AddChild(BuildNodeRecursive(child)); node.AddChild(BuildNodeRecursive(child));
var childHC = _world.EntityManager.GetComponent<Hierarchy>(child); var childHC = _world.EntityManager.GetComponent<Hierarchy>(child);
child = childHC.ValueRO.nextSibling; child = childHC.nextSibling;
} }
return node; return node;
@@ -99,14 +94,18 @@ public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
private void BuildGraph() private void BuildGraph()
{ {
foreach (var (entity, hierarchy) in _world.Query<Hierarchy>()) var queryID = new QueryBuilder()
.WithAll<Hierarchy>()
.Build(_world);
_world.GetEntityQueryReference(queryID).ForEach<Hierarchy>((entity, ref hierarchy) =>
{ {
if (hierarchy.ValueRO.parent == Entity.Invalid) if (hierarchy.parent == Entity.Invalid)
{ {
var node = BuildNodeRecursive(entity); var node = BuildNodeRecursive(entity);
AddChild(node); AddChild(node);
} }
} });
} }
public Task LoadAsync() public Task LoadAsync()
@@ -116,7 +115,6 @@ public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
public void Unload() public void Unload()
{ {
_world.Dispose();
_world = null!; _world = null!;
Children?.Clear(); Children?.Clear();

View File

@@ -1,13 +1,13 @@
using Ghost.Editor.Core.SceneGraph; using Ghost.Editor.Core.SceneGraph;
using Ghost.Engine;
using Ghost.Engine.IO;
using Ghost.Engine.Utilities; using Ghost.Engine.Utilities;
using Ghost.SparseEntities; using Ghost.Entities;
using Ghost.SparseEntities.Components;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization;
namespace Ghost.Editor.Core.Serializer; namespace Ghost.Editor.Core.Serializer;
internal class WorldNodeSerializer : JsonConverter<WorldNode> internal class WorldNodeSerializer : CustomSerializer<WorldNode>
{ {
private static class Property private static class Property
{ {
@@ -25,112 +25,124 @@ internal class WorldNodeSerializer : JsonConverter<WorldNode>
return typeToConvert == typeof(WorldNode) || typeToConvert.IsSubclassOf(typeof(WorldNode)); return typeToConvert == typeof(WorldNode) || typeToConvert.IsSubclassOf(typeof(WorldNode));
} }
public override WorldNode? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) public unsafe override void SerializeJson(Utf8JsonWriter writer, WorldNode value, JsonSerializerOptions options)
{
var element = JsonDocument.ParseValue(ref reader).RootElement;
var name = element.GetProperty(Property.NAME).GetString() ?? "New World";
var world = World.Create();
var result = new WorldNode(world, name);
foreach (var entityElement in element.GetProperty(Property.ENTITIES).EnumerateArray())
{
var entityName = entityElement.GetProperty(Property.NAME).GetString() ?? "New Entity";
var entityID = entityElement.GetProperty(Property.ID).GetInt32();
var entity = new Entity(entityID, 0);
var node = new EntityNode(result, entity, entityName);
world.EntityManager.AddEntityInternal(entity);
result.EntityNodeLookup[entity] = node;
}
foreach (var componentElement in element.GetProperty(Property.COMPONENTS).EnumerateObject())
{
var typeName = componentElement.Name;
var type = Type.GetType(typeName) ?? throw new Exception($"Type {typeName} not found.");
foreach (var dataElement in componentElement.Value.EnumerateArray())
{
var entityID = dataElement.GetProperty(Property.ENTITY_ID).GetInt32();
var entity = new Entity(entityID, 0);
var dataProperty = dataElement.GetProperty(Property.DATA);
var component = JsonSerializer.Deserialize(dataProperty.GetRawText(), type, options);
if (component is IComponentData data)
{
world.EntityManager.AddComponent(entity, data, type);
}
}
}
foreach (var systemElement in element.GetProperty(Property.SYSTEMS).EnumerateArray())
{
var typeString = systemElement.GetString();
if (string.IsNullOrEmpty(typeString))
{
continue;
}
var systemType = Type.GetType(typeString);
if (systemType == null)
{
continue;
}
world.SystemStorage.AddSystem(systemType);
}
return result;
}
public override void Write(Utf8JsonWriter writer, WorldNode value, JsonSerializerOptions options)
{ {
writer.WriteObject(() => writer.WriteObject(() =>
{ {
writer.WriteString(Property.NAME, value.Name); writer.WriteString(Property.NAME, value.Name);
writer.WriteArray(Property.ENTITIES, value.World.EntityManager.Entities, entity =>
{
if (!entity.IsValid)
{
return;
}
writer.WriteObject(() => writer.WriteStartArray(Property.ENTITIES);
{
writer.WriteString(Property.NAME, value.EntityNodeLookup[entity].Name);
writer.WriteNumber(Property.ID, entity.ID);
});
});
writer.WriteObject(Property.COMPONENTS, () => for (var i = 0; i < value.World.ArchetypeCount; i++)
{ {
for (var i = 0; i < value.World.ComponentStorage.ComponentPools.Count; i++) ref var archetype = ref value.World.GetArchetypeReference(i);
for (var j = 0; j < archetype.ChunkCount; j++)
{ {
var pool = value.World.ComponentStorage.ComponentPools[i]; ref var chunk = ref archetype.GetChunkReference(j);
if (pool == null) for (var k = 0; k < chunk._count; k++)
{
foreach (var layout in archetype._layouts)
{
var type = ComponentRegistry.s_runtimeIDToType[layout.componentID];
var size = ComponentRegistry.GetComponentInfo(layout.componentID).size;
if (type.AssemblyQualifiedName == null)
{ {
continue; continue;
} }
var type = value.World.ComponentStorage.GetComponentPoolType(i).GetType(); writer.WriteStartObject(type.AssemblyQualifiedName);
var typeName = type.AssemblyQualifiedName ?? type.Name;
writer.WriteArray(typeName, pool.Enumerate(), data => var pComponentData = chunk.GetUnsafePtr() + layout.offset + (k * size);
ComponentSerializerRegistry.SerializeJson(layout.componentID, writer, pComponentData, options);
}
}
}
}
writer.WriteEndArray();
writer.WriteArray(Property.SYSTEMS, value.World.SystemManager.Systems, system =>
{ {
writer.WriteObject(() => var name = system.GetType().AssemblyQualifiedName;
if (name == null)
{ {
writer.WriteNumber(Property.ENTITY_ID, data.entity.ID); return;
writer.WritePropertyName(Property.DATA); }
JsonSerializer.Serialize(writer, data.component, type, options);
writer.WriteStringValue(name);
}); });
}); });
} }
});
writer.WriteArray(Property.SYSTEMS, value.World.SystemStorage.Systems, systemType => public override WorldNode? DeserializeJson(ref Utf8JsonReader reader, JsonSerializerOptions options)
{ {
writer.WriteStringValue(systemType.AssemblyQualifiedName ?? systemType.Name); throw new NotImplementedException();
});
}); //var element = JsonDocument.ParseValue(ref reader).RootElement;
//var name = element.GetProperty(Property.NAME).GetString() ?? "New World";
//var world = World.Create(EngineCore.JobScheduler);
//var result = new WorldNode(world, name);
//foreach (var entityElement in element.GetProperty(Property.ENTITIES).EnumerateArray())
//{
// var entityName = entityElement.GetProperty(Property.NAME).GetString() ?? "New Entity";
// var entityID = entityElement.GetProperty(Property.ID).GetInt32();
// var entity = new Entity(entityID, 0);
// var node = new EntityNode(result, entity, entityName);
// world.EntityManager.AddEntityInternal(entity);
// result.EntityNodeLookup[entity] = node;
//}
//foreach (var componentElement in element.GetProperty(Property.COMPONENTS).EnumerateObject())
//{
// var typeName = componentElement.Name;
// var type = Type.GetType(typeName) ?? throw new Exception($"Type {typeName} not found.");
// foreach (var dataElement in componentElement.Value.EnumerateArray())
// {
// var entityID = dataElement.GetProperty(Property.ENTITY_ID).GetInt32();
// var entity = new Entity(entityID, 0);
// var dataProperty = dataElement.GetProperty(Property.DATA);
// var component = JsonSerializer.Deserialize(dataProperty.GetRawText(), type, options);
// if (component is IComponent data)
// {
// world.EntityManager.AddComponent(entity, data, type);
// }
// }
//}
//foreach (var systemElement in element.GetProperty(Property.SYSTEMS).EnumerateArray())
//{
// var typeString = systemElement.GetString();
// if (string.IsNullOrEmpty(typeString))
// {
// continue;
// }
// var systemType = Type.GetType(typeString);
// if (systemType == null)
// {
// continue;
// }
// world.SystemStorage.AddSystem(systemType);
//}
//return result;
}
public override void SerializeBinary(BinaryWriter writer, WorldNode value)
{
throw new NotImplementedException();
}
public override WorldNode? DeserializeBinary(BinaryReader reader)
{
throw new NotImplementedException();
} }
} }

View File

@@ -5,7 +5,7 @@ namespace Ghost.Editor.Core.Utilities;
public static class TypeCache public static class TypeCache
{ {
private static readonly TypeInfo[] _types; private static readonly TypeInfo[] s_types;
static TypeCache() static TypeCache()
{ {
@@ -26,11 +26,11 @@ public static class TypeCache
} }
} }
_types = loadableTypes.Select(t => t.GetTypeInfo()).ToArray(); s_types = loadableTypes.Select(t => t.GetTypeInfo()).ToArray();
} }
public static Type[] GetTypes() public static Type[] GetTypes()
{ {
return _types; return s_types;
} }
} }

View File

@@ -36,7 +36,7 @@ internal class EditorState : IAppState
ProjectService.CurrentProject = metadataInfo; ProjectService.CurrentProject = metadataInfo;
_engineCore = App.GetService<EngineCore>(); _engineCore = App.GetService<EngineCore>();
_engineCore.Start(new Engine.Models.LaunchArgument()); _engineCore.Init(new Engine.Models.LaunchArgument());
CompositionTarget.Rendering += OnRendering; CompositionTarget.Rendering += OnRendering;
_window = App.GetService<EngineEditorWindow>(); _window = App.GetService<EngineEditorWindow>();

View File

@@ -8,49 +8,7 @@
<PublishProfile>win-$(Platform).pubxml</PublishProfile> <PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>true</UseWinUI> <UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling> <EnableMsixTooling>true</EnableMsixTooling>
<LangVersion>preview</LangVersion>
</PropertyGroup> </PropertyGroup>
<!--<ItemGroup>
<Content Remove="Assets\icon-256.png" />
<Content Remove="Assets\Icon.altform-lightunplated_targetsize-16.png" />
<Content Remove="Assets\Icon.altform-lightunplated_targetsize-24.png" />
<Content Remove="Assets\Icon.altform-lightunplated_targetsize-256.png" />
<Content Remove="Assets\Icon.altform-lightunplated_targetsize-32.png" />
<Content Remove="Assets\Icon.altform-lightunplated_targetsize-48.png" />
<Content Remove="Assets\Icon.altform-unplated_targetsize-16.png" />
<Content Remove="Assets\Icon.altform-unplated_targetsize-24.png" />
<Content Remove="Assets\Icon.altform-unplated_targetsize-256.png" />
<Content Remove="Assets\Icon.altform-unplated_targetsize-32.png" />
<Content Remove="Assets\Icon.altform-unplated_targetsize-48.png" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\Icon.scale-100.png" />
<None Remove="Assets\Icon.scale-125.png" />
<None Remove="Assets\Icon.scale-150.png" />
<None Remove="Assets\Icon.scale-200.png" />
<None Remove="Assets\Icon.scale-400.png" />
<None Remove="Assets\Icon.targetsize-16.png" />
<None Remove="Assets\Icon.targetsize-16_altform-unplated.png" />
<None Remove="Assets\Icon.targetsize-24.png" />
<None Remove="Assets\Icon.targetsize-24_altform-lightunplated.png" />
<None Remove="Assets\Icon.targetsize-256.png" />
<None Remove="Assets\Icon.targetsize-256_altform-unplated.png" />
<None Remove="Assets\Icon.targetsize-32.png" />
<None Remove="Assets\Icon.targetsize-32_altform-lightunplated.png" />
<None Remove="Assets\Icon.targetsize-48.png" />
<None Remove="Assets\Icon.targetsize-48_altform-unplated.png" />
<None Remove="View\Pages\EngineEditor\ConsolePage.xaml" />
<None Remove="View\Pages\EngineEditor\HierarchyPage.xaml" />
<None Remove="View\Pages\EngineEditor\InspectorPage.xaml" />
<None Remove="View\Pages\EngineEditor\ProjectPage.xaml" />
<None Remove="View\Pages\EngineEditor\ScenePage.xaml" />
<None Remove="View\Pages\Landing\CreateProjectPage.xaml" />
<None Remove="View\Pages\Landing\OpenProjectPage.xaml" />
<None Remove="View\Windows\EngineEditorWindow.xaml" />
</ItemGroup>
<ItemGroup>
<Page Remove="App.xaml" />
</ItemGroup>-->
<ItemGroup> <ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" /> <Content Include="Assets\SplashScreen.scale-200.png" />
@@ -75,7 +33,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" /> <PackageReference Include="CommunityToolkit.WinUI.Controls.Primitives" Version="8.2.250402" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.TabbedCommandBar" Version="8.2.250402" /> <PackageReference Include="CommunityToolkit.WinUI.Controls.TabbedCommandBar" Version="8.2.250402" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.1" />
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" /> <PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7175" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.251106002" />
@@ -83,6 +41,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" /> <ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
<ProjectReference Include="..\Ghost.Entities\Ghost.Entities.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Page Update="View\Pages\Landing\CreateProjectPage.xaml"> <Page Update="View\Pages\Landing\CreateProjectPage.xaml">

View File

@@ -72,7 +72,7 @@ internal partial class CreateProjectViewModel(INotificationService notificationS
return; return;
} }
var result = await projectService.CreateProjectAsync(ProjectName, ProjectLocation, EngineData.s_engineVersion, SelectedTemplate.Value.directory); var result = await projectService.CreateProjectAsync(ProjectName, ProjectLocation, EngineData.EngineVersion, SelectedTemplate.Value.directory);
if (result.IsFailure) if (result.IsFailure)
{ {
notificationService.ShowNotification(result.Message, MessageType.Error); notificationService.ShowNotification(result.Message, MessageType.Error);

View File

@@ -7,7 +7,7 @@ namespace Ghost.Editor.ViewModels.Windows;
internal partial class EngineEditorViewModel : ObservableRecipient internal partial class EngineEditorViewModel : ObservableRecipient
{ {
public string engineVersionDescriptor = $"{EngineData.ENGINE_NAME} - {EngineData.s_engineVersion}"; public string engineVersionDescriptor = $"{EngineData.ENGINE_NAME} - {EngineData.EngineVersion}";
public ProjectMetadataInfo CurrentProject => ProjectService.CurrentProject; public ProjectMetadataInfo CurrentProject => ProjectService.CurrentProject;
} }

View File

@@ -2,5 +2,6 @@ using Ghost.Core.Attributes;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Ghost.Editor")] [assembly: InternalsVisibleTo("Ghost.Editor")]
[assembly: InternalsVisibleTo("Ghost.Editor.Core")]
[assembly: EngineAssembly] [assembly: EngineAssembly]

View File

@@ -1,13 +1,12 @@
using Ghost.Engine.Editor; using Ghost.Engine.Editor;
using Ghost.SparseEntities; using Ghost.Entities;
using Ghost.SparseEntities.Components;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Ghost.Engine.Components; namespace Ghost.Engine.Components;
[SkipLocalsInit] [SkipLocalsInit]
[HideEditor] [HideEditor]
public struct Hierarchy : IComponentData public struct Hierarchy : IComponent
{ {
public Entity parent; public Entity parent;
public Entity firstChild; public Entity firstChild;

View File

@@ -1,21 +1,11 @@
using Ghost.Engine.Utilities; using Ghost.Entities;
using Ghost.SparseEntities.Components; using Misaki.HighPerformance.Mathematics;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Ghost.Engine.Components; namespace Ghost.Engine.Components;
[SkipLocalsInit] [SkipLocalsInit]
public struct LocalToWorld : IComponentData public struct LocalToWorld : IComponent
{ {
public Matrix4x4 matrix; public float4x4 matrix;
public static LocalToWorld Identity
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new()
{
matrix = MatrixUtility.CreateTRS(Vector3.Zero, Quaternion.Identity, Vector3.One)
};
}
} }

View File

@@ -1,28 +1,55 @@
using Ghost.Core; using Ghost.Entities;
using Ghost.Engine.Models; using Misaki.HighPerformance.Jobs;
namespace Ghost.Engine; namespace Ghost.Engine;
internal class EngineCore [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
internal class EngineEntryAttribute : Attribute
{ {
public void Start(LaunchArgument args) }
internal partial class EngineCoreImpl : IDisposable
{
internal readonly JobScheduler _jobScheduler;
internal EngineCoreImpl()
{ {
ActivationHandler.Handle(args); _jobScheduler = new JobScheduler(Environment.ProcessorCount - 2); // We -2 here, one for main thread, one for render thread
//GraphicsPipeline.Initialize();
//GraphicsPipeline.Start();
Logger.LogInfo("Engine started successfully.");
} }
public void IncrementCPUFenceValue() internal void IncrementCPUFenceValue()
{ {
//GraphicsPipeline.SignalCPUReady(); //GraphicsPipeline.SignalCPUReady();
} }
public void ShutDown() public void Dispose()
{ {
//GraphicsPipeline.SignalCPUReady(); _jobScheduler.Dispose();
//GraphicsPipeline.Shutdown(); JobScheduler.ReleaseTempAllocator();
}
}
[EngineEntry]
public static partial class EngineCore
{
internal static readonly EngineCoreImpl s_impl;
public static JobScheduler JobScheduler => s_impl._jobScheduler;
static EngineCore()
{
s_impl = new EngineCoreImpl();
ComponentRegistry.GetOrRegisterComponent<ManagedEntityRef>();
RegisterIComponentTypes();
}
internal static void Init()
{
}
internal static void Dispose()
{
s_impl.Dispose();
} }
} }

View File

@@ -16,9 +16,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ghost.SparseEntities\Ghost.SparseEntities.csproj" /> <ProjectReference Include="..\Ghost.Core\Ghost.Core.csproj" />
<ProjectReference Include="..\Ghost.Entities\Ghost.Entities.csproj" />
<ProjectReference Include="..\Ghost.Generator\Ghost.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\Ghost.Graphics\Ghost.Graphics.csproj" /> <ProjectReference Include="..\Ghost.Graphics\Ghost.Graphics.csproj" />
<!--<ProjectReference Include="..\Ghost.Generator\Ghost.Generator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />-->
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,32 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Ghost.Engine.IO;
public class CustomSerializerAttribute : JsonConverterAttribute
{
public CustomSerializerAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type serializerType)
: base(serializerType)
{
}
}
public abstract class CustomSerializer<T> : JsonConverter<T>
{
public sealed override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DeserializeJson(ref reader, options);
}
public sealed override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
SerializeJson(writer, value, options);
}
public abstract void SerializeJson(Utf8JsonWriter writer, T value, JsonSerializerOptions options);
public abstract T? DeserializeJson(ref Utf8JsonReader reader, JsonSerializerOptions options);
public abstract void SerializeBinary(BinaryWriter writer, T value);
public abstract T? DeserializeBinary(BinaryReader reader);
}

View File

@@ -0,0 +1,52 @@
using Ghost.Core;
using Ghost.Entities;
using System.Text.Json;
namespace Ghost.Engine.IO;
public static unsafe class ComponentSerializerRegistry
{
public delegate void BinaryWriteDelegate(BinaryWriter writer, void* ptr);
public delegate void JsonWriteDelegate(Utf8JsonWriter writer, void* ptr, JsonSerializerOptions options);
private static BinaryWriteDelegate[] s_binWriters = new BinaryWriteDelegate[64];
private static JsonWriteDelegate[] s_jsonWriters = new JsonWriteDelegate[64];
public static void Register(int typeID, BinaryWriteDelegate binWriter, JsonWriteDelegate jsonWriter)
{
if (typeID < 0)
{
throw new Exception($"Type ID cannot be negative: {typeID}");
}
if (typeID >= s_binWriters.Length)
{
Array.Resize(ref s_binWriters, typeID + 16);
Array.Resize(ref s_jsonWriters, typeID + 16);
}
s_binWriters[typeID] = binWriter;
s_jsonWriters[typeID] = jsonWriter;
}
public static void SerializeBinary(Identifier<IComponent> typeID, BinaryWriter writer, void* ptr)
{
if (s_binWriters[typeID] == null)
{
throw new Exception($"No serializer for ID {typeID}");
}
s_binWriters[typeID](writer, ptr);
}
public static void SerializeJson(Identifier<IComponent> typeID, Utf8JsonWriter writer, void* ptr, JsonSerializerOptions options)
{
if (s_jsonWriters[typeID] == null)
{
// TODO: Fallback to reflection?
return;
}
s_jsonWriters[typeID](writer, ptr, options);
}
}

View File

@@ -4,5 +4,5 @@ internal class EngineData
{ {
public const string ENGINE_NAME = "Ghost Engine"; public const string ENGINE_NAME = "Ghost Engine";
public readonly static Version s_engineVersion = new(0, 1, 0); public readonly static Version EngineVersion = new(0, 1, 0);
} }

View File

@@ -2,7 +2,7 @@ using System.Text.Json;
namespace Ghost.Engine.Resources; namespace Ghost.Engine.Resources;
public static class StaticResource public static class EngineResource
{ {
public static readonly JsonSerializerOptions defaultSerializerOptions = new() public static readonly JsonSerializerOptions defaultSerializerOptions = new()
{ {

View File

@@ -1,57 +0,0 @@
using Ghost.SparseEntities;
namespace Ghost.Engine.Services;
internal static class PlayerLoopService
{
private static bool _isRunning = false;
// TODO: Implement the actual time system
public static float fixedDeltaTime = 0.02f;
public static void Start()
{
if (_isRunning)
{
return;
}
for (var i = 0; i < World.WorldCount; i++)
{
var world = World.GetWorld(i);
foreach (var script in world.QueryScript())
{
script.Start();
}
}
}
public static void Update()
{
for (var i = 0; i < World.WorldCount; i++)
{
var world = World.GetWorld(i);
world.SystemStorage.UpdateSystems();
foreach (var script in world.QueryScript())
{
script.Update();
}
}
}
public static void Shutdown()
{
for (var i = 0; i < World.WorldCount; i++)
{
var world = World.GetWorld(i);
foreach (var script in world.QueryScript())
{
script.OnDestroy();
}
}
_isRunning = false;
}
}

View File

@@ -1,5 +1,6 @@
using Ghost.Test.Core; using Ghost.Test.Core;
using Misaki.HighPerformance.Jobs; using Misaki.HighPerformance.Jobs;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.Mathematics; using Misaki.HighPerformance.Mathematics;
namespace Ghost.Entities.Test; namespace Ghost.Entities.Test;
@@ -40,7 +41,11 @@ public partial class EntityQueryTest : ITest
public void Run() public void Run()
{ {
var entities = (Span<Entity>)stackalloc Entity[1000]; var entities = (Span<Entity>)stackalloc Entity[1000];
_world.EntityManager.CreateEntities(entities, ComponentTypeID<Transform>.value);
using var scope = AllocationManager.CreateStackScope();
using var set = new ComponentSet(scope.AllocationHandle, ComponentTypeID<Transform>.Value);
_world.EntityManager.CreateEntities(entities, set);
var queryID = new QueryBuilder().WithAllRW<Transform>().Build(_world); var queryID = new QueryBuilder().WithAllRW<Transform>().Build(_world);
ref var query = ref _world.GetEntityQueryReference(queryID); ref var query = ref _world.GetEntityQueryReference(queryID);

View File

@@ -5,6 +5,8 @@
<TargetFramework>net10.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PublishAot>True</PublishAot>
<PublishTrimmed>True</PublishTrimmed>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -74,7 +74,7 @@ internal unsafe sealed class ChunkDebugView
var it = archetype._signature.GetIterator(); var it = archetype._signature.GetIterator();
while (it.Next(out var index)) while (it.Next(out var index))
{ {
var type = ComponentRegister.s_runtimeIDToType[index]; var type = ComponentRegistry.s_runtimeIDToType[index];
if (type == null) if (type == null)
{ {
continue; continue;
@@ -238,7 +238,7 @@ internal unsafe struct Archetype : IDisposable
for (var i = 0; i < componentIds.Length; i++) for (var i = 0; i < componentIds.Length; i++)
{ {
_signature.SetBit(componentIds[i]); _signature.SetBit(componentIds[i]);
components[i] = ComponentRegister.GetComponentInfo(componentIds[i]); components[i] = ComponentRegistry.GetComponentInfo(componentIds[i]);
} }
// Calculate total size per entity to get an initial capacity estimate // Calculate total size per entity to get an initial capacity estimate
@@ -394,7 +394,7 @@ internal unsafe struct Archetype : IDisposable
ref var chunk = ref _chunks[chunkIndex]; ref var chunk = ref _chunks[chunkIndex];
var chunkBase = chunk.GetUnsafePtr(); var chunkBase = chunk.GetUnsafePtr();
var size = ComponentRegister.GetComponentInfo(componentID).size; var size = ComponentRegistry.GetComponentInfo(componentID).size;
var dst = chunkBase + offset + (size * rowIndex); var dst = chunkBase + offset + (size * rowIndex);
MemoryUtility.MemCpy(dst, pComponent, (nuint)size); MemoryUtility.MemCpy(dst, pComponent, (nuint)size);
@@ -418,7 +418,7 @@ internal unsafe struct Archetype : IDisposable
var chunk = _chunks[chunkIndex]; var chunk = _chunks[chunkIndex];
var chunkBase = chunk.GetUnsafePtr(); var chunkBase = chunk.GetUnsafePtr();
var size = ComponentRegister.GetComponentInfo(componentID).size; var size = ComponentRegistry.GetComponentInfo(componentID).size;
return chunkBase + offset + (size * rowIndex); return chunkBase + offset + (size * rowIndex);
} }

View File

@@ -1,4 +1,5 @@
using Ghost.Core; using Ghost.Core;
using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.LowLevel.Collections; using Misaki.HighPerformance.LowLevel.Collections;
using Misaki.HighPerformance.LowLevel.Utilities; using Misaki.HighPerformance.LowLevel.Utilities;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@@ -16,26 +17,88 @@ public interface IEnableableComponent : IComponent
internal struct ComponentInfo internal struct ComponentInfo
{ {
// public string stableName; // Do we actually need this? // public string stableName; // Do we actually need this?
public int id; public Identifier<IComponent> id;
public int size; public int size;
public int alignment; public int alignment;
public bool isEnableable; public bool isEnableable;
} }
/// <summary>
/// Represents an immutable set of component identifiers used to define a group of components within an entity or system.
/// </summary>
public struct ComponentSet : IDisposable, IEquatable<ComponentSet>
{
private UnsafeArray<Identifier<IComponent>> _components;
private int _hashCode;
public readonly ReadOnlySpan<Identifier<IComponent>> Components => _components.AsSpan();
public ComponentSet(AllocationHandle allocationHandle, params ReadOnlySpan<Identifier<IComponent>> components)
{
_components = new UnsafeArray<Identifier<IComponent>>(components.Length, allocationHandle);
components.CopyTo(_components.AsSpan());
_hashCode = -1;
}
public ComponentSet(Allocator allocator, params ReadOnlySpan<Identifier<IComponent>> components)
: this(AllocationManager.GetAllocationHandle(allocator), components)
{
}
public readonly bool Equals(ComponentSet other)
{
return _hashCode == other._hashCode;
}
public override int GetHashCode()
{
if (_hashCode == -1)
{
_hashCode = ComponentRegistry.GetHashCode(_components.AsSpan());
}
return _hashCode;
}
public override bool Equals(object? obj)
{
return obj is ComponentSet set && Equals(set);
}
public static bool operator ==(ComponentSet left, ComponentSet right)
{
return left.Equals(right);
}
public static bool operator !=(ComponentSet left, ComponentSet right)
{
return !(left == right);
}
public void Dispose()
{
_components.Dispose();
}
}
/// <summary>
/// Provides a unique identifier for the specified unmanaged component type.
/// </summary>
/// <typeparam name="T">The component type for which to obtain an identifier. Must be unmanaged and implement <see cref="IComponent"/>.</typeparam>
public static class ComponentTypeID<T> public static class ComponentTypeID<T>
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
public static readonly Identifier<IComponent> value = ComponentRegister.GetOrRegisterComponent<T>(); public static readonly Identifier<IComponent> Value = ComponentRegistry.GetOrRegisterComponent<T>();
} }
internal static class ComponentRegister internal static class ComponentRegistry
{ {
private static readonly List<ComponentInfo> s_registeredComponents = new(); private static readonly List<ComponentInfo> s_registeredComponents = new();
private static readonly Dictionary<IntPtr, int> s_typeHandleToID = new(); private static readonly Dictionary<IntPtr, int> s_typeHandleToID = new();
private static readonly Dictionary<string, int> s_nameToRuntimeID = new(); private static readonly Dictionary<string, int> s_nameToRuntimeID = new();
#if DEBUG || GHOST_EDITOR
internal static readonly Dictionary<int, Type> s_runtimeIDToType = new(); internal static readonly Dictionary<int, Type> s_runtimeIDToType = new();
#endif
public static unsafe Identifier<IComponent> GetOrRegisterComponent<T>() public static unsafe Identifier<IComponent> GetOrRegisterComponent<T>()
where T : unmanaged, IComponent where T : unmanaged, IComponent
@@ -66,9 +129,7 @@ internal static class ComponentRegister
s_typeHandleToID[typeHandle] = newID; s_typeHandleToID[typeHandle] = newID;
s_nameToRuntimeID[stableName] = newID; s_nameToRuntimeID[stableName] = newID;
#if DEBUG || GHOST_EDITOR
s_runtimeIDToType[newID.value] = typeof(T); s_runtimeIDToType[newID.value] = typeof(T);
#endif
return newID; return newID;
} }
@@ -98,7 +159,21 @@ internal static class ComponentRegister
} }
} }
// TODO: A ComponentSet structure to cache the hashcode for better performance. [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ComponentInfo GetComponentInfo(Type type)
{
lock (s_registeredComponents)
{
var typeId = GetComponentID(type);
if (typeId.IsInvalid)
{
throw new KeyNotFoundException($"Component type {type.FullName} is not registered.");
}
return s_registeredComponents[typeId];
}
}
public static int GetHashCode(params ReadOnlySpan<Identifier<IComponent>> componentTypeIDs) public static int GetHashCode(params ReadOnlySpan<Identifier<IComponent>> componentTypeIDs)
{ {
var largestID = 0; var largestID = 0;

View File

@@ -108,12 +108,12 @@ public unsafe class EntityCommandBuffer : IDisposable
Write(count); Write(count);
} }
public void CreateEntity(int count, params ReadOnlySpan<Identifier<IComponent>> componentTypeIDs) public void CreateEntity(int count, ComponentSet set)
{ {
WriteHeader(ECBOpCode.CreateEntityWithComponents); WriteHeader(ECBOpCode.CreateEntityWithComponents);
Write(count); Write(count);
Write(componentTypeIDs.Length); Write(set.Components.Length);
WriteSpan(componentTypeIDs); WriteSpan(set.Components);
} }
public void DestroyEntity(Entity entity) public void DestroyEntity(Entity entity)
@@ -127,7 +127,7 @@ public unsafe class EntityCommandBuffer : IDisposable
{ {
WriteHeader(ECBOpCode.AddComponent); WriteHeader(ECBOpCode.AddComponent);
Write(entity); Write(entity);
Write(ComponentTypeID<T>.value); Write(ComponentTypeID<T>.Value);
Write(component); Write(component);
} }
@@ -136,7 +136,7 @@ public unsafe class EntityCommandBuffer : IDisposable
{ {
WriteHeader(ECBOpCode.RemoveComponent); WriteHeader(ECBOpCode.RemoveComponent);
Write(entity); Write(entity);
Write(ComponentTypeID<T>.value); Write(ComponentTypeID<T>.Value);
} }
public void SetComponent<T>(Entity entity, T component) public void SetComponent<T>(Entity entity, T component)
@@ -144,7 +144,7 @@ public unsafe class EntityCommandBuffer : IDisposable
{ {
WriteHeader(ECBOpCode.SetComponent); WriteHeader(ECBOpCode.SetComponent);
Write(entity); Write(entity);
Write(ComponentTypeID<T>.value); Write(ComponentTypeID<T>.Value);
Write(component); Write(component);
} }
@@ -157,6 +157,8 @@ public unsafe class EntityCommandBuffer : IDisposable
{ {
var op = Read<ECBOpCode>(ref cursor); var op = Read<ECBOpCode>(ref cursor);
using var scope = AllocationManager.CreateStackScope();
switch (op) switch (op)
{ {
case ECBOpCode.CreateEntity: case ECBOpCode.CreateEntity:
@@ -168,7 +170,8 @@ public unsafe class EntityCommandBuffer : IDisposable
var entityCount = Read<int>(ref cursor); var entityCount = Read<int>(ref cursor);
var compCount = Read<int>(ref cursor); var compCount = Read<int>(ref cursor);
var compTypeIDs = ReadSpan<Identifier<IComponent>>(ref cursor, compCount); var compTypeIDs = ReadSpan<Identifier<IComponent>>(ref cursor, compCount);
_entityManager.CreateEntities(entityCount, compTypeIDs); var set = new ComponentSet(scope.AllocationHandle, compTypeIDs);
_entityManager.CreateEntities(entityCount, set);
break; break;
case ECBOpCode.DestroyEntity: case ECBOpCode.DestroyEntity:
@@ -179,7 +182,7 @@ public unsafe class EntityCommandBuffer : IDisposable
case ECBOpCode.AddComponent: case ECBOpCode.AddComponent:
var entityToAdd = Read<Entity>(ref cursor); var entityToAdd = Read<Entity>(ref cursor);
var addCompTypeID = Read<Identifier<IComponent>>(ref cursor); var addCompTypeID = Read<Identifier<IComponent>>(ref cursor);
var pAddCompData = ReadBuffer(ref cursor, ComponentRegister.GetComponentInfo(addCompTypeID).size); var pAddCompData = ReadBuffer(ref cursor, ComponentRegistry.GetComponentInfo(addCompTypeID).size);
_entityManager.AddComponent(entityToAdd, addCompTypeID, pAddCompData); _entityManager.AddComponent(entityToAdd, addCompTypeID, pAddCompData);
break; break;
@@ -192,7 +195,7 @@ public unsafe class EntityCommandBuffer : IDisposable
case ECBOpCode.SetComponent: case ECBOpCode.SetComponent:
var entityToSet = Read<Entity>(ref cursor); var entityToSet = Read<Entity>(ref cursor);
var setCompTypeID = Read<Identifier<IComponent>>(ref cursor); var setCompTypeID = Read<Identifier<IComponent>>(ref cursor);
var pSetCompData = ReadBuffer(ref cursor, ComponentRegister.GetComponentInfo(setCompTypeID).size); var pSetCompData = ReadBuffer(ref cursor, ComponentRegistry.GetComponentInfo(setCompTypeID).size);
_entityManager.SetComponent(entityToSet, setCompTypeID, pSetCompData); _entityManager.SetComponent(entityToSet, setCompTypeID, pSetCompData);
break; break;
} }

View File

@@ -110,7 +110,7 @@ public partial class EntityManager
var location = _entityLocations.GetElementAt(entity.ID, entity.Generation); var location = _entityLocations.GetElementAt(entity.ID, entity.Generation);
ref var archetype = ref _world.GetArchetypeReference(location.archetypeID); ref var archetype = ref _world.GetArchetypeReference(location.archetypeID);
var pManagedEntityRef = (ManagedEntityRef*)archetype.GetComponentData(location.chunkIndex, location.rowIndex, ComponentTypeID<ManagedEntityRef>.value); var pManagedEntityRef = (ManagedEntityRef*)archetype.GetComponentData(location.chunkIndex, location.rowIndex, ComponentTypeID<ManagedEntityRef>.Value);
if (pManagedEntityRef == null) if (pManagedEntityRef == null)
{ {
throw new InvalidOperationException($"Entity {entity} does not have ManagedEntityRef component."); throw new InvalidOperationException($"Entity {entity} does not have ManagedEntityRef component.");

View File

@@ -7,18 +7,8 @@ using System.Diagnostics;
namespace Ghost.Entities; namespace Ghost.Entities;
/// <summary> internal struct EntityLocation : IComparable<EntityLocation>
/// A manager for creating, destroying, and managing entities and their components.
/// </summary>
/// <remarks>
/// All methods in this class are not thread-safe and all of them will cause structural changes if not mentioned otherwise.
/// Use <see cref="EntityCommandBuffer"/> to defer structural changes to a safe point.
/// Use <see cref="World.GetThreadLocalEntityCommandBuffer(int)"/> to get a thread-local command buffer for multithreaded scenarios.
/// </remarks>
public unsafe partial class EntityManager : IDisposable
{ {
private struct EntityLocation : IComparable<EntityLocation>
{
public int archetypeID; public int archetypeID;
public int chunkIndex; public int chunkIndex;
public int rowIndex; public int rowIndex;
@@ -39,12 +29,24 @@ public unsafe partial class EntityManager : IDisposable
return rowIndex.CompareTo(other.rowIndex); return rowIndex.CompareTo(other.rowIndex);
} }
} }
/// <summary>
/// A manager for creating, destroying, and managing entities and their components.
/// </summary>
/// <remarks>
/// All methods in this class are not thread-safe and all of them will cause structural changes if not mentioned otherwise.
/// Use <see cref="EntityCommandBuffer"/> to defer structural changes to a safe point.
/// Use <see cref="World.GetThreadLocalEntityCommandBuffer(int)"/> to get a thread-local command buffer for multithreaded scenarios.
/// </remarks>
public unsafe partial class EntityManager : IDisposable
{
private readonly World _world; private readonly World _world;
private UnsafeSlotMap<EntityLocation> _entityLocations; private UnsafeSlotMap<EntityLocation> _entityLocations;
private bool _disposed; private bool _disposed;
public World World => _world;
internal EntityManager(World world, int initialCapacity) internal EntityManager(World world, int initialCapacity)
{ {
_world = world; _world = world;
@@ -73,6 +75,16 @@ public unsafe partial class EntityManager : IDisposable
return ErrorStatus.None; return ErrorStatus.None;
} }
internal Result<EntityLocation, ErrorStatus> GetEntityLocation(Entity entity)
{
if (_entityLocations.TryGetElementAt(entity.ID, entity.Generation, out var location))
{
return location;
}
return ErrorStatus.NotFound;
}
/// <summary> /// <summary>
/// Create an entity with no components. /// Create an entity with no components.
/// </summary> /// </summary>
@@ -88,12 +100,12 @@ public unsafe partial class EntityManager : IDisposable
/// <summary> /// <summary>
/// Create an entity with specified components. /// Create an entity with specified components.
/// </summary> /// </summary>
/// <param name="componentTypeIDs">The component type IDs to add to the entity.</param> /// <param name="set">A set of component type IDs to add to the entities.</param>
/// <returns>The created entity.</returns> /// <returns>The created entity.</returns>
public Entity CreateEntity(params ReadOnlySpan<Identifier<IComponent>> componentTypeIDs) public Entity CreateEntity(ComponentSet set)
{ {
var entities = (Span<Entity>)stackalloc Entity[1]; var entities = (Span<Entity>)stackalloc Entity[1];
CreateEntities(entities, componentTypeIDs); CreateEntities(entities, set);
return entities[0]; return entities[0];
} }
@@ -150,16 +162,15 @@ public unsafe partial class EntityManager : IDisposable
/// Create multiple entities with specified components. /// Create multiple entities with specified components.
/// </summary> /// </summary>
/// <param name="allocator">The allocator to use for the returned array.</param> /// <param name="allocator">The allocator to use for the returned array.</param>
/// <param name="componentTypeIDs">The component type IDs to add to the entities. </param> /// <param name="set">A set of component type IDs to add to the entities.</param>
/// <returns>An array of the created entities.</returns> /// <returns>An array of the created entities.</returns>
public void CreateEntities(Span<Entity> entities, params ReadOnlySpan<Identifier<IComponent>> componentTypeIDs) public void CreateEntities(Span<Entity> entities, ComponentSet set)
{ {
var signatureHash = ComponentRegister.GetHashCode(componentTypeIDs); var arcID = _world.GetArchetypeIDBySignatureHash(set.GetHashCode());
var arcID = _world.GetArchetypeIDBySignatureHash(signatureHash);
if (arcID.IsNotValid) if (arcID.IsInvalid)
{ {
arcID = _world.CreateArchetype(componentTypeIDs, signatureHash); arcID = _world.CreateArchetype(set.Components, set.GetHashCode());
} }
ref var archetype = ref _world.GetArchetypeReference(arcID); ref var archetype = ref _world.GetArchetypeReference(arcID);
@@ -186,15 +197,15 @@ public unsafe partial class EntityManager : IDisposable
/// Create multiple entities with specified components. /// Create multiple entities with specified components.
/// </summary> /// </summary>
/// <param name="count">The number of entities to create.</param> /// <param name="count">The number of entities to create.</param>
/// <param name="componentTypeIDs">The component type IDs to add to the entities. </param> /// <param name="set">A set of component type IDs to add to the entities.</param>
public void CreateEntities(int count, params ReadOnlySpan<Identifier<IComponent>> componentTypeIDs) public void CreateEntities(int count, ComponentSet set)
{ {
var signatureHash = ComponentRegister.GetHashCode(componentTypeIDs); var hash = set.GetHashCode();
var arcID = _world.GetArchetypeIDBySignatureHash(signatureHash); var arcID = _world.GetArchetypeIDBySignatureHash(hash);
if (arcID.IsNotValid) if (arcID.IsInvalid)
{ {
arcID = _world.CreateArchetype(componentTypeIDs, signatureHash); arcID = _world.CreateArchetype(set.Components, hash);
} }
ref var archetype = ref _world.GetArchetypeReference(arcID); ref var archetype = ref _world.GetArchetypeReference(arcID);
@@ -217,7 +228,7 @@ public unsafe partial class EntityManager : IDisposable
private void DestoryManagedEntityIfExists(ref readonly Archetype archetype, EntityLocation location) private void DestoryManagedEntityIfExists(ref readonly Archetype archetype, EntityLocation location)
{ {
var pManagedRef = archetype.GetComponentData(location.chunkIndex, location.rowIndex, ComponentTypeID<ManagedEntityRef>.value); var pManagedRef = archetype.GetComponentData(location.chunkIndex, location.rowIndex, ComponentTypeID<ManagedEntityRef>.Value);
if (pManagedRef != null) if (pManagedRef != null)
{ {
DestroyManagedEntity(((ManagedEntityRef*)pManagedRef)->entity); DestroyManagedEntity(((ManagedEntityRef*)pManagedRef)->entity);
@@ -260,7 +271,7 @@ public unsafe partial class EntityManager : IDisposable
{ {
void RemoveManagedEntity(ReadOnlySpan<int> rowIndicesCache, ref readonly Archetype archetype, int chunkIndex) void RemoveManagedEntity(ReadOnlySpan<int> rowIndicesCache, ref readonly Archetype archetype, int chunkIndex)
{ {
for (int j = 0; j < rowIndicesCache.Length; j++) for (var j = 0; j < rowIndicesCache.Length; j++)
{ {
var rowIndex = rowIndicesCache[j]; var rowIndex = rowIndicesCache[j];
var location = new EntityLocation var location = new EntityLocation
@@ -285,7 +296,7 @@ public unsafe partial class EntityManager : IDisposable
// 1. GATHER // 1. GATHER
// Resolve all entities to their locations // Resolve all entities to their locations
for (int i = 0; i < entities.Length; i++) for (var i = 0; i < entities.Length; i++)
{ {
var entity = entities[i]; var entity = entities[i];
if (_entityLocations.TryGetElementAt(entity.ID, entity.Generation, out var location)) if (_entityLocations.TryGetElementAt(entity.ID, entity.Generation, out var location))
@@ -309,12 +320,12 @@ public unsafe partial class EntityManager : IDisposable
var prevArchetypeID = firstLoc.archetypeID; var prevArchetypeID = firstLoc.archetypeID;
var prevChunkIndex = firstLoc.chunkIndex; var prevChunkIndex = firstLoc.chunkIndex;
for (int i = 0; i < batchDestroy.Count; i++) for (var i = 0; i < batchDestroy.Count; i++)
{ {
var loc = batchDestroy[i]; var loc = batchDestroy[i];
// Check if we have crossed a boundary (Different Chunk OR Different Archetype) // Check if we have crossed a boundary (Different Chunk OR Different Archetype)
bool isNewBatch = (loc.chunkIndex != prevChunkIndex) || (loc.archetypeID != prevArchetypeID); var isNewBatch = (loc.chunkIndex != prevChunkIndex) || (loc.archetypeID != prevArchetypeID);
if (isNewBatch) if (isNewBatch)
{ {
@@ -348,7 +359,7 @@ public unsafe partial class EntityManager : IDisposable
} }
// 5. Remove from Entity Locations // 5. Remove from Entity Locations
for (int i = 0; i < entities.Length; i++) for (var i = 0; i < entities.Length; i++)
{ {
var entity = entities[i]; var entity = entities[i];
_entityLocations.Remove(entity.ID, entity.Generation); _entityLocations.Remove(entity.ID, entity.Generation);
@@ -379,7 +390,7 @@ public unsafe partial class EntityManager : IDisposable
} }
// Check if singleton already exists // Check if singleton already exists
var signatureHash = ComponentRegister.GetHashCode(componentID); var signatureHash = ComponentRegistry.GetHashCode(componentID);
var arcID = _world.GetArchetypeIDBySignatureHash(signatureHash); var arcID = _world.GetArchetypeIDBySignatureHash(signatureHash);
if (arcID.IsValid) if (arcID.IsValid)
@@ -415,7 +426,7 @@ public unsafe partial class EntityManager : IDisposable
public ErrorStatus CreateSingleton<T>(T component = default) public ErrorStatus CreateSingleton<T>(T component = default)
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
return CreateSingleton(ComponentTypeID<T>.value, &component); return CreateSingleton(ComponentTypeID<T>.Value, &component);
} }
/// <summary> /// <summary>
@@ -425,10 +436,10 @@ public unsafe partial class EntityManager : IDisposable
/// <returns>Pointer to the component data, or null if not found.</returns> /// <returns>Pointer to the component data, or null if not found.</returns>
public void* GetSingleton(Identifier<IComponent> componentID) public void* GetSingleton(Identifier<IComponent> componentID)
{ {
var signatureHash = ComponentRegister.GetHashCode(componentID); var signatureHash = ComponentRegistry.GetHashCode(componentID);
var arcID = _world.GetArchetypeIDBySignatureHash(signatureHash); var arcID = _world.GetArchetypeIDBySignatureHash(signatureHash);
if (arcID.IsNotValid) if (arcID.IsInvalid)
{ {
return null; return null;
} }
@@ -454,7 +465,7 @@ public unsafe partial class EntityManager : IDisposable
public ref T GetSingleton<T>() public ref T GetSingleton<T>()
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
var ptr = GetSingleton(ComponentTypeID<T>.value); var ptr = GetSingleton(ComponentTypeID<T>.Value);
return ref *(T*)ptr; // This will return null ref if ptr is null. return ref *(T*)ptr; // This will return null ref if ptr is null.
} }
@@ -508,7 +519,7 @@ public unsafe partial class EntityManager : IDisposable
} }
var newArcID = oldArchetype.GetEdgeAdd(componentID); var newArcID = oldArchetype.GetEdgeAdd(componentID);
if (newArcID.IsNotValid) if (newArcID.IsInvalid)
{ {
var largestComponentID = Math.Max(oldSignature.Count, componentID); var largestComponentID = Math.Max(oldSignature.Count, componentID);
var length = UnsafeBitSet.RequiredLength(largestComponentID + 1); var length = UnsafeBitSet.RequiredLength(largestComponentID + 1);
@@ -532,7 +543,7 @@ public unsafe partial class EntityManager : IDisposable
// Find or create new archetype // Find or create new archetype
var newSignatureHash = newSignature.GetHashCode(); var newSignatureHash = newSignature.GetHashCode();
newArcID = _world.GetArchetypeIDBySignatureHash(newSignatureHash); newArcID = _world.GetArchetypeIDBySignatureHash(newSignatureHash);
if (newArcID.IsNotValid) if (newArcID.IsInvalid)
{ {
// Create new archetype // Create new archetype
Span<Identifier<IComponent>> componentTypeIDs = stackalloc Identifier<IComponent>[compCount]; Span<Identifier<IComponent>> componentTypeIDs = stackalloc Identifier<IComponent>[compCount];
@@ -584,7 +595,7 @@ public unsafe partial class EntityManager : IDisposable
public ErrorStatus AddComponent<T>(Entity entity, T component = default) public ErrorStatus AddComponent<T>(Entity entity, T component = default)
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
return AddComponent(entity, ComponentTypeID<T>.value, &component); return AddComponent(entity, ComponentTypeID<T>.Value, &component);
} }
/// <summary> /// <summary>
@@ -607,7 +618,7 @@ public unsafe partial class EntityManager : IDisposable
var oldSignature = oldArchetype._signature; var oldSignature = oldArchetype._signature;
var newArcID = oldArchetype.GetEdgeRemove(componentID); var newArcID = oldArchetype.GetEdgeRemove(componentID);
if (newArcID.IsNotValid) if (newArcID.IsInvalid)
{ {
var largestComponentID = Math.Max(oldSignature.Count, componentID); var largestComponentID = Math.Max(oldSignature.Count, componentID);
var length = UnsafeBitSet.RequiredLength(largestComponentID + 1); var length = UnsafeBitSet.RequiredLength(largestComponentID + 1);
@@ -631,7 +642,7 @@ public unsafe partial class EntityManager : IDisposable
// Find or create new archetype // Find or create new archetype
var newSignatureHash = newSignature.GetHashCode(); var newSignatureHash = newSignature.GetHashCode();
newArcID = _world.GetArchetypeIDBySignatureHash(newSignatureHash); newArcID = _world.GetArchetypeIDBySignatureHash(newSignatureHash);
if (newArcID.IsNotValid) if (newArcID.IsInvalid)
{ {
// Create new archetype // Create new archetype
Span<Identifier<IComponent>> componentTypeIDs = stackalloc Identifier<IComponent>[compCount]; Span<Identifier<IComponent>> componentTypeIDs = stackalloc Identifier<IComponent>[compCount];
@@ -664,7 +675,7 @@ public unsafe partial class EntityManager : IDisposable
return r; return r;
} }
var pManagedRef = oldArchetype.GetComponentData(location.chunkIndex, location.rowIndex, ComponentTypeID<ManagedEntityRef>.value); var pManagedRef = oldArchetype.GetComponentData(location.chunkIndex, location.rowIndex, ComponentTypeID<ManagedEntityRef>.Value);
if (pManagedRef != null) if (pManagedRef != null)
{ {
DestroyManagedEntity(((ManagedEntityRef*)pManagedRef)->entity); DestroyManagedEntity(((ManagedEntityRef*)pManagedRef)->entity);
@@ -687,7 +698,7 @@ public unsafe partial class EntityManager : IDisposable
public ErrorStatus RemoveComponent<T>(Entity entity) public ErrorStatus RemoveComponent<T>(Entity entity)
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
return RemoveComponent(entity, ComponentTypeID<T>.value); return RemoveComponent(entity, ComponentTypeID<T>.Value);
} }
/// <summary> /// <summary>
@@ -719,7 +730,7 @@ public unsafe partial class EntityManager : IDisposable
public ErrorStatus SetComponent<T>(Entity entity, T component) public ErrorStatus SetComponent<T>(Entity entity, T component)
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
return SetComponent(entity, ComponentTypeID<T>.value, &component); return SetComponent(entity, ComponentTypeID<T>.Value, &component);
} }
/// <summary> /// <summary>
@@ -748,7 +759,7 @@ public unsafe partial class EntityManager : IDisposable
public ref T GetComponent<T>(Entity entity) public ref T GetComponent<T>(Entity entity)
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
var ptr = GetComponent(entity, ComponentTypeID<T>.value); var ptr = GetComponent(entity, ComponentTypeID<T>.Value);
return ref *(T*)ptr; // This will return null ref if ptr is null. return ref *(T*)ptr; // This will return null ref if ptr is null.
} }
@@ -778,7 +789,7 @@ public unsafe partial class EntityManager : IDisposable
public bool HasComponent<T>(Entity entity) public bool HasComponent<T>(Entity entity)
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
return HasComponent(entity, ComponentTypeID<T>.value); return HasComponent(entity, ComponentTypeID<T>.Value);
} }
/// <summary> /// <summary>
@@ -834,7 +845,7 @@ public unsafe partial class EntityManager : IDisposable
public ErrorStatus SetEnabled<T>(Entity entity, bool enabled) public ErrorStatus SetEnabled<T>(Entity entity, bool enabled)
where T : unmanaged, IEnableableComponent where T : unmanaged, IEnableableComponent
{ {
return SetEnabled(entity, ComponentTypeID<T>.value, enabled); return SetEnabled(entity, ComponentTypeID<T>.Value, enabled);
} }
public void Dispose() public void Dispose()

View File

@@ -17,10 +17,6 @@
<IsTrimmable>True</IsTrimmable> <IsTrimmable>True</IsTrimmable>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Templates\ForEach.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Templates\EntityQuery.ForEach.gen.cs"> <None Include="Templates\EntityQuery.ForEach.gen.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>

View File

@@ -24,7 +24,7 @@ public readonly struct Managed<T> : IComponent, IManagedWrapper
public static class ManagedComponemtnID<T> public static class ManagedComponemtnID<T>
where T : IManagedComponent where T : IManagedComponent
{ {
public static readonly Identifier<IManagedComponent> value = ManagedComponentRegister.GetOrRegisterComponent<T>(); public static readonly Identifier<IManagedComponent> value = ManagedComponentRegistry.GetOrRegisterComponent<T>();
} }
internal struct ManagedComponentInfo internal struct ManagedComponentInfo
@@ -33,7 +33,7 @@ internal struct ManagedComponentInfo
public bool isScriptComponent; public bool isScriptComponent;
} }
internal static class ManagedComponentRegister internal static class ManagedComponentRegistry
{ {
private static readonly List<ManagedComponentInfo> s_registeredComponents = new(); private static readonly List<ManagedComponentInfo> s_registeredComponents = new();
private static readonly Dictionary<IntPtr, int> s_typeHandleToID = new(); private static readonly Dictionary<IntPtr, int> s_typeHandleToID = new();

View File

@@ -145,7 +145,7 @@ public readonly unsafe ref struct ChunkView
public readonly bool HasChanged<T>(int version) public readonly bool HasChanged<T>(int version)
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
var layout = GetLayout(ComponentTypeID<T>.value); var layout = GetLayout(ComponentTypeID<T>.Value);
return version < _pVersion[layout.versionIndex]; return version < _pVersion[layout.versionIndex];
} }
@@ -180,7 +180,7 @@ public readonly unsafe ref struct ChunkView
public readonly int GetComponentVersion<T>() public readonly int GetComponentVersion<T>()
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
return _pVersion[ComponentTypeID<T>.value]; return _pVersion[ComponentTypeID<T>.Value];
} }
/// <summary> /// <summary>
@@ -204,7 +204,7 @@ public readonly unsafe ref struct ChunkView
public ReadOnlySpan<T> GetComponentData<T>() public ReadOnlySpan<T> GetComponentData<T>()
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
var layout = GetLayout(ComponentTypeID<T>.value); var layout = GetLayout(ComponentTypeID<T>.Value);
var pComponentData = _pChunkData + layout.offset; var pComponentData = _pChunkData + layout.offset;
return new ReadOnlySpan<T>(pComponentData, _entityCount); return new ReadOnlySpan<T>(pComponentData, _entityCount);
} }
@@ -219,7 +219,7 @@ public readonly unsafe ref struct ChunkView
public Span<T> GetComponentDataRW<T>() public Span<T> GetComponentDataRW<T>()
where T : unmanaged, IComponent where T : unmanaged, IComponent
{ {
var compId = ComponentTypeID<T>.value; var compId = ComponentTypeID<T>.Value;
var layout = GetLayout(compId); var layout = GetLayout(compId);
_pVersion[layout.versionIndex] = _currentVersion; _pVersion[layout.versionIndex] = _currentVersion;
@@ -239,7 +239,7 @@ public readonly unsafe ref struct ChunkView
public SpanBitSet GetEnableBits<T>() public SpanBitSet GetEnableBits<T>()
where T : unmanaged, IEnableableComponent where T : unmanaged, IEnableableComponent
{ {
var layout = _layouts[ComponentTypeID<T>.value]; var layout = _layouts[ComponentTypeID<T>.Value];
var maskBase = _pChunkData + layout.enableBitsOffset; var maskBase = _pChunkData + layout.enableBitsOffset;
return new SpanBitSet(new Span<uint>(maskBase, (_entityCount + 31) / 32)); return new SpanBitSet(new Span<uint>(maskBase, (_entityCount + 31) / 32));
} }
@@ -255,7 +255,7 @@ public readonly unsafe ref struct ChunkView
public bool IsComponentEnabled<T>(int index) public bool IsComponentEnabled<T>(int index)
where T : unmanaged, IEnableableComponent where T : unmanaged, IEnableableComponent
{ {
var layout = GetLayout(ComponentTypeID<T>.value); var layout = GetLayout(ComponentTypeID<T>.Value);
var pMask = _pChunkData + layout.enableBitsOffset; var pMask = _pChunkData + layout.enableBitsOffset;
return EntityQuery.CheckBit(pMask, index); return EntityQuery.CheckBit(pMask, index);
} }
@@ -545,7 +545,7 @@ public ref partial struct QueryBuilder
foreach (var id in _none) foreach (var id in _none)
{ {
if (ComponentRegister.GetComponentInfo(id).isEnableable) if (ComponentRegistry.GetComponentInfo(id).isEnableable)
{ {
mask.rejectIfEnabled.SetBit(id); // Filter: Must Not be Enabled (Can be Absent or Disabled) mask.rejectIfEnabled.SetBit(id); // Filter: Must Not be Enabled (Can be Absent or Disabled)
} }

View File

@@ -61,12 +61,12 @@ public abstract class SystemBase : ISystem
_requiredQueries.Add(queryID.value); _requiredQueries.Add(queryID.value);
} }
public void Initialize(ref readonly SystemAPI systemAPI) void ISystem.Initialize(ref readonly SystemAPI systemAPI)
{ {
OnInitialize(in systemAPI); OnInitialize(in systemAPI);
} }
public void Update(ref readonly SystemAPI systemAPI) void ISystem.Update(ref readonly SystemAPI systemAPI)
{ {
if (ShouldUpdate()) if (ShouldUpdate())
{ {
@@ -87,7 +87,7 @@ public abstract class SystemBase : ISystem
} }
} }
public void Cleanup(ref readonly SystemAPI systemAPI) void ISystem.Cleanup(ref readonly SystemAPI systemAPI)
{ {
OnCleanup(in systemAPI); OnCleanup(in systemAPI);
} }
@@ -352,6 +352,8 @@ public class SystemManager
private readonly List<ISystem> _systems = []; private readonly List<ISystem> _systems = [];
internal IReadOnlyList<ISystem> Systems => _systems;
internal SystemManager(World world) internal SystemManager(World world)
{ {
_world = world; _world = world;

View File

@@ -35,7 +35,7 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
@@ -224,11 +224,11 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
@@ -425,15 +425,15 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
@@ -636,19 +636,19 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
@@ -857,23 +857,23 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
_compTypeIDs[4] = ComponentTypeID<T4>.value; _compTypeIDs[4] = ComponentTypeID<T4>.Value;
_offsets[4] = 0; _offsets[4] = 0;
_compBasePtrs[4] = 0; _compBasePtrs[4] = 0;
@@ -1088,27 +1088,27 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
_compTypeIDs[4] = ComponentTypeID<T4>.value; _compTypeIDs[4] = ComponentTypeID<T4>.Value;
_offsets[4] = 0; _offsets[4] = 0;
_compBasePtrs[4] = 0; _compBasePtrs[4] = 0;
_compTypeIDs[5] = ComponentTypeID<T5>.value; _compTypeIDs[5] = ComponentTypeID<T5>.Value;
_offsets[5] = 0; _offsets[5] = 0;
_compBasePtrs[5] = 0; _compBasePtrs[5] = 0;
@@ -1329,31 +1329,31 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
_compTypeIDs[4] = ComponentTypeID<T4>.value; _compTypeIDs[4] = ComponentTypeID<T4>.Value;
_offsets[4] = 0; _offsets[4] = 0;
_compBasePtrs[4] = 0; _compBasePtrs[4] = 0;
_compTypeIDs[5] = ComponentTypeID<T5>.value; _compTypeIDs[5] = ComponentTypeID<T5>.Value;
_offsets[5] = 0; _offsets[5] = 0;
_compBasePtrs[5] = 0; _compBasePtrs[5] = 0;
_compTypeIDs[6] = ComponentTypeID<T6>.value; _compTypeIDs[6] = ComponentTypeID<T6>.Value;
_offsets[6] = 0; _offsets[6] = 0;
_compBasePtrs[6] = 0; _compBasePtrs[6] = 0;
@@ -1580,35 +1580,35 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
_compTypeIDs[4] = ComponentTypeID<T4>.value; _compTypeIDs[4] = ComponentTypeID<T4>.Value;
_offsets[4] = 0; _offsets[4] = 0;
_compBasePtrs[4] = 0; _compBasePtrs[4] = 0;
_compTypeIDs[5] = ComponentTypeID<T5>.value; _compTypeIDs[5] = ComponentTypeID<T5>.Value;
_offsets[5] = 0; _offsets[5] = 0;
_compBasePtrs[5] = 0; _compBasePtrs[5] = 0;
_compTypeIDs[6] = ComponentTypeID<T6>.value; _compTypeIDs[6] = ComponentTypeID<T6>.Value;
_offsets[6] = 0; _offsets[6] = 0;
_compBasePtrs[6] = 0; _compBasePtrs[6] = 0;
_compTypeIDs[7] = ComponentTypeID<T7>.value; _compTypeIDs[7] = ComponentTypeID<T7>.Value;
_offsets[7] = 0; _offsets[7] = 0;
_compBasePtrs[7] = 0; _compBasePtrs[7] = 0;

View File

@@ -71,7 +71,7 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_compTypeIDs[<#= j #>] = ComponentTypeID<T<#= j #>>.value; _compTypeIDs[<#= j #>] = ComponentTypeID<T<#= j #>>.Value;
_offsets[<#= j #>] = 0; _offsets[<#= j #>] = 0;
_compBasePtrs[<#= j #>] = 0; _compBasePtrs[<#= j #>] = 0;

View File

@@ -55,7 +55,7 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
@@ -253,11 +253,11 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
@@ -461,15 +461,15 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
@@ -679,19 +679,19 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
@@ -907,23 +907,23 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
_compTypeIDs[4] = ComponentTypeID<T4>.value; _compTypeIDs[4] = ComponentTypeID<T4>.Value;
_offsets[4] = 0; _offsets[4] = 0;
_compBasePtrs[4] = 0; _compBasePtrs[4] = 0;
@@ -1145,27 +1145,27 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
_compTypeIDs[4] = ComponentTypeID<T4>.value; _compTypeIDs[4] = ComponentTypeID<T4>.Value;
_offsets[4] = 0; _offsets[4] = 0;
_compBasePtrs[4] = 0; _compBasePtrs[4] = 0;
_compTypeIDs[5] = ComponentTypeID<T5>.value; _compTypeIDs[5] = ComponentTypeID<T5>.Value;
_offsets[5] = 0; _offsets[5] = 0;
_compBasePtrs[5] = 0; _compBasePtrs[5] = 0;
@@ -1393,31 +1393,31 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
_compTypeIDs[4] = ComponentTypeID<T4>.value; _compTypeIDs[4] = ComponentTypeID<T4>.Value;
_offsets[4] = 0; _offsets[4] = 0;
_compBasePtrs[4] = 0; _compBasePtrs[4] = 0;
_compTypeIDs[5] = ComponentTypeID<T5>.value; _compTypeIDs[5] = ComponentTypeID<T5>.Value;
_offsets[5] = 0; _offsets[5] = 0;
_compBasePtrs[5] = 0; _compBasePtrs[5] = 0;
_compTypeIDs[6] = ComponentTypeID<T6>.value; _compTypeIDs[6] = ComponentTypeID<T6>.Value;
_offsets[6] = 0; _offsets[6] = 0;
_compBasePtrs[6] = 0; _compBasePtrs[6] = 0;
@@ -1651,35 +1651,35 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
_compTypeIDs[0] = ComponentTypeID<T0>.value; _compTypeIDs[0] = ComponentTypeID<T0>.Value;
_offsets[0] = 0; _offsets[0] = 0;
_compBasePtrs[0] = 0; _compBasePtrs[0] = 0;
_compTypeIDs[1] = ComponentTypeID<T1>.value; _compTypeIDs[1] = ComponentTypeID<T1>.Value;
_offsets[1] = 0; _offsets[1] = 0;
_compBasePtrs[1] = 0; _compBasePtrs[1] = 0;
_compTypeIDs[2] = ComponentTypeID<T2>.value; _compTypeIDs[2] = ComponentTypeID<T2>.Value;
_offsets[2] = 0; _offsets[2] = 0;
_compBasePtrs[2] = 0; _compBasePtrs[2] = 0;
_compTypeIDs[3] = ComponentTypeID<T3>.value; _compTypeIDs[3] = ComponentTypeID<T3>.Value;
_offsets[3] = 0; _offsets[3] = 0;
_compBasePtrs[3] = 0; _compBasePtrs[3] = 0;
_compTypeIDs[4] = ComponentTypeID<T4>.value; _compTypeIDs[4] = ComponentTypeID<T4>.Value;
_offsets[4] = 0; _offsets[4] = 0;
_compBasePtrs[4] = 0; _compBasePtrs[4] = 0;
_compTypeIDs[5] = ComponentTypeID<T5>.value; _compTypeIDs[5] = ComponentTypeID<T5>.Value;
_offsets[5] = 0; _offsets[5] = 0;
_compBasePtrs[5] = 0; _compBasePtrs[5] = 0;
_compTypeIDs[6] = ComponentTypeID<T6>.value; _compTypeIDs[6] = ComponentTypeID<T6>.Value;
_offsets[6] = 0; _offsets[6] = 0;
_compBasePtrs[6] = 0; _compBasePtrs[6] = 0;
_compTypeIDs[7] = ComponentTypeID<T7>.value; _compTypeIDs[7] = ComponentTypeID<T7>.Value;
_offsets[7] = 0; _offsets[7] = 0;
_compBasePtrs[7] = 0; _compBasePtrs[7] = 0;

View File

@@ -75,7 +75,7 @@ public unsafe partial struct EntityQuery
internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world) internal Enumerator(ReadOnlyUnsafeCollection<Identifier<Archetype>> matchingArchetypes, EntityQueryMask mask, World world)
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_compTypeIDs[<#= j #>] = ComponentTypeID<T<#= j #>>.value; _compTypeIDs[<#= j #>] = ComponentTypeID<T<#= j #>>.Value;
_offsets[<#= j #>] = 0; _offsets[<#= j #>] = 0;
_compBasePtrs[<#= j #>] = 0; _compBasePtrs[<#= j #>] = 0;

View File

@@ -1,3 +1,4 @@
namespace Ghost.Entities; namespace Ghost.Entities;
public unsafe partial struct EntityQuery public unsafe partial struct EntityQuery
@@ -8,7 +9,7 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -93,8 +94,8 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -182,9 +183,9 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -275,10 +276,10 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -372,11 +373,11 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var comp4TypeID = ComponentTypeID<T4>.value; var comp4TypeID = ComponentTypeID<T4>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -473,12 +474,12 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var comp4TypeID = ComponentTypeID<T4>.value; var comp4TypeID = ComponentTypeID<T4>.Value;
var comp5TypeID = ComponentTypeID<T5>.value; var comp5TypeID = ComponentTypeID<T5>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -578,13 +579,13 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var comp4TypeID = ComponentTypeID<T4>.value; var comp4TypeID = ComponentTypeID<T4>.Value;
var comp5TypeID = ComponentTypeID<T5>.value; var comp5TypeID = ComponentTypeID<T5>.Value;
var comp6TypeID = ComponentTypeID<T6>.value; var comp6TypeID = ComponentTypeID<T6>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -687,14 +688,14 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var comp4TypeID = ComponentTypeID<T4>.value; var comp4TypeID = ComponentTypeID<T4>.Value;
var comp5TypeID = ComponentTypeID<T5>.value; var comp5TypeID = ComponentTypeID<T5>.Value;
var comp6TypeID = ComponentTypeID<T6>.value; var comp6TypeID = ComponentTypeID<T6>.Value;
var comp7TypeID = ComponentTypeID<T7>.value; var comp7TypeID = ComponentTypeID<T7>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -792,7 +793,7 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -878,8 +879,8 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -968,9 +969,9 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -1062,10 +1063,10 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -1160,11 +1161,11 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var comp4TypeID = ComponentTypeID<T4>.value; var comp4TypeID = ComponentTypeID<T4>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -1262,12 +1263,12 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var comp4TypeID = ComponentTypeID<T4>.value; var comp4TypeID = ComponentTypeID<T4>.Value;
var comp5TypeID = ComponentTypeID<T5>.value; var comp5TypeID = ComponentTypeID<T5>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -1368,13 +1369,13 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var comp4TypeID = ComponentTypeID<T4>.value; var comp4TypeID = ComponentTypeID<T4>.Value;
var comp5TypeID = ComponentTypeID<T5>.value; var comp5TypeID = ComponentTypeID<T5>.Value;
var comp6TypeID = ComponentTypeID<T6>.value; var comp6TypeID = ComponentTypeID<T6>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {
@@ -1478,14 +1479,14 @@ public unsafe partial struct EntityQuery
var world = World.GetWorldUncheck(_worldID); var world = World.GetWorldUncheck(_worldID);
var globalVersion = world.Version; var globalVersion = world.Version;
var comp0TypeID = ComponentTypeID<T0>.value; var comp0TypeID = ComponentTypeID<T0>.Value;
var comp1TypeID = ComponentTypeID<T1>.value; var comp1TypeID = ComponentTypeID<T1>.Value;
var comp2TypeID = ComponentTypeID<T2>.value; var comp2TypeID = ComponentTypeID<T2>.Value;
var comp3TypeID = ComponentTypeID<T3>.value; var comp3TypeID = ComponentTypeID<T3>.Value;
var comp4TypeID = ComponentTypeID<T4>.value; var comp4TypeID = ComponentTypeID<T4>.Value;
var comp5TypeID = ComponentTypeID<T5>.value; var comp5TypeID = ComponentTypeID<T5>.Value;
var comp6TypeID = ComponentTypeID<T6>.value; var comp6TypeID = ComponentTypeID<T6>.Value;
var comp7TypeID = ComponentTypeID<T7>.value; var comp7TypeID = ComponentTypeID<T7>.Value;
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]
{ {

View File

@@ -26,7 +26,7 @@ public unsafe partial struct EntityQuery
var globalVersion = world.Version; var globalVersion = world.Version;
<# for (var localIndex = 0; localIndex < i; localIndex++) { #> <# for (var localIndex = 0; localIndex < i; localIndex++) { #>
var comp<#= localIndex #>TypeID = ComponentTypeID<T<#= localIndex #>>.value; var comp<#= localIndex #>TypeID = ComponentTypeID<T<#= localIndex #>>.Value;
<# } #> <# } #>
var compTypeIDs = stackalloc int[] var compTypeIDs = stackalloc int[]

View File

@@ -1118,7 +1118,7 @@ public unsafe partial struct EntityQuery
} }
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
var layout0 = arch.GetLayout(ComponentTypeID<T0>.value) var layout0 = arch.GetLayout(ComponentTypeID<T0>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
// Add all chunks from this archetype // Add all chunks from this archetype
@@ -1154,7 +1154,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))
@@ -1255,9 +1255,9 @@ public unsafe partial struct EntityQuery
} }
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
var layout0 = arch.GetLayout(ComponentTypeID<T0>.value) var layout0 = arch.GetLayout(ComponentTypeID<T0>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout1 = arch.GetLayout(ComponentTypeID<T1>.value) var layout1 = arch.GetLayout(ComponentTypeID<T1>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
// Add all chunks from this archetype // Add all chunks from this archetype
@@ -1301,7 +1301,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))
@@ -1419,11 +1419,11 @@ public unsafe partial struct EntityQuery
} }
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
var layout0 = arch.GetLayout(ComponentTypeID<T0>.value) var layout0 = arch.GetLayout(ComponentTypeID<T0>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout1 = arch.GetLayout(ComponentTypeID<T1>.value) var layout1 = arch.GetLayout(ComponentTypeID<T1>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout2 = arch.GetLayout(ComponentTypeID<T2>.value) var layout2 = arch.GetLayout(ComponentTypeID<T2>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
// Add all chunks from this archetype // Add all chunks from this archetype
@@ -1475,7 +1475,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))
@@ -1610,13 +1610,13 @@ public unsafe partial struct EntityQuery
} }
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
var layout0 = arch.GetLayout(ComponentTypeID<T0>.value) var layout0 = arch.GetLayout(ComponentTypeID<T0>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout1 = arch.GetLayout(ComponentTypeID<T1>.value) var layout1 = arch.GetLayout(ComponentTypeID<T1>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout2 = arch.GetLayout(ComponentTypeID<T2>.value) var layout2 = arch.GetLayout(ComponentTypeID<T2>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout3 = arch.GetLayout(ComponentTypeID<T3>.value) var layout3 = arch.GetLayout(ComponentTypeID<T3>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
// Add all chunks from this archetype // Add all chunks from this archetype
@@ -1676,7 +1676,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))
@@ -1828,15 +1828,15 @@ public unsafe partial struct EntityQuery
} }
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
var layout0 = arch.GetLayout(ComponentTypeID<T0>.value) var layout0 = arch.GetLayout(ComponentTypeID<T0>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout1 = arch.GetLayout(ComponentTypeID<T1>.value) var layout1 = arch.GetLayout(ComponentTypeID<T1>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout2 = arch.GetLayout(ComponentTypeID<T2>.value) var layout2 = arch.GetLayout(ComponentTypeID<T2>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout3 = arch.GetLayout(ComponentTypeID<T3>.value) var layout3 = arch.GetLayout(ComponentTypeID<T3>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout4 = arch.GetLayout(ComponentTypeID<T4>.value) var layout4 = arch.GetLayout(ComponentTypeID<T4>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
// Add all chunks from this archetype // Add all chunks from this archetype
@@ -1904,7 +1904,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))
@@ -2073,17 +2073,17 @@ public unsafe partial struct EntityQuery
} }
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
var layout0 = arch.GetLayout(ComponentTypeID<T0>.value) var layout0 = arch.GetLayout(ComponentTypeID<T0>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout1 = arch.GetLayout(ComponentTypeID<T1>.value) var layout1 = arch.GetLayout(ComponentTypeID<T1>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout2 = arch.GetLayout(ComponentTypeID<T2>.value) var layout2 = arch.GetLayout(ComponentTypeID<T2>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout3 = arch.GetLayout(ComponentTypeID<T3>.value) var layout3 = arch.GetLayout(ComponentTypeID<T3>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout4 = arch.GetLayout(ComponentTypeID<T4>.value) var layout4 = arch.GetLayout(ComponentTypeID<T4>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout5 = arch.GetLayout(ComponentTypeID<T5>.value) var layout5 = arch.GetLayout(ComponentTypeID<T5>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
// Add all chunks from this archetype // Add all chunks from this archetype
@@ -2159,7 +2159,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))
@@ -2345,19 +2345,19 @@ public unsafe partial struct EntityQuery
} }
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
var layout0 = arch.GetLayout(ComponentTypeID<T0>.value) var layout0 = arch.GetLayout(ComponentTypeID<T0>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout1 = arch.GetLayout(ComponentTypeID<T1>.value) var layout1 = arch.GetLayout(ComponentTypeID<T1>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout2 = arch.GetLayout(ComponentTypeID<T2>.value) var layout2 = arch.GetLayout(ComponentTypeID<T2>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout3 = arch.GetLayout(ComponentTypeID<T3>.value) var layout3 = arch.GetLayout(ComponentTypeID<T3>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout4 = arch.GetLayout(ComponentTypeID<T4>.value) var layout4 = arch.GetLayout(ComponentTypeID<T4>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout5 = arch.GetLayout(ComponentTypeID<T5>.value) var layout5 = arch.GetLayout(ComponentTypeID<T5>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout6 = arch.GetLayout(ComponentTypeID<T6>.value) var layout6 = arch.GetLayout(ComponentTypeID<T6>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
// Add all chunks from this archetype // Add all chunks from this archetype
@@ -2441,7 +2441,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))
@@ -2644,21 +2644,21 @@ public unsafe partial struct EntityQuery
} }
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
var layout0 = arch.GetLayout(ComponentTypeID<T0>.value) var layout0 = arch.GetLayout(ComponentTypeID<T0>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout1 = arch.GetLayout(ComponentTypeID<T1>.value) var layout1 = arch.GetLayout(ComponentTypeID<T1>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout2 = arch.GetLayout(ComponentTypeID<T2>.value) var layout2 = arch.GetLayout(ComponentTypeID<T2>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout3 = arch.GetLayout(ComponentTypeID<T3>.value) var layout3 = arch.GetLayout(ComponentTypeID<T3>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout4 = arch.GetLayout(ComponentTypeID<T4>.value) var layout4 = arch.GetLayout(ComponentTypeID<T4>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout5 = arch.GetLayout(ComponentTypeID<T5>.value) var layout5 = arch.GetLayout(ComponentTypeID<T5>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout6 = arch.GetLayout(ComponentTypeID<T6>.value) var layout6 = arch.GetLayout(ComponentTypeID<T6>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
var layout7 = arch.GetLayout(ComponentTypeID<T7>.value) var layout7 = arch.GetLayout(ComponentTypeID<T7>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
// Add all chunks from this archetype // Add all chunks from this archetype
@@ -2750,7 +2750,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))

View File

@@ -151,7 +151,7 @@ public unsafe partial struct EntityQuery
// Get offsets ONCE per archetype // Get offsets ONCE per archetype
<# for (var j = 0; j < i; j++){ #> <# for (var j = 0; j < i; j++){ #>
var layout<#= j #> = arch.GetLayout(ComponentTypeID<T<#= j #>>.value) var layout<#= j #> = arch.GetLayout(ComponentTypeID<T<#= j #>>.Value)
.GetValueOrThrow(); .GetValueOrThrow();
<# } #> <# } #>
@@ -192,7 +192,7 @@ public unsafe partial struct EntityQuery
version = world.Version, version = world.Version,
}; };
runner.componentIDs[0] = ComponentTypeID<T0>.value; runner.componentIDs[0] = ComponentTypeID<T0>.Value;
var it = _mask.writeAccess.GetIterator(); var it = _mask.writeAccess.GetIterator();
while (it.Next(out var id)) while (it.Next(out var id))

View File

@@ -13,7 +13,7 @@ public ref partial struct QueryBuilder
public QueryBuilder WithAll<T0>() public QueryBuilder WithAll<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.value); _all.Add(ComponentTypeID<T0>.Value);
return this; return this;
} }
@@ -26,8 +26,8 @@ public ref partial struct QueryBuilder
public QueryBuilder WithAllRW<T0>() public QueryBuilder WithAllRW<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.value); _all.Add(ComponentTypeID<T0>.Value);
_rw.Add(ComponentTypeID<T0>.value); _rw.Add(ComponentTypeID<T0>.Value);
return this; return this;
} }
@@ -40,7 +40,7 @@ public ref partial struct QueryBuilder
public QueryBuilder WithAny<T0>() public QueryBuilder WithAny<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_any.Add(ComponentTypeID<T0>.value); _any.Add(ComponentTypeID<T0>.Value);
return this; return this;
} }
@@ -53,7 +53,7 @@ public ref partial struct QueryBuilder
public QueryBuilder WithAbsent<T0>() public QueryBuilder WithAbsent<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_absent.Add(ComponentTypeID<T0>.value); _absent.Add(ComponentTypeID<T0>.Value);
return this; return this;
} }
@@ -66,7 +66,7 @@ public ref partial struct QueryBuilder
public QueryBuilder WithNone<T0>() public QueryBuilder WithNone<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_none.Add(ComponentTypeID<T0>.value); _none.Add(ComponentTypeID<T0>.Value);
return this; return this;
} }
@@ -79,7 +79,7 @@ public ref partial struct QueryBuilder
public QueryBuilder WithDisabled<T0>() public QueryBuilder WithDisabled<T0>()
where T0 : unmanaged, IEnableableComponent where T0 : unmanaged, IEnableableComponent
{ {
_disabled.Add(ComponentTypeID<T0>.value); _disabled.Add(ComponentTypeID<T0>.Value);
return this; return this;
} }
@@ -92,7 +92,7 @@ public ref partial struct QueryBuilder
public QueryBuilder WithPresent<T0>() public QueryBuilder WithPresent<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.value); _present.Add(ComponentTypeID<T0>.Value);
return this; return this;
} }
@@ -105,8 +105,8 @@ public ref partial struct QueryBuilder
public QueryBuilder WithPresentRW<T0>() public QueryBuilder WithPresentRW<T0>()
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.value); _present.Add(ComponentTypeID<T0>.Value);
_rw.Add(ComponentTypeID<T0>.value); _rw.Add(ComponentTypeID<T0>.Value);
return this; return this;
} }
@@ -120,8 +120,8 @@ public ref partial struct QueryBuilder
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.value); _all.Add(ComponentTypeID<T0>.Value);
_all.Add(ComponentTypeID<T1>.value); _all.Add(ComponentTypeID<T1>.Value);
return this; return this;
} }
@@ -135,10 +135,10 @@ public ref partial struct QueryBuilder
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.value); _all.Add(ComponentTypeID<T0>.Value);
_rw.Add(ComponentTypeID<T0>.value); _rw.Add(ComponentTypeID<T0>.Value);
_all.Add(ComponentTypeID<T1>.value); _all.Add(ComponentTypeID<T1>.Value);
_rw.Add(ComponentTypeID<T1>.value); _rw.Add(ComponentTypeID<T1>.Value);
return this; return this;
} }
@@ -152,8 +152,8 @@ public ref partial struct QueryBuilder
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_any.Add(ComponentTypeID<T0>.value); _any.Add(ComponentTypeID<T0>.Value);
_any.Add(ComponentTypeID<T1>.value); _any.Add(ComponentTypeID<T1>.Value);
return this; return this;
} }
@@ -167,8 +167,8 @@ public ref partial struct QueryBuilder
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_absent.Add(ComponentTypeID<T0>.value); _absent.Add(ComponentTypeID<T0>.Value);
_absent.Add(ComponentTypeID<T1>.value); _absent.Add(ComponentTypeID<T1>.Value);
return this; return this;
} }
@@ -182,8 +182,8 @@ public ref partial struct QueryBuilder
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_none.Add(ComponentTypeID<T0>.value); _none.Add(ComponentTypeID<T0>.Value);
_none.Add(ComponentTypeID<T1>.value); _none.Add(ComponentTypeID<T1>.Value);
return this; return this;
} }
@@ -197,8 +197,8 @@ public ref partial struct QueryBuilder
where T0 : unmanaged, IEnableableComponent where T0 : unmanaged, IEnableableComponent
where T1 : unmanaged, IEnableableComponent where T1 : unmanaged, IEnableableComponent
{ {
_disabled.Add(ComponentTypeID<T0>.value); _disabled.Add(ComponentTypeID<T0>.Value);
_disabled.Add(ComponentTypeID<T1>.value); _disabled.Add(ComponentTypeID<T1>.Value);
return this; return this;
} }
@@ -212,8 +212,8 @@ public ref partial struct QueryBuilder
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.value); _present.Add(ComponentTypeID<T0>.Value);
_present.Add(ComponentTypeID<T1>.value); _present.Add(ComponentTypeID<T1>.Value);
return this; return this;
} }
@@ -227,10 +227,10 @@ public ref partial struct QueryBuilder
where T0 : unmanaged, IComponent where T0 : unmanaged, IComponent
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.value); _present.Add(ComponentTypeID<T0>.Value);
_rw.Add(ComponentTypeID<T0>.value); _rw.Add(ComponentTypeID<T0>.Value);
_present.Add(ComponentTypeID<T1>.value); _present.Add(ComponentTypeID<T1>.Value);
_rw.Add(ComponentTypeID<T1>.value); _rw.Add(ComponentTypeID<T1>.Value);
return this; return this;
} }
@@ -245,9 +245,9 @@ public ref partial struct QueryBuilder
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.value); _all.Add(ComponentTypeID<T0>.Value);
_all.Add(ComponentTypeID<T1>.value); _all.Add(ComponentTypeID<T1>.Value);
_all.Add(ComponentTypeID<T2>.value); _all.Add(ComponentTypeID<T2>.Value);
return this; return this;
} }
@@ -262,12 +262,12 @@ public ref partial struct QueryBuilder
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
{ {
_all.Add(ComponentTypeID<T0>.value); _all.Add(ComponentTypeID<T0>.Value);
_rw.Add(ComponentTypeID<T0>.value); _rw.Add(ComponentTypeID<T0>.Value);
_all.Add(ComponentTypeID<T1>.value); _all.Add(ComponentTypeID<T1>.Value);
_rw.Add(ComponentTypeID<T1>.value); _rw.Add(ComponentTypeID<T1>.Value);
_all.Add(ComponentTypeID<T2>.value); _all.Add(ComponentTypeID<T2>.Value);
_rw.Add(ComponentTypeID<T2>.value); _rw.Add(ComponentTypeID<T2>.Value);
return this; return this;
} }
@@ -282,9 +282,9 @@ public ref partial struct QueryBuilder
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
{ {
_any.Add(ComponentTypeID<T0>.value); _any.Add(ComponentTypeID<T0>.Value);
_any.Add(ComponentTypeID<T1>.value); _any.Add(ComponentTypeID<T1>.Value);
_any.Add(ComponentTypeID<T2>.value); _any.Add(ComponentTypeID<T2>.Value);
return this; return this;
} }
@@ -299,9 +299,9 @@ public ref partial struct QueryBuilder
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
{ {
_absent.Add(ComponentTypeID<T0>.value); _absent.Add(ComponentTypeID<T0>.Value);
_absent.Add(ComponentTypeID<T1>.value); _absent.Add(ComponentTypeID<T1>.Value);
_absent.Add(ComponentTypeID<T2>.value); _absent.Add(ComponentTypeID<T2>.Value);
return this; return this;
} }
@@ -316,9 +316,9 @@ public ref partial struct QueryBuilder
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
{ {
_none.Add(ComponentTypeID<T0>.value); _none.Add(ComponentTypeID<T0>.Value);
_none.Add(ComponentTypeID<T1>.value); _none.Add(ComponentTypeID<T1>.Value);
_none.Add(ComponentTypeID<T2>.value); _none.Add(ComponentTypeID<T2>.Value);
return this; return this;
} }
@@ -333,9 +333,9 @@ public ref partial struct QueryBuilder
where T1 : unmanaged, IEnableableComponent where T1 : unmanaged, IEnableableComponent
where T2 : unmanaged, IEnableableComponent where T2 : unmanaged, IEnableableComponent
{ {
_disabled.Add(ComponentTypeID<T0>.value); _disabled.Add(ComponentTypeID<T0>.Value);
_disabled.Add(ComponentTypeID<T1>.value); _disabled.Add(ComponentTypeID<T1>.Value);
_disabled.Add(ComponentTypeID<T2>.value); _disabled.Add(ComponentTypeID<T2>.Value);
return this; return this;
} }
@@ -350,9 +350,9 @@ public ref partial struct QueryBuilder
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.value); _present.Add(ComponentTypeID<T0>.Value);
_present.Add(ComponentTypeID<T1>.value); _present.Add(ComponentTypeID<T1>.Value);
_present.Add(ComponentTypeID<T2>.value); _present.Add(ComponentTypeID<T2>.Value);
return this; return this;
} }
@@ -367,12 +367,12 @@ public ref partial struct QueryBuilder
where T1 : unmanaged, IComponent where T1 : unmanaged, IComponent
where T2 : unmanaged, IComponent where T2 : unmanaged, IComponent
{ {
_present.Add(ComponentTypeID<T0>.value); _present.Add(ComponentTypeID<T0>.Value);
_rw.Add(ComponentTypeID<T0>.value); _rw.Add(ComponentTypeID<T0>.Value);
_present.Add(ComponentTypeID<T1>.value); _present.Add(ComponentTypeID<T1>.Value);
_rw.Add(ComponentTypeID<T1>.value); _rw.Add(ComponentTypeID<T1>.Value);
_present.Add(ComponentTypeID<T2>.value); _present.Add(ComponentTypeID<T2>.Value);
_rw.Add(ComponentTypeID<T2>.value); _rw.Add(ComponentTypeID<T2>.Value);
return this; return this;
} }

View File

@@ -25,7 +25,7 @@ public ref partial struct QueryBuilder
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_all.Add(ComponentTypeID<T<#= j #>>.value); _all.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return this;
@@ -40,8 +40,8 @@ public ref partial struct QueryBuilder
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_all.Add(ComponentTypeID<T<#= j #>>.value); _all.Add(ComponentTypeID<T<#= j #>>.Value);
_rw.Add(ComponentTypeID<T<#= j #>>.value); _rw.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return this;
@@ -56,7 +56,7 @@ public ref partial struct QueryBuilder
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_any.Add(ComponentTypeID<T<#= j #>>.value); _any.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return this;
@@ -71,7 +71,7 @@ public ref partial struct QueryBuilder
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_absent.Add(ComponentTypeID<T<#= j #>>.value); _absent.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return this;
@@ -86,7 +86,7 @@ public ref partial struct QueryBuilder
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_none.Add(ComponentTypeID<T<#= j #>>.value); _none.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return this;
@@ -101,7 +101,7 @@ public ref partial struct QueryBuilder
<#= enableRestrictions #> <#= enableRestrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_disabled.Add(ComponentTypeID<T<#= j #>>.value); _disabled.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return this;
@@ -116,7 +116,7 @@ public ref partial struct QueryBuilder
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_present.Add(ComponentTypeID<T<#= j #>>.value); _present.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return this;
@@ -131,8 +131,8 @@ public ref partial struct QueryBuilder
<#= restrictions #> <#= restrictions #>
{ {
<# for (var j = 0; j < i; j++) { #> <# for (var j = 0; j < i; j++) { #>
_present.Add(ComponentTypeID<T<#= j #>>.value); _present.Add(ComponentTypeID<T<#= j #>>.Value);
_rw.Add(ComponentTypeID<T<#= j #>>.value); _rw.Add(ComponentTypeID<T<#= j #>>.Value);
<# } #> <# } #>
return this; return this;

View File

@@ -0,0 +1,138 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using System.Threading;
namespace Ghost.Generator
{
[Generator]
public class ComponentRegistrationGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 1. Pipeline: Find all structs implementing IComponent
var componentCandidates = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (s, _) => s is StructDeclarationSyntax,
transform: GetComponentSymbol)
.Where(symbol => symbol != null)
.Collect();
// 2. Pipeline: Find the ONE class with [EngineEntry]
var engineEntryClass = context.SyntaxProvider
.CreateSyntaxProvider(
predicate: (s, _) => s is ClassDeclarationSyntax,
transform: GetEngineEntrySymbol)
.Where(symbol => symbol != null)
.Collect(); // Returns ImmutableArray<INamedTypeSymbol>
// 3. COMBINE: Pair the list of components with the list of entry classes
// The result 'source' in the callback will be a tuple: (ImmutableArray<Info>, ImmutableArray<Entry>)
var combinedProvider = componentCandidates.Combine(engineEntryClass);
// 4. Output: Generate the source using both pieces of data at once
context.RegisterSourceOutput(combinedProvider, GenerateRegistrationCode);
}
// Extraction Logic for Components
private static INamedTypeSymbol GetComponentSymbol(GeneratorSyntaxContext ctx, CancellationToken _)
{
var structSyntax = (StructDeclarationSyntax)ctx.Node;
if (!(ctx.SemanticModel.GetDeclaredSymbol(structSyntax) is INamedTypeSymbol symbol))
{
return null;
}
var iComponentSymbol = ctx.SemanticModel.Compilation.GetTypeByMetadataName("Ghost.Entities.IComponent");
if (iComponentSymbol == null)
{
return null;
}
foreach (var iface in symbol.AllInterfaces)
{
if (SymbolEqualityComparer.Default.Equals(iface, iComponentSymbol))
{
return symbol;
}
}
return null;
}
// Extraction Logic for Engine Entry
private static INamedTypeSymbol GetEngineEntrySymbol(GeneratorSyntaxContext ctx, CancellationToken _)
{
var classSyntax = (ClassDeclarationSyntax)ctx.Node;
if (!(ctx.SemanticModel.GetDeclaredSymbol(classSyntax) is INamedTypeSymbol symbol))
{
return null;
}
// Check attributes
foreach (var attribute in symbol.GetAttributes())
{
if (attribute.AttributeClass?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) == "global::Ghost.Engine.EngineEntryAttribute")
{
return symbol;
}
}
return null;
}
// The Generation Logic (Stateless)
private static void GenerateRegistrationCode(
SourceProductionContext context,
(ImmutableArray<INamedTypeSymbol> Components, ImmutableArray<INamedTypeSymbol> Entries) source)
{
var components = source.Components;
var entries = source.Entries;
// 1. Validation: Ensure we found exactly one [EngineEntry] class
if (entries.IsDefaultOrEmpty)
{
return;
}
// Pick the first one (if multiple exist, you might want to report a diagnostic error)
var targetClass = entries[0];
if (components.IsDefaultOrEmpty)
{
return;
}
// 2. Extract Namespace and Class Name directly from the symbol found in the pipeline
var targetNamespace = targetClass.ContainingNamespace.ToDisplayString();
var targetClassName = targetClass.Name;
var sb = new StringBuilder();
sb.Append($@"
namespace {targetNamespace}
{{
public partial class {targetClassName}
{{
private static void RegisterIComponentTypes()
{{");
foreach (var symbol in components.Distinct(SymbolEqualityComparer.Default))
{
if (symbol is null) continue;
sb.Append($@"
global::Ghost.Entities.ComponentRegistry.GetOrRegisterComponent<{symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>();");
}
sb.Append(@"
}
}
}");
context.AddSource($"{targetClassName}.ComponentReg.gen.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
}
}
}

View File

@@ -1,6 +1,5 @@
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -10,67 +9,200 @@ namespace Ghost.Generator
[Generator] [Generator]
public class ComponentSerializationGenerator : IIncrementalGenerator public class ComponentSerializationGenerator : IIncrementalGenerator
{ {
private void GenerateJsonContext(SourceProductionContext context, ImmutableArray<INamedTypeSymbol> symbols) private string GetJsonWriteCall(ITypeSymbol type, string fieldName)
{ {
if (symbols.IsDefaultOrEmpty) // 1. PRIMITIVES (Fastest)
switch (type.SpecialType)
{ {
return; case SpecialType.System_Byte:
case SpecialType.System_SByte:
case SpecialType.System_Int16:
case SpecialType.System_Int32:
case SpecialType.System_Int64:
case SpecialType.System_Single:
case SpecialType.System_Double:
case SpecialType.System_Decimal:
case SpecialType.System_UInt64:
case SpecialType.System_UInt16:
case SpecialType.System_UInt32:
case SpecialType.System_IntPtr:
case SpecialType.System_UIntPtr:
return $@"writer.WriteNumber(""{fieldName}"", value.{fieldName});";
case SpecialType.System_Boolean:
return $@"writer.WriteBoolean(""{fieldName}"", value.{fieldName});";
case SpecialType.System_Char:
return $@"writer.WriteString(""{fieldName}"", [value.{fieldName}]);";
} }
var sb = new StringBuilder(); // TODO: Add well-known types like float3, Vector3, etc.
sb.Append(@" #if false
using System; // 2. KNOWN MATH TYPES (Optimized Arrays)
using System.Collections.Generic; // Checking by name is simple and effective for standard math libs
using System.Collections.Generic; if (type.Name == "float3" || type.Name == "Vector3")
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
namespace Ghost.Engine.Components.Serialization
{
[JsonSourceGenerationOptions(WriteIndented = true, IncludeFields = true)]");
foreach (var symbol in symbols.Distinct(SymbolEqualityComparer.Default))
{ {
if (symbol is null) return $@"writer.WritePropertyName(""{fieldName}"");
{ writer.WriteStartArray();
continue; writer.WriteNumberValue(value.{fieldName}.x);
writer.WriteNumberValue(value.{fieldName}.y);
writer.WriteNumberValue(value.{fieldName}.z);
writer.WriteEndArray();";
}
#endif
// 3. FALLBACK: System.Text.Json (Reflection)
// If we don't know what it is, let the standard serializer handle it.
// This handles float4x4, List<T>, and other nested structs automatically.
return $@"writer.WritePropertyName(""{fieldName}""); global::System.Text.Json.JsonSerializer.Serialize(writer, value.{fieldName}, options);";
} }
var fqtn = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); private string GetJsonReadCall(ITypeSymbol type)
sb.Append($@"
[JsonSerializable(typeof({fqtn}))]");
}
sb.Append(@"
public partial class ComponentJsonContext : JsonSerializerContext
{ {
private static readonly Dictionary<Type, JsonTypeInfo> _typeLookup = new() switch (type.SpecialType)
{");
foreach (var symbol in symbols.Distinct(SymbolEqualityComparer.Default))
{ {
if (symbol is null) case SpecialType.System_Byte: return "reader.GetByte()";
case SpecialType.System_SByte: return "reader.GetSByte()";
case SpecialType.System_Int16: return "reader.GetInt16()";
case SpecialType.System_Int32: return "reader.GetInt32()";
case SpecialType.System_Int64: return "reader.GetInt64()";
case SpecialType.System_Single: return "reader.GetSingle()";
case SpecialType.System_Double: return "reader.GetDouble()";
case SpecialType.System_Decimal: return "reader.GetDecimal()";
case SpecialType.System_UInt16: return "reader.GetUInt16()";
case SpecialType.System_UInt32: return "reader.GetUInt32()";
case SpecialType.System_UInt64: return "reader.GetUInt64()";
case SpecialType.System_IntPtr: return "reader.GetInt64()"; // Note: IntPtr size varies by platform
case SpecialType.System_UIntPtr: return "reader.GetUInt64()"; // Note: UIntPtr size varies by platform
case SpecialType.System_Boolean: return "reader.GetBoolean()";
case SpecialType.System_Char: return "reader.GetString()[0]";
}
#if false
// For custom math types, you'd need to generate code to read the array back
if (type.Name == "float3") return "new float3(reader.GetSingle(), reader.GetSingle(), reader.GetSingle())"; // Simplified
#endif
return $"global::System.Text.Json.JsonSerializer.Deserialize<{type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}>(ref reader, options)";
}
private void GenerateJsonSerializer(SourceProductionContext context, ImmutableArray<INamedTypeSymbol> symbols)
{ {
continue; var sbWrites = new StringBuilder();
var sbReads = new StringBuilder();
foreach (var symbol in symbols)
{
var namespaceName = symbol.ContainingNamespace.ToDisplayString();
var structName = symbol.Name;
var fullTypeName = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
// 1. Build Field Logic (Same as before)
sbWrites.Clear();
sbReads.Clear();
var fields = symbol.GetMembers()
.OfType<IFieldSymbol>()
.Where(f => !f.IsStatic && f.DeclaredAccessibility == Accessibility.Public);
foreach (var field in fields)
{
// Note: GetJsonWriteCall returns a string ending with ";"
var writeCall = GetJsonWriteCall(field.Type, field.Name);
if (writeCall != null)
{
sbWrites.Append(" "); // Indentation
sbWrites.AppendLine(writeCall);
} }
var fqtn = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var readCall = GetJsonReadCall(field.Type);
sb.Append($@" if (readCall != null)
{{ typeof({fqtn}), ComponentJsonContext.{symbol.Name} }},"); {
// Note the double quotes ""{field.Name}"" for the case string
sbReads.Append(" "); // Indentation
sbReads.AppendLine($@"case ""{field.Name}"": result.{field.Name} = {readCall}; break;");
}
} }
sb.Append(@" // 2. The Main Template using $@
}; // Watch the double braces {{ }} and double quotes "" ""
var sourceCode = $@"// <auto-generated/>
/// <summary> namespace {namespaceName}
/// Tries to retrieve the generated JsonTypeInfo for a given component type. {{
/// </summary> public unsafe static class {structName}_Serializer
public static bool TryGetTypeInfo(Type componentType, out JsonTypeInfo jsonTypeInfo) => {{
_typeLookup.TryGetValue(componentType, out jsonTypeInfo); [global::System.Runtime.CompilerServices.ModuleInitializer]
internal static void Init()
{{
var id = Ghost.Entities.ComponentTypeID<{fullTypeName}>.Value;
Ghost.Engine.IO.ComponentSerializerRegistry.Register(id, SerializeBinaryUnsafe, SerializeJsonUnsafe);
}}
// ---------------------------------------------------------
// BINARY (Fast Path)
// ---------------------------------------------------------
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static unsafe void SerializeBinaryUnsafe(global::System.IO.BinaryWriter writer, void* value)
{{
writer.Write(new global::System.ReadOnlySpan<byte>(value, sizeof({fullTypeName})));
}}
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static void SerializeBinary(this global::System.IO.BinaryWriter writer, ref {fullTypeName} value)
{{
unsafe {{ writer.Write(new global::System.ReadOnlySpan<byte>(global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref value), sizeof({fullTypeName}))); }}
}}
[global::System.Runtime.CompilerServices.MethodImpl(global::System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static void DeserializeBinary(this global::System.IO.BinaryReader reader, ref {fullTypeName} value)
{{
unsafe {{ reader.Read(new global::System.Span<byte>(global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref value), sizeof({fullTypeName}))); }}
}}
// ---------------------------------------------------------
// JSON WRITE
// ---------------------------------------------------------
public static unsafe void SerializeJsonUnsafe(System.Text.Json.Utf8JsonWriter writer, void* ptr, System.Text.Json.JsonSerializerOptions? options)
{{
SerializeJson(writer, ref *( {fullTypeName}*)ptr, options);
}}
public static void SerializeJson(this global::System.Text.Json.Utf8JsonWriter writer, ref {fullTypeName} value, global::System.Text.Json.JsonSerializerOptions? options)
{{
writer.WriteStartObject();
{sbWrites}
writer.WriteEndObject();
}}
// ---------------------------------------------------------
// JSON READ
// ---------------------------------------------------------
public static {fullTypeName} DeserializeJson(ref global::System.Text.Json.Utf8JsonReader reader, global::System.Text.Json.JsonSerializerOptions? options)
{{
var result = default({fullTypeName});
if (reader.TokenType != global::System.Text.Json.JsonTokenType.StartObject) throw new global::System.Text.Json.JsonException();
while (reader.Read())
{{
if (reader.TokenType == global::System.Text.Json.JsonTokenType.EndObject) return result;
if (reader.TokenType != global::System.Text.Json.JsonTokenType.PropertyName) throw new global::System.Text.Json.JsonException();
var propName = reader.GetString();
reader.Read();
switch (propName)
{{
{sbReads}
default: reader.Skip(); break;
}}
}}
return result;
}}
}}
}}";
context.AddSource($"{structName}.Serializer.gen.cs", sourceCode);
} }
}");
context.AddSource("ComponentJsonContext.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
} }
public void Initialize(IncrementalGeneratorInitializationContext context) public void Initialize(IncrementalGeneratorInitializationContext context)
@@ -88,16 +220,16 @@ namespace Ghost.Engine.Components.Serialization
} }
var compilation = ctx.SemanticModel.Compilation; var compilation = ctx.SemanticModel.Compilation;
var iComponentDataSymbol = compilation.GetTypeByMetadataName("Ghost.Entities.Components.IComponentData"); var iComponentSymbol = compilation.GetTypeByMetadataName("Ghost.Entities.IComponent");
if (iComponentDataSymbol == null) if (iComponentSymbol == null)
{ {
return null; return null;
} }
foreach (var iface in symbol.AllInterfaces) foreach (var iface in symbol.AllInterfaces)
{ {
if (SymbolEqualityComparer.Default.Equals(iface, iComponentDataSymbol)) if (SymbolEqualityComparer.Default.Equals(iface, iComponentSymbol))
{ {
return symbol; return symbol;
} }
@@ -108,7 +240,7 @@ namespace Ghost.Engine.Components.Serialization
.Where(symbol => symbol != null) .Where(symbol => symbol != null)
.Collect(); .Collect();
context.RegisterSourceOutput(componentCandidates, GenerateJsonContext); context.RegisterSourceOutput(componentCandidates, GenerateJsonSerializer);
} }
} }
} }

View File

@@ -5,6 +5,12 @@
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules> <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Remove="Shader\**" />
<EmbeddedResource Remove="Shader\**" />
<None Remove="Shader\**" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0"> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="4.14.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
@@ -13,8 +19,4 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="Shader\" />
</ItemGroup>
</Project> </Project>

View File

@@ -53,7 +53,6 @@
<PackageReference Include="MSTest.TestFramework" Version="4.0.2" /> <PackageReference Include="MSTest.TestFramework" Version="4.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Ghost.Editor.Core\Ghost.Editor.Core.csproj" />
<ProjectReference Include="..\Ghost.Engine\Ghost.Engine.csproj" /> <ProjectReference Include="..\Ghost.Engine\Ghost.Engine.csproj" />
<ProjectReference Include="..\Ghost.Test.Core\Ghost.Test.Core.csproj" /> <ProjectReference Include="..\Ghost.Test.Core\Ghost.Test.Core.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -1,9 +1,9 @@
using Ghost.Graphics.RHI; using Ghost.Graphics.RHI;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media;
using Misaki.HighPerformance.LowLevel.Buffer; using Misaki.HighPerformance.LowLevel.Buffer;
using Misaki.HighPerformance.Mathematics; using Misaki.HighPerformance.Mathematics;
using System.Text.Json;
namespace Ghost.Graphics.Test.Windows; namespace Ghost.Graphics.Test.Windows;
@@ -57,6 +57,8 @@ public sealed partial class GraphicsTestWindow : Window
Target = SwapChainTarget.FromCompositionSurface(Panel) Target = SwapChainTarget.FromCompositionSurface(Panel)
}); });
_renderer.SetSwapChain(_swapChain);
_renderSystem.Start(); _renderSystem.Start();
CompositionTarget.Rendering += OnRendering; CompositionTarget.Rendering += OnRendering;

View File

@@ -74,7 +74,7 @@ internal class RenderSystem : IRenderSystem
public readonly AutoResetEvent cpuReadyEvent; public readonly AutoResetEvent cpuReadyEvent;
public readonly AutoResetEvent gpuReadyEvent; public readonly AutoResetEvent gpuReadyEvent;
public FrameResource(ICommandBuffer cmd) public FrameResource()
{ {
cpuReadyEvent = new AutoResetEvent(false); cpuReadyEvent = new AutoResetEvent(false);
gpuReadyEvent = new AutoResetEvent(true); gpuReadyEvent = new AutoResetEvent(true);