package gohan import ( "reflect" ) // 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 // 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 } func componentIDByValue(v interface{}) componentID { sV := reflect.ValueOf(v) sT := reflect.TypeOf(v) if sV.Kind() == reflect.Ptr { sV = sV.Elem() sT = sT.Elem() } componentName := sV.Type().String() return componentIDByName(componentName) } func componentIDByName(name string) componentID { if len(name) == 0 { return 0 } if name[0:1] == "*" { name = name[1:] } if !w.haveSystemComponentName[name] { w.systemComponentNames = append(w.systemComponentNames, name) w.haveSystemComponentName[name] = true id := newComponentID() return id } for i, savedName := range w.systemComponentNames { if savedName == name { return componentID(i) } } return 0 } // AddComponent adds a Component to an Entity. func (e Entity) AddComponent(component interface{}) { w.componentMutex.Lock() defer w.componentMutex.Unlock() id := componentIDByValue(component) w.components[e][id] = component w.entityMutex.Lock() defer w.entityMutex.Unlock() w.modifiedEntities = append(w.modifiedEntities, e) } // With accepts any function which takes one or more components as arguments. // This function will block until the provided function returns. func (e Entity) With(f interface{}) { components := w.components[e] 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()) arg := reflect.ValueOf(components[id]) if components[id] == nil { arg = reflect.New(t.In(i)).Elem() } args[i] = arg } v.Call(args) } // getComponent gets a Component of an Entity. func (e Entity) getComponent(componentID componentID) interface{} { components := w.components[e] if components == nil { return nil } return components[componentID] }