Add component editors and UI controls
Added the `HierarchyEditor` and `LocalToWorldEditor` classes to implement custom component editing functionality. Added the `Vector3Field` control for 3D vector manipulation and its corresponding XAML definition. Added the `ComponentDataView` and `ComponentObject` classes to manage component data display and access. Added the `CustomEditorAttribute` to mark classes as custom editors for specific components. Changed the `IInspectable` interface to use properties for `Icon`, `HeaderContent`, and `InspectorContent`. Changed the `PropertyField` class to enhance UI control binding capabilities. Changed the `EditorWorldManager` to improve world data loading and deserialization processes. Changed the `EntityNode` and `WorldNode` classes to update entity construction and component querying. Changed the `StaticResource` class to include new binding flags for component properties. Changed the `InspectorService` to remove old contract references and adopt new interfaces. Changed the `QueryEnumerable` and related files to update generic constraints for improved type safety. Changed the `QueryItem` class to reflect new generic constraints and enhance deconstruction. Changed the `World.Query` methods to utilize the updated generic constraints. Updated the `SerializationTest` to align with new entity creation and management practices.
This commit is contained in:
20
Ghost.App/Components/HierarchyEditor.cs
Normal file
20
Ghost.App/Components/HierarchyEditor.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Components;
|
||||
|
||||
//[CustomEditor(typeof(Hierarchy))]
|
||||
internal class HierarchyEditor : IComponentEditor
|
||||
{
|
||||
public void Create(ComponentObject componentObject, StackPanel container)
|
||||
{
|
||||
}
|
||||
|
||||
public void Update(ComponentObject componentObject)
|
||||
{
|
||||
}
|
||||
|
||||
public void Destroy(ComponentObject componentObject)
|
||||
{
|
||||
}
|
||||
}
|
||||
72
Ghost.App/Components/LocalToWorldEditor.cs
Normal file
72
Ghost.App/Components/LocalToWorldEditor.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using Ghost.Editor.Controls;
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
using Ghost.Engine.Components;
|
||||
using Ghost.Engine.Utilities;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Components;
|
||||
|
||||
[CustomEditor(typeof(LocalToWorld))]
|
||||
internal class LocalToWorldEditor : IComponentEditor
|
||||
{
|
||||
private Vector3Field _translationField = null!;
|
||||
private Vector3Field _rotationField = null!;
|
||||
private Vector3Field _scaleField = null!;
|
||||
|
||||
public void Create(ComponentObject componentObject, StackPanel container)
|
||||
{
|
||||
_translationField = new Vector3Field();
|
||||
_rotationField = new Vector3Field();
|
||||
_scaleField = new Vector3Field();
|
||||
|
||||
_translationField.OnValueChanged += (s, e) =>
|
||||
{
|
||||
var data = componentObject.GetData<LocalToWorld>();
|
||||
MatrixUtility.GetTRS(data.ValueRO.matrix, out var oldTranslation, out var oldRotation, out var oldScale);
|
||||
data.ValueRW.matrix = MatrixUtility.CreateTRS(e.NewValue, oldRotation, oldScale);
|
||||
};
|
||||
|
||||
_rotationField.OnValueChanged += (s, e) =>
|
||||
{
|
||||
var data = componentObject.GetData<LocalToWorld>();
|
||||
MatrixUtility.GetTRS(data.ValueRO.matrix, out var oldTranslation, out var oldRotation, out var oldScale);
|
||||
data.ValueRW.matrix = MatrixUtility.CreateTRS(oldTranslation, e.NewValue.ToQuaternion(), oldScale);
|
||||
};
|
||||
|
||||
_scaleField.OnValueChanged += (s, e) =>
|
||||
{
|
||||
var data = componentObject.GetData<LocalToWorld>();
|
||||
MatrixUtility.GetTRS(data.ValueRO.matrix, out var oldTranslation, out var oldRotation, out var oldScale);
|
||||
data.ValueRW.matrix = MatrixUtility.CreateTRS(oldTranslation, oldRotation, e.NewValue);
|
||||
};
|
||||
|
||||
container.Children.Add(new PropertyField() { Label = "Position", Content = _translationField });
|
||||
container.Children.Add(new PropertyField() { Label = "Rotation", Content = _rotationField });
|
||||
container.Children.Add(new PropertyField() { Label = "Scale", Content = _scaleField });
|
||||
}
|
||||
|
||||
public void Update(ComponentObject componentObject)
|
||||
{
|
||||
var data = componentObject.GetData<LocalToWorld>();
|
||||
MatrixUtility.GetTRS(data.ValueRO.matrix, out var translation, out var rotation, out var scale);
|
||||
|
||||
if (_translationField.FocusState == Microsoft.UI.Xaml.FocusState.Unfocused)
|
||||
{
|
||||
_translationField.Value = translation;
|
||||
}
|
||||
|
||||
if (_rotationField.FocusState == Microsoft.UI.Xaml.FocusState.Unfocused)
|
||||
{
|
||||
_rotationField.Value = VectorUtility.CreateFromQuaternion(rotation);
|
||||
}
|
||||
|
||||
if (_scaleField.FocusState == Microsoft.UI.Xaml.FocusState.Unfocused)
|
||||
{
|
||||
_scaleField.Value = scale;
|
||||
}
|
||||
}
|
||||
|
||||
public void Destroy(ComponentObject componentObject)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Contracts;
|
||||
|
||||
public interface IInspectable
|
||||
{
|
||||
public IconSource? Icon
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public UIElement? HeaderContent();
|
||||
public UIElement? InspectorContent();
|
||||
}
|
||||
@@ -1,10 +1,30 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System.Reflection;
|
||||
using Windows.Globalization.NumberFormatting;
|
||||
|
||||
namespace Ghost.Editor.Controls;
|
||||
|
||||
public sealed partial class PropertyField : ContentControl
|
||||
{
|
||||
private static readonly Dictionary<Type, DependencyProperty> _valueProperties = new()
|
||||
{
|
||||
{ typeof(TextBox), TextBox.TextProperty },
|
||||
{ typeof(NumberBox), NumberBox.ValueProperty },
|
||||
{ typeof(ToggleButton), ToggleButton.IsCheckedProperty },
|
||||
{ typeof(ToggleSwitch), ToggleSwitch.IsOnProperty },
|
||||
{ typeof(ComboBox), Selector.SelectedValueProperty },
|
||||
{ typeof(RangeBase), RangeBase.ValueProperty },
|
||||
};
|
||||
|
||||
private object? sourceObject;
|
||||
private FieldInfo? propertyInfo;
|
||||
private Type? _fieldType;
|
||||
|
||||
private object? _lastValue;
|
||||
|
||||
public string Label
|
||||
{
|
||||
get => (string)GetValue(LabelProperty);
|
||||
@@ -21,4 +41,106 @@ public sealed partial class PropertyField : ContentControl
|
||||
{
|
||||
DefaultStyleKey = typeof(PropertyField);
|
||||
}
|
||||
|
||||
private static DependencyProperty? GetValueProperty(Type? fieldType)
|
||||
{
|
||||
while (fieldType != null)
|
||||
{
|
||||
if (_valueProperties.TryGetValue(fieldType, out var dp))
|
||||
{
|
||||
return dp;
|
||||
}
|
||||
fieldType = fieldType.BaseType;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TField ConfigureField<TField>(PropertyField propertyField, FieldInfo fieldInfo, object sourceObject, Func<TField> factory)
|
||||
where TField : FrameworkElement
|
||||
{
|
||||
propertyField.sourceObject = sourceObject;
|
||||
propertyField.propertyInfo = fieldInfo;
|
||||
propertyField._fieldType = typeof(TField);
|
||||
|
||||
var field = factory();
|
||||
|
||||
var dp = GetValueProperty(typeof(TField));
|
||||
field.SetBinding(dp, new Binding
|
||||
{
|
||||
Source = sourceObject,
|
||||
Path = new PropertyPath(fieldInfo.Name),
|
||||
Mode = BindingMode.TwoWay,
|
||||
});
|
||||
return field;
|
||||
}
|
||||
|
||||
public static PropertyField Create(string label, FieldInfo fieldInfo, object sourceObject)
|
||||
{
|
||||
var propertyField = new PropertyField
|
||||
{
|
||||
Label = label
|
||||
};
|
||||
|
||||
FrameworkElement content;
|
||||
switch (fieldInfo.FieldType)
|
||||
{
|
||||
case Type t when t == typeof(string):
|
||||
content = ConfigureField(propertyField, fieldInfo, sourceObject, () => new TextBox());
|
||||
break;
|
||||
case Type t when t == typeof(int) || t == typeof(float) || t == typeof(double):
|
||||
content = ConfigureField(propertyField, fieldInfo, sourceObject, () => new NumberBox
|
||||
{
|
||||
SpinButtonPlacementMode = NumberBoxSpinButtonPlacementMode.Hidden,
|
||||
AcceptsExpression = true,
|
||||
NumberFormatter = new DecimalFormatter
|
||||
{
|
||||
FractionDigits = t == typeof(int) ? 0 : 9,
|
||||
}
|
||||
});
|
||||
break;
|
||||
case Type t when t == typeof(bool):
|
||||
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),
|
||||
SelectedValuePath = "Value",
|
||||
});
|
||||
break;
|
||||
default:
|
||||
content = new TextBlock
|
||||
{
|
||||
Text = $"Unsupported type: {fieldInfo.FieldType.Name}",
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Foreground = new Microsoft.UI.Xaml.Media.SolidColorBrush(Microsoft.UI.Colors.Red)
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
propertyField.Content = content;
|
||||
return propertyField;
|
||||
}
|
||||
|
||||
public void UpdateValue()
|
||||
{
|
||||
if (sourceObject == null || propertyInfo == null || _fieldType == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var currentValue = propertyInfo.GetValue(sourceObject);
|
||||
if (Equals(currentValue, _lastValue))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dp = GetValueProperty(_fieldType);
|
||||
if (dp != null)
|
||||
{
|
||||
SetValue(dp, propertyInfo.GetValue(sourceObject));
|
||||
_lastValue = currentValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
96
Ghost.App/Controls/BasicInput/Vector3Field.cs
Normal file
96
Ghost.App/Controls/BasicInput/Vector3Field.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Ghost.Editor.Event;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ghost.Editor.Controls;
|
||||
|
||||
// TODO: value update event
|
||||
public sealed partial class Vector3Field : Control
|
||||
{
|
||||
private bool _suppressCallback;
|
||||
|
||||
public Vector3 Value
|
||||
{
|
||||
get => new((float)X, (float)Y, (float)Z);
|
||||
set
|
||||
{
|
||||
if (value == Value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_suppressCallback = true;
|
||||
|
||||
X = value.X;
|
||||
Y = value.Y;
|
||||
Z = value.Z;
|
||||
|
||||
_suppressCallback = false;
|
||||
}
|
||||
}
|
||||
|
||||
public double X
|
||||
{
|
||||
get => (double)GetValue(XProperty);
|
||||
set => SetValue(XProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty XProperty =
|
||||
DependencyProperty.Register(nameof(X), typeof(double), typeof(Vector3Field), new PropertyMetadata(0.0, ValueChanged));
|
||||
|
||||
public double Y
|
||||
{
|
||||
get => (double)GetValue(YProperty);
|
||||
set => SetValue(YProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty YProperty =
|
||||
DependencyProperty.Register(nameof(Y), typeof(double), typeof(Vector3Field), new PropertyMetadata(0.0, ValueChanged));
|
||||
|
||||
public double Z
|
||||
{
|
||||
get => (double)GetValue(ZProperty);
|
||||
set => SetValue(ZProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ZProperty =
|
||||
DependencyProperty.Register(nameof(Z), typeof(double), typeof(Vector3Field), new PropertyMetadata(0.0, ValueChanged));
|
||||
|
||||
public event ValueChangedEventHandler<Vector3>? OnValueChanged;
|
||||
|
||||
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is Vector3Field vector3Field)
|
||||
{
|
||||
if (vector3Field._suppressCallback)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var oldValue = vector3Field.Value;
|
||||
if (e.Property == XProperty)
|
||||
{
|
||||
var f = (float)(double)e.OldValue;
|
||||
oldValue.X = f;
|
||||
}
|
||||
else if (e.Property == YProperty)
|
||||
{
|
||||
var f = (float)(double)e.OldValue;
|
||||
oldValue.Y = f;
|
||||
}
|
||||
else if (e.Property == ZProperty)
|
||||
{
|
||||
var f = (float)(double)e.OldValue;
|
||||
oldValue.Z = f;
|
||||
}
|
||||
|
||||
vector3Field.OnValueChanged?.Invoke(vector3Field, new ValueChangedEventArgs<Vector3>(oldValue, vector3Field.Value));
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3Field()
|
||||
{
|
||||
DefaultStyleKey = typeof(Vector3Field);
|
||||
}
|
||||
}
|
||||
41
Ghost.App/Controls/BasicInput/Vector3Field.xaml
Normal file
41
Ghost.App/Controls/BasicInput/Vector3Field.xaml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.Editor.Controls">
|
||||
|
||||
<Style TargetType="local:Vector3Field">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:Vector3Field">
|
||||
<Grid ColumnSpacing="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="X" />
|
||||
<NumberBox Grid.Column="1" Value="{Binding X, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
|
||||
<TextBlock
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Text="Y" />
|
||||
<NumberBox Grid.Column="3" Value="{TemplateBinding Y}" />
|
||||
<TextBlock
|
||||
Grid.Column="4"
|
||||
VerticalAlignment="Center"
|
||||
Text="Z" />
|
||||
<NumberBox Grid.Column="5" Value="{TemplateBinding Z}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -2,6 +2,8 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Controls/BasicInput/PropertyField.xaml" />
|
||||
<ResourceDictionary Source="/Controls/BasicInput/Vector3Field.xaml" />
|
||||
|
||||
<ResourceDictionary Source="/Controls/Internal/InternalControls.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
||||
122
Ghost.App/Controls/Internal/ComponentDataView.cs
Normal file
122
Ghost.App/Controls/Internal/ComponentDataView.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
using Ghost.Editor.Resources;
|
||||
using Ghost.Editor.Utilities;
|
||||
using Ghost.Entities;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ghost.Editor.Controls.Internal;
|
||||
|
||||
internal unsafe sealed partial class ComponentDataView : Control
|
||||
{
|
||||
private StackPanel? _contentContainer;
|
||||
|
||||
private readonly World? _world;
|
||||
private readonly Entity _entity = Entity.Invalid;
|
||||
private readonly Type? _componentType;
|
||||
|
||||
private EventHandler<object>? _updateHandler;
|
||||
private IComponentEditor? _customEditor;
|
||||
private PropertyField[]? _propertyFields;
|
||||
|
||||
public string HeaderText
|
||||
{
|
||||
get => (string)GetValue(HeaderTextProperty);
|
||||
set => SetValue(HeaderTextProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty HeaderTextProperty =
|
||||
DependencyProperty.Register(nameof(HeaderText), typeof(string), typeof(ComponentDataView), new PropertyMetadata(string.Empty));
|
||||
|
||||
internal ComponentDataView()
|
||||
{
|
||||
DefaultStyleKey = typeof(ComponentDataView);
|
||||
|
||||
Unloaded += (s, e) =>
|
||||
{
|
||||
CompositionTarget.Rendering -= _updateHandler;
|
||||
_contentContainer = null;
|
||||
_customEditor = null;
|
||||
_propertyFields = null;
|
||||
};
|
||||
}
|
||||
|
||||
public ComponentDataView(string header, World world, Entity entity, Type componentType) : this()
|
||||
{
|
||||
HeaderText = header;
|
||||
_world = world;
|
||||
_entity = entity;
|
||||
_componentType = componentType;
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
_contentContainer = (StackPanel)GetTemplateChild("ContentContainer");
|
||||
|
||||
base.OnApplyTemplate();
|
||||
ReBuild();
|
||||
}
|
||||
|
||||
private void ReflectionUpdate(object? sender, object e)
|
||||
{
|
||||
if (_propertyFields == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var propertyField in _propertyFields)
|
||||
{
|
||||
propertyField.UpdateValue();
|
||||
}
|
||||
}
|
||||
|
||||
private void CustomEditorUpdate(object? sender, object e)
|
||||
{
|
||||
_customEditor!.Update(new ComponentObject(_world!, _entity));
|
||||
}
|
||||
|
||||
public void ReBuild()
|
||||
{
|
||||
if (_contentContainer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_contentContainer.Children.Clear();
|
||||
if (_world == null || _componentType == null || _entity == Entity.Invalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var componentObject = new ComponentObject(_world, _entity);
|
||||
var editorType = TypeCache.GetTypes().FirstOrDefault(t =>
|
||||
typeof(IComponentEditor).IsAssignableFrom(t) &&
|
||||
t.GetCustomAttribute<CustomEditorAttribute>()?.TargetType.IsAssignableFrom(_componentType) == true);
|
||||
|
||||
if (editorType != null)
|
||||
{
|
||||
_customEditor = (IComponentEditor)Activator.CreateInstance(editorType)!;
|
||||
_customEditor.Create(componentObject, _contentContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
var fields = _componentType.GetFields(StaticResource.componentPropertyBindingFlags);
|
||||
_propertyFields = new PropertyField[fields.Length];
|
||||
|
||||
for (var i = 0; i < fields.Length; i++)
|
||||
{
|
||||
var field = fields[i];
|
||||
var component = _world.ComponentStorage.ComponentPools[_componentType.TypeHandle.Value].Get(_entity);
|
||||
var propertyField = PropertyField.Create(field.Name, field, component);
|
||||
|
||||
_propertyFields[i] = propertyField;
|
||||
_contentContainer.Children.Add(propertyField);
|
||||
}
|
||||
}
|
||||
|
||||
_updateHandler = _customEditor == null ? ReflectionUpdate : CustomEditorUpdate;
|
||||
CompositionTarget.Rendering += _updateHandler;
|
||||
}
|
||||
}
|
||||
27
Ghost.App/Controls/Internal/ComponentDataView.xaml
Normal file
27
Ghost.App/Controls/Internal/ComponentDataView.xaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Ghost.Editor.Controls.Internal">
|
||||
|
||||
<Style TargetType="local:ComponentDataView">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:ComponentDataView">
|
||||
<StackPanel Margin="0,0,0,16">
|
||||
<Border
|
||||
Padding="8"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{ThemeResource SolidBackgroundFillColorSecondaryBrush}">
|
||||
<TextBlock Style="{StaticResource BodyStrongTextBlockStyle}" Text="{TemplateBinding HeaderText}" />
|
||||
</Border>
|
||||
<StackPanel
|
||||
x:Name="ContentContainer"
|
||||
Margin="8,2,2,0"
|
||||
Spacing="2" />
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<ResourceDictionary.MergedDictionaries />
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Controls/Internal/ComponentDataView.xaml" />
|
||||
<ResourceDictionary Source="/Controls/Internal/NavigationTabView.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
||||
29
Ghost.App/Core/Inspector/ComponentObject.cs
Normal file
29
Ghost.App/Core/Inspector/ComponentObject.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Ghost.Entities;
|
||||
using Ghost.Entities.Components;
|
||||
using Ghost.Entities.Query;
|
||||
|
||||
namespace Ghost.Editor.Core.Inspector;
|
||||
|
||||
public unsafe readonly struct ComponentObject
|
||||
{
|
||||
private readonly World _world;
|
||||
private readonly Entity _entity;
|
||||
|
||||
internal ComponentObject(World world, Entity entity)
|
||||
{
|
||||
_world = world;
|
||||
_entity = entity;
|
||||
}
|
||||
|
||||
public Ref<T> GetData<T>()
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
return _world.EntityManager.GetComponent<T>(_entity);
|
||||
}
|
||||
|
||||
public void SetData<T>(in T data)
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
_world.EntityManager.SetComponent(_entity, in data);
|
||||
}
|
||||
}
|
||||
10
Ghost.App/Core/Inspector/CustomEditorAttribute.cs
Normal file
10
Ghost.App/Core/Inspector/CustomEditorAttribute.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Ghost.Editor.Core.Inspector;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class CustomEditorAttribute(Type targetType) : Attribute
|
||||
{
|
||||
internal Type TargetType
|
||||
{
|
||||
get;
|
||||
} = targetType;
|
||||
}
|
||||
25
Ghost.App/Core/Inspector/IComponentEditor.cs
Normal file
25
Ghost.App/Core/Inspector/IComponentEditor.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Core.Inspector;
|
||||
|
||||
interface IComponentEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Called when the component editor is created.
|
||||
/// </summary>
|
||||
/// <param name="componentObject">The component data to edit.</param>
|
||||
/// <param name="container">The container to add the editor controls to.</param>
|
||||
public void Create(ComponentObject componentObject, StackPanel container);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the component editor needs to update its UI based on the current state of the component data.
|
||||
/// </summary>
|
||||
/// <param name="componentObject">The component data to edit.</param>
|
||||
public void Update(ComponentObject componentObject);
|
||||
|
||||
/// <summary>
|
||||
/// Called when the component editor is destroyed.
|
||||
/// </summary>
|
||||
/// <param name="componentObject">The component data to edit.</param>
|
||||
public void Destroy(ComponentObject componentObject);
|
||||
}
|
||||
22
Ghost.App/Core/Inspector/IInspectable.cs
Normal file
22
Ghost.App/Core/Inspector/IInspectable.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Ghost.Editor.Core.Inspector;
|
||||
|
||||
public interface IInspectable
|
||||
{
|
||||
public IconSource? Icon
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public UIElement? HeaderContent
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public UIElement? InspectorContent
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using Ghost.Editor.Resources;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
using Ghost.Engine.Resources;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Ghost.Editor.Core.SceneGraph;
|
||||
@@ -40,7 +39,7 @@ public static class EditorWorldManager
|
||||
}
|
||||
|
||||
await using var readStream = new FileStream(worldPath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
var deserializedScene = await JsonSerializer.DeserializeAsync<WorldNode>(readStream, StaticResource.defaultSerializerOptions) ?? throw new Exception("Deserialization failed.");
|
||||
var deserializedScene = await JsonSerializer.DeserializeAsync<WorldNode>(readStream, Engine.Resources.StaticResource.defaultSerializerOptions) ?? throw new Exception("Deserialization failed.");
|
||||
|
||||
_loadedWorlds.Clear();
|
||||
|
||||
|
||||
@@ -1,70 +1,102 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Controls.Internal;
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
using Ghost.Editor.Resources;
|
||||
using Ghost.Engine.Editor;
|
||||
using Ghost.Entities;
|
||||
using Microsoft.UI.Text;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ghost.Editor.Core.SceneGraph;
|
||||
|
||||
public partial class EntityNode : SceneGraphNode
|
||||
{
|
||||
private WorldNode _owner;
|
||||
private readonly Entity _entity;
|
||||
|
||||
public Entity Entity => _entity;
|
||||
public override SceneGraphNodeType NodeType => SceneGraphNodeType.Entity;
|
||||
|
||||
public EntityNode(Entity entity, string name)
|
||||
public EntityNode(WorldNode owner, Entity entity, string name)
|
||||
{
|
||||
_owner = owner;
|
||||
_entity = entity;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
internal EntityNode()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public partial class EntityNode : IInspectable
|
||||
{
|
||||
public IconSource? Icon => EditorIconSource.entity_24;
|
||||
|
||||
public UIElement? HeaderContent()
|
||||
public UIElement? HeaderContent
|
||||
{
|
||||
var root = new StackPanel()
|
||||
get
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
var root = new StackPanel()
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
|
||||
var nameText = new TextBox
|
||||
{
|
||||
Text = Name,
|
||||
FontWeight = FontWeights.Bold,
|
||||
};
|
||||
var idText = new TextBlock
|
||||
{
|
||||
Text = $"ID: {_entity.ID}",
|
||||
Margin = new Thickness(0, 5, 0, 0),
|
||||
};
|
||||
var nameText = new TextBox
|
||||
{
|
||||
Text = Name,
|
||||
FontWeight = FontWeights.Bold,
|
||||
};
|
||||
var idText = new TextBlock
|
||||
{
|
||||
Text = $"ID: {_entity.ID} Generation: {_entity.Generation}",
|
||||
Margin = new Thickness(5, 7, 0, 0),
|
||||
Opacity = 0.75,
|
||||
Style = Application.Current.Resources["CaptionTextBlockStyle"] as Style
|
||||
};
|
||||
|
||||
nameText.SetBinding(TextBox.TextProperty, new Binding
|
||||
{
|
||||
Source = this,
|
||||
Path = new PropertyPath(nameof(Name)),
|
||||
Mode = BindingMode.TwoWay,
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.LostFocus,
|
||||
});
|
||||
nameText.SetBinding(TextBox.TextProperty, new Binding
|
||||
{
|
||||
Source = this,
|
||||
Path = new PropertyPath(nameof(Name)),
|
||||
Mode = BindingMode.TwoWay,
|
||||
UpdateSourceTrigger = UpdateSourceTrigger.LostFocus,
|
||||
});
|
||||
|
||||
root.Children.Add(nameText);
|
||||
root.Children.Add(idText);
|
||||
root.Children.Add(nameText);
|
||||
root.Children.Add(idText);
|
||||
|
||||
return root;
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
public UIElement? InspectorContent()
|
||||
public UIElement? InspectorContent
|
||||
{
|
||||
return null;
|
||||
get
|
||||
{
|
||||
var root = new StackPanel()
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Top
|
||||
};
|
||||
|
||||
foreach (var (typeHandle, componentPtr) in _owner.World.EntityManager.GetComponentsUnsafe(_entity))
|
||||
{
|
||||
if (componentPtr == IntPtr.Zero)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var type = Type.GetTypeFromHandle(RuntimeTypeHandle.FromIntPtr(typeHandle));
|
||||
if (type == null || type.GetCustomAttribute<HideEditorAttribute>() != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var dataView = new ComponentDataView(type.Name, _owner.World, _entity, type);
|
||||
root.Children.Add(dataView);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,21 +10,21 @@ public class SceneGraphHelpers
|
||||
/// </summary>
|
||||
/// <param name="world">The world context where the entity will be created.</param>
|
||||
/// <param name="entity">The entity to be wrapped in the <see cref="EntityNode"/>.</param>
|
||||
public static EntityNode CreateEntityNode(World world, Entity entity, string name)
|
||||
public static EntityNode CreateEntityNode(WorldNode owner, Entity entity, string name)
|
||||
{
|
||||
world.EntityManager.AddComponent(entity, LocalToWorld.Identity);
|
||||
world.EntityManager.AddComponent(entity, Hierarchy.Root);
|
||||
return new EntityNode(entity, name);
|
||||
owner.World.EntityManager.AddComponent(entity, LocalToWorld.Identity);
|
||||
owner.World.EntityManager.AddComponent(entity, Hierarchy.Root);
|
||||
return new EntityNode(owner, entity, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="Entity"/> and <see cref="EntityNode"/> entity with default components.
|
||||
/// </summary>
|
||||
/// <param name="world">The world context where the entity will be created.</param>
|
||||
public static EntityNode CreateEntityNode(World world, string name)
|
||||
/// <param name="owner">The world context where the entity will be created.</param>
|
||||
public static EntityNode CreateEntityNode(WorldNode owner, string name)
|
||||
{
|
||||
var entity = world.EntityManager.CreateEntity();
|
||||
return CreateEntityNode(world, entity, name);
|
||||
var entity = owner.World.EntityManager.CreateEntity();
|
||||
return CreateEntityNode(owner, entity, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Core.AssetHandle;
|
||||
using Ghost.Editor.Core.AssetHandle;
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
using Ghost.Editor.Core.Serializer;
|
||||
using Ghost.Editor.Resources;
|
||||
using Ghost.Engine.Components;
|
||||
@@ -76,21 +76,21 @@ public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
|
||||
return result;
|
||||
}
|
||||
|
||||
private EntityNode BuildNodeRecursive(Entity entity, World world)
|
||||
private EntityNode BuildNodeRecursive(Entity entity)
|
||||
{
|
||||
if (!_entityNodeLookup.TryGetValue(entity, out var node))
|
||||
{
|
||||
node = new EntityNode(entity, "New Entity");
|
||||
node = new EntityNode(this, entity, "New Entity");
|
||||
_entityNodeLookup[entity] = node;
|
||||
}
|
||||
|
||||
var hc = world.EntityManager.GetComponent<Hierarchy>(entity);
|
||||
var hc = _world.EntityManager.GetComponent<Hierarchy>(entity);
|
||||
var child = hc.ValueRO.firstChild;
|
||||
|
||||
while (child != Entity.Invalid)
|
||||
{
|
||||
node.AddChild(BuildNodeRecursive(child, world));
|
||||
var childHC = world.EntityManager.GetComponent<Hierarchy>(child);
|
||||
node.AddChild(BuildNodeRecursive(child));
|
||||
var childHC = _world.EntityManager.GetComponent<Hierarchy>(child);
|
||||
child = childHC.ValueRO.nextSibling;
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ public partial class WorldNode : SceneGraphNode, IEquatable<WorldNode>
|
||||
{
|
||||
if (hierarchy.ValueRO.parent == Entity.Invalid)
|
||||
{
|
||||
var node = BuildNodeRecursive(entity, _world);
|
||||
var node = BuildNodeRecursive(entity);
|
||||
AddChild(node);
|
||||
}
|
||||
}
|
||||
@@ -178,18 +178,7 @@ public partial class WorldNode : IInspectable
|
||||
await EditorWorldManager.LoadWorld(path);
|
||||
}
|
||||
|
||||
public UIElement? HeaderContent()
|
||||
{
|
||||
return new TextBlock
|
||||
{
|
||||
Text = Name,
|
||||
Style = Application.Current.Resources["SubtitleTextBlockStyle"] as Style,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
}
|
||||
public UIElement? HeaderContent => null;
|
||||
|
||||
public UIElement? InspectorContent()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public UIElement? InspectorContent => null;
|
||||
}
|
||||
@@ -39,7 +39,7 @@ internal class WorldNodeSerializer : JsonConverter<WorldNode>
|
||||
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(entity, entityName);
|
||||
var node = new EntityNode(result, entity, entityName);
|
||||
|
||||
world.EntityManager.AddEntityInternal(entity);
|
||||
result.EntityNodeLookup[entity] = node;
|
||||
|
||||
22
Ghost.App/Event/ValueChangedEventHandler.cs
Normal file
22
Ghost.App/Event/ValueChangedEventHandler.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Ghost.Editor.Event;
|
||||
|
||||
public delegate void ValueChangedEventHandler<T>(object? sender, ValueChangedEventArgs<T> args);
|
||||
|
||||
public class ValueChangedEventArgs<T> : EventArgs
|
||||
{
|
||||
public T OldValue
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public T NewValue
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ValueChangedEventArgs(T oldValue, T newValue)
|
||||
{
|
||||
OldValue = oldValue;
|
||||
NewValue = newValue;
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,9 @@
|
||||
<None Remove="Assets\Icon.targetsize-48.png" />
|
||||
<None Remove="Assets\Icon.targetsize-48_altform-unplated.png" />
|
||||
<None Remove="Controls\BasicInput\PropertyField.xaml" />
|
||||
<None Remove="Controls\BasicInput\Vector3Field.xaml" />
|
||||
<None Remove="Controls\EditorControls.xaml" />
|
||||
<None Remove="Controls\Internal\ComponentDataView.xaml" />
|
||||
<None Remove="Controls\Internal\InternalControls.xaml" />
|
||||
<None Remove="Controls\Internal\NavigationTabView.xaml" />
|
||||
<None Remove="View\Pages\EngineEditor\ConsolePage.xaml" />
|
||||
@@ -159,6 +161,16 @@
|
||||
<ItemGroup>
|
||||
<Folder Include="Controls\Layout\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\BasicInput\Vector3Field.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\Internal\ComponentDataView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Controls\Internal\NavigationTabView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
8
Ghost.App/Resources/StaticResource.cs
Normal file
8
Ghost.App/Resources/StaticResource.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ghost.Editor.Resources;
|
||||
|
||||
internal static class StaticResource
|
||||
{
|
||||
public static readonly BindingFlags componentPropertyBindingFlags = BindingFlags.Public | BindingFlags.Instance;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
|
||||
namespace Ghost.Editor.Services.Contracts;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
|
||||
namespace Ghost.Editor.Services;
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
<StaticResource x:Key="TabViewItemHeaderBackgroundSelected" ResourceKey="ControlFillColorSecondaryBrush" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
|
||||
<Style TargetType="internal:NavigationTabView">
|
||||
<Setter Property="TabWidthMode" Value="Compact" />
|
||||
</Style>
|
||||
<Style TargetType="NumberBox" />
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,27 @@
|
||||
using Ghost.Engine.Utilities;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Ghost.Editor.Utilities.Converters;
|
||||
|
||||
public partial class Vector3ToQuaternionConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is Vector3 vector)
|
||||
{
|
||||
return Quaternion.CreateFromYawPitchRoll(vector.Y, vector.X, vector.Z);
|
||||
}
|
||||
|
||||
throw new ArgumentException("Value must be of type System.Numerics.Vector3.", nameof(value));
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is Quaternion quaternion)
|
||||
{
|
||||
return VectorUtility.CreateFromQuaternion(quaternion);
|
||||
}
|
||||
throw new ArgumentException("Value must be of type System.Numerics.Quaternion.", nameof(value));
|
||||
}
|
||||
}
|
||||
46
Ghost.App/Utilities/ReflectionBinding.cs
Normal file
46
Ghost.App/Utilities/ReflectionBinding.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ghost.Editor.Utilities;
|
||||
|
||||
public class ReflectionBinding
|
||||
{
|
||||
private void RefreshField(FieldInfo field, FrameworkElement control, object source)
|
||||
{
|
||||
var value = field.GetValue(source);
|
||||
|
||||
switch (control)
|
||||
{
|
||||
case TextBox tb:
|
||||
tb.Text = value?.ToString();
|
||||
break;
|
||||
case NumberBox nb when value is double d:
|
||||
nb.Value = d;
|
||||
break;
|
||||
// Add more controls...
|
||||
}
|
||||
}
|
||||
|
||||
public void StartPollingField(FieldInfo field, FrameworkElement control, object component)
|
||||
{
|
||||
var lastValue = field.GetValue(component);
|
||||
|
||||
DispatcherTimer timer = new()
|
||||
{
|
||||
Interval = TimeSpan.FromMilliseconds(200)
|
||||
};
|
||||
|
||||
timer.Tick += (_, _) =>
|
||||
{
|
||||
var currentValue = field.GetValue(component);
|
||||
if (!Equals(currentValue, lastValue))
|
||||
{
|
||||
RefreshField(field, control, component);
|
||||
lastValue = currentValue;
|
||||
}
|
||||
};
|
||||
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,25 @@
|
||||
using Ghost.Entities;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Ghost.Editor.Utilities;
|
||||
|
||||
public static class TypeCache
|
||||
{
|
||||
private static readonly TypeInfo[] _types;
|
||||
|
||||
static TypeCache()
|
||||
{
|
||||
_types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(assembly => assembly.DefinedTypes)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static Type[] GetTypes()
|
||||
{
|
||||
return _types;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ComponentTypeCache
|
||||
{
|
||||
private static readonly Type?[][] _componentTypes;
|
||||
@@ -13,22 +13,22 @@
|
||||
<internal:NavigationTabPage.Resources>
|
||||
<DataTemplate x:Key="SceneTemplate" x:DataType="sg:SceneGraphNode">
|
||||
<TreeViewItem
|
||||
AutomationProperties.Name="{x:Bind Name}"
|
||||
AutomationProperties.Name="{x:Bind Name, Mode=OneWay}"
|
||||
Background="{ThemeResource ControlSolidFillColorDefaultBrush}"
|
||||
IsExpanded="True"
|
||||
ItemsSource="{x:Bind Children}">
|
||||
ItemsSource="{x:Bind Children, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<FontIcon FontSize="14" Glyph="" />
|
||||
<TextBlock Margin="10,0" Text="{x:Bind Name}" />
|
||||
<TextBlock Margin="10,0" Text="{x:Bind Name, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="EntityTemplate" x:DataType="sg:SceneGraphNode">
|
||||
<TreeViewItem AutomationProperties.Name="{x:Bind Name}" ItemsSource="{x:Bind Children}">
|
||||
<TreeViewItem AutomationProperties.Name="{x:Bind Name, Mode=OneWay}" ItemsSource="{x:Bind Children, Mode=OneWay}">
|
||||
<StackPanel Margin="10,0" Orientation="Horizontal">
|
||||
<FontIcon FontSize="14" Glyph="" />
|
||||
<TextBlock Margin="5,0,0,0" Text="{x:Bind Name}" />
|
||||
<TextBlock Margin="5,0,0,0" Text="{x:Bind Name, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</TreeViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Controls.Internal;
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
using Ghost.Editor.Core.SceneGraph;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
using Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
IconSource="{x:Bind ViewModel.Inspectable.Icon, Mode=OneWay}" />
|
||||
<ContentPresenter Grid.Column="1" Content="{x:Bind ViewModel.Inspectable.HeaderContent(), Mode=OneWay}" />
|
||||
<ContentPresenter Grid.Column="1" Content="{x:Bind ViewModel.Inspectable.HeaderContent, Mode=OneWay}" />
|
||||
</Grid>
|
||||
|
||||
<!-- Content -->
|
||||
<Grid Grid.Row="1" Padding="10,0,10,0">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<ContentPresenter Content="{x:Bind ViewModel.Inspectable.InspectorContent(), Mode=OneWay}" />
|
||||
<Grid Grid.Row="1" Padding="0,0,0,0">
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<ContentPresenter Content="{x:Bind ViewModel.Inspectable.InspectorContent, Mode=OneWay}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ghost.Editor.Contracts;
|
||||
using Ghost.Editor.Core.Inspector;
|
||||
using Ghost.Editor.Services.Contracts;
|
||||
|
||||
namespace Ghost.Editor.ViewModels.Pages.EngineEditor;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using Ghost.Entities;
|
||||
using Ghost.Engine.Editor;
|
||||
using Ghost.Entities;
|
||||
using Ghost.Entities.Components;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Engine.Components;
|
||||
|
||||
[SkipLocalsInit]
|
||||
[HideEditor]
|
||||
public struct Hierarchy : IComponentData
|
||||
{
|
||||
public Entity parent;
|
||||
|
||||
@@ -15,7 +15,7 @@ public struct LocalToWorld : IComponentData
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => new()
|
||||
{
|
||||
matrix = MatrixUtilities.CreateTRS(Vector3.Zero, Quaternion.Identity, Vector3.One)
|
||||
matrix = MatrixUtility.CreateTRS(Vector3.Zero, Quaternion.Identity, Vector3.One)
|
||||
};
|
||||
}
|
||||
}
|
||||
6
Ghost.Engine/Editor/HideEditorAttribute.cs
Normal file
6
Ghost.Engine/Editor/HideEditorAttribute.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Ghost.Engine.Editor;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
|
||||
public class HideEditorAttribute : Attribute
|
||||
{
|
||||
}
|
||||
@@ -4,7 +4,7 @@ namespace Ghost.Engine.Resources;
|
||||
|
||||
public static class StaticResource
|
||||
{
|
||||
public static JsonSerializerOptions defaultSerializerOptions = new()
|
||||
public static readonly JsonSerializerOptions defaultSerializerOptions = new()
|
||||
{
|
||||
WriteIndented = true,
|
||||
IncludeFields = true,
|
||||
|
||||
31
Ghost.Engine/Utilities/MathUtility.cs
Normal file
31
Ghost.Engine/Utilities/MathUtility.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Engine.Utilities;
|
||||
|
||||
public static class MathUtility
|
||||
{
|
||||
public const float RAD_TO_DEG = 180f / MathF.PI;
|
||||
public const float DEG_TO_RAD = MathF.PI / 180f;
|
||||
|
||||
/// <summary>
|
||||
/// Converts radians to degrees.
|
||||
/// </summary>
|
||||
/// <param name="radians">The angle in radians to convert.</param>
|
||||
/// <returns>The angle in degrees.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float RadToDeg(float radians)
|
||||
{
|
||||
return radians * RAD_TO_DEG;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts degrees to radians.
|
||||
/// </summary>
|
||||
/// <param name="degrees">The angle in degrees to convert.</param>
|
||||
/// <returns>The angle in radians.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static float DegToRad(float degrees)
|
||||
{
|
||||
return degrees * DEG_TO_RAD;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Engine.Utilities;
|
||||
|
||||
public static class MatrixUtilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a transformation matrix from position, rotation, and scale vectors.
|
||||
/// </summary>
|
||||
/// <param name="position">Defines the translation component of the transformation matrix.</param>
|
||||
/// <param name="rotation">Specifies the orientation of the object in 3D space.</param>
|
||||
/// <param name="scale">Determines the size of the object along each axis.</param>
|
||||
/// <returns>Returns a transformation matrix that combines the specified position, rotation, and scale.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix4x4 CreateTRS(Vector3 position, Quaternion rotation, Vector3 scale)
|
||||
{
|
||||
return Matrix4x4.CreateScale(scale) * Matrix4x4.CreateFromQuaternion(rotation) * Matrix4x4.CreateTranslation(position);
|
||||
}
|
||||
}
|
||||
49
Ghost.Engine/Utilities/MatrixUtility.cs
Normal file
49
Ghost.Engine/Utilities/MatrixUtility.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Engine.Utilities;
|
||||
|
||||
public static class MatrixUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a transformation matrix from position, rotation, and scale vectors.
|
||||
/// </summary>
|
||||
/// <param name="position">Defines the translation component of the transformation matrix.</param>
|
||||
/// <param name="rotation">Specifies the orientation of the object in 3D space.</param>
|
||||
/// <param name="scale">Determines the size of the object along each axis.</param>
|
||||
/// <returns>Returns a transformation matrix that combines the specified position, rotation, and scale.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Matrix4x4 CreateTRS(Vector3 position, Quaternion rotation, Vector3 scale)
|
||||
{
|
||||
return Matrix4x4.CreateScale(scale) * Matrix4x4.CreateFromQuaternion(rotation) * Matrix4x4.CreateTranslation(position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decomposes a transformation matrix into its position, rotation, and scale components.
|
||||
/// </summary>
|
||||
/// <remarks>This method assumes the input matrix represents a valid affine transformation, including
|
||||
/// translation, rotation, and scaling. If the matrix contains skew or other non-standard transformations, the
|
||||
/// results may be undefined.</remarks>
|
||||
/// <param name="matrix">The <see cref="Matrix4x4"/> to decompose. Must represent a valid transformation matrix.</param>
|
||||
/// <param name="position">When the method returns, contains the position component extracted from the matrix.</param>
|
||||
/// <param name="rotation">When the method returns, contains the rotation component extracted from the matrix as a <see
|
||||
/// cref="Quaternion"/>.</param>
|
||||
/// <param name="scale">When the method returns, contains the scale component extracted from the matrix.</param>
|
||||
public static void GetTRS(Matrix4x4 matrix, out Vector3 position, out Quaternion rotation, out Vector3 scale)
|
||||
{
|
||||
position = new(matrix.M41, matrix.M42, matrix.M43);
|
||||
|
||||
var scaleX = new Vector3(matrix.M11, matrix.M12, matrix.M13).Length();
|
||||
var scaleY = new Vector3(matrix.M21, matrix.M22, matrix.M23).Length();
|
||||
var scaleZ = new Vector3(matrix.M31, matrix.M32, matrix.M33).Length();
|
||||
scale = new(scaleX, scaleY, scaleZ);
|
||||
|
||||
Matrix4x4 rotationMatrix = new(
|
||||
matrix.M11 / scale.X, matrix.M12 / scale.X, matrix.M13 / scale.X, 0,
|
||||
matrix.M21 / scale.Y, matrix.M22 / scale.Y, matrix.M23 / scale.Y, 0,
|
||||
matrix.M31 / scale.Z, matrix.M32 / scale.Z, matrix.M33 / scale.Z, 0,
|
||||
0, 0, 0, 1);
|
||||
|
||||
rotation = Quaternion.CreateFromRotationMatrix(rotationMatrix);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Ghost.Engine.Utilities;
|
||||
|
||||
public static class Utf8JsonWriterExtensions
|
||||
public static class Utf8JsonWriterExtension
|
||||
{
|
||||
public static void WriteArray<T>(this Utf8JsonWriter writer, ReadOnlySpan<char> name, IEnumerable<T> source, Action<T> writeAction)
|
||||
{
|
||||
45
Ghost.Engine/Utilities/VectorUtility.cs
Normal file
45
Ghost.Engine/Utilities/VectorUtility.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ghost.Engine.Utilities;
|
||||
|
||||
public static class VectorUtility
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a Vector3 representing Euler angles (in degrees) to a Quaternion.
|
||||
/// </summary>
|
||||
/// <param name="v">The Vector3 containing Euler angles (X: Pitch, Y: Yaw, Z: Roll) in degrees.</param>
|
||||
/// <returns>A Quaternion representing the rotation defined by the Euler angles.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Quaternion ToQuaternion(this Vector3 v)
|
||||
{
|
||||
return Quaternion.CreateFromYawPitchRoll(MathUtility.DegToRad(v.Y), MathUtility.DegToRad(v.X), MathUtility.DegToRad(v.Z));
|
||||
}
|
||||
|
||||
public static Vector3 CreateFromQuaternion(Quaternion quaternion)
|
||||
{
|
||||
// Convert quaternion to Euler angles (Yaw, Pitch, Roll)
|
||||
quaternion = Quaternion.Normalize(quaternion);
|
||||
|
||||
// Extract pitch (X), yaw (Y), roll (Z)
|
||||
var ysqr = quaternion.Y * quaternion.Y;
|
||||
|
||||
// Pitch (X-axis rotation)
|
||||
var t0 = +2.0 * (quaternion.W * quaternion.X + quaternion.Y * quaternion.Z);
|
||||
var t1 = +1.0 - 2.0 * (quaternion.X * quaternion.X + ysqr);
|
||||
var pitch = Math.Atan2(t0, t1);
|
||||
|
||||
// Yaw (Y-axis rotation)
|
||||
var t2 = +2.0 * (quaternion.W * quaternion.Y - quaternion.Z * quaternion.X);
|
||||
t2 = Math.Clamp(t2, -1.0, 1.0);
|
||||
var yaw = Math.Asin(t2);
|
||||
|
||||
// Roll (Z-axis rotation)
|
||||
var t3 = +2.0 * (quaternion.W * quaternion.Z + quaternion.X * quaternion.Y);
|
||||
var t4 = +1.0 - 2.0 * (ysqr + quaternion.Z * quaternion.Z);
|
||||
var roll = Math.Atan2(t3, t4);
|
||||
|
||||
const float radToDeg = 180f / MathF.PI;
|
||||
return new Vector3((float)pitch, (float)yaw, (float)roll) * radToDeg;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@
|
||||
using Misaki.HighPerformance.Unsafe.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ghost.Entities.Components;
|
||||
|
||||
internal static class SingletonContainer<T>
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
public static readonly Dictionary<int, T> container = new();
|
||||
}
|
||||
@@ -22,6 +23,7 @@ internal interface IComponentPool : IDisposable
|
||||
public bool Remove(Entity entity);
|
||||
public bool Has(Entity entity);
|
||||
public IComponentData Get(Entity entity);
|
||||
public IntPtr GetUnsafe(Entity entity);
|
||||
public void Set(Entity entity, in IComponentData component);
|
||||
|
||||
public IEnumerable<(Entity entity, IComponentData component)> Enumerate();
|
||||
@@ -35,7 +37,7 @@ internal interface IComponentPool<T> : IComponentPool
|
||||
}
|
||||
|
||||
internal class ComponentPool<T> : IComponentPool<T>
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
private struct ComponentData
|
||||
{
|
||||
@@ -142,6 +144,11 @@ internal class ComponentPool<T> : IComponentPool<T>
|
||||
return GetRef(entity);
|
||||
}
|
||||
|
||||
public unsafe IntPtr GetUnsafe(Entity entity)
|
||||
{
|
||||
return (IntPtr)Unsafe.AsPointer(ref GetRef(entity));
|
||||
}
|
||||
|
||||
public ref T GetRef(Entity entity)
|
||||
{
|
||||
if (!entity.IsValid)
|
||||
@@ -341,7 +348,29 @@ internal class ScriptComponentPool : IComponentPool<ScriptComponent>
|
||||
[Obsolete("Use GetAll instead of Get for ScriptComponentPool.")]
|
||||
public IComponentData Get(Entity entity)
|
||||
{
|
||||
throw new NotSupportedException("Use GetAll instead of Get for ScriptComponentPool.");
|
||||
if (!Has(entity)
|
||||
|| !_scriptComponents!.TryGetValue(entity, out var scriptList)
|
||||
|| scriptList == null
|
||||
|| scriptList.Count == 0)
|
||||
{
|
||||
return null!;
|
||||
}
|
||||
|
||||
return scriptList[0];
|
||||
}
|
||||
|
||||
[Obsolete("Use GetAll instead of GetUnsafe for ScriptComponentPool.")]
|
||||
public unsafe IntPtr GetUnsafe(Entity entity)
|
||||
{
|
||||
if (!Has(entity)
|
||||
|| !_scriptComponents!.TryGetValue(entity, out var scriptList)
|
||||
|| scriptList == null
|
||||
|| scriptList.Count == 0)
|
||||
{
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
return (IntPtr)Unsafe.AsPointer(ref CollectionsMarshal.AsSpan(scriptList)[0]);
|
||||
}
|
||||
|
||||
public void Set(Entity entity, in IComponentData component)
|
||||
@@ -385,12 +414,12 @@ internal class ScriptComponentPool : IComponentPool<ScriptComponent>
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IComponentData> GetAll(Entity entity)
|
||||
public IReadOnlyList<IComponentData>? GetAll(Entity entity)
|
||||
{
|
||||
if (_scriptComponents == null
|
||||
|| !_scriptComponents.TryGetValue(entity, out var scriptList))
|
||||
{
|
||||
return Enumerable.Empty<ScriptComponent>();
|
||||
return null;
|
||||
}
|
||||
|
||||
return scriptList;
|
||||
@@ -463,7 +492,7 @@ internal readonly struct ComponentStorage : IDisposable
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGetPool<T>([MaybeNullWhen(false)] out ComponentPool<T> pool)
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
var result = TryGetPool(TypeHandle.Get<T>(), out var obj);
|
||||
pool = (ComponentPool<T>?)obj ?? default;
|
||||
@@ -471,7 +500,7 @@ internal readonly struct ComponentStorage : IDisposable
|
||||
}
|
||||
|
||||
public ComponentPool<T> GetOrCreateComponentPool<T>()
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
var key = TypeHandle.Get<T>();
|
||||
if (!_componentPools.TryGetValue(key, out var obj))
|
||||
@@ -498,7 +527,7 @@ internal readonly struct ComponentStorage : IDisposable
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGetMask<T>([MaybeNullWhen(false)] out BitSet bitSet)
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
return TryGetMask(TypeHandle.Get<T>(), out bitSet);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ public readonly struct EntityManager : IDisposable
|
||||
/// <param name="component">The component value to add.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly void AddComponent<T>(Entity entity, T component)
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
_world.ComponentStorage.GetOrCreateComponentPool<T>().Add(entity, component);
|
||||
_world.ComponentStorage.GetOrCreateMask(TypeHandle.Get<T>()).SetBit(entity.ID);
|
||||
@@ -121,7 +121,7 @@ public readonly struct EntityManager : IDisposable
|
||||
/// <param name="entity">The entity for which the component is to be remove.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly bool RemoveComponent<T>(Entity entity)
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
if (!_world.ComponentStorage.TryGetPool<T>(out var pool) || !pool.Has(entity))
|
||||
{
|
||||
@@ -138,6 +138,29 @@ public readonly struct EntityManager : IDisposable
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a component of the specified type for the given <see cref="Entity"/>.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity for which the component is to be set.</param>
|
||||
/// <param name="component">The component value to set.</param>
|
||||
/// <param name="type">The type of the component to set.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly void SetComponent(Entity entity, IComponentData component, Type type)
|
||||
{
|
||||
var typeHandle = TypeHandle.Get(type);
|
||||
if (!_world.ComponentStorage.TryGetPool(typeHandle, out var pool))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pool.Has(entity))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pool.Set(entity, component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a component of type <typeparamref name="T"/> for the given <see cref="Entity"/>.
|
||||
/// </summary>
|
||||
@@ -146,7 +169,7 @@ public readonly struct EntityManager : IDisposable
|
||||
/// <param name="component">The component value to set.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly void SetComponent<T>(Entity entity, in T component)
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
_world.ComponentStorage.GetOrCreateComponentPool<T>().Set(entity, in component);
|
||||
}
|
||||
@@ -171,7 +194,7 @@ public readonly struct EntityManager : IDisposable
|
||||
/// <returns>A <see cref="Ref{T}"/> to the component, or a null reference if the component does not exist.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly Ref<T> GetComponent<T>(Entity entity)
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
if (_world.ComponentStorage.TryGetPool<T>(out var pool) && pool.Has(entity))
|
||||
{
|
||||
@@ -183,6 +206,49 @@ public readonly struct EntityManager : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves all components associated with the specified entity.
|
||||
/// </summary>
|
||||
/// <remarks>This method iterates through all available component pools to find components associated
|
||||
/// with the given entity. It is designed to lazily yield components, making it efficient for scenarios where only
|
||||
/// a subset of components may be needed.</remarks>
|
||||
/// <param name="entity">The entity for which components are to be retrieved.</param>
|
||||
/// <returns>An enumerable collection of components associated with the specified entity. If the entity has no components,
|
||||
/// the collection will be empty.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly IEnumerable<IComponentData> GetComponents(Entity entity)
|
||||
{
|
||||
foreach (var pool in _world.ComponentStorage.ComponentPools.Values)
|
||||
{
|
||||
if (pool.Has(entity))
|
||||
{
|
||||
yield return pool.Get(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an enumerable collection of raw pointers to the components associated with the specified entity.
|
||||
/// </summary>
|
||||
/// <remarks>This method provides direct access to the memory locations of components, bypassing type
|
||||
/// safety. Use with caution, as improper handling of raw pointers can lead to undefined behavior or memory
|
||||
/// corruption. Ensure that the entity is valid and exists within the current world context before calling this
|
||||
/// method.</remarks>
|
||||
/// <param name="entity">The entity whose components are to be retrieved.</param>
|
||||
/// <returns>An enumerable collection of <see cref="IntPtr"/> representing the memory addresses of the components associated
|
||||
/// with the specified entity. The collection will be empty if the entity has no associated components.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public readonly IEnumerable<(IntPtr, IntPtr)> GetComponentsUnsafe(Entity entity)
|
||||
{
|
||||
foreach (var (typeHandle, pool) in _world.ComponentStorage.ComponentPools)
|
||||
{
|
||||
if (pool.Has(entity))
|
||||
{
|
||||
yield return (typeHandle, pool.GetUnsafe(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a script of type <typeparamref name="T"/> to the given <see cref="Entity"/>.
|
||||
/// </summary>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,7 @@ namespace Ghost.Entities;
|
||||
|
||||
<# for (int arity = 1; arity <= Amount; arity++) {
|
||||
var generics = AppendGenerics(arity);
|
||||
var restrictions = AppendGenericRestrictions(arity, "struct, IComponentData");
|
||||
var restrictions = AppendGenericRestrictions(arity, "unmanaged, IComponentData");
|
||||
var poolParams = Enumerable.Range(0, arity)
|
||||
.Select(i => $"ComponentPool<T{i}> pool{i}")
|
||||
.Aggregate((a, b) => a + ", " + b);
|
||||
@@ -105,7 +105,7 @@ public struct QueryEnumerable<<#= generics #>>
|
||||
}
|
||||
<# for (int i = 1; i <= ExtensionAmount; i++) {
|
||||
var compGenerics = AppendGenerics(i, "TComponent");
|
||||
var compRestrictions = AppendGenericRestrictions(i, "TComponent", "struct, IComponentData");
|
||||
var compRestrictions = AppendGenericRestrictions(i, "TComponent", "unmanaged, IComponentData");
|
||||
#>
|
||||
|
||||
public readonly QueryEnumerable<<#= generics #>> WithAll<<#= compGenerics #>>()
|
||||
|
||||
@@ -6,7 +6,7 @@ using Ghost.Entities.Query;
|
||||
namespace Ghost.Entities;
|
||||
|
||||
public readonly struct QueryItem<T0>
|
||||
where T0 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
private readonly ComponentPool<T0> _pool0;
|
||||
@@ -25,12 +25,12 @@ public readonly struct QueryItem<T0>
|
||||
public void Deconstruct(out Entity entity, out Ref<T0> c0)
|
||||
{
|
||||
entity = _entity;
|
||||
c0 = new(ref _pool0.GetRef(_entity));
|
||||
c0 = new (ref _pool0.GetRef(_entity));
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct QueryItem<T0, T1>
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
private readonly ComponentPool<T0> _pool0;
|
||||
@@ -52,13 +52,12 @@ public readonly struct QueryItem<T0, T1>
|
||||
public void Deconstruct(out Entity entity, out Ref<T0> c0, out Ref<T1> c1)
|
||||
{
|
||||
entity = _entity;
|
||||
c0 = new(ref _pool0.GetRef(_entity));
|
||||
c1 = new(ref _pool1.GetRef(_entity));
|
||||
c0 = new (ref _pool0.GetRef(_entity));c1 = new (ref _pool1.GetRef(_entity));
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct QueryItem<T0, T1, T2>
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
private readonly ComponentPool<T0> _pool0;
|
||||
@@ -83,14 +82,12 @@ public readonly struct QueryItem<T0, T1, T2>
|
||||
public void Deconstruct(out Entity entity, out Ref<T0> c0, out Ref<T1> c1, out Ref<T2> c2)
|
||||
{
|
||||
entity = _entity;
|
||||
c0 = new(ref _pool0.GetRef(_entity));
|
||||
c1 = new(ref _pool1.GetRef(_entity));
|
||||
c2 = new(ref _pool2.GetRef(_entity));
|
||||
c0 = new (ref _pool0.GetRef(_entity));c1 = new (ref _pool1.GetRef(_entity));c2 = new (ref _pool2.GetRef(_entity));
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct QueryItem<T0, T1, T2, T3>
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
private readonly ComponentPool<T0> _pool0;
|
||||
@@ -118,15 +115,12 @@ public readonly struct QueryItem<T0, T1, T2, T3>
|
||||
public void Deconstruct(out Entity entity, out Ref<T0> c0, out Ref<T1> c1, out Ref<T2> c2, out Ref<T3> c3)
|
||||
{
|
||||
entity = _entity;
|
||||
c0 = new(ref _pool0.GetRef(_entity));
|
||||
c1 = new(ref _pool1.GetRef(_entity));
|
||||
c2 = new(ref _pool2.GetRef(_entity));
|
||||
c3 = new(ref _pool3.GetRef(_entity));
|
||||
c0 = new (ref _pool0.GetRef(_entity));c1 = new (ref _pool1.GetRef(_entity));c2 = new (ref _pool2.GetRef(_entity));c3 = new (ref _pool3.GetRef(_entity));
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct QueryItem<T0, T1, T2, T3, T4>
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
private readonly ComponentPool<T0> _pool0;
|
||||
@@ -157,16 +151,12 @@ public readonly struct QueryItem<T0, T1, T2, T3, T4>
|
||||
public void Deconstruct(out Entity entity, out Ref<T0> c0, out Ref<T1> c1, out Ref<T2> c2, out Ref<T3> c3, out Ref<T4> c4)
|
||||
{
|
||||
entity = _entity;
|
||||
c0 = new(ref _pool0.GetRef(_entity));
|
||||
c1 = new(ref _pool1.GetRef(_entity));
|
||||
c2 = new(ref _pool2.GetRef(_entity));
|
||||
c3 = new(ref _pool3.GetRef(_entity));
|
||||
c4 = new(ref _pool4.GetRef(_entity));
|
||||
c0 = new (ref _pool0.GetRef(_entity));c1 = new (ref _pool1.GetRef(_entity));c2 = new (ref _pool2.GetRef(_entity));c3 = new (ref _pool3.GetRef(_entity));c4 = new (ref _pool4.GetRef(_entity));
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct QueryItem<T0, T1, T2, T3, T4, T5>
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
private readonly ComponentPool<T0> _pool0;
|
||||
@@ -200,17 +190,12 @@ public readonly struct QueryItem<T0, T1, T2, T3, T4, T5>
|
||||
public void Deconstruct(out Entity entity, out Ref<T0> c0, out Ref<T1> c1, out Ref<T2> c2, out Ref<T3> c3, out Ref<T4> c4, out Ref<T5> c5)
|
||||
{
|
||||
entity = _entity;
|
||||
c0 = new(ref _pool0.GetRef(_entity));
|
||||
c1 = new(ref _pool1.GetRef(_entity));
|
||||
c2 = new(ref _pool2.GetRef(_entity));
|
||||
c3 = new(ref _pool3.GetRef(_entity));
|
||||
c4 = new(ref _pool4.GetRef(_entity));
|
||||
c5 = new(ref _pool5.GetRef(_entity));
|
||||
c0 = new (ref _pool0.GetRef(_entity));c1 = new (ref _pool1.GetRef(_entity));c2 = new (ref _pool2.GetRef(_entity));c3 = new (ref _pool3.GetRef(_entity));c4 = new (ref _pool4.GetRef(_entity));c5 = new (ref _pool5.GetRef(_entity));
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct QueryItem<T0, T1, T2, T3, T4, T5, T6>
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData where T6 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
private readonly ComponentPool<T0> _pool0;
|
||||
@@ -247,18 +232,12 @@ public readonly struct QueryItem<T0, T1, T2, T3, T4, T5, T6>
|
||||
public void Deconstruct(out Entity entity, out Ref<T0> c0, out Ref<T1> c1, out Ref<T2> c2, out Ref<T3> c3, out Ref<T4> c4, out Ref<T5> c5, out Ref<T6> c6)
|
||||
{
|
||||
entity = _entity;
|
||||
c0 = new(ref _pool0.GetRef(_entity));
|
||||
c1 = new(ref _pool1.GetRef(_entity));
|
||||
c2 = new(ref _pool2.GetRef(_entity));
|
||||
c3 = new(ref _pool3.GetRef(_entity));
|
||||
c4 = new(ref _pool4.GetRef(_entity));
|
||||
c5 = new(ref _pool5.GetRef(_entity));
|
||||
c6 = new(ref _pool6.GetRef(_entity));
|
||||
c0 = new (ref _pool0.GetRef(_entity));c1 = new (ref _pool1.GetRef(_entity));c2 = new (ref _pool2.GetRef(_entity));c3 = new (ref _pool3.GetRef(_entity));c4 = new (ref _pool4.GetRef(_entity));c5 = new (ref _pool5.GetRef(_entity));c6 = new (ref _pool6.GetRef(_entity));
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct QueryItem<T0, T1, T2, T3, T4, T5, T6, T7>
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData where T6 : struct, IComponentData where T7 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData where T7 : unmanaged, IComponentData
|
||||
{
|
||||
private readonly Entity _entity;
|
||||
private readonly ComponentPool<T0> _pool0;
|
||||
@@ -298,14 +277,7 @@ public readonly struct QueryItem<T0, T1, T2, T3, T4, T5, T6, T7>
|
||||
public void Deconstruct(out Entity entity, out Ref<T0> c0, out Ref<T1> c1, out Ref<T2> c2, out Ref<T3> c3, out Ref<T4> c4, out Ref<T5> c5, out Ref<T6> c6, out Ref<T7> c7)
|
||||
{
|
||||
entity = _entity;
|
||||
c0 = new(ref _pool0.GetRef(_entity));
|
||||
c1 = new(ref _pool1.GetRef(_entity));
|
||||
c2 = new(ref _pool2.GetRef(_entity));
|
||||
c3 = new(ref _pool3.GetRef(_entity));
|
||||
c4 = new(ref _pool4.GetRef(_entity));
|
||||
c5 = new(ref _pool5.GetRef(_entity));
|
||||
c6 = new(ref _pool6.GetRef(_entity));
|
||||
c7 = new(ref _pool7.GetRef(_entity));
|
||||
c0 = new (ref _pool0.GetRef(_entity));c1 = new (ref _pool1.GetRef(_entity));c2 = new (ref _pool2.GetRef(_entity));c3 = new (ref _pool3.GetRef(_entity));c4 = new (ref _pool4.GetRef(_entity));c5 = new (ref _pool5.GetRef(_entity));c6 = new (ref _pool6.GetRef(_entity));c7 = new (ref _pool7.GetRef(_entity));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<#@ include file="Helpers.ttinclude" #>
|
||||
<#@ output extension=".cs" #>
|
||||
|
||||
using Ghost.Entities.Components;
|
||||
using Ghost.Entities.Query;
|
||||
|
||||
namespace Ghost.Entities;
|
||||
@@ -11,7 +12,7 @@ namespace Ghost.Entities;
|
||||
<# for (int arity = 1; arity <= Amount; arity++)
|
||||
{
|
||||
var generics = AppendGenerics(arity);
|
||||
var restrictions = AppendGenericRestrictions(arity, "struct, IComponentData");
|
||||
var restrictions = AppendGenericRestrictions(arity, "unmanaged, IComponentData");
|
||||
var constructorParams = Enumerable.Range(0, arity)
|
||||
.Select(i => $"ComponentPool<T{i}> pool{i}")
|
||||
.Aggregate((a, b) => a + ", " + b);
|
||||
|
||||
@@ -5,18 +5,18 @@ using Ghost.Entities.Components;
|
||||
namespace Ghost.Entities;
|
||||
|
||||
public delegate void QueryRefComponent<T0>(Entity entity, ref T0 t0Component)
|
||||
where T0 : struct, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1>(Entity entity, ref T0 t0Component, ref T1 t1Component)
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2>(Entity entity, ref T0 t0Component, ref T1 t1Component, ref T2 t2Component)
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3>(Entity entity, ref T0 t0Component, ref T1 t1Component, ref T2 t2Component, ref T3 t3Component)
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3, T4>(Entity entity, ref T0 t0Component, ref T1 t1Component, ref T2 t2Component, ref T3 t3Component, ref T4 t4Component)
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3, T4, T5>(Entity entity, ref T0 t0Component, ref T1 t1Component, ref T2 t2Component, ref T3 t3Component, ref T4 t4Component, ref T5 t5Component)
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3, T4, T5, T6>(Entity entity, ref T0 t0Component, ref T1 t1Component, ref T2 t2Component, ref T3 t3Component, ref T4 t4Component, ref T5 t5Component, ref T6 t6Component)
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData where T6 : struct, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3, T4, T5, T6, T7>(Entity entity, ref T0 t0Component, ref T1 t1Component, ref T2 t2Component, ref T3 t3Component, ref T4 t4Component, ref T5 t5Component, ref T6 t6Component, ref T7 t7Component)
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData where T6 : struct, IComponentData where T7 : struct, IComponentData;
|
||||
where T0 : unmanaged, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1>(Entity entity, ref T0 t0Component,ref T1 t1Component)
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component)
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component)
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3, T4>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component)
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3, T4, T5>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component)
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3, T4, T5, T6>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component,ref T6 t6Component)
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData;
|
||||
public delegate void QueryRefComponent<T0, T1, T2, T3, T4, T5, T6, T7>(Entity entity, ref T0 t0Component,ref T1 t1Component,ref T2 t2Component,ref T3 t3Component,ref T4 t4Component,ref T5 t5Component,ref T6 t6Component,ref T7 t7Component)
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData where T7 : unmanaged, IComponentData;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ include file="Helpers.ttinclude" #>
|
||||
|
||||
using Ghost.Entities.Components;
|
||||
|
||||
namespace Ghost.Entities;
|
||||
|
||||
<#
|
||||
@@ -10,7 +12,7 @@ for (var index = 1; index <= Amount; index++)
|
||||
{
|
||||
var generics = AppendGenerics(index);
|
||||
var parameters = AppendGenericRefParameters(index);
|
||||
var restrictions = AppendGenericRestrictions(index, "struct, IComponentData");
|
||||
var restrictions = AppendGenericRestrictions(index, "unmanaged, IComponentData");
|
||||
#>
|
||||
public delegate void QueryRefComponent<<#= generics #>>(Entity entity, <#= parameters.ToString() #>)
|
||||
<#= restrictions.ToString() #>;
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Ghost.Entities;
|
||||
public partial class World
|
||||
{
|
||||
public QueryEnumerable<T0> Query<T0>()
|
||||
where T0 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData
|
||||
{
|
||||
if (!(_componentStorage.TryGetPool<T0>(out var pool0)))
|
||||
return default;
|
||||
@@ -19,7 +19,7 @@ public partial class World
|
||||
}
|
||||
|
||||
public QueryEnumerable<T0, T1> Query<T0, T1>()
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData
|
||||
{
|
||||
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1)))
|
||||
return default;
|
||||
@@ -31,7 +31,7 @@ public partial class World
|
||||
}
|
||||
|
||||
public QueryEnumerable<T0, T1, T2> Query<T0, T1, T2>()
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData
|
||||
{
|
||||
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2)))
|
||||
return default;
|
||||
@@ -43,7 +43,7 @@ public partial class World
|
||||
}
|
||||
|
||||
public QueryEnumerable<T0, T1, T2, T3> Query<T0, T1, T2, T3>()
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData
|
||||
{
|
||||
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3)))
|
||||
return default;
|
||||
@@ -55,7 +55,7 @@ public partial class World
|
||||
}
|
||||
|
||||
public QueryEnumerable<T0, T1, T2, T3, T4> Query<T0, T1, T2, T3, T4>()
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData
|
||||
{
|
||||
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4)))
|
||||
return default;
|
||||
@@ -67,7 +67,7 @@ public partial class World
|
||||
}
|
||||
|
||||
public QueryEnumerable<T0, T1, T2, T3, T4, T5> Query<T0, T1, T2, T3, T4, T5>()
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData
|
||||
{
|
||||
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5)))
|
||||
return default;
|
||||
@@ -79,7 +79,7 @@ public partial class World
|
||||
}
|
||||
|
||||
public QueryEnumerable<T0, T1, T2, T3, T4, T5, T6> Query<T0, T1, T2, T3, T4, T5, T6>()
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData where T6 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData
|
||||
{
|
||||
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5) && _componentStorage.TryGetPool<T6>(out var pool6)))
|
||||
return default;
|
||||
@@ -91,7 +91,7 @@ public partial class World
|
||||
}
|
||||
|
||||
public QueryEnumerable<T0, T1, T2, T3, T4, T5, T6, T7> Query<T0, T1, T2, T3, T4, T5, T6, T7>()
|
||||
where T0 : struct, IComponentData where T1 : struct, IComponentData where T2 : struct, IComponentData where T3 : struct, IComponentData where T4 : struct, IComponentData where T5 : struct, IComponentData where T6 : struct, IComponentData where T7 : struct, IComponentData
|
||||
where T0 : unmanaged, IComponentData where T1 : unmanaged, IComponentData where T2 : unmanaged, IComponentData where T3 : unmanaged, IComponentData where T4 : unmanaged, IComponentData where T5 : unmanaged, IComponentData where T6 : unmanaged, IComponentData where T7 : unmanaged, IComponentData
|
||||
{
|
||||
if (!(_componentStorage.TryGetPool<T0>(out var pool0) && _componentStorage.TryGetPool<T1>(out var pool1) && _componentStorage.TryGetPool<T2>(out var pool2) && _componentStorage.TryGetPool<T3>(out var pool3) && _componentStorage.TryGetPool<T4>(out var pool4) && _componentStorage.TryGetPool<T5>(out var pool5) && _componentStorage.TryGetPool<T6>(out var pool6) && _componentStorage.TryGetPool<T7>(out var pool7)))
|
||||
return default;
|
||||
|
||||
@@ -5,13 +5,15 @@
|
||||
<#@ import namespace="System.Text" #>
|
||||
<#@ include file="Helpers.ttinclude" #>
|
||||
|
||||
using Ghost.Entities.Components;
|
||||
|
||||
namespace Ghost.Entities;
|
||||
|
||||
public partial class World
|
||||
{
|
||||
<# for (var index = 1; index <= Amount; index++) {
|
||||
var generics = AppendGenerics(index);
|
||||
var restrictions = AppendGenericRestrictions(index, "struct, IComponentData");
|
||||
var restrictions = AppendGenericRestrictions(index, "unmanaged, IComponentData");
|
||||
var tryGetPools = TryGetComponentPools(index);
|
||||
var poolParams = Enumerable.Range(0, index)
|
||||
.Select(i => $"pool{i}")
|
||||
|
||||
@@ -67,7 +67,7 @@ public partial class World : IDisposable, IEquatable<World>
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Ref<T> GetSingleton<T>()
|
||||
where T : struct, IComponentData
|
||||
where T : unmanaged, IComponentData
|
||||
{
|
||||
ref var component = ref CollectionsMarshal.GetValueRefOrAddDefault(SingletonContainer<T>.container, _id, out _);
|
||||
return new Ref<T>(ref component);
|
||||
@@ -113,6 +113,11 @@ public partial class World : IDisposable, IEquatable<World>
|
||||
return _id.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is World other && Equals(other);
|
||||
}
|
||||
|
||||
public static bool operator ==(World? left, World? right)
|
||||
{
|
||||
return left?.Equals(right) ?? right is null;
|
||||
|
||||
@@ -12,14 +12,14 @@ internal class SerializationTest : ITest
|
||||
public void Run()
|
||||
{
|
||||
var testWorld = World.Create();
|
||||
var entity1 = SceneGraphHelpers.CreateEntityNode(testWorld, "entity 1");
|
||||
var entity2 = SceneGraphHelpers.CreateEntityNode(testWorld, "entity 2");
|
||||
var entity3 = SceneGraphHelpers.CreateEntityNode(testWorld, "entity 3");
|
||||
var entity4 = SceneGraphHelpers.CreateEntityNode(testWorld, "entity 4");
|
||||
var entity5 = SceneGraphHelpers.CreateEntityNode(testWorld, "entity 5");
|
||||
|
||||
var testScene = new WorldNode(testWorld, "Test Scene");
|
||||
|
||||
var entity1 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 1");
|
||||
var entity2 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 2");
|
||||
var entity3 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 3");
|
||||
var entity4 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 4");
|
||||
var entity5 = SceneGraphHelpers.CreateEntityNode(testScene, "entity 5");
|
||||
|
||||
testWorld.SystemStorage.AddSystem<TestSystem>();
|
||||
|
||||
SceneGraphHelpers.AttachChild(testScene, entity1, entity2);
|
||||
|
||||
Reference in New Issue
Block a user