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

mlange-42 / ark / 13898493716

17 Mar 2025 11:37AM CUT coverage: 99.782%. Remained the same
13898493716

push

github

web-flow
Update how to cite (#209)

8244 of 8262 relevant lines covered (99.78%)

20288.75 hits per line

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

96.88
/ecs/world_internal.go
1
package ecs
2

3
import (
4
        "reflect"
5
)
6

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

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

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

997✔
29
        if !w.Alive(entity) {
1,033✔
30
                panic("can't exchange components on a dead entity")
36✔
31
        }
32
        if len(add) == 0 && len(rem) == 0 {
963✔
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]
959✔
40
        oldTable := &w.storage.tables[index.table]
959✔
41
        oldArchetype := &w.storage.archetypes[oldTable.archetype]
959✔
42

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

959✔
47
        for _, id := range oldArchetype.components {
3,707✔
48
                if mask.Get(id) {
3,476✔
49
                        comp := oldTable.Get(id, uintptr(index.row))
728✔
50
                        newTable.Set(id, newIndex, comp)
728✔
51
                }
728✔
52
        }
53

54
        swapped := oldTable.Remove(index.row)
959✔
55

959✔
56
        if swapped {
1,105✔
57
                swapEntity := oldTable.GetEntity(uintptr(index.row))
146✔
58
                w.storage.entities[swapEntity.id].row = index.row
146✔
59
        }
146✔
60
        w.storage.entities[entity.id] = entityIndex{table: newTable.id, row: newIndex}
959✔
61

959✔
62
        w.storage.registerTargets(relations)
959✔
63
}
64

65
func (w *World) exchangeBatch(batch *Batch, add []ID, rem []ID,
66
        relations []RelationID, fn func(table tableID, start, len int)) {
102✔
67
        w.checkLocked()
102✔
68

102✔
69
        if len(add) == 0 && len(rem) == 0 {
104✔
70
                if len(relations) > 0 {
3✔
71
                        panic("exchange operation has no effect, but relations were specified. Use SetRelationBatch instead")
1✔
72
                }
73
                return
1✔
74
        }
75

76
        tables := w.storage.getTables(batch)
100✔
77
        lengths := make([]uint32, len(tables))
100✔
78
        var totalEntities uint32 = 0
100✔
79
        for i, table := range tables {
300✔
80
                lengths[i] = uint32(table.Len())
200✔
81
                totalEntities += uint32(table.Len())
200✔
82
        }
200✔
83

84
        for i, table := range tables {
300✔
85
                tableLen := lengths[i]
200✔
86

200✔
87
                if tableLen == 0 {
200✔
88
                        continue
×
89
                }
90
                t, start, len := w.exchangeTable(table, int(tableLen), add, rem, relations)
200✔
91
                if fn != nil {
358✔
92
                        fn(t, start, len)
158✔
93
                }
158✔
94
        }
95
}
96

97
func (w *World) exchangeTable(oldTable *table, oldLen int, add []ID, rem []ID, relations []RelationID) (tableID, int, int) {
200✔
98
        oldArchetype := &w.storage.archetypes[oldTable.archetype]
200✔
99

200✔
100
        oldIDs := oldArchetype.components
200✔
101

200✔
102
        mask := oldArchetype.mask
200✔
103
        newTable := w.storage.findOrCreateTable(oldTable, add, rem, relations, &mask)
200✔
104
        startIdx := uintptr(newTable.Len())
200✔
105
        count := uintptr(oldLen)
200✔
106

200✔
107
        var i uintptr
200✔
108
        for i = 0; i < count; i++ {
2,600✔
109
                idx := startIdx + i
2,400✔
110
                entity := oldTable.GetEntity(i)
2,400✔
111
                index := &w.storage.entities[entity.id]
2,400✔
112
                index.table = newTable.id
2,400✔
113
                index.row = uint32(idx)
2,400✔
114
        }
2,400✔
115

116
        newTable.AddAllEntities(oldTable, uint32(oldLen))
200✔
117
        for _, id := range oldIDs {
960✔
118
                if mask.Get(id) {
1,140✔
119
                        oldCol := oldTable.GetColumn(id)
380✔
120
                        newCol := newTable.GetColumn(id)
380✔
121
                        newCol.SetLast(oldCol, newTable.len, uint32(oldLen))
380✔
122
                }
380✔
123
        }
124

125
        oldTable.Reset()
200✔
126
        w.storage.registerTargets(relations)
200✔
127

200✔
128
        return newTable.id, int(startIdx), int(count)
200✔
129
}
130

