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

mlange-42 / ark / 15075416534

16 May 2025 06:54PM CUT coverage: 99.833%. Remained the same
15075416534

Pull #251

github

web-flow
Merge a3a4140a2 into 94436e9e0
Pull Request #251: Prepare release v0.4.3

8352 of 8366 relevant lines covered (99.83%)

18973.76 hits per line

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

98.05
/ecs/world_internal.go
1
package ecs
2

3
import (
4
        "reflect"
5
)
6

7
func (w *World) newEntity(ids []ID, relations []RelationID) Entity {
513,588✔
8
        w.checkLocked()
513,588✔
9
        mask := bitMask{}
513,588✔
10
        newTable := w.storage.findOrCreateTable(&w.storage.tables[0], ids, nil, relations, &mask)
513,588✔
11
        entity, _ := w.storage.createEntity(newTable.id)
513,588✔
12
        w.storage.registerTargets(relations)
513,588✔
13
        return entity
513,588✔
14
}
513,588✔
15

16
func (w *World) newEntities(count int, ids []ID, relations []RelationID) (tableID, int) {
196✔
17
        w.checkLocked()
196✔
18
        mask := bitMask{}
196✔
19
        newTable := w.storage.findOrCreateTable(&w.storage.tables[0], ids, nil, relations, &mask)
196✔
20
        startIdx := newTable.Len()
196✔
21
        w.storage.createEntities(newTable, count)
196✔
22
        w.storage.registerTargets(relations)
196✔
23
        return newTable.id, startIdx
196✔
24
}
196✔
25

26
func (w *World) exchange(entity Entity, add []ID, rem []ID, relations []RelationID) {
3,998✔
27
        w.checkLocked()
3,998✔
28

3,998✔
29
        if !w.Alive(entity) {
4,034✔
30
                panic("can't exchange components on a dead entity")
36✔
31
        }
32
        if len(add) == 0 && len(rem) == 0 {
3,964✔
33
                if len(relations) > 0 {
3✔
34
                        panic("exchange operation has no effect, but relations were specified. Use SetRelation(s) instead")
1✔
35
                }
36
                return
1✔
37
        }
38

39
        index := w.storage.entities[entity.id]
3,960✔
40
        oldTable := &w.storage.tables[index.table]
3,960✔
41
        oldArchetype := &w.storage.archetypes[oldTable.archetype]
3,960✔
42

3,960✔
43
        mask := *oldArchetype.mask
3,960✔
44
        newTable := w.storage.findOrCreateTable(oldTable, add, rem, relations, &mask)
3,960✔
45
        newIndex := newTable.Add(entity)
3,960✔
46

3,960✔
47
        // Get the old table and archetype again, as the pointer may have changed.
3,960✔
48
        oldTable = &w.storage.tables[oldTable.id]
3,960✔
49
        oldArchetype = &w.storage.archetypes[oldTable.archetype]
3,960✔
50

3,960✔
51
        for _, id := range oldArchetype.components {
10,711✔
52
                if mask.Get(id) {
11,481✔
53
                        newTable.Set(id, newIndex, oldTable.Column(id), int(index.row), w.storage.registry.IsTrivial[id.id])
4,730✔
54
                }
4,730✔
55
        }
56

57
        swapped := oldTable.Remove(index.row, &w.storage.registry)
3,960✔
58

3,960✔
59
        if swapped {
5,606✔
60
                swapEntity := oldTable.GetEntity(uintptr(index.row))
1,646✔
61
                w.storage.entities[swapEntity.id].row = index.row
1,646✔
62
        }
1,646✔
63
        w.storage.entities[entity.id] = entityIndex{table: newTable.id, row: newIndex}
3,960✔
64

3,960✔
65
        w.storage.registerTargets(relations)
3,960✔
66
}
67

