mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Name the builtin components (#117)
* Add nth parameter to world:target * Put archetype record creation into function * Fix docs and comments * Make EcsWildcard a component * Name the builtin components
This commit is contained in:
parent
07efaf39e9
commit
f8b2c8c2b3
2 changed files with 322 additions and 282 deletions
|
@ -57,7 +57,7 @@ local function flip()
|
||||||
end
|
end
|
||||||
|
|
||||||
local common = 0
|
local common = 0
|
||||||
local N = 2^16-2
|
local N = 5000
|
||||||
local archetypes = {}
|
local archetypes = {}
|
||||||
|
|
||||||
local hm = 0
|
local hm = 0
|
||||||
|
@ -170,13 +170,8 @@ return {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
Functions = {
|
Functions = {
|
||||||
Matter = function()
|
Mirror = function()
|
||||||
for entityId, firstComponent in newWorld:query(A1, A2, A3, A4) do
|
for entityId, firstComponent in mcs:query(E1, E2, E3, E4) do
|
||||||
end
|
|
||||||
end,
|
|
||||||
|
|
||||||
ECR = function()
|
|
||||||
for entityId, firstComponent in registry2:view(B1, B2, B3, B3) do
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
|
593
src/init.luau
593
src/init.luau
|
@ -69,9 +69,8 @@ local EcsOnDelete = HI_COMPONENT_ID + 7
|
||||||
local EcsOnDeleteTarget = HI_COMPONENT_ID + 8
|
local EcsOnDeleteTarget = HI_COMPONENT_ID + 8
|
||||||
local EcsDelete = HI_COMPONENT_ID + 9
|
local EcsDelete = HI_COMPONENT_ID + 9
|
||||||
local EcsRemove = HI_COMPONENT_ID + 10
|
local EcsRemove = HI_COMPONENT_ID + 10
|
||||||
local EcsTag = HI_COMPONENT_ID + 11
|
local EcsName = HI_COMPONENT_ID + 11
|
||||||
local EcsName = HI_COMPONENT_ID + 12
|
local EcsRest = HI_COMPONENT_ID + 12
|
||||||
local EcsRest = HI_COMPONENT_ID + 13
|
|
||||||
|
|
||||||
local ECS_PAIR_FLAG = 0x8
|
local ECS_PAIR_FLAG = 0x8
|
||||||
local ECS_ID_FLAGS_MASK = 0x10
|
local ECS_ID_FLAGS_MASK = 0x10
|
||||||
|
@ -937,7 +936,7 @@ local function ARM(query, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
local EMPTY_LIST = {}
|
local EMPTY_LIST = {}
|
||||||
local EmptyQuery = {
|
local EMPTY_QUERY = {
|
||||||
__iter = function()
|
__iter = function()
|
||||||
return NOOP
|
return NOOP
|
||||||
end,
|
end,
|
||||||
|
@ -954,76 +953,73 @@ local EmptyQuery = {
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
setmetatable(EmptyQuery, EmptyQuery)
|
setmetatable(EMPTY_QUERY, EMPTY_QUERY)
|
||||||
|
|
||||||
local function columns_replace_values(row, columns, ...)
|
local function query_init(query)
|
||||||
for i, column in columns do
|
local world_query_iter_next = query.iter_next
|
||||||
column[row] = select(i, ...)
|
if world_query_iter_next then
|
||||||
|
return world_query_iter_next
|
||||||
|
end
|
||||||
|
local compatible_archetypes = query.compatible_archetypes
|
||||||
|
local ids = query.ids
|
||||||
|
local A, B, C, D, E, F, G, H, I = unpack(ids)
|
||||||
|
local a, b, c, d, e, f, g, h
|
||||||
|
local lastArchetype = 1
|
||||||
|
local archetype = compatible_archetypes[1]
|
||||||
|
if not archetype then
|
||||||
|
return EMPTY_QUERY
|
||||||
end
|
end
|
||||||
end
|
local columns = archetype.columns
|
||||||
|
local entities = archetype.entities
|
||||||
|
local i = #entities
|
||||||
|
|
||||||
local function world_query(world: World, ...)
|
local records = archetype.records
|
||||||
local compatible_archetypes = {}
|
if not B then
|
||||||
local length = 0
|
a = columns[records[A].column]
|
||||||
|
elseif not C then
|
||||||
local ids = { ... }
|
a = columns[records[A].column]
|
||||||
local A, B, C, D, E, F, G, H, I = ...
|
b = columns[records[B].column]
|
||||||
local a, b, c, d, e, f, g, h
|
elseif not D then
|
||||||
|
a = columns[records[A].column]
|
||||||
local archetypes = world.archetypes
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
local idr: ArchetypeMap
|
elseif not E then
|
||||||
local componentIndex = world.componentIndex
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
for _, id in ids do
|
c = columns[records[C].column]
|
||||||
local map = componentIndex[id]
|
d = columns[records[D].column]
|
||||||
if not map then
|
elseif not F then
|
||||||
return EmptyQuery
|
a = columns[records[A].column]
|
||||||
end
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
if idr == nil or map.size < idr.size then
|
d = columns[records[D].column]
|
||||||
idr = map
|
e = columns[records[E].column]
|
||||||
end
|
elseif not G then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
elseif not H then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
g = columns[records[G].column]
|
||||||
|
elseif not I then
|
||||||
|
a = columns[records[A].column]
|
||||||
|
b = columns[records[B].column]
|
||||||
|
c = columns[records[C].column]
|
||||||
|
d = columns[records[D].column]
|
||||||
|
e = columns[records[E].column]
|
||||||
|
f = columns[records[F].column]
|
||||||
|
g = columns[records[G].column]
|
||||||
|
h = columns[records[H].column]
|
||||||
end
|
end
|
||||||
|
|
||||||
for archetype_id in idr.cache do
|
|
||||||
local compatibleArchetype = archetypes[archetype_id]
|
|
||||||
if #compatibleArchetype.entities == 0 then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
local records = compatibleArchetype.records
|
|
||||||
|
|
||||||
local skip = false
|
|
||||||
|
|
||||||
for i, id in ids do
|
|
||||||
local tr = records[id]
|
|
||||||
if not tr then
|
|
||||||
skip = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if skip then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
length += 1
|
|
||||||
compatible_archetypes[length] = compatibleArchetype
|
|
||||||
end
|
|
||||||
|
|
||||||
if length == 0 then
|
|
||||||
return EmptyQuery
|
|
||||||
end
|
|
||||||
|
|
||||||
local lastArchetype = 1
|
|
||||||
local archetype
|
|
||||||
local columns
|
|
||||||
local entities
|
|
||||||
local i
|
|
||||||
local queryOutput
|
|
||||||
|
|
||||||
local world_query_iter_next
|
|
||||||
|
|
||||||
if not B then
|
if not B then
|
||||||
function world_query_iter_next(): any
|
function world_query_iter_next(): any
|
||||||
local entityId = entities[i]
|
local entityId = entities[i]
|
||||||
|
@ -1135,6 +1131,7 @@ local function world_query(world: World, ...)
|
||||||
return entityId, a[row], b[row], c[row], d[row]
|
return entityId, a[row], b[row], c[row], d[row]
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
local queryOutput = {}
|
||||||
function world_query_iter_next(): any
|
function world_query_iter_next(): any
|
||||||
local entityId = entities[i]
|
local entityId = entities[i]
|
||||||
while entityId == nil do
|
while entityId == nil do
|
||||||
|
@ -1208,221 +1205,210 @@ local function world_query(world: World, ...)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local init = false
|
query.iter_next = world_query_iter_next
|
||||||
local drain = false
|
return world_query_iter_next
|
||||||
|
end
|
||||||
|
|
||||||
local function query_init(query)
|
local function query_iter(query)
|
||||||
if init and drain then
|
return query_init(query)
|
||||||
return true
|
end
|
||||||
end
|
|
||||||
|
|
||||||
init = true
|
local function query_drain(query)
|
||||||
lastArchetype = 1
|
local query_iter_next = query_init(query)
|
||||||
archetype = compatible_archetypes[lastArchetype]
|
query.next = query_iter_next
|
||||||
|
return query
|
||||||
|
end
|
||||||
|
|
||||||
if not archetype then
|
local function query_next(query)
|
||||||
return false
|
error("Did you forget to call drain?")
|
||||||
end
|
end
|
||||||
|
|
||||||
queryOutput = {}
|
|
||||||
|
|
||||||
entities = archetype.entities
|
|
||||||
i = #entities
|
|
||||||
columns = archetype.columns
|
|
||||||
|
|
||||||
|
local function query_without(query, ...)
|
||||||
|
local compatible_archetypes = query.compatible_archetypes
|
||||||
|
local N = select("#", ...)
|
||||||
|
for i = #compatible_archetypes, 1, -1 do
|
||||||
|
local archetype = compatible_archetypes[i]
|
||||||
local records = archetype.records
|
local records = archetype.records
|
||||||
if not B then
|
local shouldRemove = false
|
||||||
a = columns[records[A].column]
|
|
||||||
elseif not C then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
elseif not D then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
elseif not E then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
elseif not F then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
elseif not G then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
elseif not H then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
g = columns[records[G].column]
|
|
||||||
elseif not I then
|
|
||||||
a = columns[records[A].column]
|
|
||||||
b = columns[records[B].column]
|
|
||||||
c = columns[records[C].column]
|
|
||||||
d = columns[records[D].column]
|
|
||||||
e = columns[records[E].column]
|
|
||||||
f = columns[records[F].column]
|
|
||||||
g = columns[records[G].column]
|
|
||||||
h = columns[records[H].column]
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
local function world_query_without(query, ...)
|
for j = 1, N do
|
||||||
local N = select("#", ...)
|
local id = select(j, ...)
|
||||||
for i = #compatible_archetypes, 1, -1 do
|
if records[id] then
|
||||||
local archetype = compatible_archetypes[i]
|
shouldRemove = true
|
||||||
local records = archetype.records
|
break
|
||||||
local shouldRemove = false
|
|
||||||
|
|
||||||
for j = 1, N do
|
|
||||||
local id = select(j, ...)
|
|
||||||
if records[id] then
|
|
||||||
shouldRemove = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if shouldRemove then
|
|
||||||
local last = #compatible_archetypes
|
|
||||||
if last ~= i then
|
|
||||||
compatible_archetypes[i] = compatible_archetypes[last]
|
|
||||||
end
|
|
||||||
compatible_archetypes[last] = nil
|
|
||||||
length -= 1
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if length == 0 then
|
if shouldRemove then
|
||||||
return EmptyQuery
|
local last = #compatible_archetypes
|
||||||
|
if last ~= i then
|
||||||
|
compatible_archetypes[i] = compatible_archetypes[last]
|
||||||
|
end
|
||||||
|
compatible_archetypes[last] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
return query
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_query_replace(query, fn: (...any) -> ...any)
|
if #compatible_archetypes == 0 then
|
||||||
query_init(query)
|
return EMPTY_QUERY
|
||||||
|
end
|
||||||
|
|
||||||
for i, archetype in compatible_archetypes do
|
return query
|
||||||
local columns = archetype.columns
|
end
|
||||||
local records = archetype.records
|
|
||||||
for row in archetype.entities do
|
|
||||||
if not B then
|
|
||||||
local va = columns[records[A].column]
|
|
||||||
local pa = fn(va[row])
|
|
||||||
|
|
||||||
va[row] = pa
|
local function query_with(query, ...)
|
||||||
elseif not C then
|
local compatible_archetypes = query.compatible_archetypes
|
||||||
local va = columns[records[A].column]
|
local N = select("#", ...)
|
||||||
local vb = columns[records[B].column]
|
for i = #compatible_archetypes, 1, -1 do
|
||||||
|
local archetype = compatible_archetypes[i]
|
||||||
|
local records = archetype.records
|
||||||
|
local shouldRemove = false
|
||||||
|
|
||||||
va[row], vb[row] = fn(va[row], vb[row])
|
for j = 1, N do
|
||||||
elseif not D then
|
local id = select(j, ...)
|
||||||
local va = columns[records[A].column]
|
if not records[id] then
|
||||||
local vb = columns[records[B].column]
|
shouldRemove = true
|
||||||
local vc = columns[records[C].column]
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
va[row], vb[row], vc[row] = fn(va[row], vb[row], vc[row])
|
if shouldRemove then
|
||||||
elseif not E then
|
local last = #compatible_archetypes
|
||||||
local va = columns[records[A].column]
|
if last ~= i then
|
||||||
local vb = columns[records[B].column]
|
compatible_archetypes[i] = compatible_archetypes[last]
|
||||||
local vc = columns[records[C].column]
|
end
|
||||||
local vd = columns[records[D].column]
|
compatible_archetypes[last] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #compatible_archetypes == 0 then
|
||||||
|
return EMPTY_QUERY
|
||||||
|
end
|
||||||
|
return query
|
||||||
|
end
|
||||||
|
|
||||||
va[row], vb[row], vc[row], vd[row] = fn(va[row], vb[row], vc[row], vd[row])
|
local function columns_replace_values(row, columns, ...)
|
||||||
else
|
for i, column in columns do
|
||||||
for j, id in ids do
|
column[row] = select(i, ...)
|
||||||
local tr = records[id]
|
end
|
||||||
queryOutput[j] = columns[tr.column][row]
|
end
|
||||||
end
|
|
||||||
columns_replace_values(row, columns, fn(unpack(queryOutput)))
|
local function query_replace(query, fn: (...any) -> ...any)
|
||||||
|
local compatible_archetypes = query.compatible_archetypes
|
||||||
|
local ids = query.ids
|
||||||
|
local A, B, C, D, E = unpack(ids, 1, 5)
|
||||||
|
local queryOutput = {}
|
||||||
|
for i, archetype in compatible_archetypes do
|
||||||
|
local columns = archetype.columns
|
||||||
|
local records = archetype.records
|
||||||
|
for row in archetype.entities do
|
||||||
|
if not B then
|
||||||
|
local va = columns[records[A].column]
|
||||||
|
local pa = fn(va[row])
|
||||||
|
|
||||||
|
va[row] = pa
|
||||||
|
elseif not C then
|
||||||
|
local va = columns[records[A].column]
|
||||||
|
local vb = columns[records[B].column]
|
||||||
|
|
||||||
|
va[row], vb[row] = fn(va[row], vb[row])
|
||||||
|
elseif not D then
|
||||||
|
local va = columns[records[A].column]
|
||||||
|
local vb = columns[records[B].column]
|
||||||
|
local vc = columns[records[C].column]
|
||||||
|
|
||||||
|
va[row], vb[row], vc[row] = fn(va[row], vb[row], vc[row])
|
||||||
|
elseif not E then
|
||||||
|
local va = columns[records[A].column]
|
||||||
|
local vb = columns[records[B].column]
|
||||||
|
local vc = columns[records[C].column]
|
||||||
|
local vd = columns[records[D].column]
|
||||||
|
|
||||||
|
va[row], vb[row], vc[row], vd[row] = fn(va[row], vb[row], vc[row], vd[row])
|
||||||
|
else
|
||||||
|
for j, id in ids do
|
||||||
|
local tr = records[id]
|
||||||
|
queryOutput[j] = columns[tr.column][row]
|
||||||
end
|
end
|
||||||
|
columns_replace_values(row, columns, fn(unpack(queryOutput)))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function world_query_with(query, ...)
|
-- Meant for directly iterating over archetypes to minimize
|
||||||
local N = select("#", ...)
|
-- function call overhead. Should not be used unless iterating over
|
||||||
for i = #compatible_archetypes, 1, -1 do
|
-- hundreds of thousands of entities in bulk.
|
||||||
local archetype = compatible_archetypes[i]
|
local function query_archetypes(query)
|
||||||
local records = archetype.records
|
return query.compatible_archetypes
|
||||||
local shouldRemove = false
|
end
|
||||||
|
|
||||||
for j = 1, N do
|
local Query = {}
|
||||||
local id = select(j, ...)
|
Query.__index = Query
|
||||||
if not records[id] then
|
Query.__iter = query_iter
|
||||||
shouldRemove = true
|
Query.iter = query_iter
|
||||||
break
|
Query.without = query_without
|
||||||
end
|
Query.with = query_with
|
||||||
end
|
Query.archetypes = query_archetypes
|
||||||
|
Query.drain = query_drain
|
||||||
|
Query.next = query_next
|
||||||
|
Query.replace = query_replace
|
||||||
|
|
||||||
if shouldRemove then
|
local function world_query(world: World, ...)
|
||||||
local last = #compatible_archetypes
|
local compatible_archetypes = {}
|
||||||
if last ~= i then
|
local length = 0
|
||||||
compatible_archetypes[i] = compatible_archetypes[last]
|
|
||||||
end
|
local ids = { ... }
|
||||||
compatible_archetypes[last] = nil
|
|
||||||
length -= 1
|
local archetypes = world.archetypes
|
||||||
|
|
||||||
|
local idr: ArchetypeMap
|
||||||
|
local componentIndex = world.componentIndex
|
||||||
|
|
||||||
|
for _, id in ids do
|
||||||
|
local map = componentIndex[id]
|
||||||
|
if not map then
|
||||||
|
return EMPTY_QUERY
|
||||||
|
end
|
||||||
|
|
||||||
|
if idr == nil or map.size < idr.size then
|
||||||
|
idr = map
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for archetype_id in idr.cache do
|
||||||
|
local compatibleArchetype = archetypes[archetype_id]
|
||||||
|
if #compatibleArchetype.entities == 0 then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
local records = compatibleArchetype.records
|
||||||
|
|
||||||
|
local skip = false
|
||||||
|
|
||||||
|
for i, id in ids do
|
||||||
|
local tr = records[id]
|
||||||
|
if not tr then
|
||||||
|
skip = true
|
||||||
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if length == 0 then
|
|
||||||
return EmptyQuery
|
if skip then
|
||||||
|
continue
|
||||||
end
|
end
|
||||||
return query
|
|
||||||
|
length += 1
|
||||||
|
compatible_archetypes[length] = compatibleArchetype
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Meant for directly iterating over archetypes to minimize
|
if length == 0 then
|
||||||
-- function call overhead. Should not be used unless iterating over
|
return EMPTY_QUERY
|
||||||
-- hundreds of thousands of entities in bulk.
|
|
||||||
local function world_query_archetypes()
|
|
||||||
return compatible_archetypes
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function world_query_drain(query)
|
local q = setmetatable({
|
||||||
drain = true
|
compatible_archetypes = compatible_archetypes,
|
||||||
if query_init(query) then
|
ids = ids,
|
||||||
return query
|
}, Query) :: any
|
||||||
end
|
|
||||||
return EmptyQuery
|
|
||||||
end
|
|
||||||
|
|
||||||
local function world_query_iter(query)
|
return q
|
||||||
query_init(query)
|
|
||||||
return world_query_iter_next
|
|
||||||
end
|
|
||||||
|
|
||||||
local function world_query_next(world)
|
|
||||||
if not drain then
|
|
||||||
error("Did you forget to call query:drain()?")
|
|
||||||
end
|
|
||||||
return world_query_iter_next(world)
|
|
||||||
end
|
|
||||||
|
|
||||||
local it = {
|
|
||||||
__iter = world_query_iter,
|
|
||||||
iter = world_query_iter,
|
|
||||||
drain = world_query_drain,
|
|
||||||
next = world_query_next,
|
|
||||||
with = world_query_with,
|
|
||||||
without = world_query_without,
|
|
||||||
replace = world_query_replace,
|
|
||||||
archetypes = world_query_archetypes,
|
|
||||||
} :: any
|
|
||||||
|
|
||||||
setmetatable(it, it)
|
|
||||||
|
|
||||||
return it
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local World = {}
|
local World = {}
|
||||||
|
@ -1442,13 +1428,17 @@ World.target = world_target
|
||||||
World.parent = world_parent
|
World.parent = world_parent
|
||||||
World.contains = world_contains
|
World.contains = world_contains
|
||||||
|
|
||||||
if _G.__JECS_DEBUG == true then
|
if _G.__JECS_DEBUG then
|
||||||
-- taken from https://github.com/centau/ecr/blob/main/src/ecr.luau
|
-- taken from https://github.com/centau/ecr/blob/main/src/ecr.luau
|
||||||
-- error but stack trace always starts at first callsite outside of this file
|
-- error but stack trace always starts at first callsite outside of this file
|
||||||
local function throw(msg: string)
|
local function throw(msg: string)
|
||||||
local s = 1
|
local s = 1
|
||||||
repeat s += 1 until debug.info(s, "s") ~= debug.info(1, "s")
|
repeat s += 1 until debug.info(s, "s") ~= debug.info(1, "s")
|
||||||
error(msg, s)
|
if warn then
|
||||||
|
error(msg, s)
|
||||||
|
else
|
||||||
|
print(`[jecs] error: {msg}\n`)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ASSERT<T>(v: T, msg: string)
|
local function ASSERT<T>(v: T, msg: string)
|
||||||
|
@ -1458,21 +1448,45 @@ if _G.__JECS_DEBUG == true then
|
||||||
throw(msg)
|
throw(msg)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function get_name(world, id): string | number
|
||||||
|
local name: string | nil
|
||||||
|
if ECS_IS_PAIR(id) then
|
||||||
|
name = `({get_name(world, ECS_ENTITY_T_HI(id))}, {get_name(world, ECS_ENTITY_T_LO(id))})`
|
||||||
|
else
|
||||||
|
local _1 = world_get_one_inline(world, id, EcsName)
|
||||||
|
if _1 then
|
||||||
|
name = `${_1}`
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if name then
|
||||||
|
return name
|
||||||
|
else
|
||||||
|
return `${id}`
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ID_IS_TAG(world, id)
|
||||||
|
return not world_has_one_inline(world, ECS_ENTITY_T_HI(id), EcsComponent)
|
||||||
|
end
|
||||||
|
|
||||||
World.query = function(world: World, ...)
|
World.query = function(world: World, ...)
|
||||||
ASSERT((...), "Requires at least a single component")
|
ASSERT((...), "Requires at least a single component")
|
||||||
return world_query(world, ...)
|
return world_query(world, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
World.set = function(world: World, entity: i53, id: i53, value: any): ()
|
World.set = function(world: World, entity: i53, id: i53, value: any): ()
|
||||||
local idr = world.componentIndex[id]
|
local is_tag = ID_IS_TAG(world, id)
|
||||||
local flags = idr.flags
|
if (is_tag and value == nil) then
|
||||||
local id_is_tag = bit32.band(flags, ECS_ID_IS_TAG) ~= 0
|
local _1 = get_name(world, entity)
|
||||||
if id_is_tag then
|
local _2 = get_name(world, id)
|
||||||
local name = world_get_one_inline(world, id, EcsName) or `${id}`
|
local why = "cannot set component value to nil"
|
||||||
throw(`({name}) is a tag. Did you mean to use "world:add(entity, {name})"`)
|
throw(why)
|
||||||
elseif value == nil then
|
elseif (value ~= nil and is_tag) then
|
||||||
local name = world_get_one_inline(world, id, EcsName) or `${id}`
|
local _1 = get_name(world, entity)
|
||||||
throw(`cannot set component ({name}) value to nil. If this was intentional, use "world:add(entity, {name})"`)
|
local _2 = get_name(world, id)
|
||||||
|
local why = `cannot set a component value because {_2} is a tag`
|
||||||
|
why ..= `\n[jecs] note: consider using "world:add({_1}, {_2})" instead`
|
||||||
|
throw(why)
|
||||||
end
|
end
|
||||||
|
|
||||||
world_set(world, entity, id, value)
|
world_set(world, entity, id, value)
|
||||||
|
@ -1480,8 +1494,10 @@ if _G.__JECS_DEBUG == true then
|
||||||
|
|
||||||
World.add = function(world: World, entity: i53, id: i53, value: nil)
|
World.add = function(world: World, entity: i53, id: i53, value: nil)
|
||||||
if value ~= nil then
|
if value ~= nil then
|
||||||
local name = world_get_one_inline(world, id, EcsName) or `${id}`
|
local _1 = get_name(world, entity)
|
||||||
throw(`You provided a value when none was expected. Did you mean to use "world:add(entity, {name})"`)
|
local _2 = get_name(world, id)
|
||||||
|
throw("You provided a value when none was expected. "
|
||||||
|
..`Did you mean to use "world:add({_1}, {_2})"`)
|
||||||
end
|
end
|
||||||
|
|
||||||
world_add(world, entity, id)
|
world_add(world, entity, id)
|
||||||
|
@ -1489,20 +1505,35 @@ if _G.__JECS_DEBUG == true then
|
||||||
|
|
||||||
World.get = function(world: World, entity: i53, ...)
|
World.get = function(world: World, entity: i53, ...)
|
||||||
local length = select("#", ...)
|
local length = select("#", ...)
|
||||||
ASSERT(length > 4, "world:get does not support more than 4 components")
|
ASSERT(length < 5, "world:get does not support more than 4 components")
|
||||||
|
local _1
|
||||||
for i = 1, length do
|
for i = 1, length do
|
||||||
local id = select(i, ...)
|
local id = select(i, ...)
|
||||||
local idr = world.componentIndex[id]
|
local id_is_tag = not world_has(world, id, EcsComponent)
|
||||||
local flags = idr.flags
|
|
||||||
local id_is_tag = bit32.band(flags, ECS_ID_IS_TAG) ~= 0
|
|
||||||
if id_is_tag then
|
if id_is_tag then
|
||||||
local name = world_get_one_inline(world, id, EcsName) or `${id}`
|
local name = get_name(world, id)
|
||||||
throw(`cannot get component ({name}) value because it is a tag. If this was intentional, use "world:has(entity, {name})"`)
|
if not _1 then
|
||||||
|
_1 = get_name(world, entity)
|
||||||
|
end
|
||||||
|
throw(
|
||||||
|
`cannot get (#{i}) component {name} value because it is a tag.`
|
||||||
|
..`\n[jecs] note: If this was intentional, use "world:has({_1}, {name}) instead"`)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return world_get(world, entity, ...)
|
return world_get(world, entity, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
World.target = function(world, entity, relation, index)
|
||||||
|
if index == nil then
|
||||||
|
local _1 = get_name(world, entity)
|
||||||
|
local _2 = get_name(world, relation)
|
||||||
|
|
||||||
|
throw("We have changed the function call to require an index parameter,"
|
||||||
|
..` please use world:target({_1}, {_2}, 0)`)
|
||||||
|
end
|
||||||
|
return world_target(world, entity, relation, index)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function World.new()
|
function World.new()
|
||||||
|
@ -1527,11 +1558,26 @@ function World.new()
|
||||||
entity_index_new_id(self.entityIndex, i)
|
entity_index_new_id(self.entityIndex, i)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
world_add(self, EcsName, EcsComponent)
|
||||||
world_add(self, EcsOnSet, EcsComponent)
|
world_add(self, EcsOnSet, EcsComponent)
|
||||||
world_add(self, EcsOnAdd, EcsComponent)
|
world_add(self, EcsOnAdd, EcsComponent)
|
||||||
world_add(self, EcsOnRemove, EcsComponent)
|
world_add(self, EcsOnRemove, EcsComponent)
|
||||||
|
world_add(self, EcsWildcard, EcsComponent)
|
||||||
world_add(self, EcsRest, EcsComponent)
|
world_add(self, EcsRest, EcsComponent)
|
||||||
world_add(self, EcsName, EcsComponent)
|
|
||||||
|
world_set(self, EcsOnAdd, EcsName, "jecs.OnAdd")
|
||||||
|
world_set(self, EcsOnRemove, EcsName, "jecs.OnRemove")
|
||||||
|
world_set(self, EcsOnSet, EcsName, "jecs.OnSet")
|
||||||
|
world_set(self, EcsWildcard, EcsName, "jecs.Wildcard")
|
||||||
|
world_set(self, EcsChildOf, EcsName, "jecs.ChildOf")
|
||||||
|
world_set(self, EcsComponent, EcsName, "jecs.Component")
|
||||||
|
world_set(self, EcsOnDelete, EcsName, "jecs.OnDelete")
|
||||||
|
world_set(self, EcsOnDeleteTarget, EcsName, "jecs.OnDeleteTarget")
|
||||||
|
world_set(self, EcsDelete, EcsName, "jecs.Delete")
|
||||||
|
world_set(self, EcsRemove, EcsName, "jecs.Remove")
|
||||||
|
world_set(self, EcsName, EcsName, "jecs.Name")
|
||||||
|
world_set(self, EcsRest, EcsRest, "jecs.Rest")
|
||||||
|
|
||||||
world_add(self, EcsChildOf, ECS_PAIR(EcsOnDeleteTarget, EcsDelete))
|
world_add(self, EcsChildOf, ECS_PAIR(EcsOnDeleteTarget, EcsDelete))
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
@ -1665,11 +1711,10 @@ return {
|
||||||
OnDeleteTarget = EcsOnDeleteTarget :: Entity,
|
OnDeleteTarget = EcsOnDeleteTarget :: Entity,
|
||||||
Delete = EcsDelete :: Entity,
|
Delete = EcsDelete :: Entity,
|
||||||
Remove = EcsRemove :: Entity,
|
Remove = EcsRemove :: Entity,
|
||||||
Tag = EcsTag :: Entity,
|
|
||||||
Name = EcsName :: Entity<string>,
|
Name = EcsName :: Entity<string>,
|
||||||
Rest = EcsRest :: Entity,
|
Rest = EcsRest :: Entity,
|
||||||
|
|
||||||
pair = (ECS_PAIR :: any) :: <R, T>(pred: Entity, obj: Entity) -> number,
|
pair = ECS_PAIR,
|
||||||
|
|
||||||
-- Inwards facing API for testing
|
-- Inwards facing API for testing
|
||||||
ECS_ID = ECS_ENTITY_T_LO,
|
ECS_ID = ECS_ENTITY_T_LO,
|
||||||
|
|
Loading…
Reference in a new issue