diff --git a/component.go b/component.go index 3d16d6d..346c0bf 100644 --- a/component.go +++ b/component.go @@ -12,6 +12,11 @@ type ComponentInterface interface { GetComponentId() ComponentId } +type ComponentIdConf struct { + ComponentId + conf any +} + func (world *World) getComponentsIds(components ...ComponentInterface) []ComponentId { componentsIds := make([]ComponentId, len(components)) @@ -367,6 +372,40 @@ func (world *World) AddComponent(entityId EntityId, componentId ComponentId, con return nil } +// AddComponents adds variadic components to the EntityId. +// +// This non-generic version is adapted for when generics are not available, though might be slower. +// It returns an error if: +// - the entity already has the components Ids +// - the componentsIds are not registered in the World +// - an internal error occurs +func (world *World) AddComponents(entityId EntityId, componentsIdsConfs ...ComponentIdConf) error { + var componentsIds []ComponentId + for _, componentIdConf := range componentsIdsConfs { + componentsIds = append(componentsIds, componentIdConf.ComponentId) + } + + if world.HasComponents(entityId, componentsIds...) { + return fmt.Errorf("the entity %d already owns the components %v", entityId, componentsIds) + } + + for _, componentIdConf := range componentsIdsConfs { + componentRegistry, err := world.getConfigByComponentId(componentIdConf.ComponentId) + if err != nil { + return err + } + + err = componentRegistry.addComponent(world, entityId, componentIdConf.conf) + if err != nil { + return err + } + + world.componentAddedFn(entityId, componentIdConf.ComponentId) + } + + return nil +} + // RemoveComponent removes the component to EntityId. // // It returns an error if the EntityId does not have the component. @@ -498,16 +537,14 @@ func addComponentsToArchetype1[A ComponentInterface](world *World, entityRecord // If the entity has no component, simply add it the archetype if entityRecord.archetypeId == 0 { world.setArchetype(entityRecord, archetype) - storageA.add(archetype.Id, component) } else { oldArchetype := world.getArchetype(entityRecord) if archetype.Id != oldArchetype.Id { moveComponentsToArchetype(world, entityRecord, oldArchetype, archetype) world.setArchetype(entityRecord, archetype) } - - storageA.add(archetype.Id, component) } + storageA.add(archetype.Id, component) return nil } diff --git a/component_test.go b/component_test.go index 60dfee5..134b2b2 100644 --- a/component_test.go +++ b/component_test.go @@ -111,6 +111,32 @@ func TestAddComponent(t *testing.T) { } } +func TestAddComponents(t *testing.T) { + entities := make([]EntityId, TEST_ENTITY_NUMBER) + world := CreateWorld(1024) + + RegisterComponent[testComponent1](world, &ComponentConfig[testComponent1]{BuilderFn: func(component any, configuration any) {}}) + RegisterComponent[testComponent2](world, &ComponentConfig[testComponent2]{BuilderFn: func(component any, configuration any) {}}) + RegisterComponent[testComponent3](world, &ComponentConfig[testComponent3]{BuilderFn: func(component any, configuration any) {}}) + RegisterComponent[testComponent4](world, &ComponentConfig[testComponent4]{BuilderFn: func(component any, configuration any) {}}) + RegisterComponent[testComponent5](world, &ComponentConfig[testComponent5]{BuilderFn: func(component any, configuration any) {}}) + + for i := 0; i < TEST_ENTITY_NUMBER; i++ { + entities[i] = world.CreateEntity(fmt.Sprint(i)) + + err := world.AddComponents(entities[i], ComponentIdConf{ComponentId: testComponent1Id}, ComponentIdConf{ComponentId: testComponent2Id}, ComponentIdConf{ComponentId: testComponent3Id}, ComponentIdConf{ComponentId: testComponent4Id}, ComponentIdConf{ComponentId: testComponent5Id}) + if err != nil { + t.Errorf("could not add components to entity %d: %s", entities[i], err) + } + } + + for _, entityId := range entities { + if !world.HasComponents(entityId, testComponent1Id, testComponent2Id, testComponent3Id, testComponent4Id, testComponent5Id) { + t.Errorf("Expected 5 components for entity %d", entityId) + } + } +} + func TestConfigureComponent(t *testing.T) { world := CreateWorld(1024) RegisterComponent[testComponent1](world, &ComponentConfig[testComponent1]{BuilderFn: func(component any, configuration any) {