gohan/component.go

111 lines
2.4 KiB
Go
Raw Permalink Normal View History

2021-11-19 04:13:28 +00:00
package gohan
2021-12-12 05:04:11 +00:00
import (
"reflect"
2021-12-12 05:04:11 +00:00
)
// componentID is a component identifier. Each Component is assigned a unique ID
// via world.NewComponentID, and implements a componentID method returning its ID.
type componentID int
2021-11-19 04:13:28 +00:00
// newComponentID returns the next available componentID.
func newComponentID() componentID {
w.maxComponentID++
for i := Entity(1); i <= w.maxEntityID; i++ {
w.components[i] = append(w.components[i], nil)
}
return w.maxComponentID
2021-11-19 04:13:28 +00:00
}
func componentIDByValue(v interface{}) componentID {
sV := reflect.ValueOf(v)
sT := reflect.TypeOf(v)
if sV.Kind() == reflect.Ptr {
sV = sV.Elem()
sT = sT.Elem()
}
2021-11-19 04:13:28 +00:00
componentName := sV.Type().String()
return componentIDByName(componentName)
}
2021-11-19 04:13:28 +00:00
func componentIDByName(name string) componentID {
if len(name) == 0 {
return 0
}
if name[0:1] == "*" {
name = name[1:]
2021-11-19 04:13:28 +00:00
}
if !w.haveSystemComponentName[name] {
w.systemComponentNames = append(w.systemComponentNames, name)
w.haveSystemComponentName[name] = true
2022-06-11 08:05:47 +00:00
id := newComponentID()
return id
}
2021-12-12 05:04:11 +00:00
for i, savedName := range w.systemComponentNames {
if savedName == name {
return componentID(i)
}
}
return 0
}
// AddComponent adds a Component to an Entity.
2022-06-11 00:44:51 +00:00
func (e Entity) AddComponent(component interface{}) {
w.componentMutex.Lock()
defer w.componentMutex.Unlock()
id := componentIDByValue(component)
2022-06-11 00:44:51 +00:00
w.components[e][id] = component
2021-11-19 04:13:28 +00:00
w.entityMutex.Lock()
defer w.entityMutex.Unlock()
2022-06-11 00:44:51 +00:00
w.modifiedEntities = append(w.modifiedEntities, e)
2021-11-19 04:13:28 +00:00
}
2022-02-10 20:21:03 +00:00
// With accepts any function which takes one or more components as arguments.
// This function will block until the provided function returns.
2022-06-11 00:44:51 +00:00
func (e Entity) With(f interface{}) {
components := w.components[e]
2022-02-10 20:21:03 +00:00
if components == nil {
return
}
t := reflect.TypeOf(f)
v := reflect.ValueOf(f)
numIn := t.NumIn()
if t.Kind() != reflect.Func || v.IsNil() || numIn == 0 {
panic("component.With() must be provided with a function containing one or more components as arguments")
}
args := make([]reflect.Value, numIn)
for i := 0; i < numIn; i++ {
id := componentIDByName(t.In(i).String())
2022-06-11 08:05:47 +00:00
arg := reflect.ValueOf(components[id])
if components[id] == nil {
arg = reflect.New(t.In(i)).Elem()
}
args[i] = arg
2022-02-10 20:21:03 +00:00
}
v.Call(args)
}
// getComponent gets a Component of an Entity.
2022-06-11 00:44:51 +00:00
func (e Entity) getComponent(componentID componentID) interface{} {
components := w.components[e]
2021-11-19 04:13:28 +00:00
if components == nil {
return nil
}
return components[componentID]
}