Skip to content

Commit efc2101

Browse files
authored
feat: AddComponents function for non generic usage (#24)
For benchmarks and serialization we need a way to add variadic components
1 parent 65b5e7d commit efc2101

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

component.go

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ type ComponentInterface interface {
1212
GetComponentId() ComponentId
1313
}
1414

15+
type ComponentIdConf struct {
16+
ComponentId
17+
conf any
18+
}
19+
1520
func (world *World) getComponentsIds(components ...ComponentInterface) []ComponentId {
1621
componentsIds := make([]ComponentId, len(components))
1722

@@ -367,6 +372,40 @@ func (world *World) AddComponent(entityId EntityId, componentId ComponentId, con
367372
return nil
368373
}
369374

375+
// AddComponents adds variadic components to the EntityId.
376+
//
377+
// This non-generic version is adapted for when generics are not available, though might be slower.
378+
// It returns an error if:
379+
// - the entity already has the components Ids
380+
// - the componentsIds are not registered in the World
381+
// - an internal error occurs
382+
func (world *World) AddComponents(entityId EntityId, componentsIdsConfs ...ComponentIdConf) error {
383+
var componentsIds []ComponentId
384+
for _, componentIdConf := range componentsIdsConfs {
385+
componentsIds = append(componentsIds, componentIdConf.ComponentId)
386+
}
387+
388+
if world.HasComponents(entityId, componentsIds...) {
389+
return fmt.Errorf("the entity %d already owns the components %v", entityId, componentsIds)
390+
}
391+
392+
for _, componentIdConf := range componentsIdsConfs {
393+
componentRegistry, err := world.getConfigByComponentId(componentIdConf.ComponentId)
394+
if err != nil {
395+
return err
396+
}
397+
398+
err = componentRegistry.addComponent(world, entityId, componentIdConf.conf)
399+
if err != nil {
400+
return err
401+
}
402+
403+
world.componentAddedFn(entityId, componentIdConf.ComponentId)
404+
}
405+
406+
return nil
407+
}
408+
370409
// RemoveComponent removes the component to EntityId.
371410
//
372411
// It returns an error if the EntityId does not have the component.
@@ -498,16 +537,14 @@ func addComponentsToArchetype1[A ComponentInterface](world *World, entityRecord
498537
// If the entity has no component, simply add it the archetype
499538
if entityRecord.archetypeId == 0 {
500539
world.setArchetype(entityRecord, archetype)
501-
storageA.add(archetype.Id, component)
502540
} else {
503541
oldArchetype := world.getArchetype(entityRecord)
504542
if archetype.Id != oldArchetype.Id {
505543
moveComponentsToArchetype(world, entityRecord, oldArchetype, archetype)
506544
world.setArchetype(entityRecord, archetype)
507545
}
508-
509-
storageA.add(archetype.Id, component)
510546
}
547+
storageA.add(archetype.Id, component)
511548

512549
return nil
513550
}

component_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,32 @@ func TestAddComponent(t *testing.T) {
111111
}
112112
}
113113

114+
func TestAddComponents(t *testing.T) {
115+
entities := make([]EntityId, TEST_ENTITY_NUMBER)
116+
world := CreateWorld(1024)
117+
118+
RegisterComponent[testComponent1](world, &ComponentConfig[testComponent1]{BuilderFn: func(component any, configuration any) {}})
119+
RegisterComponent[testComponent2](world, &ComponentConfig[testComponent2]{BuilderFn: func(component any, configuration any) {}})
120+
RegisterComponent[testComponent3](world, &ComponentConfig[testComponent3]{BuilderFn: func(component any, configuration any) {}})
121+
RegisterComponent[testComponent4](world, &ComponentConfig[testComponent4]{BuilderFn: func(component any, configuration any) {}})
122+
RegisterComponent[testComponent5](world, &ComponentConfig[testComponent5]{BuilderFn: func(component any, configuration any) {}})
123+
124+
for i := 0; i < TEST_ENTITY_NUMBER; i++ {
125+
entities[i] = world.CreateEntity(fmt.Sprint(i))
126+
127+
err := world.AddComponents(entities[i], ComponentIdConf{ComponentId: testComponent1Id}, ComponentIdConf{ComponentId: testComponent2Id}, ComponentIdConf{ComponentId: testComponent3Id}, ComponentIdConf{ComponentId: testComponent4Id}, ComponentIdConf{ComponentId: testComponent5Id})
128+
if err != nil {
129+
t.Errorf("could not add components to entity %d: %s", entities[i], err)
130+
}
131+
}
132+
133+
for _, entityId := range entities {
134+
if !world.HasComponents(entityId, testComponent1Id, testComponent2Id, testComponent3Id, testComponent4Id, testComponent5Id) {
135+
t.Errorf("Expected 5 components for entity %d", entityId)
136+
}
137+
}
138+
}
139+
114140
func TestConfigureComponent(t *testing.T) {
115141
world := CreateWorld(1024)
116142
RegisterComponent[testComponent1](world, &ComponentConfig[testComponent1]{BuilderFn: func(component any, configuration any) {

0 commit comments

Comments
 (0)