mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Generational indices+get/free entity+free list
This commit is contained in:
@ -1,5 +1,19 @@
|
|||||||
package entity
|
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 {
|
type Entity struct {
|
||||||
|
|
||||||
// Byte 1: Generation; Byte 2: Flags; Bytes 3-8: Index
|
// Byte 1: Generation; Byte 2: Flags; Bytes 3-8: Index
|
||||||
@ -7,6 +21,26 @@ type Entity struct {
|
|||||||
Comps []Comp
|
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 {
|
type Comp interface {
|
||||||
Name() string
|
Name() string
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,30 +1,89 @@
|
|||||||
package entity
|
package entity
|
||||||
|
|
||||||
import "github.com/bloeys/nmage/assert"
|
import (
|
||||||
|
"github.com/bloeys/nmage/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type freeListitem struct {
|
||||||
|
EntityIndex uint64
|
||||||
|
nextFree *freeListitem
|
||||||
|
}
|
||||||
|
|
||||||
type Registry struct {
|
type Registry struct {
|
||||||
EntityCount uint64
|
EntityCount uint64
|
||||||
Entities []Entity
|
Entities []Entity
|
||||||
|
FreeList *freeListitem
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Registry) NewEntity() *Entity {
|
func (r *Registry) NewEntity() *Entity {
|
||||||
|
|
||||||
assert.T(r.EntityCount < uint64(len(r.Entities)), "Can not add more entities to registry because it is full")
|
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++ {
|
for i := 0; i < len(r.Entities); i++ {
|
||||||
|
|
||||||
// @TODO: Implement generational indices
|
|
||||||
e := &r.Entities[i]
|
e := &r.Entities[i]
|
||||||
if e.ID == 0 {
|
if GetFlags(e.ID) != byte(EntityFlag_Unknown) && !e.HasFlag(EntityFlag_Dead) {
|
||||||
r.EntityCount++
|
continue
|
||||||
e.ID = uint64(i) + 1
|
}
|
||||||
|
|
||||||
|
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
|
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 {
|
func NewRegistry(size uint32) *Registry {
|
||||||
|
|||||||
64
main.go
64
main.go
@ -8,7 +8,9 @@ import (
|
|||||||
"github.com/bloeys/nmage/assets"
|
"github.com/bloeys/nmage/assets"
|
||||||
"github.com/bloeys/nmage/camera"
|
"github.com/bloeys/nmage/camera"
|
||||||
"github.com/bloeys/nmage/engine"
|
"github.com/bloeys/nmage/engine"
|
||||||
|
"github.com/bloeys/nmage/entity"
|
||||||
"github.com/bloeys/nmage/input"
|
"github.com/bloeys/nmage/input"
|
||||||
|
"github.com/bloeys/nmage/level"
|
||||||
"github.com/bloeys/nmage/logging"
|
"github.com/bloeys/nmage/logging"
|
||||||
"github.com/bloeys/nmage/materials"
|
"github.com/bloeys/nmage/materials"
|
||||||
"github.com/bloeys/nmage/meshes"
|
"github.com/bloeys/nmage/meshes"
|
||||||
@ -52,45 +54,45 @@ type OurGame struct {
|
|||||||
ImGUIInfo nmageimgui.ImguiInfo
|
ImGUIInfo nmageimgui.ImguiInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// type TransformComp struct {
|
type TransformComp struct {
|
||||||
// Pos *gglm.Vec3
|
Pos *gglm.Vec3
|
||||||
// Rot *gglm.Quat
|
Rot *gglm.Quat
|
||||||
// Scale *gglm.Vec3
|
Scale *gglm.Vec3
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func (t TransformComp) Name() string {
|
func (t TransformComp) Name() string {
|
||||||
// return "Transform Component"
|
return "Transform Component"
|
||||||
// }
|
}
|
||||||
|
|
||||||
// func Test() {
|
func Test() {
|
||||||
|
|
||||||
// lvl := level.NewLevel("test level", 1000)
|
lvl := level.NewLevel("test level", 1000)
|
||||||
// e := lvl.Registry.NewEntity()
|
e1 := lvl.Registry.NewEntity()
|
||||||
|
|
||||||
// trComp := entity.GetComp[*TransformComp](e)
|
trComp := entity.GetComp[*TransformComp](e1)
|
||||||
// fmt.Println("Got comp 1:", trComp)
|
fmt.Println("Got comp 1:", trComp)
|
||||||
|
|
||||||
// e.Comps = append(e.Comps, &TransformComp{
|
e1.Comps = append(e1.Comps, &TransformComp{
|
||||||
// Pos: gglm.NewVec3(0, 0, 0),
|
Pos: gglm.NewVec3(0, 0, 0),
|
||||||
// Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||||
// Scale: gglm.NewVec3(0, 0, 0),
|
Scale: gglm.NewVec3(0, 0, 0),
|
||||||
// }, &TransformComp{
|
}, &TransformComp{
|
||||||
// Pos: gglm.NewVec3(0, 0, 0),
|
Pos: gglm.NewVec3(0, 0, 0),
|
||||||
// Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||||
// Scale: gglm.NewVec3(1, 1, 1),
|
Scale: gglm.NewVec3(1, 1, 1),
|
||||||
// })
|
})
|
||||||
|
|
||||||
// trComp = entity.GetComp[*TransformComp](e)
|
trComp = entity.GetComp[*TransformComp](e1)
|
||||||
// fmt.Println("Got comp 2:", trComp)
|
fmt.Println("Got comp 2:", trComp)
|
||||||
|
|
||||||
// trComps := entity.GetAllCompOfType[*TransformComp](e)
|
trComps := entity.GetAllCompOfType[*TransformComp](e1)
|
||||||
// fmt.Printf("Got comp 3: %+v, %+v\n", trComps[0], trComps[1])
|
fmt.Printf("Got comp 3: %+v, %+v\n", trComps[0], trComps[1])
|
||||||
|
|
||||||
// fmt.Printf("Entity: %+v\n", e)
|
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())
|
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() {
|
func main() {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user