68
func (w *World) exchangeBatch(batch *Batch, add []ID, rem []ID,
69
        relations []RelationID, fn func(table tableID, start, len int)) {
103✔
70
        w.checkLocked()
103✔
71

103✔
72
        if len(add) == 0 && len(rem) == 0 {
105✔
73
                if len(relations) > 0 {
3✔
74
                        panic("exchange operation has no effect, but relations were specified. Use SetRelationBatch instead")
1✔
75
                }
76
                return
1✔
77
        }
78

79
        tables := w.storage.getTables(batch)
101✔
80
        lengths := make([]uint32, len(tables))
101✔
81
        var totalEntities uint32 = 0
101✔
82
        for i, tableID := range tables {
302✔
83
                table := &w.storage.tables[tableID]
201✔
84
                lengths[i] = uint32(table.Len())
201✔
85
                totalEntities += uint32(table.Len())
201✔
86
        }
201✔
87

88
        for i, tableID := range tables {
302✔
89
                tableLen := lengths[i]
201✔
90

201✔
91
                if tableLen == 0 {
201✔
92
                        continue
×
93
                }
94
                table := &w.storage.tables[tableID]
201✔
95
                t, start, len := w.exchangeTable(table, int(tableLen), add, rem, relations)
201✔
96
                if fn != nil {
360✔
97
                        fn(t, start, len)
159✔
98
                }
159✔
99
        }
100
}
101

102
func (w *World) exchangeTable(oldTable *table, oldLen int, add []ID, rem []ID, relations []RelationID) (tableID, int, int) {
201✔
103
        oldArchetype := &w.storage.archetypes[oldTable.archetype]
201✔
104

201✔
105
        oldIDs := oldArchetype.components
201✔
106

201✔
107
        mask := *oldArchetype.mask
201✔
108
        newTable := w.storage.findOrCreateTable(oldTable, add, rem, relations, &mask)
201✔
109
        // Get the old table again, as pointers may have changed.
201✔
110
        oldTable = &w.storage.tables[oldTable.id]
201✔
111

201✔
112
        startIdx := uintptr(newTable.Len())
201✔
113
        count := uintptr(oldLen)
201✔
114

201✔
115
        var i uintptr
201✔
116
        for i = range count {
2,613✔
117
                idx := startIdx + i
2,412✔
118
                entity := oldTable.GetEntity(i)
2,412✔
119
                index := &w.storage.entities[entity.id]
2,412✔
120
                index.table = newTable.id
2,412✔
121
                index.row = uint32(idx)
2,412✔
122
        }
2,412✔
123

124
        newTable.AddAllEntities(oldTable, uint32(oldLen))
201✔
125
        for _, id := range oldIDs {
962✔
126
                if mask.Get(id) {
1,142✔
127
                        oldCol := oldTable.GetColumn(id)
381✔
128
                        newCol := newTable.GetColumn(id)
381✔
129
                        newCol.SetLast(oldCol, newTable.len, uint32(oldLen), w.storage.registry.IsTrivial[id.id])
381✔
130
                }
381✔
131
        }
132

133
        oldTable.Reset()
201✔
134
        w.storage.registerTargets(relations)
201✔
135

201✔
136
        return newTable.id, int(startIdx), int(count)
201✔
137
}
138

139
// setRelations sets the target entities for an entity relations.
140
func (w *World) setRelations(entity Entity, relations []RelationID) {
76✔
141
        w.checkLocked()
76✔
142

76✔
143
        if !w.storage.entityPool.Alive(entity) {
88✔
144
                panic("can't set relation for a dead entity")
12✔
145
        }
146
        if len(relations) == 0 {
76✔
147
                panic("no relations specified")
12✔
148
        }
149

150
        index := &w.storage.entities[entity.id]
52✔
151
        oldTable := &w.storage.tables[index.table]
52✔
152

52✔
153
        newRelations, changed := w.storage.getExchangeTargets(oldTable, relations)
52✔
154
        if !changed {
53✔
155
                return
1✔
156
        }
1✔
157

158
        oldArch := &w.storage.archetypes[oldTable.archetype]
50✔
159
        newTable, ok := oldArch.GetTable(&w.storage, newRelations)
50✔
160
        if !ok {
67✔
161
                newTable = w.storage.createTable(oldArch, newRelations)
17✔
162
                // Get the old table again, as pointers may have changed.
17✔
163
                oldTable = &w.storage.tables[oldTable.id]
17✔
164
        }
17✔
165
        newIndex := newTable.Add(entity)
50✔
166

50✔
167
        for _, id := range oldArch.components {
203✔
168
                newTable.Set(id, newIndex, oldTable.Column(id), int(index.row), w.storage.registry.IsTrivial[id.id])
153✔
169
        }
153✔
170

171
        swapped := oldTable.Remove(index.row, &w.storage.registry)
50✔
172

50✔
173
        if swapped {
66✔
174
                swapEntity := oldTable.GetEntity(uintptr(index.row))
16✔
175
                w.storage.entities[swapEntity.id].row = index.row
16✔
176
        }
16✔
177
        w.storage.entities[entity.id] = entityIndex{table: newTable.id, row: newIndex}
50✔
178

50✔
179
        w.storage.registerTargets(relations)
50✔
180
}
181

