From 6a8673d95db5c79d41168ef2a62f522753edb3f5 Mon Sep 17 00:00:00 2001 From: xiaojin Date: Tue, 17 Aug 2021 09:12:49 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=B3=20chore(=E5=BA=93):=20=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=20lua=20ecs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- framework/lualib-src/lua-ecs/luaecs.c | 195 ++++++++---------------- framework/lualib-src/lua-ecs/test12.lua | 9 +- framework/lualib-src/lua-ecs/test2.lua | 7 - framework/lualib-src/lua-ecs/test6.lua | 9 +- framework/lualib-src/lua-ecs/test9.lua | 11 ++ framework/lualib/3rd/misc/ecs.lua | 49 +++--- 6 files changed, 116 insertions(+), 164 deletions(-) diff --git a/framework/lualib-src/lua-ecs/luaecs.c b/framework/lualib-src/lua-ecs/luaecs.c index 9cdb1cb..ec9d62e 100644 --- a/framework/lualib-src/lua-ecs/luaecs.c +++ b/framework/lualib-src/lua-ecs/luaecs.c @@ -40,6 +40,7 @@ init_component_pool(struct entity_world *w, int index, int stride, int opt_size) c->n = 0; c->stride = stride; c->id = NULL; + c->last_lookup = 0; if (stride > 0) { c->buffer = NULL; } else { @@ -282,18 +283,23 @@ lookup_component(struct component_pool *pool, unsigned int eid, int guess_index) int n = pool->n; if (n == 0) return -1; - if (guess_index + GUESS_RANGE >= n) + if (guess_index < 0 || guess_index >= pool->n) return binary_search(pool->id, 0, pool->n, eid); unsigned int *a = pool->id; + int lower = a[guess_index]; + if (eid <= lower) { + if (eid == lower) + return guess_index; + return binary_search(a, 0, guess_index, eid); + } + if (guess_index + GUESS_RANGE*2 >= pool->n) { + return binary_search(a, guess_index + 1, pool->n, eid); + } int higher = a[guess_index + GUESS_RANGE]; if (eid > higher) { return binary_search(a, guess_index + GUESS_RANGE + 1, pool->n, eid); } - int lower = a[guess_index]; - if (eid < lower) { - return binary_search(a, 0, guess_index, eid); - } - return binary_search(a, guess_index, guess_index + GUESS_RANGE, eid); + return binary_search(a, guess_index + 1, guess_index + GUESS_RANGE + 1, eid); } static inline void @@ -1629,122 +1635,6 @@ lorderkey(lua_State *L) { return 0; } -static int -search_id(lua_State *L, int begin, int end, struct entity_world *w, int cid, int64_t value) { - while (begin < end) { - int mid = (begin + end)/2; - int64_t * v = entity_iter_(w, cid, mid); - if (*v == value) { - // found - lua_pushinteger(L, mid + 1); - lua_seti(L, -2, 1); - return 1; - } - if (*v < value) { - begin = mid + 1; - } else { - end = mid; - } - } - return 0; -} - -static int -lfetch(lua_State *L) { - struct entity_world *w = getW(L); - int cid = check_cid(L, w, 2); - lua_Integer value = luaL_checkinteger(L, 3); - struct component_pool *c = &w->c[cid]; - if (c->stride != sizeof(int64_t)) { - return luaL_error(L, "Id component is not int64"); - } - if (lua_istable(L, 4)) { - // cache iter - lua_settop(L, 4); - lua_geti(L, 4, 1); - int mid = lua_tointeger(L, -1) - 1; - lua_pop(L, 1); - if (mid >=0 && mid < c->n) { - int64_t * v = entity_iter_(w, cid, mid); - if (*v == value) - return 1; - if (*v < value) { - return search_id(L, mid+1, c->n, w, cid, value); - } else { - if (mid > GUESS_RANGE) { - return search_id(L, mid - GUESS_RANGE, mid, w, cid, value) || - search_id(L, 0, mid - GUESS_RANGE, w, cid, value); - } - return search_id(L, 0, mid, w, cid, value); - } - } - return 0; - } else { - // new iter - lua_createtable(L, 2, 0); - lua_pushinteger(L, cid); - lua_seti(L, -2, 2); - return search_id(L, 0, c->n, w, cid, value); - } -} - -static int -lbsearch(lua_State *L) { - struct entity_world *w = getW(L); - int sorted_id = check_cid(L, w, 2); - int value_id = check_cid(L, w, 3); - int value = luaL_checkinteger(L, 4); - - struct component_pool *c = &w->c[sorted_id]; - - int begin = 0, end = c->n; - - if (sorted_id == value_id) { - while (begin < end) { - int mid = (begin + end)/2; - int * v = entity_iter_(w, value_id, mid); - if (*v == value) { - // found - 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) { - begin = mid + 1; - } else { - end = mid; - } - } - } else { - while (begin < end) { - int mid = (begin + end)/2; - int index = entity_sibling_index_(w, sorted_id, mid, value_id); - if (index == 0) { - return luaL_error(L, "Invalid value component"); - } - int * v = entity_iter_(w, value_id, index - 1); - if (*v == value) { - // found - 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) { - begin = mid + 1; - } else { - end = mid; - } - } - } - return 0; -} - static int lobject(lua_State *L) { struct group_iter *iter = luaL_checkudata(L, 1, "ENTITY_GROUPITER"); @@ -1866,6 +1756,26 @@ next_removed_index(int removed_index, struct component_pool *removed, unsigned i return removed_index; } +// remove reference object where id == 0 +static void +remove_unused_reference(lua_State *L, struct component_pool *c, int from) { + int i; + int to = from; + for (i=from; i < c->n; i++) { + if (c->id[i]) { + c->id[to] = c->id[i]; + lua_geti(L, -1, i+1); + lua_seti(L, -2, to+1); + ++to; + } + } + for (i=to;i<=c->n;i++) { + lua_pushnil(L); + lua_seti(L, -2, i+1); + } + c->n = to; +} + static int lupdate_reference(lua_State *L) { struct entity_world *w = getW(L); @@ -1874,7 +1784,7 @@ lupdate_reference(lua_State *L) { return 0; int cid = check_cid(L, w, 2); struct component_pool *reference = &w->c[cid]; - if (reference == 0) + if (reference->n == 0) return 0; // no reference if (lua_getiuservalue(L, 1, cid * 2 + 2) != LUA_TTABLE) { return luaL_error(L, "Invalid reference component %d", cid); @@ -1884,8 +1794,11 @@ lupdate_reference(lua_State *L) { unsigned int removed_eid = removed->id[removed_index]; int index = find_boundary(0, reference->n, reference->id, removed_eid); int reference_index = index + 1; + int removed_reference = 0; for (i=index; i< reference->n; i++) { - if (lua_geti(L, -1, i+1) != LUA_TTABLE) { + int rtype = lua_geti(L, -1, i+1); + if (rtype != LUA_TBOOLEAN && rtype != LUA_TTABLE) { + // false means removed reference return luaL_error(L, "Invalid reference object"); } if (removed_eid) { @@ -1902,12 +1815,39 @@ lupdate_reference(lua_State *L) { lua_pushinteger(L, reference_index); ++reference_index; } - lua_seti(L, -2, 1); - lua_pop(L, 1); + if (rtype == LUA_TBOOLEAN) { + // set id = 0, so removed_reference() can remove them + --reference_index; + reference->id[i] = 0; + if (removed_reference == 0) { + removed_reference = i + 1; + } + lua_pop(L, 2); + } else { + lua_seti(L, -2, 1); + lua_pop(L, 1); + } + } + if (removed_reference) { + remove_unused_reference(L, reference, removed_reference - 1); } return 0; } +static int +ldumpid(lua_State *L) { + struct entity_world *w = getW(L); + int cid = check_cid(L, w, 2); + struct component_pool *c = &w->c[cid]; + lua_createtable(L, c->n, 0); + int i; + for (i=0;in;i++) { + lua_pushinteger(L, c->id[i]); + lua_rawseti(L, -2, i+1); + } + return 1; +} + LUAMOD_API int luaopen_ecs_core(lua_State *L) { luaL_checkversion(L); @@ -1936,10 +1876,9 @@ luaopen_ecs_core(lua_State *L) { { "_object", lobject }, { "_sync", lsync }, { "_release", lrelease }, - { "_bsearch", lbsearch }, { "_reuse", lreuse }, - { "_fetch", lfetch }, { "_update_reference", lupdate_reference }, + { "_dumpid", ldumpid }, { NULL, NULL }, }; luaL_setfuncs(L,l,0); diff --git a/framework/lualib-src/lua-ecs/test12.lua b/framework/lualib-src/lua-ecs/test12.lua index d629fbc..b3c1d6d 100644 --- a/framework/lualib-src/lua-ecs/test12.lua +++ b/framework/lualib-src/lua-ecs/test12.lua @@ -11,9 +11,10 @@ w:register { local r = {} for i=1, 42 do - r[i] = w:new { + r[i] = {} + w:new { value = i, - reference = true, + reference = r[i], } w:new { value = -i, @@ -32,11 +33,15 @@ local function read(i) return v.value end +w:update() + w:remove(r[1]) w:remove(r[10]) w:remove(r[20]) w:remove(r[30]) +w:remove_reference(r[40]) + w:update() for i=1,42 do diff --git a/framework/lualib-src/lua-ecs/test2.lua b/framework/lualib-src/lua-ecs/test2.lua index 6ab56b8..c797f8a 100644 --- a/framework/lualib-src/lua-ecs/test2.lua +++ b/framework/lualib-src/lua-ecs/test2.lua @@ -35,10 +35,6 @@ 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", @@ -52,7 +48,4 @@ 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) diff --git a/framework/lualib-src/lua-ecs/test6.lua b/framework/lualib-src/lua-ecs/test6.lua index 8992724..b1e3d55 100644 --- a/framework/lualib-src/lua-ecs/test6.lua +++ b/framework/lualib-src/lua-ecs/test6.lua @@ -16,10 +16,13 @@ w:new { } local function print_v() + local v = w:singleton("t", "t:in") + print(".a = ",v.t.a) + print(".b = ",v.t.b) local v = w:singleton "t" - - print(".a = ",v.a) - print(".b = ",v.b) + w:sync("t:in", v) + print(".a = ", v.t.a) + print(".a = ", v.t.b) end local ctx = w:context { "t" } diff --git a/framework/lualib-src/lua-ecs/test9.lua b/framework/lualib-src/lua-ecs/test9.lua index 2e8e27c..87e6844 100644 --- a/framework/lualib-src/lua-ecs/test9.lua +++ b/framework/lualib-src/lua-ecs/test9.lua @@ -26,6 +26,12 @@ w:new { vector = { x = 1, y = 2 }, text = "Hello World", mark = true, + index = 2, +} + +w:new { + text = "Hello World 2", + mark = true, index = 1, } @@ -38,6 +44,11 @@ for v in w:select "mark" do end end +local ids = w:dumpid "sort" + +for idx, id in ipairs(ids) do + print(idx, id) +end diff --git a/framework/lualib/3rd/misc/ecs.lua b/framework/lualib/3rd/misc/ecs.lua index 8b9b1e0..47fa6df 100644 --- a/framework/lualib/3rd/misc/ecs.lua +++ b/framework/lualib/3rd/misc/ecs.lua @@ -279,7 +279,6 @@ function M:new(obj) local typenames = context[self].typenames local reference = obj.reference if reference then - reference = {} obj.reference = nil end for k,v in pairs(obj) do @@ -295,6 +294,7 @@ function M:new(obj) reference[1] = id reference[2] = REFERENCE_ID self:object("reference", id, reference) + obj.reference = reference return reference end end @@ -401,27 +401,9 @@ function M:order(sorted, refname, order_array) self:_orderkey(sid, rid, order_array) end -function M:bsearch(sorted, name, value) +function M:dumpid(name) 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 - -function M:fetch(idtype, id) - local c = context[self].typenames[idtype] - local f = c.fetch - if not f then - f = setmetatable({}, { __mode = "kv" }) - c.fetch = f - end - local cid = c.id - local iter = f[id] - local ret = self:_fetch(cid, id, iter) - if not iter then - f[id] = ret - end - return ret + return self:_dumpid(typenames[name].id) end function M:update() @@ -429,6 +411,12 @@ function M:update() self:_update() end +function M:remove_reference(ref) + ref.reference = false + self:sync("reference:out", ref) + ref[1] = nil +end + do local _object = M._object function M:object(name, refid, v) @@ -436,9 +424,22 @@ do return _object(pat, v, refid) end - function M:singleton(name, v) - local pat = context[self].ref[name] - return _object(pat, v, 1) + function M:singleton(name, pattern, iter) + local typenames = context[self].typenames + if iter == nil then + iter = { 1, typenames[name].id } + if pattern then + local p = context[self].select[pattern] + self:_sync(p, iter) + end + return iter + else + iter[1] = 1 + iter[2] = typenames[name].id + local p = context[self].select[pattern] + self:_sync(p, iter) + end + return iter end end