Skip to content

Commit

Permalink
Merge internal package (#101)
Browse files Browse the repository at this point in the history
* simplify internal package

* refactor components struct to support larger number of component types

* minor imporovement
  • Loading branch information
yohamta authored Apr 7, 2023
1 parent 3e8cebd commit cd6a0a4
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 48 deletions.
6 changes: 3 additions & 3 deletions entity.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package donburi

import "github.com/yohamta/donburi/internal/entity"
import "github.com/yohamta/donburi/internal/storage"

// Entity is identifier of an entity.
// Entity is just a wrapper of uint64.
type Entity = entity.Entity
type Entity = storage.Entity

// Null represents a invalid entity which is zero.
var Null = entity.Null
var Null = storage.Null
5 changes: 2 additions & 3 deletions entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ import (
"unsafe"

"github.com/yohamta/donburi/component"
"github.com/yohamta/donburi/internal/entity"
"github.com/yohamta/donburi/internal/storage"
)

// Entry is a struct that contains an entity and a location in an archetype.
type Entry struct {
World *world

id entity.EntityId
id storage.EntityId
entity Entity
loc *storage.Location
}
Expand Down Expand Up @@ -54,7 +53,7 @@ func Valid(e *Entry) bool {
}

// Id returns the entity id.
func (e *Entry) Id() entity.EntityId {
func (e *Entry) Id() storage.EntityId {
return e.id
}

Expand Down
11 changes: 5 additions & 6 deletions internal/storage/archetype.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package storage

import (
"github.com/yohamta/donburi/component"
"github.com/yohamta/donburi/internal/entity"
)

type ArchetypeIndex int
Expand All @@ -11,15 +10,15 @@ type ArchetypeIndex int
// This structure allows to quickly find entities based on their components.
type Archetype struct {
index ArchetypeIndex
entities []entity.Entity
entities []Entity
layout *Layout
}

// NewArchetype creates a new archetype.
func NewArchetype(index ArchetypeIndex, layout *Layout) *Archetype {
return &Archetype{
index: index,
entities: make([]entity.Entity, 0, 256),
entities: make([]Entity, 0, 256),
layout: layout,
}
}
Expand All @@ -30,12 +29,12 @@ func (archetype *Archetype) Layout() *Layout {
}

// Entities returns all entities in this archetype.
func (archetype *Archetype) Entities() []entity.Entity {
func (archetype *Archetype) Entities() []Entity {
return archetype.entities
}

// SwapRemove removes an entity from the archetype and returns it.
func (archetype *Archetype) SwapRemove(entity_index int) entity.Entity {
func (archetype *Archetype) SwapRemove(entity_index int) Entity {
removed := archetype.entities[entity_index]
archetype.entities[entity_index] = archetype.entities[len(archetype.entities)-1]
archetype.entities = archetype.entities[:len(archetype.entities)-1]
Expand All @@ -56,7 +55,7 @@ func (archetype *Archetype) LayoutMatches(components []component.IComponentType)
}

// PushEntity adds an entity to the archetype.
func (archetype *Archetype) PushEntity(entity entity.Entity) {
func (archetype *Archetype) PushEntity(entity Entity) {
archetype.entities = append(archetype.entities, entity)
}

Expand Down
34 changes: 21 additions & 13 deletions internal/storage/components.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,34 @@ package storage

import "github.com/yohamta/donburi/component"

// ComponentIndex represents the index of component in a archetype.
// ComponentIndex represents the index of component in an archetype.
type ComponentIndex int

// Components is a structure that stores data of components.
type Components struct {
storages []*Storage
// TODO: optimize to use slice instead of map for performance
storages []*Storage
componentIndices map[ArchetypeIndex]ComponentIndex
}

// NewComponents creates a new empty structure that stores data of components.
func NewComponents() *Components {
return &Components{
storages: make([]*Storage, 512), // TODO: expand as the number of component types increases
storages: make([]*Storage, 0, 512),
componentIndices: make(map[ArchetypeIndex]ComponentIndex),
}
}

// PUshComponent stores the new data of the component in the archetype.
// PushComponents stores the new data of the component in the archetype.
func (cs *Components) PushComponents(components []component.IComponentType, archetypeIndex ArchetypeIndex) ComponentIndex {
for _, componentType := range components {
if v := cs.storages[componentType.Id()]; v == nil {
cs.storages[componentType.Id()] = NewStorage()
id := int(componentType.Id())
if id >= len(cs.storages) {
cs.storages = append(cs.storages, make([]*Storage, id-len(cs.storages)+1)...)
}
cs.storages[componentType.Id()].PushComponent(componentType, archetypeIndex)
if cs.storages[id] == nil {
cs.storages[id] = NewStorage()
}
cs.storages[id].PushComponent(componentType, archetypeIndex)
}
if _, ok := cs.componentIndices[archetypeIndex]; !ok {
cs.componentIndices[archetypeIndex] = 0
Expand All @@ -44,16 +47,21 @@ func (cs *Components) Move(src ArchetypeIndex, dst ArchetypeIndex) {

// Storage returns the pointer to data of the component in the archetype.
func (cs *Components) Storage(c component.IComponentType) *Storage {
if storage := cs.storages[c.Id()]; storage != nil {
return storage
id := int(c.Id())
if id < len(cs.storages) && cs.storages[id] != nil {
return cs.storages[id]
}
if id >= len(cs.storages) {
cs.storages = append(cs.storages, make([]*Storage, id-len(cs.storages)+1)...)
}
cs.storages[c.Id()] = NewStorage()
return cs.storages[c.Id()]
cs.storages[id] = NewStorage()
return cs.storages[id]
}

// Remove removes the component from the storage.
func (cs *Components) Remove(a *Archetype, ci ComponentIndex) {
for _, ct := range a.Layout().Components() {
components := a.Layout().Components()
for _, ct := range components {
cs.remove(ct, a.index, ci)
}
cs.componentIndices[a.index]--
Expand Down
2 changes: 1 addition & 1 deletion internal/entity/entity.go → internal/storage/entity.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package entity
package storage

import "fmt"

Expand Down
4 changes: 1 addition & 3 deletions internal/storage/iterator.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package storage

import "github.com/yohamta/donburi/internal/entity"

// EntityIterator is an iterator for entity lists in archetypes.
type EntityIterator struct {
current int
Expand All @@ -24,7 +22,7 @@ func (it *EntityIterator) HasNext() bool {
}

// Next returns the next entity list.
func (it *EntityIterator) Next() []entity.Entity {
func (it *EntityIterator) Next() []Entity {
archetypeIndex := it.indices[it.current]
it.current++
return it.archetypes[archetypeIndex].Entities()
Expand Down
18 changes: 7 additions & 11 deletions internal/storage/location_map.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package storage

import (
"github.com/yohamta/donburi/internal/entity"
)

// LocationMap is a storage of entity locations.
type LocationMap struct {
LocationMap []*Location
Expand All @@ -19,19 +15,19 @@ func NewLocationMap() *LocationMap {
}

// Contains returns true if the storage contains the given entity id.
func (lm *LocationMap) Contains(id entity.EntityId) bool {
func (lm *LocationMap) Contains(id EntityId) bool {
val := lm.LocationMap[id]
return val != nil && val.Valid
}

// Remove removes the given entity id from the storage.
func (lm *LocationMap) Remove(id entity.EntityId) {
func (lm *LocationMap) Remove(id EntityId) {
lm.LocationMap[id].Valid = false
lm.Len--
}

// Insert inserts the given entity id and archetype index to the storage.
func (lm *LocationMap) Insert(id entity.EntityId, archetype ArchetypeIndex, component ComponentIndex) {
func (lm *LocationMap) Insert(id EntityId, archetype ArchetypeIndex, component ComponentIndex) {
if int(id) == len(lm.LocationMap) {
loc := NewLocation(archetype, component)
lm.LocationMap = append(lm.LocationMap, loc)
Expand All @@ -48,21 +44,21 @@ func (lm *LocationMap) Insert(id entity.EntityId, archetype ArchetypeIndex, comp
}

// Set sets the given entity id and archetype index to the storage.
func (lm *LocationMap) Set(id entity.EntityId, loc *Location) {
func (lm *LocationMap) Set(id EntityId, loc *Location) {
lm.Insert(id, loc.Archetype, loc.Component)
}

// Location returns the location of the given entity id.
func (lm *LocationMap) Location(id entity.EntityId) *Location {
func (lm *LocationMap) Location(id EntityId) *Location {
return lm.LocationMap[id]
}

// Archetype returns the archetype of the given entity id.
func (lm *LocationMap) Archetype(id entity.EntityId) ArchetypeIndex {
func (lm *LocationMap) Archetype(id EntityId) ArchetypeIndex {
return lm.LocationMap[id].Archetype
}

// Component returns the component of the given entity id.
func (lm *LocationMap) Component(id entity.EntityId) ComponentIndex {
func (lm *LocationMap) Component(id EntityId) ComponentIndex {
return lm.LocationMap[id].Component
}
3 changes: 1 addition & 2 deletions query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package donburi

import (
"github.com/yohamta/donburi/filter"
"github.com/yohamta/donburi/internal/entity"
"github.com/yohamta/donburi/internal/storage"
)

Expand Down Expand Up @@ -36,7 +35,7 @@ func (q *Query) Each(w World, callback func(*Entry)) {
accessor := w.StorageAccessor()
result := q.evaluateQuery(w, &accessor)
iter := storage.NewEntityIterator(0, accessor.Archetypes, result)
f := func(entity entity.Entity) {
f := func(entity storage.Entity) {
entry := w.Entry(entity)
callback(entry)
}
Expand Down
5 changes: 2 additions & 3 deletions world.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/yohamta/donburi/component"
"github.com/yohamta/donburi/filter"
"github.com/yohamta/donburi/internal/entity"
"github.com/yohamta/donburi/internal/storage"
)

Expand Down Expand Up @@ -55,7 +54,7 @@ type world struct {
archetypes []*storage.Archetype
destroyed []Entity
entries []*Entry
nextEntityId entity.EntityId
nextEntityId storage.EntityId
}

var nextWorldId WorldId = 0
Expand Down Expand Up @@ -235,7 +234,7 @@ func (w *world) nextEntity() Entity {
if len(w.destroyed) == 0 {
id := w.nextEntityId
w.nextEntityId++
return entity.NewEntity(id)
return storage.NewEntity(id)
}
entity := w.destroyed[len(w.destroyed)-1]
w.destroyed = w.destroyed[:len(w.destroyed)-1]
Expand Down
5 changes: 2 additions & 3 deletions world_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/stretchr/testify/require"
"github.com/yohamta/donburi"
"github.com/yohamta/donburi/filter"
"github.com/yohamta/donburi/internal/entity"
"github.com/yohamta/donburi/internal/storage"
)

Expand Down Expand Up @@ -95,7 +94,7 @@ func TestArchetype(t *testing.T) {
func TestAddComponent(t *testing.T) {
world := donburi.NewWorld()

entities := []entity.Entity{
entities := []storage.Entity{
world.Create(tagA, transform),
world.Create(tagA, transform),
world.Create(tagA, transform),
Expand Down Expand Up @@ -123,7 +122,7 @@ func TestAddComponent(t *testing.T) {
func TestRemoveComponent(t *testing.T) {
world := donburi.NewWorld()

entities := []entity.Entity{
entities := []storage.Entity{
world.Create(tagA, transform, velocity),
world.Create(tagA, transform, velocity),
world.Create(tagA, transform, velocity),
Expand Down

0 comments on commit cd6a0a4

Please sign in to comment.