182
func (w *World) setRelationsBatch(batch *Batch, relations []RelationID, fn func(table tableID, start, len int)) {
25✔
183
        w.checkLocked()
25✔
184

25✔
185
        if len(relations) == 0 {
37✔
186
                panic("no relations specified")
12✔
187
        }
188

189
        tables := w.storage.getTables(batch)
13✔
190
        lengths := make([]uint32, len(tables))
13✔
191
        var totalEntities uint32 = 0
13✔
192
        for i, tableID := range tables {
26✔
193
                table := &w.storage.tables[tableID]
13✔
194
                lengths[i] = uint32(table.Len())
13✔
195
                totalEntities += uint32(table.Len())
13✔
196
        }
13✔
197

198
        for i, tableID := range tables {
26✔
199
                tableLen := lengths[i]
13✔
200

13✔
201
                if tableLen == 0 {
13✔
202
                        continue
×
203
                }
204
                table := &w.storage.tables[tableID]
13✔
205
                t, start, len := w.setRelationsTable(table, int(tableLen), relations)
13✔
206
                if fn != nil {
26✔
207
                        fn(t, start, len)
13✔
208
                }
13✔
209
        }
210

211
        w.storage.registerTargets(relations)
13✔
212
}
213

214
func (w *World) setRelationsTable(oldTable *table, oldLen int, relations []RelationID) (tableID, int, int) {
13✔
215
        newRelations, changed := w.storage.getExchangeTargets(oldTable, relations)
13✔
216

13✔
217
        if !changed {
13✔
218
                return oldTable.id, 0, oldLen
×
219
        }
×
220
        oldArch := &w.storage.archetypes[oldTable.archetype]
13✔
221
        newTable, ok := oldArch.GetTable(&w.storage, newRelations)
13✔
222
        if !ok {
26✔
223
                newTable = w.storage.createTable(oldArch, newRelations)
13✔
224
                // Get the old table again, as pointers may have changed.
13✔
225
                oldTable = &w.storage.tables[oldTable.id]
13✔
226
        }
13✔
227
        startIdx := newTable.Len()
13✔
228
        w.storage.moveEntities(oldTable, newTable, uint32(oldLen))
13✔
229

13✔
230
        return newTable.id, startIdx, oldLen
13✔
231

232
}
233

234
func (w *World) componentID(tp reflect.Type) ID {
5,401✔
235
        id, newID := w.storage.registry.ComponentID(tp)
5,401✔
236
        if newID {
6,729✔
237
                if w.IsLocked() {
1,329✔
238
                        w.storage.registry.unregisterLastComponent()
1✔
239
                        panic("attempt to register a new component in a locked world")
1✔
240
                }
241
                w.storage.AddComponent(id)
1,327✔
242
        }
243
        return ID{id: id}
5,400✔
244
}
245

246
func (w *World) resourceID(tp reflect.Type) ResID {
17✔
247
        id, _ := w.resources.registry.ComponentID(tp)
17✔
248
        return ResID{id: id}
17✔
249
}
17✔
250

251
// lock the world and get the lock bit for later unlocking.
252
func (w *World) lock() uint8 {
1,629✔
253
        return w.locks.Lock()
1,629✔
254
}
1,629✔
255

256
// unlock unlocks the given lock bit.
257
func (w *World) unlock(l uint8) {
1,628✔
258
        w.locks.Unlock(l)
1,628✔
259
}
1,628✔
260

261
// checkLocked checks if the world is locked, and panics if so.
262
func (w *World) checkLocked() {
1,029,202✔
263
        if w.IsLocked() {
1,029,203✔
264
                panic("attempt to modify a locked world")
1✔
265
        }
266
}
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