131
// setRelations sets the target entities for an entity relations.
132
func (w *World) setRelations(entity Entity, relations []RelationID) {
73✔
133
        w.checkLocked()
73✔
134

73✔
135
        if !w.storage.entityPool.Alive(entity) {
85✔
136
                panic("can't set relation for a dead entity")
12✔
137
        }
138
        if len(relations) == 0 {
73✔
139
                panic("no relations specified")
12✔
140
        }
141

142
        index := &w.storage.entities[entity.id]
49✔
143
        oldTable := &w.storage.tables[index.table]
49✔
144

49✔
145
        newRelations, changed := w.storage.getExchangeTargets(oldTable, relations)
49✔
146
        if !changed {
49✔
147
                return
×
148
        }
×
149

150
        oldArch := &w.storage.archetypes[oldTable.archetype]
49✔
151
        newTable, ok := oldArch.GetTable(&w.storage, newRelations)
49✔
152
        if !ok {
66✔
153
                newTable = w.storage.createTable(oldArch, newRelations)
17✔
154
        }
17✔
155
        newIndex := newTable.Add(entity)
49✔
156

49✔
157
        for _, id := range oldArch.components {
199✔
158
                comp := oldTable.Get(id, uintptr(index.row))
150✔
159
                newTable.Set(id, newIndex, comp)
150✔
160
        }
150✔
161

162
        swapped := oldTable.Remove(index.row)
49✔
163

49✔
164
        if swapped {
65✔
165
                swapEntity := oldTable.GetEntity(uintptr(index.row))
16✔
166
                w.storage.entities[swapEntity.id].row = index.row
16✔
167
        }
16✔
168
        w.storage.entities[entity.id] = entityIndex{table: newTable.id, row: newIndex}
49✔
169

49✔
170
        w.storage.registerTargets(relations)
49✔
171
}
172

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

25✔
176
        if len(relations) == 0 {
37✔
177
                panic("no relations specified")
12✔
178
        }
179

180
        tables := w.storage.getTables(batch)
13✔
181
        lengths := make([]uint32, len(tables))
13✔
182
        var totalEntities uint32 = 0
13✔
183
        for i, table := range tables {
26✔
184
                lengths[i] = uint32(table.Len())
13✔
185
                totalEntities += uint32(table.Len())
13✔
186
        }
13✔
187

188
        for i, table := range tables {
26✔
189
                tableLen := lengths[i]
13✔
190

13✔
191
                if tableLen == 0 {
13✔
192
                        continue
×
193
                }
194
                t, start, len := w.setRelationsTable(table, int(tableLen), relations)
13✔
195
                if fn != nil {
26✔
196
                        fn(t, start, len)
13✔
197
                }
13✔
198
        }
199

200
        w.storage.registerTargets(relations)
13✔
201
}
202

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

13✔
206
        if !changed {
13✔
207
                return oldTable.id, 0, oldLen
×
208
        }
×
209
        oldArch := &w.storage.archetypes[oldTable.archetype]
13✔
210
        newTable, ok := oldArch.GetTable(&w.storage, newRelations)
13✔
211
        if !ok {
26✔
212
                newTable = w.storage.createTable(oldArch, newRelations)
13✔
213
        }
13✔
214
        startIdx := newTable.Len()
13✔
215
        w.storage.moveEntities(oldTable, newTable, uint32(oldLen))
13✔
216

13✔
217
        return newTable.id, startIdx, oldLen
13✔
218

219
}
220

221
func (w *World) componentID(tp reflect.Type) ID {
3,388✔
222
        id, newID := w.storage.registry.ComponentID(tp)
3,388✔
223
        if newID {
4,709✔
224
                if w.IsLocked() {
1,322✔
225
                        w.storage.registry.unregisterLastComponent()
1✔
226
                        panic("attempt to register a new component in a locked world")
1✔
227
                }
228
                w.storage.AddComponent(id)
1,320✔
229
        }
230
        return ID{id: id}
3,387✔
231
}
232

233
func (w *World) resourceID(tp reflect.Type) ResID {
15✔
234
        id, _ := w.resources.registry.ComponentID(tp)
15✔
235
        return ResID{id: id}
15✔
236
}
15✔
237

238
// lock the world and get the lock bit for later unlocking.
239
func (w *World) lock() uint8 {
1,622✔
240
        return w.locks.Lock()
1,622✔
241
}
1,622✔
242

243
// unlock unlocks the given lock bit.
244
func (w *World) unlock(l uint8) {
1,621✔
245
        w.locks.Unlock(l)
1,621✔
246
}
1,621✔
247

248
// checkLocked checks if the world is locked, and panics if so.
249
func (w *World) checkLocked() {
997,240✔
250
        if w.IsLocked() {
997,241✔
251
                panic("attempt to modify a locked world")
1✔
252
        }
253
}
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