-
Notifications
You must be signed in to change notification settings - Fork 23
/
component.go
175 lines (147 loc) · 4.79 KB
/
component.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package donburi
import (
"fmt"
"iter"
"reflect"
"unsafe"
"github.com/yohamta/donburi/component"
"github.com/yohamta/donburi/filter"
)
// IComponentType is an interface for component types.
type IComponentType = component.IComponentType
// NewComponentType creates a new component type.
// The function is used to create a new component of the type.
// It receives a function that returns a pointer to a new component.
// The first argument is a default value of the component.
func NewComponentType[T any](opts ...interface{}) *ComponentType[T] {
var t T
if len(opts) == 0 {
return newComponentType(t, nil)
}
return newComponentType(t, opts[0])
}
// CompnentType represents a type of component. It is used to identify
// a component when getting or setting components of an entity.
type ComponentType[T any] struct {
id component.ComponentTypeId
typ reflect.Type
name string
defaultVal interface{}
query *Query
}
// Typ returns the reflect.Type of the ComponentType.
func (c *ComponentType[T]) Typ() reflect.Type {
return c.typ
}
// Get returns component data from the entry.
func (c *ComponentType[T]) Get(entry *Entry) *T {
return (*T)(entry.Component(c))
}
// GetValue returns value of the component from the entry.
func (c *ComponentType[T]) GetValue(entry *Entry) T {
return *Get[T](entry, c)
}
// Set sets component data to the entry.
func (c *ComponentType[T]) Set(entry *Entry, component *T) {
entry.SetComponent(c, unsafe.Pointer(component))
}
// Each iterates over the entities that have the component.
func (c *ComponentType[T]) Each(w World, callback func(*Entry)) {
c.query.Each(w, callback)
}
// Iter returns an iterator for the entities that have the component.
func (c *ComponentType[T]) Iter(w World) iter.Seq[*Entry] {
return c.query.Iter(w)
}
// deprecated: use Each instead
func (c *ComponentType[T]) EachEntity(w World, callback func(*Entry)) {
c.Each(w, callback)
}
// First returns the first entity that has the component.
func (c *ComponentType[T]) First(w World) (*Entry, bool) {
return c.query.First(w)
}
// deprecated: use First instead
func (c *ComponentType[T]) FirstEntity(w World) (*Entry, bool) {
return c.First(w)
}
// MustFirst returns the first entity that has the component or panics.
func (c *ComponentType[T]) MustFirst(w World) *Entry {
e, ok := c.query.First(w)
if !ok {
panic(fmt.Sprintf("no entity has the component %s", c.name))
}
return e
}
// deprecated: use MustFirst instead
func (c *ComponentType[T]) MustFirstEntity(w World) *Entry {
return c.MustFirst(w)
}
// SetValue sets the value of the component.
func (c *ComponentType[T]) SetValue(entry *Entry, value T) {
comp := c.Get(entry)
*comp = value
}
// String returns the component type name.
func (c *ComponentType[T]) String() string {
return c.name
}
// SetName sets the component type name.
func (c *ComponentType[T]) SetName(name string) *ComponentType[T] {
c.name = name
return c
}
// Name returns the component type name.
func (c *ComponentType[T]) Name() string {
return c.name
}
// Id returns the component type id.
func (c *ComponentType[T]) Id() component.ComponentTypeId {
return c.id
}
func (c *ComponentType[T]) New() unsafe.Pointer {
val := reflect.New(c.typ)
v := reflect.Indirect(val)
ptr := unsafe.Pointer(v.UnsafeAddr())
if c.defaultVal != nil {
c.setDefaultVal(ptr)
}
return ptr
}
func (c *ComponentType[T]) setDefaultVal(ptr unsafe.Pointer) {
v := reflect.Indirect(reflect.ValueOf(c.defaultVal))
reflect.NewAt(c.typ, ptr).Elem().Set(v)
}
func (c *ComponentType[T]) validateDefaultVal() {
if !reflect.TypeOf(c.defaultVal).AssignableTo(c.typ) {
err := fmt.Sprintf("default value is not assignable to component type: %s", c.name)
panic(err)
}
}
var nextComponentTypeId component.ComponentTypeId = 1
var globalComponentTypes []component.IComponentType
// NewComponentType creates a new component type.
// The argument is a struct that represents a data of the component.
func newComponentType[T any](s T, defaultVal interface{}) *ComponentType[T] {
typ := reflect.TypeOf(s)
componentType := &ComponentType[T]{
id: nextComponentTypeId,
typ: typ,
name: typ.Name(),
defaultVal: defaultVal,
}
componentType.query = NewQuery(filter.Contains(componentType))
if defaultVal != nil {
componentType.validateDefaultVal()
}
nextComponentTypeId++
globalComponentTypes = append(globalComponentTypes, componentType)
return componentType
}
// AllComponentTypes returns all IComponentTypes created at that point in time.
// All types created using `donburi.NewComponentType()` will be in this list.
// This is useful if you want to use introspection on the ECS, such as when doing (de)serialization.
// This includes components which are not in any archetypes or on any entity.
func AllComponentTypes() []IComponentType {
return globalComponentTypes
}