Generational indices+get/free entity+free list

This commit is contained in:
bloeys
2022-09-24 23:20:08 +04:00
parent 35ff496a9a
commit ac0ca8ee39
3 changed files with 136 additions and 41 deletions

View File

@ -1,5 +1,19 @@
package entity
type EntityFlag byte
const (
EntityFlag_Unknown EntityFlag = 0
EntityFlag_Dead EntityFlag = 1 << (iota - 1)
EntityFlag_Alive
)
const (
GenerationShiftBits = 64 - 8
FlagsShiftBits = 64 - 16
IndexBitMask = 0x00_00_FFFF_FFFF_FFFF
)
type Entity struct {
// Byte 1: Generation; Byte 2: Flags; Bytes 3-8: Index
@ -7,6 +21,26 @@ type Entity struct {
Comps []Comp
}
func GetGeneration(id uint64) byte {
return byte(id >> GenerationShiftBits)
}
func GetFlags(id uint64) byte {
return byte(id >> FlagsShiftBits)
}
func GetIndex(id uint64) uint64 {
return id & IndexBitMask
}
func (e *Entity) HasFlag(ef EntityFlag) bool {
return GetFlags(e.ID)&byte(ef) > 0
}
func NewEntityId(generation, flags byte, index uint64) uint64 {
return index | (uint64(generation) << GenerationShiftBits) | (uint64(flags) << FlagsShiftBits)
}
type Comp interface {
Name() string
}

View File

@ -1,30 +1,89 @@
package entity
import "github.com/bloeys/nmage/assert"
import (
"github.com/bloeys/nmage/assert"
)
type freeListitem struct {
EntityIndex uint64
nextFree *freeListitem
}
type Registry struct {
EntityCount uint64
Entities []Entity
FreeList *freeListitem
}
func (r *Registry) NewEntity() *Entity {
assert.T(r.EntityCount < uint64(len(r.Entities)), "Can not add more entities to registry because it is full")
entityToUseIndex := uint64(0)
var entityToUse *Entity = nil
if r.FreeList != nil {
entityToUseIndex = r.FreeList.EntityIndex
entityToUse = &r.Entities[entityToUseIndex]
r.FreeList = r.FreeList.nextFree
} else {
for i := 0; i < len(r.Entities); i++ {
// @TODO: Implement generational indices
e := &r.Entities[i]
if e.ID == 0 {
r.EntityCount++
e.ID = uint64(i) + 1
if GetFlags(e.ID) != byte(EntityFlag_Unknown) && !e.HasFlag(EntityFlag_Dead) {
continue
}
entityToUse = e
entityToUseIndex = uint64(i)
break
}
}
if entityToUse == nil {
panic("failed to create new entity because we did not find a free spot in the registry. Why did the assert not go off?")
}
r.EntityCount++
entityToUse.ID = NewEntityId(GetGeneration(entityToUse.ID)+1, byte(EntityFlag_Alive), entityToUseIndex)
assert.T(entityToUse.ID != 0, "Entity ID must not be zero")
return entityToUse
}
func (r *Registry) GetEntity(id uint64) *Entity {
index := GetIndex(id)
gen := GetGeneration(id)
e := &r.Entities[index]
eGen := GetGeneration(e.ID)
if gen != eGen {
return nil
}
assert.T(e.ID != 0, "Entity ID must not be zero")
return e
}
func (r *Registry) FreeEntity(id uint64) {
e := r.GetEntity(id)
if e == nil {
return
}
panic("failed to create new entity because we did not find a free spot in the registry. Why did the assert not go off?")
r.EntityCount--
eIndex := GetIndex(e.ID)
e.Comps = []Comp{}
e.ID = NewEntityId(GetGeneration(e.ID), byte(EntityFlag_Dead), eIndex)
r.FreeList = &freeListitem{
EntityIndex: eIndex,
nextFree: r.FreeList,
}
}
func NewRegistry(size uint32) *Registry {

64
main.go
View File

@ -8,7 +8,9 @@ import (
"github.com/bloeys/nmage/assets"
"github.com/bloeys/nmage/camera"
"github.com/bloeys/nmage/engine"
"github.com/bloeys/nmage/entity"
"github.com/bloeys/nmage/input"
"github.com/bloeys/nmage/level"
"github.com/bloeys/nmage/logging"
"github.com/bloeys/nmage/materials"
"github.com/bloeys/nmage/meshes"
@ -52,45 +54,45 @@ type OurGame struct {
ImGUIInfo nmageimgui.ImguiInfo
}
// type TransformComp struct {
// Pos *gglm.Vec3
// Rot *gglm.Quat
// Scale *gglm.Vec3
// }
type TransformComp struct {
Pos *gglm.Vec3
Rot *gglm.Quat
Scale *gglm.Vec3
}
// func (t TransformComp) Name() string {
// return "Transform Component"
// }
func (t TransformComp) Name() string {
return "Transform Component"
}
// func Test() {
func Test() {
// lvl := level.NewLevel("test level", 1000)
// e := lvl.Registry.NewEntity()
lvl := level.NewLevel("test level", 1000)
e1 := lvl.Registry.NewEntity()
// trComp := entity.GetComp[*TransformComp](e)
// fmt.Println("Got comp 1:", trComp)
trComp := entity.GetComp[*TransformComp](e1)
fmt.Println("Got comp 1:", trComp)
// e.Comps = append(e.Comps, &TransformComp{
// Pos: gglm.NewVec3(0, 0, 0),
// Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
// Scale: gglm.NewVec3(0, 0, 0),
// }, &TransformComp{
// Pos: gglm.NewVec3(0, 0, 0),
// Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
// Scale: gglm.NewVec3(1, 1, 1),
// })
e1.Comps = append(e1.Comps, &TransformComp{
Pos: gglm.NewVec3(0, 0, 0),
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
Scale: gglm.NewVec3(0, 0, 0),
}, &TransformComp{
Pos: gglm.NewVec3(0, 0, 0),
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
Scale: gglm.NewVec3(1, 1, 1),
})
// trComp = entity.GetComp[*TransformComp](e)
// fmt.Println("Got comp 2:", trComp)
trComp = entity.GetComp[*TransformComp](e1)
fmt.Println("Got comp 2:", trComp)
// trComps := entity.GetAllCompOfType[*TransformComp](e)
// fmt.Printf("Got comp 3: %+v, %+v\n", trComps[0], trComps[1])
trComps := entity.GetAllCompOfType[*TransformComp](e1)
fmt.Printf("Got comp 3: %+v, %+v\n", trComps[0], trComps[1])
// fmt.Printf("Entity: %+v\n", e)
// fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
// fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
// fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
// }
fmt.Printf("Entity: %+v\n", e1)
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
}
func main() {