• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / ark / 13619591564

02 Mar 2025 09:42PM CUT coverage: 97.72%. Remained the same
13619591564

push

github

web-flow
Update README (#103)

5101 of 5220 relevant lines covered (97.72%)

36056.23 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.63
/ecs/world_internal.go
1
package ecs
2

3
import (
4
        "reflect"
5
        "unsafe"
6
)
7

8
func (w *World) newEntityWith(ids []ID, comps []unsafe.Pointer, relations []RelationID) Entity {
501,023✔
9
        w.checkLocked()
501,023✔
10

501,023✔
11
        mask := NewMask(ids...)
501,023✔
12
        newTable := w.storage.findOrCreateTable(&w.storage.tables[0], &mask, relations)
501,023✔
13
        entity, idx := w.storage.createEntity(newTable.id)
501,023✔
14

501,023✔
15
        if comps != nil {
1,001,972✔
16
                if len(ids) != len(comps) {
500,949✔
17
                        panic("lengths of IDs and components to add do not match")
×
18
                }
19
                for i, id := range ids {
1,004,852✔
20
                        newTable.Set(id, idx, comps[i])
503,903✔
21
                }
503,903✔
22
        }
23
        w.storage.registerTargets(relations)
501,023✔
24
        return entity
501,023✔
25
}
26

27
func (w *World) newEntitiesWith(count int, ids []ID, comps []unsafe.Pointer, relations []RelationID) {
26✔
28
        w.checkLocked()
26✔
29

26✔
30
        mask := NewMask(ids...)
26✔
31
        newTable := w.storage.findOrCreateTable(&w.storage.tables[0], &mask, relations)
26✔
32

26✔
33
        startIdx := newTable.Len()
26✔
34
        w.storage.createEntities(newTable, count)
26✔
35

26✔
36
        if comps != nil {
52✔
37
                if len(ids) != len(comps) {
26✔
38
                        panic("lengths of IDs and components to add do not match")
×
39
                }
40
                for i := range count {
650✔
41
                        for j, id := range ids {
3,360✔
42
                                newTable.Set(id, uint32(startIdx+i), comps[j])
2,736✔
43
                        }
2,736✔
44
                }
45
        }
46
        w.storage.registerTargets(relations)
26✔
47
}
48

49
func (w *World) newEntities(count int, ids []ID, relations []RelationID) (tableID, int) {
107✔
50
        w.checkLocked()
107✔
51

107✔
52
        mask := NewMask(ids...)
107✔
53
        newTable := w.storage.findOrCreateTable(&w.storage.tables[0], &mask, relations)
107✔
54

107✔
55
        startIdx := newTable.Len()
107✔
56
        w.storage.createEntities(newTable, count)
107✔
57
        w.storage.registerTargets(relations)
107✔
58

107✔
59
        return newTable.id, startIdx
107✔
60
}
107✔
61

62
func (w *World) exchange(entity Entity, add []ID, rem []ID, addComps []unsafe.Pointer, relations []RelationID) {
646✔
63
        w.checkLocked()
646✔
64

646✔
65
        if !w.Alive(entity) {
646✔
66
                panic("can't exchange components on a dead entity")
×
67
        }
68
        if len(add) == 0 && len(rem) == 0 {
646✔
69
                if len(relations) > 0 {
×
70
                        panic("exchange operation has no effect, but relations were specified. Use SetRelation(s) instead")
×
71
                }
72
                return
×
73
        }
74

75
        index := &w.storage.entities[entity.id]
646✔
76
        oldTable := &w.storage.tables[index.table]
646✔
77
        oldArchetype := &w.storage.archetypes[oldTable.archetype]
646✔
78

646✔
79
        mask := oldArchetype.mask
646✔
80
        w.storage.getExchangeMask(&mask, add, rem)
646✔
81

646✔
82
        oldIDs := oldArchetype.components
646✔
83

646✔
84
        newTable := w.storage.findOrCreateTable(oldTable, &mask, relations)
646✔
85
        newIndex := newTable.Add(entity)
646✔
86

646✔
87
        for _, id := range oldIDs {
2,348✔
88
                if mask.Get(id) {
2,414✔
89
                        comp := oldTable.Get(id, uintptr(index.row))
712✔
90
                        newTable.Set(id, newIndex, comp)
712✔
91
                }
712✔
92
        }
93
        if addComps != nil {
973✔
94
                if len(add) != len(addComps) {
327✔
95
                        panic("lengths of IDs and components to add do not match")
×
96
                }
97
                for i, id := range add {
1,046✔
98
                        newTable.Set(id, newIndex, addComps[i])
719✔
99
                }
719✔
100
        }
101

102
        swapped := oldTable.Remove(index.row)
646✔
103

646✔
104
        if swapped {
744✔
105
                swapEntity := oldTable.GetEntity(uintptr(index.row))
98✔
106
                w.storage.entities[swapEntity.id].row = index.row
98✔
107
        }
98✔
108
        w.storage.entities[entity.id] = entityIndex{table: newTable.id, row: newIndex}
646✔
109

646✔
110
        w.storage.registerTargets(relations)
646✔
111
}
112

113
func (w *World) exchangeBatch(batch *Batch, add []ID, rem []ID,
114
        addComps []unsafe.Pointer, relations []RelationID, fn func(table tableID, start, len int)) {
80✔
115
        w.checkLocked()
80✔
116

80✔
117
        if len(add) == 0 && len(rem) == 0 {
80✔
118
                if len(relations) > 0 {
×
119
                        panic("exchange operation has no effect, but relations were specified. Use SetRelationBatch instead")
×
120
                }
121
                return
×
122
        }
123

124
        tables := w.getTables(batch)
80✔
125
        lengths := make([]uint32, len(tables))
80✔
126
        var totalEntities uint32 = 0
80✔
127
        for i, table := range tables {
240✔
128
                lengths[i] = uint32(table.Len())
160✔
129
                totalEntities += uint32(table.Len())
160✔
130
        }
160✔
131

132
        for i, table := range tables {
240✔
133
                tableLen := lengths[i]
160✔
134

160✔
135
                if tableLen == 0 {
160✔
136
                        continue
×
137
                }
138
                t, start, len := w.exchangeTable(table, int(tableLen), add, rem, addComps, relations)
160✔
139
                if fn != nil {
240✔
140
                        fn(t, start, len)
80✔
141
                }
80✔
142
        }
143
}
144

145
func (w *World) exchangeTable(oldTable *table, oldLen int, add []ID, rem []ID, addComps []unsafe.Pointer, relations []RelationID) (tableID, int, int) {
160✔
146
        oldArchetype := &w.storage.archetypes[oldTable.archetype]
160✔
147

160✔
148
        mask := oldArchetype.mask
160✔
149
        w.storage.getExchangeMask(&mask, add, rem)
160✔
150

160✔
151
        oldIDs := oldArchetype.components
160✔
152

160✔
153
        newTable := w.storage.findOrCreateTable(oldTable, &mask, relations)
160✔
154
        startIdx := uintptr(newTable.Len())
160✔
155
        count := uintptr(oldLen)
160✔
156

160✔
157
        var i uintptr
160✔
158
        for i = 0; i < count; i++ {
2,080✔
159
                idx := startIdx + i
1,920✔
160
                entity := oldTable.GetEntity(i)
1,920✔
161
                index := &w.storage.entities[entity.id]
1,920✔
162
                index.table = newTable.id
1,920✔
163
                index.row = uint32(idx)
1,920✔
164
        }
1,920✔
165

166
        newTable.AddAllEntities(oldTable, uint32(oldLen), true)
160✔
167
        for _, id := range oldIDs {
688✔
168
                if mask.Get(id) {
848✔
169
                        oldCol := oldTable.GetColumn(id)
320✔
170
                        newCol := newTable.GetColumn(id)
320✔
171
                        newCol.SetLast(oldCol, uint32(oldLen))
320✔
172
                }
320✔
173
        }
174
        if addComps != nil {
208✔
175
                if len(add) != len(addComps) {
48✔
176
                        panic("lengths of IDs and components to add do not match")
×
177
                }
178
                for i := range count {
624✔
179
                        for j, id := range add {
3,168✔
180
                                newTable.Set(id, uint32(startIdx+i), addComps[j])
2,592✔
181
                        }
2,592✔
182
                }
183
        }
184

185
        oldTable.Reset()
160✔
186
        w.storage.registerTargets(relations)
160✔
187

160✔
188
        return newTable.id, int(startIdx), int(count)
160✔
189
}
190

191
// setRelations sets the target entities for an entity relations.
192
func (w *World) setRelations(entity Entity, relations []RelationID) {
43✔
193
        w.checkLocked()
43✔
194

43✔
195
        if !w.storage.entityPool.Alive(entity) {
43✔
196
                panic("can't set relation for a dead entity")
×
197
        }
198
        if len(relations) == 0 {
43✔
199
                panic("ne relations specified")
×
200
        }
201

202
        index := &w.storage.entities[entity.id]
43✔
203
        oldTable := &w.storage.tables[index.table]
43✔
204

43✔
205
        newRelations, changed := w.storage.getExchangeTargets(oldTable, relations)
43✔
206
        if !changed {
43✔
207
                return
×
208
        }
×
209

210
        oldArch := &w.storage.archetypes[oldTable.archetype]
43✔
211
        newTable, ok := oldArch.GetTable(&w.storage, newRelations)
43✔
212
        if !ok {
55✔
213
                newTable = w.storage.createTable(oldArch, newRelations)
12✔
214
        }
12✔
215
        newIndex := newTable.Add(entity)
43✔
216

43✔
217
        for _, id := range oldArch.components {
149✔
218
                comp := oldTable.Get(id, uintptr(index.row))
106✔
219
                newTable.Set(id, newIndex, comp)
106✔
220
        }
106✔
221

222
        swapped := oldTable.Remove(index.row)
43✔
223

43✔
224
        if swapped {
59✔
225
                swapEntity := oldTable.GetEntity(uintptr(index.row))
16✔
226
                w.storage.entities[swapEntity.id].row = index.row
16✔
227
        }
16✔
228
        w.storage.entities[entity.id] = entityIndex{table: newTable.id, row: newIndex}
43✔
229

43✔
230
        w.storage.registerTargets(relations)
43✔
231
}
232

233
func (w *World) setRelationsBatch(batch *Batch, relations []RelationID, fn func(table tableID, start, len int)) {
9✔
234
        w.checkLocked()
9✔
235

9✔
236
        if len(relations) == 0 {
9✔
237
                panic("ne relations specified")
×
238
        }
239

240
        tables := w.getTables(batch)
9✔
241
        lengths := make([]uint32, len(tables))
9✔
242
        var totalEntities uint32 = 0
9✔
243
        for i, table := range tables {
18✔
244
                lengths[i] = uint32(table.Len())
9✔
245
                totalEntities += uint32(table.Len())
9✔
246
        }
9✔
247

248
        for i, table := range tables {
18✔
249
                tableLen := lengths[i]
9✔
250

9✔
251
                if tableLen == 0 {
9✔
252
                        continue
×
253
                }
254
                t, start, len := w.setRelationsTable(table, int(tableLen), relations)
9✔
255
                if fn != nil {
18✔
256
                        fn(t, start, len)
9✔
257
                }
9✔
258
        }
259

260
        w.storage.registerTargets(relations)
9✔
261
}
262

263
func (w *World) setRelationsTable(oldTable *table, oldLen int, relations []RelationID) (tableID, int, int) {
9✔
264
        newRelations, changed := w.storage.getExchangeTargets(oldTable, relations)
9✔
265

9✔
266
        if !changed {
9✔
267
                return oldTable.id, 0, oldLen
×
268
        }
×
269
        oldArch := &w.storage.archetypes[oldTable.archetype]
9✔
270
        newTable, ok := oldArch.GetTable(&w.storage, newRelations)
9✔
271
        if !ok {
18✔
272
                newTable = w.storage.createTable(oldArch, newRelations)
9✔
273
        }
9✔
274
        startIdx := newTable.Len()
9✔
275
        w.storage.moveEntities(oldTable, newTable, uint32(oldLen))
9✔
276

9✔
277
        return newTable.id, startIdx, oldLen
9✔
278

279
}
280

281
func (w *World) getTables(batch *Batch) []*table {
90✔
282
        tables := []*table{}
90✔
283

90✔
284
        for i := range w.storage.archetypes {
416✔
285
                archetype := &w.storage.archetypes[i]
326✔
286
                if !batch.filter.matches(&archetype.mask) {
481✔
287
                        continue
155✔
288
                }
289

290
                if !archetype.HasRelations() {
333✔
291
                        table := &w.storage.tables[archetype.tables[0]]
162✔
292
                        tables = append(tables, table)
162✔
293
                        continue
162✔
294
                }
295

296
                tableIDs := archetype.GetTables(batch.relations)
9✔
297
                for _, tab := range tableIDs {
18✔
298
                        table := &w.storage.tables[tab]
9✔
299
                        if !table.Matches(batch.relations) {
9✔
300
                                continue
×
301
                        }
302
                        tables = append(tables, table)
9✔
303
                }
304
        }
305
        return tables
90✔
306
}
307

308
func (w *World) componentID(tp reflect.Type) ID {
2,521✔
309
        id, newID := w.storage.registry.ComponentID(tp)
2,521✔
310
        if newID {
3,360✔
311
                if w.IsLocked() {
839✔
312
                        w.storage.registry.unregisterLastComponent()
×
313
                        panic("attempt to register a new component in a locked world")
×
314
                }
315
                w.storage.AddComponent(id)
839✔
316
        }
317
        return ID{id: id}
2,521✔
318
}
319

320
func (w *World) resourceID(tp reflect.Type) ResID {
9✔
321
        id, _ := w.resources.registry.ComponentID(tp)
9✔
322
        return ResID{id: id}
9✔
323
}
9✔
324

325
// lock the world and get the lock bit for later unlocking.
326
func (w *World) lock() uint8 {
1,394✔
327
        return w.locks.Lock()
1,394✔
328
}
1,394✔
329

330
// unlock unlocks the given lock bit.
331
func (w *World) unlock(l uint8) {
1,394✔
332
        w.locks.Unlock(l)
1,394✔
333
}
1,394✔
334

335
// checkLocked checks if the world is locked, and panics if so.
336
func (w *World) checkLocked() {
1,001,566✔
337
        if w.IsLocked() {
1,001,566✔
338
                panic("attempt to modify a locked world")
×
339
        }
340
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc