🐳 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
replace_id(struct component_pool *c, int index, unsigned int eid) {
unsigned int rid = c->id[index];
c->id[index] = eid;
replace_id(struct component_pool *c, int from, int to, unsigned int eid) {
int i;
for (i=index+1;i<c->n && c->id[i] == rid;i++) {
for (i=from;i<to;i++) {
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)
return;
}
int i;
for (i=index - 1; i>=0; i--) {
if (c->id[i] != eid) {
replace_id(c, i+1, c->id[i]);
return;
}
int from,to;
// find next tag. You may disable subsquent tags in iteration.
// For example, The sequence is 1 3 5 7 9 . We are now on 5 , and disable 7 .
// 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;
}
for (i=index+1;i<c->n;i++) {
if (c->id[i] != eid) {
replace_id(c, index, c->id[i]);
replace_id(c, from+1, to, c->id[to]);
return;
}
}
c->n = 0;
for (from = index-1; from>=0; from--) {
if (c->id[from] != eid)
break;
}
c->n = from + 1;
}
static void
@ -517,10 +521,8 @@ entity_iter_(struct entity_world *w, int cid, int index) {
if (c->stride == STRIDE_TAG) {
// it's a tag
unsigned int eid = c->id[index];
if (index > 0 && eid == c->id[index-1]) {
remove_dup(c, index);
if (index >= c->n)
return NULL;
if (index < c->n - 1 && eid == c->id[index+1]) {
remove_dup(c, index+1);
}
return DUMMY_PTR;
}
@ -1025,37 +1027,14 @@ remove_tag(lua_State *L, int lua_index, const char *name) {
}
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 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);
}
}
for (i=0;i<skip;i++) {
f += iter->k[i].field_n;
}
struct field *f = iter->f + iter->k[0].field_n;
for (i=1;i<iter->nkey;i++) {
for (i=skip;i<iter->nkey;i++) {
struct group_key *k = &iter->k[i];
if (!(k->attrib & (COMPONENT_FILTER | COMPONENT_REFINDEX))) {
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;
}
}
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) {
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
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) {
return -1;
}
index[0] = idx+1;
int j;
for (j=1;j<iter->nkey;j++) {
for (j=skip;j<iter->nkey;j++) {
struct group_key *k = &iter->k[j];
if (k->attrib & COMPONENT_ABSENT) {
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
lsync(lua_State *L) {
struct group_iter *iter = luaL_checkudata(L, 2, "ENTITY_GROUPITER");
luaL_checktype(L, 3, LUA_TTABLE);
if (lua_rawgeti(L, 3, 1) != LUA_TNUMBER) {
return luaL_error(L, "Invalid iterator");
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 idx = lua_tointeger(L, -1) - 1;
if (idx < 0)
return luaL_error(L, "Invalid iterator index %d", idx);
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
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];
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");
}
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);
return 0;
@ -1301,7 +1317,9 @@ leach_group(lua_State *L) {
int mainkey = iter->k[0].id;
unsigned int index[MAX_COMPONENT];
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)
return 0;
if (ret > 0)
@ -1548,12 +1566,6 @@ lgroupiter(lua_State *L) {
iter->readonly = 0;
}
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) {
return luaL_error(L, "The main key can't be absent");
}
@ -1565,18 +1577,6 @@ lgroupiter(lua_State *L) {
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
lremove(lua_State *L) {
struct entity_world *w = getW(L);
@ -1639,9 +1639,11 @@ lbsearch(lua_State *L) {
int * v = entity_iter_(w, value_id, mid);
if (*v == value) {
// found
lua_createtable(L, 1, 0);
lua_createtable(L, 2, 0);
lua_pushinteger(L, mid + 1);
lua_seti(L, -2, 1);
lua_pushinteger(L, sorted_id);
lua_seti(L, -2, 2);
return 1;
}
if (*v < value) {
@ -1660,9 +1662,11 @@ lbsearch(lua_State *L) {
int * v = entity_iter_(w, value_id, index - 1);
if (*v == value) {
// found
lua_createtable(L, 1, 0);
lua_createtable(L, 2, 0);
lua_pushinteger(L, index);
lua_seti(L, -2, 1);
lua_pushinteger(L, sorted_id);
lua_seti(L, -2, 2);
return 1;
}
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

@ -2,9 +2,7 @@ local ecs = require "ecs.core"
local function get_attrib(opt, inout)
if opt == nil then
return {
exist = true,
}
return { exist = true }
end
local desc = {}
if opt == "?" then
@ -139,9 +137,7 @@ local function cache_world(obj, k)
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),
@ -228,9 +224,7 @@ do -- newtype
self:_newtype(id, c.size)
if typeclass.ref then
c.ref = true
self:register{
name = name .. "_dead",
}
self:register { name = name .. "_dead" }
end
end
end
@ -267,24 +261,31 @@ function M:ref(name, refobj)
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
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)]
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)
@ -331,7 +332,7 @@ local function gen_sorted_id(self, sorted, name)
id = id,
name = sorted,
size = ecs._ORDERKEY,
tag = true,
tag = true
}
self:_newtype(id, stype.size)
typenames[sorted] = stype

Loading…
Cancel
Save