Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add World.Create(object[]) #85

Open
genaray opened this issue Apr 16, 2023 Discussed in #78 · 5 comments
Open

Add World.Create(object[]) #85

genaray opened this issue Apr 16, 2023 Discussed in #78 · 5 comments
Assignees
Labels
enhancement New feature or request

Comments

@genaray
Copy link
Owner

genaray commented Apr 16, 2023

Discussed in #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.

@genaray genaray added the enhancement New feature or request label Apr 16, 2023
@genaray genaray self-assigned this Apr 16, 2023
@proc-gen
Copy link

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.

@proc-gen
Copy link

proc-gen commented Jun 3, 2023

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.

@Doprez
Copy link

Doprez commented Nov 5, 2023

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:
image

and below is me trying to query components that are Vector3:
image

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));
	}
}

@proc-gen
Copy link

proc-gen commented Nov 5, 2023

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.

@Doprez
Copy link

Doprez commented Nov 5, 2023

Ahhh my goodness thank you! I was using inputting Type instead of object... It seems to work now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Todo
Development

No branches or pull requests

3 participants