Arch
                                
                                
                                
                                    Arch copied to clipboard
                            
                            
                            
                        Add `World.Create(object[])`
Discussed in https://github.com/genaray/Arch/discussions/78
Originally posted by Mathetis April 11, 2023 Hi, I'm curious if the following behavior is by design, if I am misusing it, or if this is a bug.
I have a use case where the array of components arrived as an object[], which contains references to struct components (boxing isn't problematic for my case here). I want to create an entity from those components. Here's a simple example:
struct SomeComponent { ... }
object[] components = new object[] { new SomeComponent() { ... } };
Entity entity = world.Create(components);
bool hasComponent = entity.Has<SomeComponent>();  // <-- this will be false.
We should probably add another World.Create overload to create entities by a object[] array :)
This should be done quickly though.
I didn't realize this wasn't a feature until I ran into needing it. I got it working with the following:
public Entity CreateFromArray(object[] components)
    {
        ComponentType[] types = getComponentTypesForArchetype(components);
        Entity entity = Create(types);
        SetFromArray(entity, components);
        return entity;
    }
    public void SetFromArray(Entity entity, object[] components)
    {
        switch (components.Length)
        {
            case 1:
                entity.Set(components[0]);
                break;
            case 2:
                entity.Set(components[0], components[1]);
                break;
        }
    }
    private ComponentType[] getComponentTypesForArchetype(object[] components)
    {
        ComponentType[] types = new ComponentType[components.Length];
        for(int i = 0; i< components.Length; i++)
        {
            ComponentType type;
            if(!ComponentRegistry.TryGet(components[i].GetType(), out type))
            {
                type = ComponentRegistry.Add(components[i].GetType());
            }
            types[i] = type;
        }
        return types;
    }
Note: The code I'm working on is directly in the World class. I haven't tried moving it anywhere else. As far as I can tell for now, you'll need individual case statements based on the number of components.
Working on some more tests now and I realized that using Set only works for a single element array. SetRange is needed for everything higher than that because even though the types are known, it's pulling the component array of the first element for all elements. I think that's the intended outcome because Set is for known types at runtime and SetRange is for unknown types at runtime.
Could something like this ever work with a Query? I am currently trying to create entities at runtime with dynamic classes and as soon as it gets added with the above code it is converted to System.RuntimeType(which probably makes sense with object).
In this image I am trying to create an entity with the following components:
and below is me trying to query components that are Vector3:
below is the code with Query.
public class TestSystem : SystemBase
{
	private DebugTextSystem _debugText;
	private QueryDescription _queryDescription;
	public override void Start()
	{
		_debugText = Services.GetService<DebugTextSystem>();
		_queryDescription = new QueryDescription().
			WithAny<Vector3>();
	}
	public override void Update(in GameTime state)
	{
		var result = World.CountEntities(in _queryDescription);
		_debugText.Print($"TestSystem: {result}", new Int2(50, 50));
	}
}
                                    
                                    
                                    
                                
When you're running your version of CreateFromArray, are you passing it an array of types or an array of objects? Based on the screenshot it seems like you're giving it the types.
The intent of that function is to be given the array of actual components to be used. The function will create an entity of that archetype and then set the components provided to that entity. I use it fairly heavily in my networking code because that's how I generate the entities client-side.
Ahhh my goodness thank you! I was using inputting Type instead of object... It seems to work now.