forked from NateTheGreatt/bitECS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEntity.js
138 lines (110 loc) · 3.86 KB
/
Entity.js
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
import { resizeComponents } from './Component.js'
import { $notQueries, $queries, queryAddEntity, queryCheckEntity, queryRemoveEntity } from './Query.js'
import { $localEntities, $localEntityLookup, resizeWorlds } from './World.js'
import { setSerializationResized } from './Serialize.js'
export const $entityMasks = Symbol('entityMasks')
export const $entityComponents = Symbol('entityComponents')
export const $entitySparseSet = Symbol('entitySparseSet')
export const $entityArray = Symbol('entityArray')
export const $entityIndices = Symbol('entityIndices')
export const $removedEntities = Symbol('removedEntities')
let defaultSize = 100000
// need a global EID cursor which all worlds and all components know about
// so that world entities can posess entire rows spanning all component tables
let globalEntityCursor = 0
let globalSize = defaultSize
let resizeThreshold = () => globalSize - (globalSize / 5)
export const getGlobalSize = () => globalSize
// removed eids should also be global to prevent memory leaks
const removed = []
export const resetGlobals = () => {
globalSize = defaultSize
globalEntityCursor = 0
removed.length = 0
}
export const getDefaultSize = () => defaultSize
/**
* Sets the default maximum number of entities for worlds and component stores.
*
* @param {number} newSize
*/
export const setDefaultSize = newSize => {
const oldSize = globalSize
defaultSize = newSize
resetGlobals()
globalSize = newSize
resizeWorlds(newSize)
resizeComponents(newSize)
setSerializationResized(true)
console.info(`👾 bitECS - resizing all data stores from ${oldSize} to ${newSize}`)
}
export const getEntityCursor = () => globalEntityCursor
export const getRemovedEntities = () => removed
export const eidToWorld = new Map()
/**
* Adds a new entity to the specified world.
*
* @param {World} world
* @returns {number} eid
*/
export const addEntity = (world) => {
// if data stores are 80% full
if (globalEntityCursor >= resizeThreshold()) {
// grow by half the original size rounded up to a multiple of 4
const size = globalSize
const amount = Math.ceil((size/2) / 4) * 4
setDefaultSize(size + amount)
}
const eid = removed.length > Math.round(defaultSize * 0.01) ? removed.shift() : globalEntityCursor++
world[$entitySparseSet].add(eid)
eidToWorld.set(eid, world)
world[$notQueries].forEach(q => {
const match = queryCheckEntity(world, q, eid)
if (match) queryAddEntity(q, eid)
})
world[$entityComponents].set(eid, new Set())
return eid
}
/**
* Removes an existing entity from the specified world.
*
* @param {World} world
* @param {number} eid
*/
export const removeEntity = (world, eid) => {
// Check if entity is already removed
if (!world[$entitySparseSet].has(eid)) return
// Remove entity from all queries
// TODO: archetype graph
world[$queries].forEach(q => {
queryRemoveEntity(world, q, eid)
})
// Free the entity
removed.push(eid)
// remove all eid state from world
world[$entitySparseSet].remove(eid)
world[$entityComponents].delete(eid)
// remove from deserializer mapping
world[$localEntities].delete(world[$localEntityLookup].get(eid))
world[$localEntityLookup].delete(eid)
// Clear entity bitmasks
for (let i = 0; i < world[$entityMasks].length; i++) world[$entityMasks][i][eid] = 0
}
/**
* Returns an array of components that an entity possesses.
*
* @param {*} world
* @param {*} eid
*/
export const getEntityComponents = (world, eid) => {
if (eid === undefined) throw new Error('bitECS - entity is undefined.')
if (!world[$entitySparseSet].has(eid)) throw new Error('bitECS - entity does not exist in the world.')
return Array.from(world[$entityComponents].get(eid))
}
/**
* Checks the existence of an entity in a world
*
* @param {World} world
* @param {number} eid
*/
export const entityExists = (world, eid) => world[$entitySparseSet].has(eid)