🐳 chore(工具): 更新 lua ecs

develop
xiaojin 5 years ago
parent 674f932099
commit 8d44c1e8b4

@ -293,11 +293,9 @@ lookup_component(struct component_pool *pool, unsigned int eid, int guess_index)
} }
static inline void static inline void
replace_id(struct component_pool *c, int index, unsigned int eid) { replace_id(struct component_pool *c, int from, int to, unsigned int eid) {
unsigned int rid = c->id[index];
c->id[index] = eid;
int i; int i;
for (i=index+1;i<c->n && c->id[i] == rid;i++) { for (i=from;i<to;i++) {
c->id[i] = eid; c->id[i] = eid;
} }
} }
@ -313,20 +311,26 @@ entity_disable_tag_(struct entity_world *w, int cid, int index, int tag_id) {
if (index < 0) if (index < 0)
return; return;
} }
int i; int from,to;
for (i=index - 1; i>=0; i--) { // find next tag. You may disable subsquent tags in iteration.
if (c->id[i] != eid) { // For example, The sequence is 1 3 5 7 9 . We are now on 5 , and disable 7 .
replace_id(c, i+1, c->id[i]); // We should change 7 to 9 ( 1 3 5 9 9 ) rather than 7 to 5 ( 1 3 5 5 9 )
// iterator -> ^ ^
for (to = index+1; to<c->n; to++) {
if (c->id[to] != eid) {
for (from = index-1; from>=0; from--) {
if (c->id[from] != eid)
break;
}
replace_id(c, from+1, to, c->id[to]);
return; return;
} }
} }
for (i=index+1;i<c->n;i++) { for (from = index-1; from>=0; from--) {
if (c->id[i] != eid) { if (c->id[from] != eid)
replace_id(c, index, c->id[i]); break;
return;
}
} }
c->n = 0; c->n = from + 1;
} }
static void static void
@ -517,10 +521,8 @@ entity_iter_(struct entity_world *w, int cid, int index) {
if (c->stride == STRIDE_TAG) { if (c->stride == STRIDE_TAG) {
// it's a tag // it's a tag
unsigned int eid = c->id[index]; unsigned int eid = c->id[index];
if (index > 0 && eid == c->id[index-1]) { if (index < c->n - 1 && eid == c->id[index+1]) {
remove_dup(c, index); remove_dup(c, index+1);
if (index >= c->n)
return NULL;
} }
return DUMMY_PTR; return DUMMY_PTR;
} }
@ -1025,37 +1027,14 @@ remove_tag(lua_State *L, int lua_index, const char *name) {
} }
static void static void
update_last_index(lua_State *L, int world_index, int lua_index, struct group_iter *iter, int idx) { update_iter(lua_State *L, int world_index, int lua_index, struct group_iter *iter, int idx, int mainkey, int skip) {
struct field *f = iter->f;
int i; int i;
int mainkey = iter->k[0].id; for (i=0;i<skip;i++) {
struct component_pool *c = &iter->world->c[mainkey]; f += iter->k[i].field_n;
int disable_mainkey = 0;
if (!(iter->k[0].attrib & COMPONENT_FILTER)) {
if (c->stride == STRIDE_TAG) {
// The mainkey is a tag, delay disable
disable_mainkey = ((iter->k[0].attrib & COMPONENT_OUT) && remove_tag(L, lua_index, iter->k[0].name));
} else if ((iter->k[0].attrib & COMPONENT_OUT)
&& get_write_component(L, lua_index, iter->k[0].name, iter->f, c)) {
struct component_pool *c = &iter->world->c[mainkey];
if (c->n <= idx) {
luaL_error(L, "Can't find component %s for index %d", iter->k[0].name, idx);
}
if (c->stride == STRIDE_LUA) {
if (lua_getiuservalue(L, world_index, mainkey * 2 + 2) != LUA_TTABLE) {
luaL_error(L, "Missing lua table for %d", mainkey);
}
lua_insert(L, -2);
lua_rawseti(L, -2, idx+1);
} else {
void * buffer = get_ptr(c, idx);
write_component_object(L, iter->k[0].field_n, iter->f, buffer);
}
}
} }
for (i=skip;i<iter->nkey;i++) {
struct field *f = iter->f + iter->k[0].field_n;
for (i=1;i<iter->nkey;i++) {
struct group_key *k = &iter->k[i]; struct group_key *k = &iter->k[i];
if (!(k->attrib & (COMPONENT_FILTER | COMPONENT_REFINDEX))) { if (!(k->attrib & (COMPONENT_FILTER | COMPONENT_REFINDEX))) {
struct component_pool *c = &iter->world->c[k->id]; struct component_pool *c = &iter->world->c[k->id];
@ -1149,6 +1128,38 @@ update_last_index(lua_State *L, int world_index, int lua_index, struct group_ite
} }
f += k->field_n; f += k->field_n;
} }
}
static void
update_last_index(lua_State *L, int world_index, int lua_index, struct group_iter *iter, int idx) {
int mainkey = iter->k[0].id;
struct component_pool *c = &iter->world->c[mainkey];
int disable_mainkey = 0;
if (!(iter->k[0].attrib & COMPONENT_FILTER)) {
if (c->stride == STRIDE_TAG) {
// The mainkey is a tag, delay disable
disable_mainkey = ((iter->k[0].attrib & COMPONENT_OUT) && remove_tag(L, lua_index, iter->k[0].name));
} else if ((iter->k[0].attrib & COMPONENT_OUT)
&& get_write_component(L, lua_index, iter->k[0].name, iter->f, c)) {
struct component_pool *c = &iter->world->c[mainkey];
if (c->n <= idx) {
luaL_error(L, "Can't find component %s for index %d", iter->k[0].name, idx);
}
if (c->stride == STRIDE_LUA) {
if (lua_getiuservalue(L, world_index, mainkey * 2 + 2) != LUA_TTABLE) {
luaL_error(L, "Missing lua table for %d", mainkey);
}
lua_insert(L, -2);
lua_rawseti(L, -2, idx+1);
} else {
void * buffer = get_ptr(c, idx);
write_component_object(L, iter->k[0].field_n, iter->f, buffer);
}
}
}
update_iter(L, world_index, lua_index, iter, idx, mainkey, 1);
if (disable_mainkey) { if (disable_mainkey) {
entity_disable_tag_(iter->world, mainkey, idx, mainkey); entity_disable_tag_(iter->world, mainkey, idx, mainkey);
} }
@ -1177,13 +1188,12 @@ read_component_in_field(lua_State *L, int lua_index, const char *name, int n, st
// -1 : end ; 0 : next ; 1 : succ // -1 : end ; 0 : next ; 1 : succ
static int static int
query_index(struct group_iter *iter, int mainkey, int idx, unsigned int index[MAX_COMPONENT]) { query_index(struct group_iter *iter, int skip, int mainkey, int idx, unsigned int index[MAX_COMPONENT]) {
if (entity_iter_(iter->world, mainkey, idx) == NULL) { if (entity_iter_(iter->world, mainkey, idx) == NULL) {
return -1; return -1;
} }
index[0] = idx+1;
int j; int j;
for (j=1;j<iter->nkey;j++) { for (j=skip;j<iter->nkey;j++) {
struct group_key *k = &iter->k[j]; struct group_key *k = &iter->k[j];
if (k->attrib & COMPONENT_ABSENT) { if (k->attrib & COMPONENT_ABSENT) {
if (entity_sibling_index_(iter->world, mainkey, idx, k->id)) { if (entity_sibling_index_(iter->world, mainkey, idx, k->id)) {
@ -1255,24 +1265,30 @@ read_iter(lua_State *L, int world_index, int obj_index, struct group_iter *iter,
} }
static int static int
lsync(lua_State *L) { get_integer(lua_State *L, int index, int i, const char *key) {
struct group_iter *iter = luaL_checkudata(L, 2, "ENTITY_GROUPITER"); if (lua_rawgeti(L, index, i) != LUA_TNUMBER) {
luaL_checktype(L, 3, LUA_TTABLE); return luaL_error(L, "Can't find %s in iterator", key);
if (lua_rawgeti(L, 3, 1) != LUA_TNUMBER) {
return luaL_error(L, "Invalid iterator");
} }
int idx = lua_tointeger(L, -1) - 1; int r = lua_tointeger(L, -1);
if (idx < 0)
return luaL_error(L, "Invalid iterator index %d", idx);
lua_pop(L, 1); lua_pop(L, 1);
if (r <= 0)
return luaL_error(L, "Invalid %s (%d)", key, r);
return r;
}
static int
lsync(lua_State *L) {
struct group_iter *iter = luaL_checkudata(L, 2, "ENTITY_GROUPITER");
luaL_checktype(L, 3, LUA_TTABLE);
int idx = get_integer(L, 3, 1, "index") - 1;
int mainkey = get_integer(L, 3, 2, "mainkey");
unsigned int index[MAX_COMPONENT]; unsigned int index[MAX_COMPONENT];
if (query_index(iter, iter->k[0].id, idx, index) <=0) { if (query_index(iter, 0, mainkey, idx, index) <=0) {
return luaL_error(L, "Read pattern fail"); return luaL_error(L, "Read pattern fail");
} }
if (!iter->readonly) { if (!iter->readonly) {
update_last_index(L, 1, 3, iter, idx); update_iter(L, 1, 3, iter, idx, mainkey, 0);
} }
read_iter(L, 1, 3, iter, index); read_iter(L, 1, 3, iter, index);
return 0; return 0;
@ -1301,7 +1317,9 @@ leach_group(lua_State *L) {
int mainkey = iter->k[0].id; int mainkey = iter->k[0].id;
unsigned int index[MAX_COMPONENT]; unsigned int index[MAX_COMPONENT];
for (;;) { for (;;) {
int ret = query_index(iter, mainkey, i++, index); int idx = i++;
index[0] = idx + 1;
int ret = query_index(iter, 1, mainkey, idx, index);
if (ret < 0) if (ret < 0)
return 0; return 0;
if (ret > 0) if (ret > 0)
@ -1548,12 +1566,6 @@ lgroupiter(lua_State *L) {
iter->readonly = 0; iter->readonly = 0;
} }
int mainkey_attrib = iter->k[0].attrib; int mainkey_attrib = iter->k[0].attrib;
if (mainkey_attrib & COMPONENT_OPTIONAL) {
return luaL_error(L, "The main key should not be optional");
}
if (is_temporary(mainkey_attrib)) {
return luaL_error(L, "The main key can't be temporary");
}
if (mainkey_attrib & COMPONENT_ABSENT) { if (mainkey_attrib & COMPONENT_ABSENT) {
return luaL_error(L, "The main key can't be absent"); return luaL_error(L, "The main key can't be absent");
} }
@ -1565,18 +1577,6 @@ lgroupiter(lua_State *L) {
return 1; return 1;
} }
static int
get_integer(lua_State *L, int index, int i, const char *key) {
if (lua_rawgeti(L, index, i) != LUA_TNUMBER) {
return luaL_error(L, "Can't find %s in iterator", key);
}
int r = lua_tointeger(L, -1);
lua_pop(L, 1);
if (r <= 0)
return luaL_error(L, "Invalid %s (%d)", key, r);
return r;
}
static int static int
lremove(lua_State *L) { lremove(lua_State *L) {
struct entity_world *w = getW(L); struct entity_world *w = getW(L);
@ -1639,9 +1639,11 @@ lbsearch(lua_State *L) {
int * v = entity_iter_(w, value_id, mid); int * v = entity_iter_(w, value_id, mid);
if (*v == value) { if (*v == value) {
// found // found
lua_createtable(L, 1, 0); lua_createtable(L, 2, 0);
lua_pushinteger(L, mid + 1); lua_pushinteger(L, mid + 1);
lua_seti(L, -2, 1); lua_seti(L, -2, 1);
lua_pushinteger(L, sorted_id);
lua_seti(L, -2, 2);
return 1; return 1;
} }
if (*v < value) { if (*v < value) {
@ -1660,9 +1662,11 @@ lbsearch(lua_State *L) {
int * v = entity_iter_(w, value_id, index - 1); int * v = entity_iter_(w, value_id, index - 1);
if (*v == value) { if (*v == value) {
// found // found
lua_createtable(L, 1, 0); lua_createtable(L, 2, 0);
lua_pushinteger(L, index); lua_pushinteger(L, index);
lua_seti(L, -2, 1); lua_seti(L, -2, 1);
lua_pushinteger(L, sorted_id);
lua_seti(L, -2, 2);
return 1; return 1;
} }
if (*v < value) { if (*v < value) {

@ -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 ecs = require "ecs.core"
local function get_attrib(opt, inout) local function get_attrib(opt, inout)
if opt == nil then if opt == nil then
return { return { exist = true }
exist = true, end
} local desc = {}
end if opt == "?" then
local desc = {} desc.opt = true
if opt == "?" then else
desc.opt = true assert(opt == ":")
else end
assert(opt == ":") if inout == "in" then
end desc.r = true
if inout == "in" then elseif inout == "out" or inout == "new" then
desc.r = true desc.w = true
elseif inout == "out" or inout == "new" then elseif inout == "update" then
desc.w = true desc.r = true
elseif inout == "update" then desc.w = true
desc.r = true elseif inout == "exist" then
desc.w = true desc.exist = true
elseif inout == "exist" then assert(not desc.opt)
desc.exist = true elseif inout == "absent" then
assert(not desc.opt) desc.absent = true
elseif inout == "absent" then assert(not desc.opt)
desc.absent = true else
assert(not desc.opt) assert(inout == "temp")
else end
assert(inout == "temp") return desc
end
return desc
end end
local function cache_world(obj, k) local function cache_world(obj, k)
local c = { local c = {
typenames = {}, typenames = {},
id = 0, id = 0,
select = {}, select = {},
ref = {}, ref = {},
} }
local function gen_ref_pat(key) local function gen_ref_pat(key)
local typenames = c.typenames local typenames = c.typenames
local desc = {} local desc = {}
local tc = typenames[key] local tc = typenames[key]
if tc == nil then if tc == nil then
error("Unknown type " .. key) error("Unknown type " .. key)
end end
local a = { local a = {
exist = true, exist = true,
name = tc.name, name = tc.name,
id = tc.id, id = tc.id,
type = tc.type, type = tc.type,
} }
local n = #tc local n = #tc
for i = 1, #tc do for i=1,#tc do
a[i] = tc[i] a[i] = tc[i]
end end
desc[1] = a desc[1] = a
return desc return desc
end end
local function gen_select_pat(pat) local function gen_select_pat(pat)
local typenames = c.typenames local typenames = c.typenames
local desc = {} local desc = {}
local idx = 1 local idx = 1
for token in pat:gmatch "[^ ]+" do for token in pat:gmatch "[^ ]+" do
local key, index, padding = token:match "^([_%w]+)%(?([_%w]*)%)?(.*)" local key, index, padding = token:match "^([_%w]+)%(?([_%w]*)%)?(.*)"
assert(key, "Invalid pattern") assert(key, "Invalid pattern")
local opt, inout local opt, inout
if padding ~= "" then if padding ~= "" then
opt, inout = padding:match "^([:?])(%l+)$" opt, inout = padding:match "^([:?])(%l+)$"
assert(opt, "Invalid pattern") assert(opt, "Invalid pattern")
end end
local tc = typenames[key] local tc = typenames[key]
if tc == nil then if tc == nil then
error("Unknown type " .. key) error("Unknown type " .. key)
end end
if index ~= "" then if index ~= "" then
local indexc = typenames[index] local indexc = typenames[index]
if indexc == nil then if indexc == nil then
error("Unknown index type " .. index) error("Unknown index type "..index)
end end
local a = get_attrib(opt, inout == "temp" and "temp" or "in") local a = get_attrib(opt, inout == "temp" and "temp" or "in")
a.name = index a.name = index
a.id = indexc.id a.id = indexc.id
a.type = indexc.type a.type = indexc.type
a.ref = true a.ref = true
desc[idx] = a desc[idx] = a
idx = idx + 1 idx = idx + 1
end end
local a = get_attrib(opt, inout) local a = get_attrib(opt, inout)
a.name = tc.name a.name = tc.name
a.id = tc.id a.id = tc.id
a.type = tc.type a.type = tc.type
local n = #tc local n = #tc
for i = 1, #tc do for i=1,#tc do
a[i] = tc[i] a[i] = tc[i]
end end
desc[idx] = a desc[idx] = a
idx = idx + 1 idx = idx + 1
if tc.ref and index == "" then if tc.ref and index == "" then
local dead = typenames[key .. "_dead"] local dead = typenames[key .. "_dead"]
local a = { local a = {
absent = true, absent = true,
name = dead.name, name = dead.name,
id = dead.id, id = dead.id,
} }
desc[idx] = a desc[idx] = a
idx = idx + 1 idx = idx + 1
end end
end end
return desc return desc
end end
local function cache_select(cache, pat) local function cache_select(cache, pat)
local pat_desc = gen_select_pat(pat) local pat_desc = gen_select_pat(pat)
cache[pat] = k:_groupiter(pat_desc) cache[pat] = k:_groupiter(pat_desc)
return cache[pat] return cache[pat]
end end
setmetatable(c.select, { setmetatable(c.select, {
__mode = "kv", __mode = "kv",
__index = cache_select, __index = cache_select,
}) })
local function cache_ref(cache, pat) local function cache_ref(cache, pat)
local pat_desc = gen_ref_pat(pat) local pat_desc = gen_ref_pat(pat)
cache[pat] = k:_groupiter(pat_desc) cache[pat] = k:_groupiter(pat_desc)
return cache[pat] return cache[pat]
end end
setmetatable(c.ref, { setmetatable(c.ref, {
__mode = "kv", __mode = "kv",
__index = cache_ref, __index = cache_ref,
}) })
obj[k] = c obj[k] = c
return c return c
end end
local context = setmetatable({}, { local context = setmetatable({}, { __index = cache_world })
__index = cache_world,
})
local typeid = { local typeid = {
int = assert(ecs._TYPEINT), int = assert(ecs._TYPEINT),
float = assert(ecs._TYPEFLOAT), float = assert(ecs._TYPEFLOAT),
bool = assert(ecs._TYPEBOOL), bool = assert(ecs._TYPEBOOL),
int64 = assert(ecs._TYPEINT64), int64 = assert(ecs._TYPEINT64),
dword = assert(ecs._TYPEDWORD), dword = assert(ecs._TYPEDWORD),
word = assert(ecs._TYPEWORD), word = assert(ecs._TYPEWORD),
byte = assert(ecs._TYPEBYTE), byte = assert(ecs._TYPEBYTE),
double = assert(ecs._TYPEDOUBLE), double = assert(ecs._TYPEDOUBLE),
userdata = assert(ecs._TYPEUSERDATA), userdata = assert(ecs._TYPEUSERDATA),
} }
local typesize = { local typesize = {
[typeid.int] = 4, [typeid.int] = 4,
[typeid.float] = 4, [typeid.float] = 4,
[typeid.bool] = 1, [typeid.bool] = 1,
[typeid.int64] = 8, [typeid.int64] = 8,
[typeid.dword] = 4, [typeid.dword] = 4,
[typeid.word] = 2, [typeid.word] = 2,
[typeid.byte] = 1, [typeid.byte] = 1,
[typeid.double] = 8, [typeid.double] = 8,
[typeid.userdata] = 8, [typeid.userdata] = 8,
} }
local M = ecs._METHODS local M = ecs._METHODS
do -- newtype do -- newtype
local function parse(s) local function parse(s)
-- s is "name:typename" -- s is "name:typename"
local name, typename = s:match "^([%w_]+):(%w+)$" local name, typename = s:match "^([%w_]+):(%w+)$"
local typeid = assert(typeid[typename]) local typeid = assert(typeid[typename])
return {typeid, name} return { typeid, name }
end end
local function align(c, field) local function align(c, field)
local t = field[1] local t = field[1]
local tsize = typesize[t] local tsize = typesize[t]
local offset = ((c.size + tsize - 1) & ~(tsize - 1)) local offset = ((c.size + tsize - 1) & ~(tsize-1))
c.size = offset + tsize c.size = offset + tsize
field[3] = offset field[3] = offset
return field return field
end end
local function align_struct(c, t) local function align_struct(c, t)
if t then if t then
local s = typesize[t] - 1 local s = typesize[t] - 1
c.size = ((c.size + s) & ~s) c.size = ((c.size + s) & ~s)
end end
end end
function M:register(typeclass) function M:register(typeclass)
local name = assert(typeclass.name) local name = assert(typeclass.name)
local ctx = context[self] local ctx = context[self]
local typenames = ctx.typenames local typenames = ctx.typenames
local id = ctx.id + 1 local id = ctx.id + 1
assert(typenames[name] == nil and id <= ecs._MAXTYPE) assert(typenames[name] == nil and id <= ecs._MAXTYPE)
ctx.id = id ctx.id = id
local c = { local c = {
id = id, id = id,
name = name, name = name,
size = 0, size = 0,
} }
for i, v in ipairs(typeclass) do for i, v in ipairs(typeclass) do
c[i] = align(c, parse(v)) c[i] = align(c, parse(v))
end end
local ttype = typeclass.type local ttype = typeclass.type
if ttype == "lua" then if ttype == "lua" then
assert(c.size == 0) assert(c.size == 0)
c.size = ecs._LUAOBJECT c.size = ecs._LUAOBJECT
assert(c[1] == nil) assert(c[1] == nil)
elseif c.size > 0 then elseif c.size > 0 then
align_struct(c, typeclass[1][1]) align_struct(c, typeclass[1][1])
else else
-- size == 0, one value -- size == 0, one value
if ttype then if ttype then
local t = assert(typeid[typeclass.type]) local t = assert(typeid[typeclass.type])
c.type = t c.type = t
c.size = typesize[t] c.size = typesize[t]
c[1] = {t, "v", 0} c[1] = { t, "v", 0 }
else else
c.tag = true c.tag = true
end end
end end
typenames[name] = c typenames[name] = c
self:_newtype(id, c.size) self:_newtype(id, c.size)
if typeclass.ref then if typeclass.ref then
c.ref = true c.ref = true
self:register{ self:register { name = name .. "_dead" }
name = name .. "_dead", end
} end
end
end
end end
local function dump(obj) local function dump(obj)
for e, v in pairs(obj) do for e,v in pairs(obj) do
if type(v) == "table" then if type(v) == "table" then
for k, v in pairs(v) do for k,v in pairs(v) do
print(e, k, v) print(e,k,v)
end end
else else
print(e, v) print(e,v)
end end
end end
end end
function M:new(obj) function M:new(obj)
-- dump(obj) -- dump(obj)
local eid = self:_newentity() local eid = self:_newentity()
local typenames = context[self].typenames local typenames = context[self].typenames
for k, v in pairs(obj) do for k,v in pairs(obj) do
local tc = typenames[k] local tc = typenames[k]
if not tc then if not tc then
error("Invalid key : " .. k) error ("Invalid key : ".. k)
end end
local id = self:_addcomponent(eid, tc.id) local id = self:_addcomponent(eid, tc.id)
self:object(k, id, v) self:object(k, id, v)
end end
end end
function M:ref(name, refobj) function M:ref(name, refobj)
local obj = assert(refobj[name]) local obj = assert(refobj[name])
local ctx = context[self] local ctx = context[self]
local typenames = ctx.typenames local typenames = ctx.typenames
local tc = assert(typenames[name]) local tc = assert(typenames[name])
local refid = self:_reuse(tc.id) local refid = self:_reuse(tc.id)
if refid then refobj[2] = tc.id
local p = context[self].select[name .. ":out"] if refid then
self:_sync(p, refobj) local p = context[self].select[name .. ":out"]
else refobj[1] = refid
local eid = self:_newentity() self:_sync(p, refobj)
refid = self:_addcomponent(eid, tc.id) else
self:object(name, refid, obj) local eid = self:_newentity()
end refid = self:_addcomponent(eid, tc.id)
refobj[1] = refid refobj[1] = refid
for k, v in pairs(refobj) do self:object(name, refid, obj)
if (v == true or v == false) and name ~= k then end
local p = context[self].select[string.format("%s %s?out", name, k)] for k,v in pairs(refobj) do
self:_sync(p, refobj) if (v == true or v == false) and name ~= k then
end local p = context[self].select[k .. "?out"]
end self:_sync(p, refobj)
return refid end
end
return refid
end
function M:object_ref(name, refid)
local typenames = context[self].typenames
return { refid, typenames[name].id }
end end
function M:release(name, refid) function M:release(name, refid)
local id = assert(context[self].typenames[name].id) local id = assert(context[self].typenames[name].id)
self:_release(id, refid) self:_release(id, refid)
end end
function M:context(t) function M:context(t)
local typenames = context[self].typenames local typenames = context[self].typenames
local id = {} local id = {}
for i, name in ipairs(t) do for i, name in ipairs(t) do
local tc = typenames[name] local tc = typenames[name]
if not tc then if not tc then
error("Invalid component name " .. name) error ("Invalid component name " .. name)
end end
id[i] = tc.id id[i] = tc.id
end end
return self:_context(id) return self:_context(id)
end end
function M:select(pat) function M:select(pat)
return context[self].select[pat]() return context[self].select[pat]()
end end
function M:sync(pat, iter) function M:sync(pat, iter)
local p = context[self].select[pat] local p = context[self].select[pat]
self:_sync(p, iter) self:_sync(p, iter)
return iter return iter
end end
function M:clear(name) function M:clear(name)
local id = assert(context[self].typenames[name].id) local id = assert(context[self].typenames[name].id)
self:_clear(id) self:_clear(id)
end end
local function gen_sorted_id(self, sorted, name) local function gen_sorted_id(self, sorted, name)
local ctx = context[self] local ctx = context[self]
local typenames = ctx.typenames local typenames = ctx.typenames
local t = assert(typenames[name]) local t = assert(typenames[name])
local stype = typenames[sorted] local stype = typenames[sorted]
if stype == nil then if stype == nil then
local id = ctx.id + 1 local id = ctx.id + 1
assert(id <= ecs._MAXTYPE) assert(id <= ecs._MAXTYPE)
ctx.id = id ctx.id = id
stype = { stype = {
id = id, id = id,
name = sorted, name = sorted,
size = ecs._ORDERKEY, size = ecs._ORDERKEY,
tag = true, tag = true
} }
self:_newtype(id, stype.size) self:_newtype(id, stype.size)
typenames[sorted] = stype typenames[sorted] = stype
else else
assert(stype.size == ecs._ORDERKEY) assert(stype.size == ecs._ORDERKEY)
end end
return stype.id, t.id return stype.id, t.id
end end
function M:sort(sorted, name) function M:sort(sorted, name)
self:_sortkey(gen_sorted_id(self, sorted, name)) self:_sortkey(gen_sorted_id(self, sorted, name))
end end
function M:order(sorted, refname, order_array) function M:order(sorted, refname, order_array)
local sid, rid = gen_sorted_id(self, sorted, refname) local sid, rid = gen_sorted_id(self, sorted, refname)
self:_orderkey(sid, rid, order_array) self:_orderkey(sid, rid, order_array)
end end
function M:bsearch(sorted, name, value) function M:bsearch(sorted, name, value)
local typenames = context[self].typenames local typenames = context[self].typenames
local sorted_id = typenames[sorted].id local sorted_id = typenames[sorted].id
local value_id = typenames[name].id local value_id = typenames[name].id
return self:_bsearch(sorted_id, value_id, value) return self:_bsearch(sorted_id, value_id, value)
end end
do do
local _object = M._object local _object = M._object
function M:object(name, refid, v) function M:object(name, refid, v)
local pat = context[self].ref[name] local pat = context[self].ref[name]
return _object(pat, v, refid) return _object(pat, v, refid)
end end
function M:singleton(name, v) function M:singleton(name, v)
local pat = context[self].ref[name] local pat = context[self].ref[name]
return _object(pat, v, 1) return _object(pat, v, 1)
end end
end end
function ecs.world() function ecs.world()
local w = ecs._world() local w = ecs._world()
context[w].typenames.REMOVED = { context[w].typenames.REMOVED = {
name = "REMOVED", name = "REMOVED",
id = ecs._REMOVED, id = ecs._REMOVED,
size = 0, size = 0,
tag = true, tag = true,
} }
return w return w
end end
return ecs return ecs

Loading…
Cancel
Save