🐳 chore(工具): 更新 lua ecs
parent
674f932099
commit
8d44c1e8b4
@ -0,0 +1,234 @@
|
||||
local ecs = require "ecs"
|
||||
|
||||
local N = 1
|
||||
|
||||
local w = ecs.world()
|
||||
print("memory:", w:memory())
|
||||
|
||||
w:register {
|
||||
name = "vector",
|
||||
"x:float",
|
||||
"y:float",
|
||||
}
|
||||
|
||||
w:register {
|
||||
name = "mark"
|
||||
}
|
||||
|
||||
w:register {
|
||||
name = "id",
|
||||
type = "int"
|
||||
}
|
||||
|
||||
w:register {
|
||||
name = "object",
|
||||
type = "lua",
|
||||
}
|
||||
|
||||
local t = {}
|
||||
for i = 1, N do
|
||||
w:new {
|
||||
vector = {
|
||||
x = 1,
|
||||
y = 2,
|
||||
}
|
||||
}
|
||||
t[i] = { x = 1, y = 2 }
|
||||
end
|
||||
|
||||
w:update()
|
||||
|
||||
local function swap_c()
|
||||
for v in w:select "vector:update" do
|
||||
local vec = v.vector
|
||||
vec.x, vec.y = vec.y, vec.x
|
||||
end
|
||||
end
|
||||
|
||||
local function swap_lua()
|
||||
for _, v in ipairs(t) do
|
||||
v.x, v.y = v.y, v.x
|
||||
end
|
||||
end
|
||||
|
||||
local function timing(f)
|
||||
local c = os.clock()
|
||||
for i = 1, 100 do
|
||||
f()
|
||||
end
|
||||
return os.clock() - c
|
||||
end
|
||||
|
||||
print("memory:", w:memory())
|
||||
|
||||
print("CSWAP", timing(swap_c))
|
||||
print("LUASWAP", timing(swap_lua))
|
||||
|
||||
w:new {
|
||||
vector = {
|
||||
x = 3,
|
||||
y = 4,
|
||||
},
|
||||
id = 100,
|
||||
}
|
||||
|
||||
table.insert(t, { x = 3, y = 4 })
|
||||
|
||||
w:new {
|
||||
vector = {
|
||||
x = 5,
|
||||
y = 6,
|
||||
},
|
||||
mark = true,
|
||||
}
|
||||
|
||||
table.insert(t, { x = 5, y = 6 })
|
||||
|
||||
w:update()
|
||||
|
||||
w:register {
|
||||
name = "singleton",
|
||||
type = "lua"
|
||||
}
|
||||
|
||||
local context = w:context {
|
||||
"vector",
|
||||
"mark",
|
||||
"id",
|
||||
"singleton",
|
||||
}
|
||||
|
||||
w:new { singleton = "Hello World" }
|
||||
|
||||
w:update()
|
||||
|
||||
local test = require "ecs.ctest"
|
||||
|
||||
print(test.get(context))
|
||||
|
||||
local function csum()
|
||||
return test.sum(context)
|
||||
end
|
||||
print("csum = ", csum())
|
||||
|
||||
local function luasum()
|
||||
local s = 0
|
||||
for v in w:select "vector:in" do
|
||||
s = s + v.vector.x + v.vector.y
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
print("luasum = ", luasum())
|
||||
|
||||
local function luanativesum()
|
||||
local s = 0
|
||||
for _, v in ipairs(t) do
|
||||
s = s + v.x + v.y
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
print("lnative sum = ", luanativesum())
|
||||
|
||||
print("CSUM", timing(csum))
|
||||
print("LUASUM", timing(luasum))
|
||||
print("LNATIVESUM", timing(luanativesum))
|
||||
|
||||
print "vector:update"
|
||||
for v in w:select "vector:update" do
|
||||
local vec = v.vector
|
||||
print(vec.x, vec.y)
|
||||
vec.x, vec.y = vec.y , vec.x
|
||||
end
|
||||
|
||||
print "vector:in id?out"
|
||||
for v in w:select "vector:in id?temp" do
|
||||
print(v.vector.x, v.vector.y, v.id)
|
||||
if v.id then
|
||||
v.id = 200
|
||||
end
|
||||
end
|
||||
|
||||
print "vector:in id:in"
|
||||
|
||||
for v in w:select "vector:in id:in" do
|
||||
print(v.vector.x, v.vector.y, v.id)
|
||||
end
|
||||
|
||||
|
||||
w:new { object = "Hello" , mark = true }
|
||||
w:new { object = "World" , mark = true }
|
||||
|
||||
w:update()
|
||||
|
||||
print "mark:update object:in"
|
||||
|
||||
for v in w:select "mark:update object:in" do
|
||||
print(v.object)
|
||||
if v.object == "World" then
|
||||
print "Disable mark where object == World"
|
||||
v.mark = false
|
||||
end
|
||||
end
|
||||
|
||||
print "mark:exist object:in"
|
||||
|
||||
for v in w:select "mark:exist object:in" do
|
||||
print(v.object)
|
||||
end
|
||||
|
||||
for v in w:select "object:exist mark:out" do
|
||||
v.mark = false
|
||||
end
|
||||
|
||||
for v in w:select "mark:exist" do
|
||||
print("Remove")
|
||||
w:remove(v)
|
||||
end
|
||||
|
||||
for v in w:select "REMOVED:exist vector:in" do
|
||||
print(v.vector.x, v.vector.y, "removed")
|
||||
end
|
||||
|
||||
w:update() -- remove all
|
||||
|
||||
local n = 0
|
||||
for v in w:select "mark:in" do
|
||||
n = n + 1
|
||||
end
|
||||
print("Marked", n)
|
||||
|
||||
|
||||
print "object:update"
|
||||
|
||||
for v in w:select "object:update" do
|
||||
print(v.object)
|
||||
v.object = v.object .. " world"
|
||||
end
|
||||
|
||||
print "object:in"
|
||||
|
||||
for v in w:select "object:in" do
|
||||
print(v.object)
|
||||
end
|
||||
|
||||
w:register {
|
||||
name = "sum",
|
||||
type = "float",
|
||||
}
|
||||
|
||||
for v in w:select "vector:in sum:temp" do
|
||||
print(v.vector.x, "+", v.vector.y)
|
||||
v.sum = v.vector.x + v.vector.y
|
||||
end
|
||||
|
||||
for v in w:select "sum:in" do
|
||||
print(v.sum)
|
||||
end
|
||||
|
||||
w:clear "sum"
|
||||
|
||||
for v in w:select "sum:exist" do
|
||||
error "Not empty"
|
||||
end
|
||||
@ -0,0 +1,58 @@
|
||||
-- test sort
|
||||
|
||||
local ecs = require "ecs"
|
||||
|
||||
local w = ecs.world()
|
||||
|
||||
w:register {
|
||||
name = "data",
|
||||
type = "float",
|
||||
}
|
||||
|
||||
w:register {
|
||||
name = "index",
|
||||
type = "int",
|
||||
}
|
||||
|
||||
local tmp = { 10,9,8,7,6,5,4,3,2,1 }
|
||||
|
||||
for i = 1, 10, 2 do
|
||||
w:new { data = tmp[i], index = tmp[i] }
|
||||
w:new { index = tmp[i+1] }
|
||||
end
|
||||
|
||||
w:update()
|
||||
|
||||
for v in w:select "index data?in" do
|
||||
print(v.data)
|
||||
end
|
||||
|
||||
w:sort("sort", "index")
|
||||
|
||||
print "sorted"
|
||||
|
||||
for v in w:select "sort data:in index:in" do
|
||||
print(v.data, v.index)
|
||||
end
|
||||
|
||||
local iter = w:bsearch("sort", "index", 5)
|
||||
w:sync("data:in", iter)
|
||||
print("Found", iter.data)
|
||||
|
||||
w:register {
|
||||
name = "sorted_index",
|
||||
type = "int",
|
||||
}
|
||||
|
||||
for i = 1, 10 do
|
||||
w:new { data = i * 0.5 , sorted_index = i * 2 }
|
||||
end
|
||||
|
||||
for v in w:select "sorted_index:in data?in" do
|
||||
print(v.sorted_index, "=>", v.data)
|
||||
end
|
||||
|
||||
local iter = w:bsearch("sorted_index", "sorted_index", 4)
|
||||
w:sync("data:in", iter)
|
||||
print("Found", iter.data)
|
||||
--w:remove(iter)
|
||||
@ -0,0 +1,126 @@
|
||||
-- test object
|
||||
local ecs = require "ecs"
|
||||
|
||||
local w = ecs.world()
|
||||
|
||||
w:register {
|
||||
name = "refobject",
|
||||
type = "int",
|
||||
ref = true,
|
||||
}
|
||||
|
||||
local id1 = w:ref("refobject", { refobject = 42 })
|
||||
local id2 = w:ref("refobject", { refobject = 0 })
|
||||
local id3 = w:ref("refobject", { refobject = 100 })
|
||||
print ("New", id1, id2, id3)
|
||||
print(w:object("refobject", id1))
|
||||
|
||||
print("Release", id1)
|
||||
|
||||
w:release("refobject", id1)
|
||||
|
||||
for v in w:select "refobject:in" do
|
||||
print(v.refobject)
|
||||
end
|
||||
|
||||
local id4 = w:ref("refobject", { refobject = -42 })
|
||||
print ("New", id4)
|
||||
|
||||
print ("Release", id2)
|
||||
|
||||
w:release("refobject", id2)
|
||||
|
||||
print ("Release", id3)
|
||||
|
||||
w:release("refobject", id3)
|
||||
|
||||
print "List refobject"
|
||||
|
||||
for v in w:select "refobject:in" do
|
||||
print(v.refobject)
|
||||
end
|
||||
|
||||
w:register {
|
||||
name = "index",
|
||||
type = "int",
|
||||
}
|
||||
|
||||
w:new {
|
||||
index = id4
|
||||
}
|
||||
|
||||
for v in w:select "index:in" do
|
||||
print(v.index)
|
||||
end
|
||||
|
||||
print "Index refobject"
|
||||
|
||||
for v in w:select "refobject(index):in" do
|
||||
print(v.refobject)
|
||||
end
|
||||
|
||||
w:register {
|
||||
name = "name",
|
||||
type = "lua",
|
||||
}
|
||||
|
||||
w:new {
|
||||
name = "Hello"
|
||||
}
|
||||
|
||||
for v in w:select "index:in" do
|
||||
print(v.index)
|
||||
end
|
||||
|
||||
|
||||
for v in w:select "name refobject(index):temp" do
|
||||
v.refobject = 42
|
||||
end
|
||||
|
||||
for v in w:select "refobject:in" do
|
||||
print(v.refobject)
|
||||
end
|
||||
|
||||
for v in w:select "refobject(index):update" do
|
||||
v.refobject = v.refobject + 1
|
||||
end
|
||||
|
||||
for v in w:select "refobject:in" do
|
||||
print(v.refobject)
|
||||
end
|
||||
|
||||
w:register {
|
||||
name = "mark"
|
||||
}
|
||||
|
||||
local ref = w:object_ref("refobject", id4)
|
||||
ref.mark = true
|
||||
w:sync("mark?out", ref)
|
||||
|
||||
|
||||
w:ref ("refobject", {
|
||||
refobject = 42,
|
||||
mark = true
|
||||
})
|
||||
|
||||
print "Marked refobject"
|
||||
|
||||
for v in w:select "mark refobject?in" do
|
||||
print(v.refobject)
|
||||
end
|
||||
|
||||
w:register {
|
||||
name = "refobject2",
|
||||
type = "int",
|
||||
ref = true,
|
||||
}
|
||||
|
||||
w:register {
|
||||
name = "mark2"
|
||||
}
|
||||
|
||||
w:ref ("refobject2", {
|
||||
refobject2 = 42,
|
||||
mark = true,
|
||||
mark2 = false,
|
||||
})
|
||||
@ -0,0 +1,51 @@
|
||||
local ecs = require "ecs"
|
||||
|
||||
local w = ecs.world()
|
||||
|
||||
w:register {
|
||||
name = "a",
|
||||
type = "int",
|
||||
}
|
||||
|
||||
w:register {
|
||||
name = "b",
|
||||
type = "float",
|
||||
}
|
||||
|
||||
for i = 1, 20 do
|
||||
w:new { a = i }
|
||||
w:new { b = i }
|
||||
end
|
||||
|
||||
for i = 20, 40 do
|
||||
w:new { a = i , b = i }
|
||||
end
|
||||
|
||||
w:update()
|
||||
|
||||
for v in w:select "a:in" do
|
||||
if v.a % 2 == 1 then
|
||||
w:remove(v)
|
||||
end
|
||||
end
|
||||
|
||||
for v in w:select "b:in" do
|
||||
if v.b < 10 then
|
||||
w:remove(v)
|
||||
end
|
||||
end
|
||||
|
||||
for v in w:select "REMOVED a?in b?in" do
|
||||
print(v.a, v.b, "Removed")
|
||||
end
|
||||
|
||||
w:update()
|
||||
|
||||
for v in w:select "a:in" do
|
||||
print(v.a)
|
||||
end
|
||||
|
||||
for v in w:select "b:in" do
|
||||
print(v.b)
|
||||
end
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
local ecs = require "ecs"
|
||||
|
||||
local w = ecs.world()
|
||||
|
||||
w:register {
|
||||
name = "a",
|
||||
type = "int",
|
||||
}
|
||||
|
||||
w:register {
|
||||
name = "temp",
|
||||
type = "int",
|
||||
}
|
||||
|
||||
for i = 1, 10 do
|
||||
w:new { a = i }
|
||||
end
|
||||
|
||||
for v in w:select "a:in" do
|
||||
if v.a %2 == 0 then
|
||||
v.a = -v.a
|
||||
v.temp = 42
|
||||
w:sync("a:out temp:temp", v)
|
||||
end
|
||||
end
|
||||
|
||||
for v in w:select "a:in temp?in" do
|
||||
print(v.a, v.temp)
|
||||
end
|
||||
@ -0,0 +1,35 @@
|
||||
local ecs = require "ecs"
|
||||
|
||||
local w = ecs.world()
|
||||
|
||||
w:register {
|
||||
name = "t",
|
||||
"a:bool",
|
||||
"b:userdata",
|
||||
}
|
||||
|
||||
w:new {
|
||||
t = {
|
||||
a = false,
|
||||
b = ecs.NULL,
|
||||
}
|
||||
}
|
||||
|
||||
local function print_v()
|
||||
local v = w:singleton "t"
|
||||
|
||||
print(".a = ",v.a)
|
||||
print(".b = ",v.b)
|
||||
end
|
||||
|
||||
local ctx = w:context { "t" }
|
||||
|
||||
print("ctx = ", ctx)
|
||||
|
||||
local test = require "ecs.ctest"
|
||||
|
||||
print_v()
|
||||
|
||||
test.testuserdata(ctx)
|
||||
|
||||
print_v()
|
||||
@ -0,0 +1,19 @@
|
||||
local ecs = require "ecs"
|
||||
|
||||
local w = ecs.world()
|
||||
|
||||
w:register {
|
||||
name = "object",
|
||||
type = "int",
|
||||
ref = true,
|
||||
}
|
||||
|
||||
for i = 1, 10 do
|
||||
w:ref("object", { object = i * 10 })
|
||||
end
|
||||
|
||||
w:order("order", "object", { 9,7,5,3,1 })
|
||||
|
||||
for v in w:select "order object:in" do
|
||||
print(v.object)
|
||||
end
|
||||
@ -0,0 +1,33 @@
|
||||
local ecs = require "ecs"
|
||||
|
||||
local w = ecs.world()
|
||||
|
||||
w:register {
|
||||
name = "v",
|
||||
type = "int",
|
||||
}
|
||||
|
||||
w:register {
|
||||
name = "marked"
|
||||
}
|
||||
|
||||
for i = 1, 10 do
|
||||
w:new {
|
||||
v = i,
|
||||
marked = i % 2 == 1,
|
||||
}
|
||||
end
|
||||
|
||||
for v in w:select "v:in marked?in" do
|
||||
print(v.v, v.marked)
|
||||
end
|
||||
|
||||
print "Marked"
|
||||
for v in w:select "v:in marked" do
|
||||
print(v.v)
|
||||
end
|
||||
|
||||
print "Not Marked"
|
||||
for v in w:select "v:in marked:absent" do
|
||||
print(v.v)
|
||||
end
|
||||
@ -1,384 +1,385 @@
|
||||
local ecs = require "ecs.core"
|
||||
|
||||
local function get_attrib(opt, inout)
|
||||
if opt == nil then
|
||||
return {
|
||||
exist = true,
|
||||
}
|
||||
end
|
||||
local desc = {}
|
||||
if opt == "?" then
|
||||
desc.opt = true
|
||||
else
|
||||
assert(opt == ":")
|
||||
end
|
||||
if inout == "in" then
|
||||
desc.r = true
|
||||
elseif inout == "out" or inout == "new" then
|
||||
desc.w = true
|
||||
elseif inout == "update" then
|
||||
desc.r = true
|
||||
desc.w = true
|
||||
elseif inout == "exist" then
|
||||
desc.exist = true
|
||||
assert(not desc.opt)
|
||||
elseif inout == "absent" then
|
||||
desc.absent = true
|
||||
assert(not desc.opt)
|
||||
else
|
||||
assert(inout == "temp")
|
||||
end
|
||||
return desc
|
||||
if opt == nil then
|
||||
return { exist = true }
|
||||
end
|
||||
local desc = {}
|
||||
if opt == "?" then
|
||||
desc.opt = true
|
||||
else
|
||||
assert(opt == ":")
|
||||
end
|
||||
if inout == "in" then
|
||||
desc.r = true
|
||||
elseif inout == "out" or inout == "new" then
|
||||
desc.w = true
|
||||
elseif inout == "update" then
|
||||
desc.r = true
|
||||
desc.w = true
|
||||
elseif inout == "exist" then
|
||||
desc.exist = true
|
||||
assert(not desc.opt)
|
||||
elseif inout == "absent" then
|
||||
desc.absent = true
|
||||
assert(not desc.opt)
|
||||
else
|
||||
assert(inout == "temp")
|
||||
end
|
||||
return desc
|
||||
end
|
||||
|
||||
local function cache_world(obj, k)
|
||||
local c = {
|
||||
typenames = {},
|
||||
id = 0,
|
||||
select = {},
|
||||
ref = {},
|
||||
}
|
||||
|
||||
local function gen_ref_pat(key)
|
||||
local typenames = c.typenames
|
||||
local desc = {}
|
||||
local tc = typenames[key]
|
||||
if tc == nil then
|
||||
error("Unknown type " .. key)
|
||||
end
|
||||
local a = {
|
||||
exist = true,
|
||||
name = tc.name,
|
||||
id = tc.id,
|
||||
type = tc.type,
|
||||
}
|
||||
local n = #tc
|
||||
for i = 1, #tc do
|
||||
a[i] = tc[i]
|
||||
end
|
||||
desc[1] = a
|
||||
return desc
|
||||
end
|
||||
|
||||
local function gen_select_pat(pat)
|
||||
local typenames = c.typenames
|
||||
local desc = {}
|
||||
local idx = 1
|
||||
for token in pat:gmatch "[^ ]+" do
|
||||
local key, index, padding = token:match "^([_%w]+)%(?([_%w]*)%)?(.*)"
|
||||
assert(key, "Invalid pattern")
|
||||
local opt, inout
|
||||
if padding ~= "" then
|
||||
opt, inout = padding:match "^([:?])(%l+)$"
|
||||
assert(opt, "Invalid pattern")
|
||||
end
|
||||
local tc = typenames[key]
|
||||
if tc == nil then
|
||||
error("Unknown type " .. key)
|
||||
end
|
||||
if index ~= "" then
|
||||
local indexc = typenames[index]
|
||||
if indexc == nil then
|
||||
error("Unknown index type " .. index)
|
||||
end
|
||||
local a = get_attrib(opt, inout == "temp" and "temp" or "in")
|
||||
a.name = index
|
||||
a.id = indexc.id
|
||||
a.type = indexc.type
|
||||
a.ref = true
|
||||
desc[idx] = a
|
||||
idx = idx + 1
|
||||
end
|
||||
local a = get_attrib(opt, inout)
|
||||
a.name = tc.name
|
||||
a.id = tc.id
|
||||
a.type = tc.type
|
||||
local n = #tc
|
||||
for i = 1, #tc do
|
||||
a[i] = tc[i]
|
||||
end
|
||||
desc[idx] = a
|
||||
idx = idx + 1
|
||||
if tc.ref and index == "" then
|
||||
local dead = typenames[key .. "_dead"]
|
||||
local a = {
|
||||
absent = true,
|
||||
name = dead.name,
|
||||
id = dead.id,
|
||||
}
|
||||
desc[idx] = a
|
||||
idx = idx + 1
|
||||
end
|
||||
end
|
||||
return desc
|
||||
end
|
||||
|
||||
local function cache_select(cache, pat)
|
||||
local pat_desc = gen_select_pat(pat)
|
||||
cache[pat] = k:_groupiter(pat_desc)
|
||||
return cache[pat]
|
||||
end
|
||||
|
||||
setmetatable(c.select, {
|
||||
__mode = "kv",
|
||||
__index = cache_select,
|
||||
})
|
||||
|
||||
local function cache_ref(cache, pat)
|
||||
local pat_desc = gen_ref_pat(pat)
|
||||
cache[pat] = k:_groupiter(pat_desc)
|
||||
return cache[pat]
|
||||
end
|
||||
|
||||
setmetatable(c.ref, {
|
||||
__mode = "kv",
|
||||
__index = cache_ref,
|
||||
})
|
||||
|
||||
obj[k] = c
|
||||
return c
|
||||
local c = {
|
||||
typenames = {},
|
||||
id = 0,
|
||||
select = {},
|
||||
ref = {},
|
||||
}
|
||||
|
||||
local function gen_ref_pat(key)
|
||||
local typenames = c.typenames
|
||||
local desc = {}
|
||||
local tc = typenames[key]
|
||||
if tc == nil then
|
||||
error("Unknown type " .. key)
|
||||
end
|
||||
local a = {
|
||||
exist = true,
|
||||
name = tc.name,
|
||||
id = tc.id,
|
||||
type = tc.type,
|
||||
}
|
||||
local n = #tc
|
||||
for i=1,#tc do
|
||||
a[i] = tc[i]
|
||||
end
|
||||
desc[1] = a
|
||||
return desc
|
||||
end
|
||||
|
||||
local function gen_select_pat(pat)
|
||||
local typenames = c.typenames
|
||||
local desc = {}
|
||||
local idx = 1
|
||||
for token in pat:gmatch "[^ ]+" do
|
||||
local key, index, padding = token:match "^([_%w]+)%(?([_%w]*)%)?(.*)"
|
||||
assert(key, "Invalid pattern")
|
||||
local opt, inout
|
||||
if padding ~= "" then
|
||||
opt, inout = padding:match "^([:?])(%l+)$"
|
||||
assert(opt, "Invalid pattern")
|
||||
end
|
||||
local tc = typenames[key]
|
||||
if tc == nil then
|
||||
error("Unknown type " .. key)
|
||||
end
|
||||
if index ~= "" then
|
||||
local indexc = typenames[index]
|
||||
if indexc == nil then
|
||||
error("Unknown index type "..index)
|
||||
end
|
||||
local a = get_attrib(opt, inout == "temp" and "temp" or "in")
|
||||
a.name = index
|
||||
a.id = indexc.id
|
||||
a.type = indexc.type
|
||||
a.ref = true
|
||||
desc[idx] = a
|
||||
idx = idx + 1
|
||||
end
|
||||
local a = get_attrib(opt, inout)
|
||||
a.name = tc.name
|
||||
a.id = tc.id
|
||||
a.type = tc.type
|
||||
local n = #tc
|
||||
for i=1,#tc do
|
||||
a[i] = tc[i]
|
||||
end
|
||||
desc[idx] = a
|
||||
idx = idx + 1
|
||||
if tc.ref and index == "" then
|
||||
local dead = typenames[key .. "_dead"]
|
||||
local a = {
|
||||
absent = true,
|
||||
name = dead.name,
|
||||
id = dead.id,
|
||||
}
|
||||
desc[idx] = a
|
||||
idx = idx + 1
|
||||
end
|
||||
end
|
||||
return desc
|
||||
end
|
||||
|
||||
local function cache_select(cache, pat)
|
||||
local pat_desc = gen_select_pat(pat)
|
||||
cache[pat] = k:_groupiter(pat_desc)
|
||||
return cache[pat]
|
||||
end
|
||||
|
||||
setmetatable(c.select, {
|
||||
__mode = "kv",
|
||||
__index = cache_select,
|
||||
})
|
||||
|
||||
local function cache_ref(cache, pat)
|
||||
local pat_desc = gen_ref_pat(pat)
|
||||
cache[pat] = k:_groupiter(pat_desc)
|
||||
return cache[pat]
|
||||
end
|
||||
|
||||
setmetatable(c.ref, {
|
||||
__mode = "kv",
|
||||
__index = cache_ref,
|
||||
})
|
||||
|
||||
obj[k] = c
|
||||
return c
|
||||
end
|
||||
|
||||
local context = setmetatable({}, {
|
||||
__index = cache_world,
|
||||
})
|
||||
local context = setmetatable({}, { __index = cache_world })
|
||||
local typeid = {
|
||||
int = assert(ecs._TYPEINT),
|
||||
float = assert(ecs._TYPEFLOAT),
|
||||
bool = assert(ecs._TYPEBOOL),
|
||||
int64 = assert(ecs._TYPEINT64),
|
||||
dword = assert(ecs._TYPEDWORD),
|
||||
word = assert(ecs._TYPEWORD),
|
||||
byte = assert(ecs._TYPEBYTE),
|
||||
double = assert(ecs._TYPEDOUBLE),
|
||||
userdata = assert(ecs._TYPEUSERDATA),
|
||||
int = assert(ecs._TYPEINT),
|
||||
float = assert(ecs._TYPEFLOAT),
|
||||
bool = assert(ecs._TYPEBOOL),
|
||||
int64 = assert(ecs._TYPEINT64),
|
||||
dword = assert(ecs._TYPEDWORD),
|
||||
word = assert(ecs._TYPEWORD),
|
||||
byte = assert(ecs._TYPEBYTE),
|
||||
double = assert(ecs._TYPEDOUBLE),
|
||||
userdata = assert(ecs._TYPEUSERDATA),
|
||||
}
|
||||
local typesize = {
|
||||
[typeid.int] = 4,
|
||||
[typeid.float] = 4,
|
||||
[typeid.bool] = 1,
|
||||
[typeid.int64] = 8,
|
||||
[typeid.dword] = 4,
|
||||
[typeid.word] = 2,
|
||||
[typeid.byte] = 1,
|
||||
[typeid.double] = 8,
|
||||
[typeid.userdata] = 8,
|
||||
[typeid.int] = 4,
|
||||
[typeid.float] = 4,
|
||||
[typeid.bool] = 1,
|
||||
[typeid.int64] = 8,
|
||||
[typeid.dword] = 4,
|
||||
[typeid.word] = 2,
|
||||
[typeid.byte] = 1,
|
||||
[typeid.double] = 8,
|
||||
[typeid.userdata] = 8,
|
||||
}
|
||||
|
||||
local M = ecs._METHODS
|
||||
|
||||
do -- newtype
|
||||
local function parse(s)
|
||||
-- s is "name:typename"
|
||||
local name, typename = s:match "^([%w_]+):(%w+)$"
|
||||
local typeid = assert(typeid[typename])
|
||||
return {typeid, name}
|
||||
end
|
||||
|
||||
local function align(c, field)
|
||||
local t = field[1]
|
||||
local tsize = typesize[t]
|
||||
local offset = ((c.size + tsize - 1) & ~(tsize - 1))
|
||||
c.size = offset + tsize
|
||||
field[3] = offset
|
||||
return field
|
||||
end
|
||||
|
||||
local function align_struct(c, t)
|
||||
if t then
|
||||
local s = typesize[t] - 1
|
||||
c.size = ((c.size + s) & ~s)
|
||||
end
|
||||
end
|
||||
|
||||
function M:register(typeclass)
|
||||
local name = assert(typeclass.name)
|
||||
local ctx = context[self]
|
||||
local typenames = ctx.typenames
|
||||
local id = ctx.id + 1
|
||||
assert(typenames[name] == nil and id <= ecs._MAXTYPE)
|
||||
ctx.id = id
|
||||
local c = {
|
||||
id = id,
|
||||
name = name,
|
||||
size = 0,
|
||||
}
|
||||
for i, v in ipairs(typeclass) do
|
||||
c[i] = align(c, parse(v))
|
||||
end
|
||||
local ttype = typeclass.type
|
||||
if ttype == "lua" then
|
||||
assert(c.size == 0)
|
||||
c.size = ecs._LUAOBJECT
|
||||
assert(c[1] == nil)
|
||||
elseif c.size > 0 then
|
||||
align_struct(c, typeclass[1][1])
|
||||
else
|
||||
-- size == 0, one value
|
||||
if ttype then
|
||||
local t = assert(typeid[typeclass.type])
|
||||
c.type = t
|
||||
c.size = typesize[t]
|
||||
c[1] = {t, "v", 0}
|
||||
else
|
||||
c.tag = true
|
||||
end
|
||||
end
|
||||
typenames[name] = c
|
||||
self:_newtype(id, c.size)
|
||||
if typeclass.ref then
|
||||
c.ref = true
|
||||
self:register{
|
||||
name = name .. "_dead",
|
||||
}
|
||||
end
|
||||
end
|
||||
do -- newtype
|
||||
local function parse(s)
|
||||
-- s is "name:typename"
|
||||
local name, typename = s:match "^([%w_]+):(%w+)$"
|
||||
local typeid = assert(typeid[typename])
|
||||
return { typeid, name }
|
||||
end
|
||||
|
||||
local function align(c, field)
|
||||
local t = field[1]
|
||||
local tsize = typesize[t]
|
||||
local offset = ((c.size + tsize - 1) & ~(tsize-1))
|
||||
c.size = offset + tsize
|
||||
field[3] = offset
|
||||
return field
|
||||
end
|
||||
|
||||
local function align_struct(c, t)
|
||||
if t then
|
||||
local s = typesize[t] - 1
|
||||
c.size = ((c.size + s) & ~s)
|
||||
end
|
||||
end
|
||||
|
||||
function M:register(typeclass)
|
||||
local name = assert(typeclass.name)
|
||||
local ctx = context[self]
|
||||
local typenames = ctx.typenames
|
||||
local id = ctx.id + 1
|
||||
assert(typenames[name] == nil and id <= ecs._MAXTYPE)
|
||||
ctx.id = id
|
||||
local c = {
|
||||
id = id,
|
||||
name = name,
|
||||
size = 0,
|
||||
}
|
||||
for i, v in ipairs(typeclass) do
|
||||
c[i] = align(c, parse(v))
|
||||
end
|
||||
local ttype = typeclass.type
|
||||
if ttype == "lua" then
|
||||
assert(c.size == 0)
|
||||
c.size = ecs._LUAOBJECT
|
||||
assert(c[1] == nil)
|
||||
elseif c.size > 0 then
|
||||
align_struct(c, typeclass[1][1])
|
||||
else
|
||||
-- size == 0, one value
|
||||
if ttype then
|
||||
local t = assert(typeid[typeclass.type])
|
||||
c.type = t
|
||||
c.size = typesize[t]
|
||||
c[1] = { t, "v", 0 }
|
||||
else
|
||||
c.tag = true
|
||||
end
|
||||
end
|
||||
typenames[name] = c
|
||||
self:_newtype(id, c.size)
|
||||
if typeclass.ref then
|
||||
c.ref = true
|
||||
self:register { name = name .. "_dead" }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function dump(obj)
|
||||
for e, v in pairs(obj) do
|
||||
if type(v) == "table" then
|
||||
for k, v in pairs(v) do
|
||||
print(e, k, v)
|
||||
end
|
||||
else
|
||||
print(e, v)
|
||||
end
|
||||
end
|
||||
for e,v in pairs(obj) do
|
||||
if type(v) == "table" then
|
||||
for k,v in pairs(v) do
|
||||
print(e,k,v)
|
||||
end
|
||||
else
|
||||
print(e,v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M:new(obj)
|
||||
-- dump(obj)
|
||||
local eid = self:_newentity()
|
||||
local typenames = context[self].typenames
|
||||
for k, v in pairs(obj) do
|
||||
local tc = typenames[k]
|
||||
if not tc then
|
||||
error("Invalid key : " .. k)
|
||||
end
|
||||
local id = self:_addcomponent(eid, tc.id)
|
||||
self:object(k, id, v)
|
||||
end
|
||||
-- dump(obj)
|
||||
local eid = self:_newentity()
|
||||
local typenames = context[self].typenames
|
||||
for k,v in pairs(obj) do
|
||||
local tc = typenames[k]
|
||||
if not tc then
|
||||
error ("Invalid key : ".. k)
|
||||
end
|
||||
local id = self:_addcomponent(eid, tc.id)
|
||||
self:object(k, id, v)
|
||||
end
|
||||
end
|
||||
|
||||
function M:ref(name, refobj)
|
||||
local obj = assert(refobj[name])
|
||||
local ctx = context[self]
|
||||
local typenames = ctx.typenames
|
||||
local tc = assert(typenames[name])
|
||||
local refid = self:_reuse(tc.id)
|
||||
if refid then
|
||||
local p = context[self].select[name .. ":out"]
|
||||
self:_sync(p, refobj)
|
||||
else
|
||||
local eid = self:_newentity()
|
||||
refid = self:_addcomponent(eid, tc.id)
|
||||
self:object(name, refid, obj)
|
||||
end
|
||||
refobj[1] = refid
|
||||
for k, v in pairs(refobj) do
|
||||
if (v == true or v == false) and name ~= k then
|
||||
local p = context[self].select[string.format("%s %s?out", name, k)]
|
||||
self:_sync(p, refobj)
|
||||
end
|
||||
end
|
||||
return refid
|
||||
local obj = assert(refobj[name])
|
||||
local ctx = context[self]
|
||||
local typenames = ctx.typenames
|
||||
local tc = assert(typenames[name])
|
||||
local refid = self:_reuse(tc.id)
|
||||
refobj[2] = tc.id
|
||||
if refid then
|
||||
local p = context[self].select[name .. ":out"]
|
||||
refobj[1] = refid
|
||||
self:_sync(p, refobj)
|
||||
else
|
||||
local eid = self:_newentity()
|
||||
refid = self:_addcomponent(eid, tc.id)
|
||||
refobj[1] = refid
|
||||
self:object(name, refid, obj)
|
||||
end
|
||||
for k,v in pairs(refobj) do
|
||||
if (v == true or v == false) and name ~= k then
|
||||
local p = context[self].select[k .. "?out"]
|
||||
self:_sync(p, refobj)
|
||||
end
|
||||
end
|
||||
return refid
|
||||
end
|
||||
|
||||
function M:object_ref(name, refid)
|
||||
local typenames = context[self].typenames
|
||||
return { refid, typenames[name].id }
|
||||
end
|
||||
|
||||
function M:release(name, refid)
|
||||
local id = assert(context[self].typenames[name].id)
|
||||
self:_release(id, refid)
|
||||
local id = assert(context[self].typenames[name].id)
|
||||
self:_release(id, refid)
|
||||
end
|
||||
|
||||
function M:context(t)
|
||||
local typenames = context[self].typenames
|
||||
local id = {}
|
||||
for i, name in ipairs(t) do
|
||||
local tc = typenames[name]
|
||||
if not tc then
|
||||
error("Invalid component name " .. name)
|
||||
end
|
||||
id[i] = tc.id
|
||||
end
|
||||
return self:_context(id)
|
||||
local typenames = context[self].typenames
|
||||
local id = {}
|
||||
for i, name in ipairs(t) do
|
||||
local tc = typenames[name]
|
||||
if not tc then
|
||||
error ("Invalid component name " .. name)
|
||||
end
|
||||
id[i] = tc.id
|
||||
end
|
||||
return self:_context(id)
|
||||
end
|
||||
|
||||
function M:select(pat)
|
||||
return context[self].select[pat]()
|
||||
return context[self].select[pat]()
|
||||
end
|
||||
|
||||
function M:sync(pat, iter)
|
||||
local p = context[self].select[pat]
|
||||
self:_sync(p, iter)
|
||||
return iter
|
||||
local p = context[self].select[pat]
|
||||
self:_sync(p, iter)
|
||||
return iter
|
||||
end
|
||||
|
||||
function M:clear(name)
|
||||
local id = assert(context[self].typenames[name].id)
|
||||
self:_clear(id)
|
||||
local id = assert(context[self].typenames[name].id)
|
||||
self:_clear(id)
|
||||
end
|
||||
|
||||
local function gen_sorted_id(self, sorted, name)
|
||||
local ctx = context[self]
|
||||
local typenames = ctx.typenames
|
||||
local t = assert(typenames[name])
|
||||
local stype = typenames[sorted]
|
||||
if stype == nil then
|
||||
local id = ctx.id + 1
|
||||
assert(id <= ecs._MAXTYPE)
|
||||
ctx.id = id
|
||||
stype = {
|
||||
id = id,
|
||||
name = sorted,
|
||||
size = ecs._ORDERKEY,
|
||||
tag = true,
|
||||
}
|
||||
self:_newtype(id, stype.size)
|
||||
typenames[sorted] = stype
|
||||
else
|
||||
assert(stype.size == ecs._ORDERKEY)
|
||||
end
|
||||
return stype.id, t.id
|
||||
local ctx = context[self]
|
||||
local typenames = ctx.typenames
|
||||
local t = assert(typenames[name])
|
||||
local stype = typenames[sorted]
|
||||
if stype == nil then
|
||||
local id = ctx.id + 1
|
||||
assert(id <= ecs._MAXTYPE)
|
||||
ctx.id = id
|
||||
stype = {
|
||||
id = id,
|
||||
name = sorted,
|
||||
size = ecs._ORDERKEY,
|
||||
tag = true
|
||||
}
|
||||
self:_newtype(id, stype.size)
|
||||
typenames[sorted] = stype
|
||||
else
|
||||
assert(stype.size == ecs._ORDERKEY)
|
||||
end
|
||||
return stype.id, t.id
|
||||
end
|
||||
|
||||
function M:sort(sorted, name)
|
||||
self:_sortkey(gen_sorted_id(self, sorted, name))
|
||||
self:_sortkey(gen_sorted_id(self, sorted, name))
|
||||
end
|
||||
|
||||
function M:order(sorted, refname, order_array)
|
||||
local sid, rid = gen_sorted_id(self, sorted, refname)
|
||||
self:_orderkey(sid, rid, order_array)
|
||||
local sid, rid = gen_sorted_id(self, sorted, refname)
|
||||
self:_orderkey(sid, rid, order_array)
|
||||
end
|
||||
|
||||
function M:bsearch(sorted, name, value)
|
||||
local typenames = context[self].typenames
|
||||
local sorted_id = typenames[sorted].id
|
||||
local value_id = typenames[name].id
|
||||
return self:_bsearch(sorted_id, value_id, value)
|
||||
local typenames = context[self].typenames
|
||||
local sorted_id = typenames[sorted].id
|
||||
local value_id = typenames[name].id
|
||||
return self:_bsearch(sorted_id, value_id, value)
|
||||
end
|
||||
|
||||
do
|
||||
local _object = M._object
|
||||
function M:object(name, refid, v)
|
||||
local pat = context[self].ref[name]
|
||||
return _object(pat, v, refid)
|
||||
end
|
||||
|
||||
function M:singleton(name, v)
|
||||
local pat = context[self].ref[name]
|
||||
return _object(pat, v, 1)
|
||||
end
|
||||
local _object = M._object
|
||||
function M:object(name, refid, v)
|
||||
local pat = context[self].ref[name]
|
||||
return _object(pat, v, refid)
|
||||
end
|
||||
|
||||
function M:singleton(name, v)
|
||||
local pat = context[self].ref[name]
|
||||
return _object(pat, v, 1)
|
||||
end
|
||||
end
|
||||
|
||||
function ecs.world()
|
||||
local w = ecs._world()
|
||||
context[w].typenames.REMOVED = {
|
||||
name = "REMOVED",
|
||||
id = ecs._REMOVED,
|
||||
size = 0,
|
||||
tag = true,
|
||||
}
|
||||
return w
|
||||
local w = ecs._world()
|
||||
context[w].typenames.REMOVED = {
|
||||
name = "REMOVED",
|
||||
id = ecs._REMOVED,
|
||||
size = 0,
|
||||
tag = true,
|
||||
}
|
||||
return w
|
||||
end
|
||||
|
||||
return ecs
|
||||
|
||||
Loading…
Reference in New Issue