diff --git a/framework/lualib-src/lua-ecs/luaecs.c b/framework/lualib-src/lua-ecs/luaecs.c index 1ff96fc..5da1b6e 100644 --- a/framework/lualib-src/lua-ecs/luaecs.c +++ b/framework/lualib-src/lua-ecs/luaecs.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -18,63 +19,52 @@ #define DUMMY_PTR (void *)(uintptr_t)(~0) #define REARRANGE_THRESHOLD 0x80000000 -struct component_pool -{ +struct component_pool { int cap; int n; - int stride; // -1 means lua object + int stride; // -1 means lua object int last_lookup; unsigned int *id; void *buffer; }; -struct entity_world -{ +struct entity_world { unsigned int max_id; struct component_pool c[MAX_COMPONENT]; }; static void -init_component_pool(struct entity_world *w, int index, int stride, int opt_size) -{ +init_component_pool(struct entity_world *w, int index, int stride, int opt_size) { struct component_pool *c = &w->c[index]; c->cap = opt_size; c->n = 0; c->stride = stride; c->id = NULL; - if (stride > 0) - { + if (stride > 0) { c->buffer = NULL; - } - else - { + } else { c->buffer = DUMMY_PTR; } } static void -entity_new_type(lua_State *L, struct entity_world *w, int cid, int stride, int opt_size) -{ - if (opt_size <= 0) - { +entity_new_type(lua_State *L, struct entity_world *w, int cid, int stride, int opt_size) { + if (opt_size <= 0) { opt_size = DEFAULT_SIZE; } - if (cid < 0 || cid >= MAX_COMPONENT || w->c[cid].cap != 0) - { + if (cid < 0 || cid >=MAX_COMPONENT || w->c[cid].cap != 0) { luaL_error(L, "Can't new type %d", cid); } init_component_pool(w, cid, stride, opt_size); } static inline struct entity_world * -getW(lua_State *L) -{ +getW(lua_State *L) { return (struct entity_world *)luaL_checkudata(L, 1, "ENTITY_WORLD"); } static int -lnew_type(lua_State *L) -{ +lnew_type(lua_State *L) { struct entity_world *w = getW(L); int cid = luaL_checkinteger(L, 2); int stride = luaL_checkinteger(L, 3); @@ -84,22 +74,18 @@ lnew_type(lua_State *L) } static int -lcount_memory(lua_State *L) -{ +lcount_memory(lua_State *L) { struct entity_world *w = getW(L); size_t sz = sizeof(*w); int i; size_t msz = sz; - for (i = 0; i < MAX_COMPONENT; i++) - { + for (i=0;ic[i]; - if (c->id) - { + if (c->id) { sz += c->cap * sizeof(unsigned int); msz += c->n * sizeof(unsigned int); } - if (c->buffer != DUMMY_PTR) - { + if (c->buffer != DUMMY_PTR) { sz += c->cap * c->stride; msz += c->cap * c->stride; } @@ -110,12 +96,10 @@ lcount_memory(lua_State *L) } static void -shrink_component_pool(lua_State *L, struct component_pool *c, int id) -{ +shrink_component_pool(lua_State *L, struct component_pool *c, int id) { if (c->id == NULL) return; - if (c->n == 0) - { + if (c->n == 0) { c->id = NULL; if (c->stride > 0) c->buffer = NULL; @@ -123,9 +107,7 @@ shrink_component_pool(lua_State *L, struct component_pool *c, int id) lua_setiuservalue(L, 1, id * 2 + 1); lua_pushnil(L); lua_setiuservalue(L, 1, id * 2 + 2); - } - else if (c->stride > 0 && c->n < c->cap) - { + } else if (c->stride > 0 && c->n < c->cap) { c->cap = c->n; c->id = (unsigned int *)lua_newuserdatauv(L, c->n * sizeof(unsigned int), 0); lua_setiuservalue(L, 1, id * 2 + 1); @@ -135,53 +117,42 @@ shrink_component_pool(lua_State *L, struct component_pool *c, int id) } static int -lcollect_memory(lua_State *L) -{ +lcollect_memory(lua_State *L) { struct entity_world *w = getW(L); int i; - for (i = 0; i < MAX_COMPONENT; i++) - { + for (i=0;ic[i], i); } return 0; } static int -add_component_id_(lua_State *L, int world_index, struct entity_world *w, int cid, unsigned int eid) -{ +add_component_id_(lua_State *L, int world_index, struct entity_world *w, int cid, unsigned int eid) { struct component_pool *pool = &w->c[cid]; int cap = pool->cap; int index = pool->n; assert(pool->stride != STRIDE_ORDER); - if (pool->n == 0) - { - if (pool->id == NULL) - { + if (pool->n == 0) { + if (pool->id == NULL) { pool->id = (unsigned int *)lua_newuserdatauv(L, cap * sizeof(unsigned int), 0); lua_setiuservalue(L, world_index, cid * 2 + 1); } - if (pool->buffer == NULL) - { + if (pool->buffer == NULL) { pool->buffer = lua_newuserdatauv(L, cap * pool->stride, 0); lua_setiuservalue(L, world_index, cid * 2 + 2); - } - else if (pool->stride == STRIDE_LUA) - { + } else if (pool->stride == STRIDE_LUA) { lua_newtable(L); lua_setiuservalue(L, world_index, cid * 2 + 2); } - } - else if (pool->n >= pool->cap) - { + } else if (pool->n >= pool->cap) { // expand pool int newcap = cap * 3 / 2; unsigned int *newid = (unsigned int *)lua_newuserdatauv(L, newcap * sizeof(unsigned int), 0); lua_setiuservalue(L, world_index, cid * 2 + 1); - memcpy(newid, pool->id, cap * sizeof(unsigned int)); + memcpy(newid, pool->id, cap * sizeof(unsigned int)); pool->id = newid; int stride = pool->stride; - if (stride > 0) - { + if (stride > 0) { void *newbuffer = lua_newuserdatauv(L, newcap * stride, 0); lua_setiuservalue(L, world_index, cid * 2 + 2); memcpy(newbuffer, pool->buffer, cap * stride); @@ -195,8 +166,7 @@ add_component_id_(lua_State *L, int world_index, struct entity_world *w, int cid } static inline void * -get_ptr(struct component_pool *c, int index) -{ +get_ptr(struct component_pool *c, int index) { if (c->stride > 0) return (void *)((char *)c->buffer + c->stride * index); else @@ -204,8 +174,7 @@ get_ptr(struct component_pool *c, int index) } static void * -add_component_(lua_State *L, int world_index, struct entity_world *w, int cid, unsigned int eid, const void *buffer) -{ +add_component_(lua_State *L, int world_index, struct entity_world *w, int cid, unsigned int eid, const void *buffer) { int index = add_component_id_(L, world_index, w, cid, eid); struct component_pool *pool = &w->c[cid]; assert(pool->stride >= 0); @@ -216,56 +185,59 @@ add_component_(lua_State *L, int world_index, struct entity_world *w, int cid, u } static inline int -check_cid(lua_State *L, struct entity_world *w, int index) -{ +check_cid(lua_State *L, struct entity_world *w, int index) { int cid = luaL_checkinteger(L, index); struct component_pool *c = &w->c[cid]; - if (cid < 0 || cid >= MAX_COMPONENT || c->cap == 0) - { + if (cid < 0 || cid >=MAX_COMPONENT || c->cap == 0) { luaL_error(L, "Invalid type %d", cid); } return cid; } static int -ladd_component(lua_State *L) -{ +ladd_component(lua_State *L) { + struct entity_world *w = getW(L); + unsigned int eid = luaL_checkinteger(L, 2); + int cid = check_cid(L, w, 3); + int index = add_component_id_(L, 1, w, cid, eid); + lua_pushinteger(L, index + 1); + return 1; +} + +/* +static int +ladd_component(lua_State *L) { struct entity_world *w = getW(L); unsigned int eid = luaL_checkinteger(L, 2); int cid = check_cid(L, w, 3); int stride = w->c[cid].stride; - if (stride <= 0) - { + if (stride <= 0) { int index = add_component_id_(L, 1, w, cid, eid); - if (stride == STRIDE_LUA) - { + if (stride == STRIDE_LUA) { // lua object lua_settop(L, 4); - if (lua_getiuservalue(L, 1, cid * 2 + 2) != LUA_TTABLE) - { + if (lua_getiuservalue(L, 1, cid * 2 + 2) != LUA_TTABLE) { luaL_error(L, "Missing lua table for %d", cid); } lua_insert(L, -2); lua_rawseti(L, -2, index + 1); } - } - else - { + lua_pushinteger(L, index + 1); + } else { size_t sz; const char *buffer = lua_tolstring(L, 4, &sz); int stride = w->c[cid].stride; - if (buffer == NULL || sz != stride) - { + if (buffer == NULL || sz != stride) { return luaL_error(L, "Invalid data (size=%d/%d) for type %d", (int)sz, stride, cid); } add_component_(L, 1, w, cid, eid, buffer); + lua_pushinteger(L, w->c[cid].n); } - return 0; + return 1; } - +*/ static int -lnew_entity(lua_State *L) -{ +lnew_entity(lua_State *L) { struct entity_world *w = getW(L); unsigned int eid = ++w->max_id; assert(eid != 0); @@ -274,36 +246,28 @@ lnew_entity(lua_State *L) } static void -insert_id(lua_State *L, int world_index, struct entity_world *w, int cid, unsigned int eid) -{ +insert_id(lua_State *L, int world_index, struct entity_world *w, int cid, unsigned int eid) { struct component_pool *c = &w->c[cid]; assert(c->stride == STRIDE_TAG); int from = 0; int to = c->n; - while (from < to) - { - int mid = (from + to) / 2; + while(from < to) { + int mid = (from + to)/2; int aa = c->id[mid]; if (aa == eid) return; - else if (aa < eid) - { + else if (aa < eid) { from = mid + 1; - } - else - { + } else { to = mid; } } // insert eid at [from] - if (from < c->n - 1) - { + if (from < c->n - 1) { int i; // Any dup id ? - for (i = from; i < c->n - 1; i++) - { - if (c->id[i] == c->id[i + 1]) - { + for (i=from;in-1;i++) { + if (c->id[i] == c->id[i+1]) { memmove(c->id + from + 1, c->id + from, sizeof(unsigned int) * (i - from)); c->id[from] = eid; return; @@ -316,29 +280,23 @@ insert_id(lua_State *L, int world_index, struct entity_world *w, int cid, unsign } static void -entity_enable_tag_(struct entity_world *w, int cid, int index, int tag_id, void *L, int world_index) -{ +entity_enable_tag_(struct entity_world *w, int cid, int index, int tag_id, void *L, int world_index) { struct component_pool *c = &w->c[cid]; - assert(index >= 0 && index < c->n); + assert(index >=0 && index < c->n); unsigned int eid = c->id[index]; insert_id((lua_State *)L, world_index, w, tag_id, eid); } static int -binary_search(unsigned int *a, int from, int to, unsigned int v) -{ - while (from < to) - { - int mid = (from + to) / 2; +binary_search(unsigned int *a, int from, int to, unsigned int v) { + while(from < to) { + int mid = (from + to)/2; int aa = a[mid]; if (aa == v) return mid; - else if (aa < v) - { + else if (aa < v) { from = mid + 1; - } - else - { + } else { to = mid; } } @@ -348,8 +306,7 @@ binary_search(unsigned int *a, int from, int to, unsigned int v) #define GUESS_RANGE 64 static inline int -lookup_component(struct component_pool *pool, unsigned int eid, int guess_index) -{ +lookup_component(struct component_pool *pool, unsigned int eid, int guess_index) { int n = pool->n; if (n == 0) return -1; @@ -357,56 +314,46 @@ lookup_component(struct component_pool *pool, unsigned int eid, int guess_index) return binary_search(pool->id, 0, pool->n, eid); unsigned int *a = pool->id; int higher = a[guess_index + GUESS_RANGE]; - if (eid > higher) - { + if (eid > higher) { return binary_search(a, guess_index + GUESS_RANGE + 1, pool->n, eid); } int lower = a[guess_index]; - if (eid < lower) - { + if (eid < lower) { return binary_search(a, 0, guess_index, eid); } return binary_search(a, guess_index, guess_index + GUESS_RANGE, eid); } static inline void -replace_id(struct component_pool *c, int index, unsigned int eid) -{ +replace_id(struct component_pool *c, int index, unsigned int eid) { unsigned int rid = c->id[index]; c->id[index] = eid; int i; - for (i = index + 1; i < c->n && c->id[i] == rid; i++) - { + for (i=index+1;in && c->id[i] == rid;i++) { c->id[i] = eid; } } static void -entity_disable_tag_(struct entity_world *w, int cid, int index, int tag_id) -{ +entity_disable_tag_(struct entity_world *w, int cid, int index, int tag_id) { struct component_pool *c = &w->c[cid]; - assert(index >= 0 && index < c->n); + assert(index >=0 && index < c->n); unsigned int eid = c->id[index]; - if (cid != tag_id) - { + if (cid != tag_id) { c = &w->c[tag_id]; index = lookup_component(c, eid, c->last_lookup); 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]); + for (i=index - 1; i>=0; i--) { + if (c->id[i] != eid) { + replace_id(c, i+1, c->id[i]); return; } } - for (i = index + 1; i < c->n; i++) - { - if (c->id[i] != eid) - { + for (i=index+1;in;i++) { + if (c->id[i] != eid) { replace_id(c, index, c->id[i]); return; } @@ -415,31 +362,25 @@ entity_disable_tag_(struct entity_world *w, int cid, int index, int tag_id) } static void -entity_remove_(struct entity_world *w, int cid, int index, void *L, int world_index) -{ +entity_remove_(struct entity_world *w, int cid, int index, void *L, int world_index) { entity_enable_tag_(w, cid, index, ENTITY_REMOVED, L, world_index); } -struct rearrange_context -{ +struct rearrange_context { struct entity_world *w; - unsigned int ptr[MAX_COMPONENT - 1]; + unsigned int ptr[MAX_COMPONENT-1]; }; static int -find_min(struct rearrange_context *ctx) -{ +find_min(struct rearrange_context *ctx) { unsigned int m = ~0; int i; int r = -1; struct entity_world *w = ctx->w; - for (i = 1; i < MAX_COMPONENT; i++) - { - int index = ctx->ptr[i - 1]; - if (index < w->c[i].n) - { - if (w->c[i].id[index] <= m) - { + for (i=1;iptr[i-1]; + if (index < w->c[i].n) { + if (w->c[i].id[index] <= m) { m = w->c[i].id[index]; r = i; } @@ -449,44 +390,37 @@ find_min(struct rearrange_context *ctx) } static void -rearrange(struct entity_world *w) -{ +rearrange(struct entity_world *w) { struct rearrange_context ctx; memset(&ctx, 0, sizeof(ctx)); ctx.w = w; int cid; unsigned int new_id = 1; unsigned int last_id = 0; - while ((cid = find_min(&ctx)) >= 0) - { - int index = ctx.ptr[cid - 1]; + while ((cid = find_min(&ctx)) >= 0) { + int index = ctx.ptr[cid-1]; unsigned int current_id = w->c[cid].id[index]; - // printf("arrange %d <- %d\n", new_id, w->c[cid].id[index]); +// printf("arrange %d <- %d\n", new_id, w->c[cid].id[index]); w->c[cid].id[index] = new_id; - if (current_id != last_id) - { + if (current_id != last_id) { ++new_id; last_id = current_id; } - ++ctx.ptr[cid - 1]; + ++ctx.ptr[cid-1]; } w->max_id = new_id; } static inline void -move_tag(struct component_pool *pool, int from, int to) -{ - if (from != to) - { +move_tag(struct component_pool *pool, int from, int to) { + if (from != to) { pool->id[to] = pool->id[from]; } } static inline void -move_item(struct component_pool *pool, int from, int to) -{ - if (from != to) - { +move_item(struct component_pool *pool, int from, int to) { + if (from != to) { pool->id[to] = pool->id[from]; int stride = pool->stride; memcpy((char *)pool->buffer + to * stride, (char *)pool->buffer + from * stride, stride); @@ -494,90 +428,70 @@ move_item(struct component_pool *pool, int from, int to) } static void -move_object(lua_State *L, struct component_pool *pool, int from, int to) -{ - if (from != to) - { +move_object(lua_State *L, struct component_pool *pool, int from, int to) { + if (from != to) { pool->id[to] = pool->id[from]; - lua_rawgeti(L, -1, from + 1); - lua_rawseti(L, -2, to + 1); + lua_rawgeti(L, -1, from+1); + lua_rawseti(L, -2, to+1); } } static void -remove_all(lua_State *L, struct component_pool *pool, struct component_pool *removed, int cid) -{ +remove_all(lua_State *L, struct component_pool *pool, struct component_pool *removed, int cid) { int index = 0; int count = 0; int i; - if (pool->stride != STRIDE_ORDER) - { + if (pool->stride != STRIDE_ORDER) { unsigned int *id = removed->id; unsigned int last_id = 0; - for (i = 0; i < removed->n; i++) - { - if (id[i] != last_id) - { + for (i=0;in;i++) { + if (id[i] != last_id) { // todo : order int r = lookup_component(pool, id[i], index); - if (r >= 0) - { + if (r >= 0) { index = r; pool->id[r] = 0; ++count; } } } - } - else - { + } else { unsigned int *id = pool->id; - for (i = 0; i < pool->n; i++) - { + for (i=0;in;i++) { int r = lookup_component(removed, id[i], 0); - if (r >= 0) - { + if (r >= 0) { id[i] = 0; ++count; } } } - if (count > 0) - { + if (count > 0) { index = 0; - switch (pool->stride) - { + switch (pool->stride) { case STRIDE_LUA: - if (lua_getiuservalue(L, 1, cid * 2 + 2) != LUA_TTABLE) - { + if (lua_getiuservalue(L, 1, cid * 2 + 2) != LUA_TTABLE) { luaL_error(L, "Missing lua object table for type %d", cid); } - for (i = 0; i < pool->n; i++) - { - if (pool->id[i] != 0) - { + for (i=0;in;i++) { + if (pool->id[i] != 0) { move_object(L, pool, i, index); ++index; } } - lua_pop(L, 1); // pop lua object table + lua_pop(L, 1); // pop lua object table break; case STRIDE_TAG: case STRIDE_ORDER: - for (i = 0; i < pool->n; i++) - { - if (pool->id[i] != 0) - { + for (i=0;in;i++) { + if (pool->id[i] != 0) { move_tag(pool, i, index); ++index; } } break; default: - for (i = 0; i < pool->n; i++) - { - if (pool->id[i] != 0) - { + for (i=0;in;i++) { + if (pool->id[i] != 0) { move_item(pool, i, index); ++index; } @@ -589,17 +503,14 @@ remove_all(lua_State *L, struct component_pool *pool, struct component_pool *rem } static int -lupdate(lua_State *L) -{ +lupdate(lua_State *L) { struct entity_world *w = getW(L); struct component_pool *removed = &w->c[ENTITY_REMOVED]; int i; - if (removed->n > 0) - { + if (removed->n > 0) { // mark removed assert(ENTITY_REMOVED == 0); - for (i = 1; i < MAX_COMPONENT; i++) - { + for (i=1;ic[i]; if (pool->n > 0) remove_all(L, pool, removed, i); @@ -607,8 +518,7 @@ lupdate(lua_State *L) removed->n = 0; } - if (w->max_id > REARRANGE_THRESHOLD) - { + if (w->max_id > REARRANGE_THRESHOLD) { rearrange(w); } @@ -616,15 +526,12 @@ lupdate(lua_State *L) } static void -remove_dup(struct component_pool *c, int index) -{ +remove_dup(struct component_pool *c, int index) { int i; unsigned int eid = c->id[index]; int to = index; - for (i = index + 1; i < c->n; i++) - { - if (c->id[i] != eid) - { + for (i=index+1;in;i++) { + if (c->id[i] != eid) { eid = c->id[i]; c->id[to] = eid; ++to; @@ -634,18 +541,15 @@ remove_dup(struct component_pool *c, int index) } static void * -entity_iter_(struct entity_world *w, int cid, int index) -{ +entity_iter_(struct entity_world *w, int cid, int index) { struct component_pool *c = &w->c[cid]; assert(index >= 0); if (index >= c->n) return NULL; - if (c->stride == STRIDE_TAG) - { + if (c->stride == STRIDE_TAG) { // it's a tag unsigned int eid = c->id[index]; - if (index > 0 && eid == c->id[index - 1]) - { + if (index > 0 && eid == c->id[index-1]) { remove_dup(c, index); if (index >= c->n) return NULL; @@ -656,19 +560,16 @@ entity_iter_(struct entity_world *w, int cid, int index) } static void * -entity_iter_lua_(struct entity_world *w, int cid, int index, void *L) -{ - void *ret = entity_iter_(w, cid, index); +entity_iter_lua_(struct entity_world *w, int cid, int index, void *L, int world_index) { + void * ret = entity_iter_(w, cid, index); if (ret != DUMMY_PTR) return ret; - if (lua_getiuservalue(L, 1, cid * 2 + 2) != LUA_TTABLE) - { + if (lua_getiuservalue(L, world_index, cid * 2 + 2) != LUA_TTABLE) { lua_pop(L, 1); - return 0; + return NULL; } - int t = lua_rawgeti(L, -1, index + 1); - switch (t) - { + int t = lua_rawgeti(L, -1, index+1); + switch(t) { case LUA_TSTRING: ret = (void *)lua_tostring(L, -1); break; @@ -684,52 +585,50 @@ entity_iter_lua_(struct entity_world *w, int cid, int index, void *L) return ret; } +static int +entity_assign_lua_(struct entity_world *w, int cid, int index, void *L, int world_index) { + struct component_pool *c = &w->c[cid]; + ++index; + assert(lua_gettop(L) > 1); + if (c->stride != STRIDE_LUA || index <=0 || index > c->n) { + lua_pop(L, 1); + return 0; + } + if (lua_getiuservalue(L, world_index, cid * 2 + 2) != LUA_TTABLE) { + lua_pop(L, 2); + return 0; + } + lua_insert(L, -2); + // table value + lua_rawseti(L, -2, index); + lua_pop(L, 1); + return 1; +} + static void -entity_clear_type_(struct entity_world *w, int cid) -{ +entity_clear_type_(struct entity_world *w, int cid) { struct component_pool *c = &w->c[cid]; c->n = 0; } static int -lclear_type(lua_State *L) -{ +lclear_type(lua_State *L) { struct entity_world *w = getW(L); - int cid = check_cid(L, w, 2); + int cid = check_cid(L,w, 2); entity_clear_type_(w, cid); return 0; } -static void * -entity_sibling_(struct entity_world *w, int cid, int index, int slibling_id) -{ - struct component_pool *c = &w->c[cid]; - if (index < 0 || index >= c->n) - return NULL; - unsigned int eid = c->id[index]; - c = &w->c[slibling_id]; - assert(c->stride != STRIDE_ORDER); - int result_index = lookup_component(c, eid, c->last_lookup); - if (result_index >= 0) - { - c->last_lookup = result_index; - return get_ptr(c, result_index); - } - return NULL; -} - static int -entity_sibling_index_(struct entity_world *w, int cid, int index, int slibling_id) -{ +entity_sibling_index_(struct entity_world *w, int cid, int index, int silbling_id) { struct component_pool *c = &w->c[cid]; if (index < 0 || index >= c->n) return 0; unsigned int eid = c->id[index]; - c = &w->c[slibling_id]; + c = &w->c[silbling_id]; assert(c->stride != STRIDE_ORDER); int result_index = lookup_component(c, eid, c->last_lookup); - if (result_index >= 0) - { + if (result_index >= 0) { c->last_lookup = result_index; return result_index + 1; } @@ -737,23 +636,36 @@ entity_sibling_index_(struct entity_world *w, int cid, int index, int slibling_i } static void * -entity_add_sibling_(struct entity_world *w, int cid, int index, int slibling_id, const void *buffer, void *L, int world_index) -{ +entity_add_sibling_(struct entity_world *w, int cid, int index, int silbling_id, const void *buffer, void *L, int world_index) { struct component_pool *c = &w->c[cid]; - assert(index >= 0 && index < c->n); + assert(index >=0 && index < c->n); unsigned int eid = c->id[index]; // todo: pcall add_component_ assert(c->stride >= 0); - void *ret = add_component_((lua_State *)L, world_index, w, slibling_id, eid, buffer); - c = &w->c[slibling_id]; - return ret; + return add_component_((lua_State *)L, world_index, w, silbling_id, eid, buffer); +} + +static int +entity_new_(struct entity_world *w, int cid, const void *buffer, void *L, int world_index) { + unsigned int eid = ++w->max_id; + assert(eid != 0); + struct component_pool *c = &w->c[cid]; + assert(c->cap > 0); + if (buffer == NULL) { + return add_component_id_(L, world_index, w, cid, eid); + } else { + assert(c->stride >= 0); + int index = add_component_id_(L, world_index, w, cid, eid); + void *ret = get_ptr(c, index); + memcpy(ret, buffer, c->stride); + return index; + } } static int -entity_add_sibling_index_(lua_State *L, int world_index, struct entity_world *w, int cid, int index, int slibling_id) -{ +entity_add_sibling_index_(lua_State *L, int world_index, struct entity_world *w, int cid, int index, int slibling_id) { struct component_pool *c = &w->c[cid]; - assert(index >= 0 && index < c->n); + assert(index >=0 && index < c->n); unsigned int eid = c->id[index]; // todo: pcall add_component_ assert(c->stride == STRIDE_LUA); @@ -761,80 +673,86 @@ entity_add_sibling_index_(lua_State *L, int world_index, struct entity_world *w, return ret; } -static int -comp_index(void *v, const void *a, const void *b) -{ +static inline int +comp_index(const void *a, const void *b, void *v) { const unsigned int *aa = (const unsigned int *)a; const unsigned int *bb = (const unsigned int *)b; - int *vv = (int *)v; + int * vv = (int *)v; return vv[*aa] - vv[*bb]; } +static inline int +comp_index_s(void *v, const void *a, const void *b) { + return comp_index(a,b,v); +} + static void -entity_sort_key_(struct entity_world *w, int orderid, int cid, void *L, int world_index) -{ +entity_sort_key_(struct entity_world *w, int orderid, int cid, void *L, int world_index) { struct component_pool *c = &w->c[cid]; assert(c->stride == sizeof(int)); struct component_pool *order = &w->c[orderid]; assert(order->stride == STRIDE_ORDER); - if (order->id == NULL || order->cap < c->cap) - { + if (order->id == NULL || order->cap < c->cap) { order->cap = c->cap; order->id = (unsigned int *)lua_newuserdatauv(L, c->cap * sizeof(unsigned int), 0); lua_setiuservalue(L, world_index, orderid * 2 + 1); } int i; - for (i = 0; i < c->n; i++) - { + for (i = 0; i < c->n ; i++) { order->id[i] = i; } - qsort_s(order->id, c->n, sizeof(unsigned int), comp_index, c->buffer); - for (i = 0; i < c->n; i++) - { +#ifdef _GNU_SOURCE + qsort_r(order->id, c->n, sizeof(unsigned int), comp_index, c->buffer); +#elif defined(__APPLE__) + qsort_r(order->id, c->n, sizeof(unsigned int), c->buffer, comp_index_s); +#elif defined(_WIN32) + qsort_s(order->id, c->n, sizeof(unsigned int), comp_index_s, c->buffer); +#else +# error Unknown operating system +#endif + for (i = 0; i < c->n ; i++) { order->id[i] = c->id[order->id[i]]; } order->n = c->n; } static int -lcontext(lua_State *L) -{ +lcontext(lua_State *L) { struct entity_world *w = getW(L); luaL_checktype(L, 2, LUA_TTABLE); lua_len(L, 2); int n = lua_tointeger(L, -1); lua_pop(L, 1); - if (n <= 0) - { + if (n <= 0) { return luaL_error(L, "Invalid length %d of table", n); } size_t sz = sizeof(struct ecs_context) + sizeof(int) * n; struct ecs_context *ctx = (struct ecs_context *)lua_newuserdatauv(L, sz, 1); ctx->L = (void *)lua_newthread(L); lua_pushvalue(L, 1); - lua_xmove(L, ctx->L, 1); // put world in the index 1 of newthread + lua_xmove(L, ctx->L, 1); // put world in the index 1 of newthread lua_setiuservalue(L, -2, 1); ctx->max_id = n; ctx->world = w; static struct ecs_capi c_api = { entity_iter_, entity_clear_type_, - entity_sibling_, + entity_sibling_index_, entity_add_sibling_, + entity_new_, entity_remove_, entity_enable_tag_, entity_disable_tag_, entity_sort_key_, entity_iter_lua_, + entity_assign_lua_, }; ctx->api = &c_api; ctx->cid[0] = ENTITY_REMOVED; int i; - for (i = 1; i <= n; i++) - { - if (lua_geti(L, 2, i) != LUA_TNUMBER) - { + for (i=1;i<=n;i++) { + if (lua_geti(L, 2, i) != LUA_TNUMBER) { return luaL_error(L, "Invalid id at index %d", i); } ctx->cid[i] = lua_tointeger(L, -1); @@ -847,8 +765,7 @@ lcontext(lua_State *L) } static int -lnew_world(lua_State *L) -{ +lnew_world(lua_State *L) { size_t sz = sizeof(struct entity_world); struct entity_world *w = (struct entity_world *)lua_newuserdatauv(L, sz, MAX_COMPONENT * 2); memset(w, 0, sz); @@ -862,22 +779,24 @@ lnew_world(lua_State *L) #define TYPE_INT 0 #define TYPE_FLOAT 1 #define TYPE_BOOL 2 - -struct field -{ +#define TYPE_INT64 3 +#define TYPE_DWORD 4 +#define TYPE_WORD 5 +#define TYPE_BYTE 6 +#define TYPE_DOUBLE 7 +#define TYPE_USERDATA 8 +#define TYPE_COUNT 9 + +struct field { const char *key; int offset; int type; }; static int -check_type(lua_State *L) -{ +check_type(lua_State *L) { int type = lua_tointeger(L, -1); - if (type != TYPE_INT && - type != TYPE_FLOAT && - type != TYPE_BOOL) - { + if (type < 0 || type >= TYPE_COUNT) { luaL_error(L, "Invalid field type(%d)", type); } lua_pop(L, 1); @@ -885,23 +804,19 @@ check_type(lua_State *L) } static void -get_field(lua_State *L, int i, struct field *f) -{ - if (lua_geti(L, -1, 1) != LUA_TNUMBER) - { +get_field(lua_State *L, int i, struct field *f) { + if (lua_geti(L, -1, 1) != LUA_TNUMBER) { luaL_error(L, "Invalid field %d [1] type", i); } f->type = check_type(L); - if (lua_geti(L, -1, 2) != LUA_TSTRING) - { + if (lua_geti(L, -1, 2) != LUA_TSTRING) { luaL_error(L, "Invalid field %d [2] key", i); } f->key = lua_tostring(L, -1); lua_pop(L, 1); - if (lua_geti(L, -1, 3) != LUA_TNUMBER) - { + if (lua_geti(L, -1, 3) != LUA_TNUMBER) { luaL_error(L, "Invalid field %d [3] offset", i); } f->offset = lua_tointeger(L, -1); @@ -911,48 +826,90 @@ get_field(lua_State *L, int i, struct field *f) } static void -write_value(lua_State *L, struct field *f, char *buffer) -{ +write_value(lua_State *L, struct field *f, char *buffer) { int luat = lua_type(L, -1); char *ptr = buffer + f->offset; - switch (f->type) - { - case TYPE_INT: - if (!lua_isinteger(L, -1)) - luaL_error(L, "Invalid .%s type %s (int)", f->key ? f->key : "*", lua_typename(L, luat)); - *(int *)ptr = lua_tointeger(L, -1); - break; - case TYPE_FLOAT: - if (luat != LUA_TNUMBER) - luaL_error(L, "Invalid .%s type %s (float)", f->key ? f->key : "*", lua_typename(L, luat)); - *(float *)ptr = lua_tonumber(L, -1); - break; - case TYPE_BOOL: - if (luat != LUA_TBOOLEAN) - luaL_error(L, "Invalid .%s type %s (bool)", f->key ? f->key : "*", lua_typename(L, luat)); - *(unsigned char *)ptr = lua_toboolean(L, -1); - break; + switch (f->type) { + case TYPE_INT: + if (!lua_isinteger(L, -1)) + luaL_error(L, "Invalid .%s type %s (int)", f->key ? f->key : "*", lua_typename(L, luat)); + *(int *)ptr = lua_tointeger(L, -1); + break; + case TYPE_FLOAT: + if (luat != LUA_TNUMBER) + luaL_error(L, "Invalid .%s type %s (float)", f->key ? f->key : "*", lua_typename(L, luat)); + *(float *)ptr = lua_tonumber(L, -1); + break; + case TYPE_BOOL: + if (luat != LUA_TBOOLEAN) + luaL_error(L, "Invalid .%s type %s (bool)", f->key ? f->key : "*", lua_typename(L, luat)); + *(unsigned char *)ptr = lua_toboolean(L, -1); + break; + case TYPE_INT64: + if (!lua_isinteger(L, -1)) + luaL_error(L, "Invalid .%s type %s (int64)", f->key ? f->key : "*", lua_typename(L, luat)); + *(int64_t *)ptr = lua_tointeger(L, -1); + break; + case TYPE_DWORD: + if (!lua_isinteger(L, -1)) + luaL_error(L, "Invalid .%s type %s (uint32)", f->key ? f->key : "*", lua_typename(L, luat)); + else { + int64_t v = lua_tointeger(L, -1); + if (v < 0 || v > 0xffffffff) { + luaL_error(L, "Invalid DWORD %d", (int)v); + } + *(uint32_t *)ptr = v; + } + break; + case TYPE_WORD: + if (!lua_isinteger(L, -1)) + luaL_error(L, "Invalid .%s type %s (uint16)", f->key ? f->key : "*", lua_typename(L, luat)); + else { + int v = lua_tointeger(L, -1); + if (v < 0 || v > 0xffff) { + luaL_error(L, "Invalid WORD %d", v); + } + *(uint16_t *)ptr = v; + } + break; + case TYPE_BYTE: + if (!lua_isinteger(L, -1)) + luaL_error(L, "Invalid .%s type %s (uint8)", f->key ? f->key : "*", lua_typename(L, luat)); + else { + int v = lua_tointeger(L, -1); + if (v < 0 || v > 255) { + luaL_error(L, "Invalid BYTE %d", v); + } + *(uint16_t *)ptr = v; + } + break; + case TYPE_DOUBLE: + if (luat != LUA_TNUMBER) + luaL_error(L, "Invalid .%s type %s (double)", f->key ? f->key : "*", lua_typename(L, luat)); + *(double *)ptr = lua_tonumber(L, -1); + break; + case TYPE_USERDATA: + if (luat != LUA_TLIGHTUSERDATA) + luaL_error(L, "Invalid .%s type %s (pointer)", f->key ? f->key : "*", lua_typename(L, luat)); + *(void **)ptr = lua_touserdata(L, -1); + break; } lua_pop(L, 1); } static inline void -write_component(lua_State *L, int field_n, struct field *f, int index, char *buffer) -{ +write_component(lua_State *L, int field_n, struct field *f, int index, char *buffer) { int i; - for (i = 0; i < field_n; i++) - { + for (i=0; i < field_n; i++) { lua_getfield(L, index, f[i].key); write_value(L, &f[i], buffer); } } static void -read_value(lua_State *L, struct field *f, const char *buffer) -{ - const char *ptr = buffer + f->offset; - switch (f->type) - { +read_value(lua_State *L, struct field *f, const char *buffer) { + const char * ptr = buffer + f->offset; + switch (f->type) { case TYPE_INT: lua_pushinteger(L, *(const int *)ptr); break; @@ -962,6 +919,24 @@ read_value(lua_State *L, struct field *f, const char *buffer) case TYPE_BOOL: lua_pushboolean(L, *ptr); break; + case TYPE_INT64: + lua_pushinteger(L, *(const int64_t *)ptr); + break; + case TYPE_DWORD: + lua_pushinteger(L, *(const uint32_t *)ptr); + break; + case TYPE_WORD: + lua_pushinteger(L, *(const uint16_t *)ptr); + break; + case TYPE_BYTE: + lua_pushinteger(L, *(const uint8_t *)ptr); + break; + case TYPE_DOUBLE: + lua_pushnumber(L, *(const double *)ptr); + break; + case TYPE_USERDATA: + lua_pushlightuserdata(L, *(void **)ptr); + break; default: // never here luaL_error(L, "Invalid field type %d", f->type); @@ -970,27 +945,22 @@ read_value(lua_State *L, struct field *f, const char *buffer) } static void -read_component(lua_State *L, int field_n, struct field *f, int index, const char *buffer) -{ +read_component(lua_State *L, int field_n, struct field *f, int index, const char * buffer) { int i; - for (i = 0; i < field_n; i++) - { + for (i=0; i < field_n; i++) { read_value(L, &f[i], buffer); lua_setfield(L, index, f[i].key); } } static int -get_len(lua_State *L, int index) -{ +get_len(lua_State *L, int index) { lua_len(L, index); - if (lua_type(L, -1) != LUA_TNUMBER) - { + if (lua_type(L, -1) != LUA_TNUMBER) { return luaL_error(L, "Invalid table length"); } int n = lua_tointeger(L, -1); - if (n < 0) - { + if (n < 0) { return luaL_error(L, "Invalid table length %d", n); } lua_pop(L, 1); @@ -1003,8 +973,7 @@ get_len(lua_State *L, int index) #define COMPONENT_OBJECT 8 #define COMPONENT_EXIST 16 -struct group_key -{ +struct group_key { const char *name; int id; int field_n; @@ -1012,15 +981,13 @@ struct group_key }; static inline int -is_temporary(int attrib) -{ +is_temporary(int attrib) { if (attrib & COMPONENT_EXIST) return 0; return (attrib & COMPONENT_IN) == 0 && (attrib & COMPONENT_OUT) == 0; } -struct group_iter -{ +struct group_iter { struct entity_world *world; struct field *f; int nkey; @@ -1029,30 +996,25 @@ struct group_iter }; static int -get_write_component(lua_State *L, int lua_index, const char *name, struct field *f, struct component_pool *c) -{ - switch (lua_getfield(L, lua_index, name)) - { +get_write_component(lua_State *L, int lua_index, const char *name, struct field *f, struct component_pool *c) { + switch (lua_getfield(L, lua_index, name)) { case LUA_TNIL: lua_pop(L, 1); // restore cache (metatable can be absent during sync) - if (lua_getmetatable(L, lua_index)) - { + if (lua_getmetatable(L, lua_index)) { lua_getfield(L, -1, name); lua_setfield(L, lua_index, name); - lua_pop(L, 1); // pop metatable + lua_pop(L, 1); // pop metatable } return 0; case LUA_TTABLE: return 1; default: - if (c->stride == STRIDE_LUA) - { + if (c->stride == STRIDE_LUA) { // lua object return 1; } - if (f->key == NULL) - { + if (f->key == NULL) { // value type return 1; } @@ -1061,25 +1023,19 @@ get_write_component(lua_State *L, int lua_index, const char *name, struct field } static void -write_component_object(lua_State *L, int n, struct field *f, void *buffer) -{ - if (f->key == NULL) - { +write_component_object(lua_State *L, int n, struct field *f, void *buffer) { + if (f->key == NULL) { write_value(L, f, buffer); - } - else - { + } else { write_component(L, n, f, -1, (char *)buffer); lua_pop(L, 1); } } static int -remove_tag(lua_State *L, int lua_index, const char *name) -{ +remove_tag(lua_State *L, int lua_index, const char *name) { int r = 0; - switch (lua_getfield(L, lua_index, name)) - { + switch (lua_getfield(L, lua_index, name)) { case LUA_TNIL: r = 1; break; @@ -1089,44 +1045,35 @@ remove_tag(lua_State *L, int lua_index, const char *name) default: return luaL_error(L, "Invalid tag type %s", lua_typename(L, lua_type(L, -1))); } + lua_pop(L, 1); return r; } -static void -update_last_index(lua_State *L, int world_index, int lua_index, struct group_iter *iter, int idx) -{ +static int +update_last_index(lua_State *L, int world_index, int lua_index, struct group_iter *iter, int idx) { + int ret = 0; int i; int mainkey = iter->k[0].id; struct component_pool *c = &iter->world->c[mainkey]; - if (!(iter->k[0].attrib & COMPONENT_EXIST)) - { - if (c->stride == STRIDE_TAG) - { - // It's a tag - if ((iter->k[0].attrib & COMPONENT_OUT) && remove_tag(L, lua_index, iter->k[0].name)) - { - entity_disable_tag_(iter->world, mainkey, idx, mainkey); - } - } - else if ((iter->k[0].attrib & COMPONENT_OUT) && get_write_component(L, lua_index, iter->k[0].name, iter->f, c)) - { + int disable_mainkey = 0; + if (!(iter->k[0].attrib & COMPONENT_EXIST)) { + 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) - { + 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) - { + 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); + 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); } } @@ -1134,28 +1081,20 @@ update_last_index(lua_State *L, int world_index, int lua_index, struct group_ite struct field *f = iter->f + iter->k[0].field_n; - for (i = 1; i < iter->nkey; i++) - { + for (i=1;inkey;i++) { struct group_key *k = &iter->k[i]; - if (!(k->attrib & COMPONENT_EXIST)) - { + if (!(k->attrib & COMPONENT_EXIST)) { struct component_pool *c = &iter->world->c[k->id]; - if (c->stride == STRIDE_TAG) - { + if (c->stride == STRIDE_TAG) { // It's a tag - if ((k->attrib & COMPONENT_OUT) || is_temporary(k->attrib)) - { - switch (lua_getfield(L, lua_index, k->name)) - { + if ((k->attrib & COMPONENT_OUT) || is_temporary(k->attrib)) { + switch (lua_getfield(L, lua_index, k->name)) { case LUA_TNIL: break; case LUA_TBOOLEAN: - if (lua_toboolean(L, -1)) - { + if (lua_toboolean(L, -1)) { entity_enable_tag_(iter->world, mainkey, idx, k->id, L, world_index); - } - else - { + } else { entity_disable_tag_(iter->world, mainkey, idx, k->id); } break; @@ -1164,43 +1103,33 @@ update_last_index(lua_State *L, int world_index, int lua_index, struct group_ite } lua_pop(L, 1); } - } - else if ((k->attrib & COMPONENT_OUT) && get_write_component(L, lua_index, k->name, f, c)) - { + } else if ((k->attrib & COMPONENT_OUT) + && get_write_component(L, lua_index, k->name, f, c)) { int index = entity_sibling_index_(iter->world, mainkey, idx, k->id); - if (index == 0) - { + if (index == 0) { luaL_error(L, "Can't find sibling %s of %s", k->name, iter->k[0].name); } - if (c->stride == STRIDE_LUA) - { - if (lua_getiuservalue(L, world_index, k->id * 2 + 2) != LUA_TTABLE) - { + ret = index; + if (c->stride == STRIDE_LUA) { + if (lua_getiuservalue(L, world_index, k->id * 2 + 2) != LUA_TTABLE) { luaL_error(L, "Missing lua table for %d", k->id); } lua_insert(L, -2); lua_rawseti(L, -2, index); - } - else - { + } else { void *buffer = get_ptr(c, index - 1); write_component_object(L, k->field_n, f, buffer); } - } - else if (is_temporary(k->attrib) && get_write_component(L, lua_index, k->name, f, c)) - { - if (c->stride == STRIDE_LUA) - { + } else if (is_temporary(k->attrib) + && get_write_component(L, lua_index, k->name, f, c)) { + if (c->stride == STRIDE_LUA) { int index = entity_add_sibling_index_(L, world_index, iter->world, mainkey, idx, k->id); - if (lua_getiuservalue(L, world_index, k->id * 2 + 2) != LUA_TTABLE) - { + if (lua_getiuservalue(L, world_index, k->id * 2 + 2) != LUA_TTABLE) { luaL_error(L, "Missing lua table for %d", k->id); } lua_insert(L, -2); lua_rawseti(L, -2, index); - } - else - { + } else { void *buffer = entity_add_sibling_(iter->world, mainkey, idx, k->id, NULL, L, world_index); write_component_object(L, k->field_n, f, buffer); } @@ -1208,60 +1137,52 @@ update_last_index(lua_State *L, int world_index, int lua_index, struct group_ite } f += k->field_n; } + if (disable_mainkey) { + entity_disable_tag_(iter->world, mainkey, idx, mainkey); + } + return ret; } static void -read_component_in_field(lua_State *L, int lua_index, const char *name, int n, struct field *f, void *buffer) -{ - if (n == 0) - { +read_component_in_field(lua_State *L, int lua_index, const char *name, int n, struct field *f, void *buffer) { + if (n == 0) { // It's tag lua_pushboolean(L, buffer ? 1 : 0); lua_setfield(L, lua_index, name); return; } - if (f->key == NULL) - { + if (f->key == NULL) { // value type read_value(L, f, buffer); lua_setfield(L, lua_index, name); return; } - if (lua_getfield(L, lua_index, name) != LUA_TTABLE) - { + if (lua_getfield(L, lua_index, name) != LUA_TTABLE) { luaL_error(L, ".%s is missing", name); } - read_component(L, n, f, lua_gettop(L), buffer); + read_component(L, n , f, lua_gettop(L), buffer); lua_pop(L, 1); } // -1 : end ; 0 : next ; 1 : succ static int -query_index(struct group_iter *iter, int mainkey, int idx, unsigned int index[MAX_COMPONENT]) -{ - if (entity_iter_(iter->world, mainkey, idx) == NULL) - { +query_index(struct group_iter *iter, int mainkey, int idx, unsigned int index[MAX_COMPONENT]) { + if (entity_iter_(iter->world, mainkey, idx) == NULL) { return -1; } - index[0] = idx + 1; + index[0] = idx+1; int j; - for (j = 1; j < iter->nkey; j++) - { + for (j=1;jnkey;j++) { struct group_key *k = &iter->k[j]; - if (!is_temporary(k->attrib)) - { + if (!is_temporary(k->attrib)) { index[j] = entity_sibling_index_(iter->world, mainkey, idx, k->id); - if (index[j] == 0) - { - if (!(k->attrib & COMPONENT_OPTIONAL)) - { + if (index[j] == 0) { + if (!(k->attrib & COMPONENT_OPTIONAL)) { // required. try next return 0; } } - } - else - { + } else { index[j] = 0; } } @@ -1269,53 +1190,37 @@ query_index(struct group_iter *iter, int mainkey, int idx, unsigned int index[MA } static void -read_iter(lua_State *L, int world_index, int obj_index, struct group_iter *iter, unsigned int index[MAX_COMPONENT]) -{ +read_iter(lua_State *L, int world_index, int obj_index, struct group_iter *iter, unsigned int index[MAX_COMPONENT]) { struct field *f = iter->f; int i; - for (i = 0; i < iter->nkey; i++) - { + for (i=0;inkey;i++) { struct group_key *k = &iter->k[i]; struct component_pool *c = &iter->world->c[k->id]; - if (c->stride == STRIDE_LUA) - { + if (c->stride == STRIDE_LUA) { // lua object component - if (index[i]) - { - if (lua_getiuservalue(L, world_index, k->id * 2 + 2) != LUA_TTABLE) - { + if (index[i]) { + if (lua_getiuservalue(L, world_index, k->id * 2 + 2) != LUA_TTABLE) { luaL_error(L, "Missing lua table for %d", k->id); } lua_rawgeti(L, -1, index[i]); lua_setfield(L, obj_index, k->name); lua_pop(L, 1); - } - else - { + } else { lua_pushnil(L); lua_setfield(L, obj_index, k->name); } - } - else if (c->stride != STRIDE_ORDER) - { - if (!(k->attrib & COMPONENT_EXIST)) - { - if (k->attrib & COMPONENT_IN) - { - if (index[i]) - { - void *ptr = get_ptr(c, index[i] - 1); + } else if (c->stride != STRIDE_ORDER) { + if (!(k->attrib & COMPONENT_EXIST)) { + if (k->attrib & COMPONENT_IN) { + if (index[i]) { + void *ptr = get_ptr(c, index[i]-1); read_component_in_field(L, obj_index, k->name, k->field_n, f, ptr); - } - else - { + } else { lua_pushnil(L); lua_setfield(L, obj_index, k->name); } - } - else if (index[i] == 0 && !is_temporary(k->attrib)) - { + } else if (index[i] == 0 && !is_temporary(k->attrib)) { lua_pushnil(L); lua_setfield(L, obj_index, k->name); } @@ -1326,12 +1231,10 @@ read_iter(lua_State *L, int world_index, int obj_index, struct group_iter *iter, } static int -lsync(lua_State *L) -{ +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) - { + if (lua_rawgeti(L, 3, 1) != LUA_TNUMBER) { return luaL_error(L, "Invalid iterator"); } int idx = lua_tointeger(L, -1) - 1; @@ -1339,26 +1242,28 @@ lsync(lua_State *L) return luaL_error(L, "Invalid iterator index %d", idx); lua_pop(L, 1); - if (!iter->readonly) - { - update_last_index(L, 1, 3, iter, idx); - } - unsigned int index[MAX_COMPONENT]; - if (query_index(iter, iter->k[0].id, idx, index) <= 0) - { + if (query_index(iter, iter->k[0].id, idx, index) <=0) { return luaL_error(L, "Read pattern fail"); } + + int ret = 0; + if (!iter->readonly) { + ret = update_last_index(L, 1, 3, iter, idx); + } read_iter(L, 1, 3, iter, index); - return 0; + if (ret) { + lua_pushinteger(L, ret); + return 1; + } else { + return 0; + } } static int -leach_group(lua_State *L) -{ - struct group_iter *iter = lua_touserdata(L, 1); - if (lua_rawgeti(L, 2, 1) != LUA_TNUMBER) - { +leach_group(lua_State *L) { + struct group_iter *iter = lua_touserdata(L, 1); + if (lua_rawgeti(L, 2, 1) != LUA_TNUMBER) { return luaL_error(L, "Invalid group iterator"); } int i = lua_tointeger(L, -1); @@ -1366,21 +1271,18 @@ leach_group(lua_State *L) return luaL_error(L, "Invalid iterator index %d", i); lua_pop(L, 1); - if (lua_getiuservalue(L, 1, 1) != LUA_TUSERDATA) - { + if (lua_getiuservalue(L, 1, 1) != LUA_TUSERDATA) { return luaL_error(L, "Missing world object for iterator"); } int world_index = lua_gettop(L); - if (i > 0 && !iter->readonly) - { - update_last_index(L, world_index, 2, iter, i - 1); + if (i > 0 && !iter->readonly) { + update_last_index(L, world_index, 2, iter, i-1); } int mainkey = iter->k[0].id; unsigned int index[MAX_COMPONENT]; - for (;;) - { + for (;;) { int ret = query_index(iter, mainkey, i++, index); if (ret < 0) return 0; @@ -1390,7 +1292,7 @@ leach_group(lua_State *L) lua_pushinteger(L, i); lua_rawseti(L, 2, 1); - + read_iter(L, world_index, 2, iter, index); lua_settop(L, 2); @@ -1398,66 +1300,63 @@ leach_group(lua_State *L) } static void -create_key_cache(lua_State *L, struct group_key *k, struct field *f) -{ +create_key_cache(lua_State *L, struct group_key *k, struct field *f) { if (k->field_n == 0 // is tag or object? - || (k->attrib & COMPONENT_EXIST)) - { // only existence + || (k->attrib & COMPONENT_EXIST)) { // only existence return; } - if (k->field_n == 1 && f[0].key == NULL) - { + if (k->field_n == 1 && f[0].key == NULL) { // value type - switch (f[0].type) - { + switch (f[0].type) { case TYPE_INT: + case TYPE_INT64: + case TYPE_DWORD: + case TYPE_WORD: + case TYPE_BYTE: lua_pushinteger(L, 0); break; case TYPE_FLOAT: + case TYPE_DOUBLE: lua_pushnumber(L, 0); break; case TYPE_BOOL: lua_pushboolean(L, 0); break; + case TYPE_USERDATA: + lua_pushlightuserdata(L, NULL); + break; default: lua_pushnil(L); break; } - } - else - { + } else { lua_createtable(L, 0, k->field_n); } lua_setfield(L, -2, k->name); } static int -lpairs_group(lua_State *L) -{ - struct group_iter *iter = lua_touserdata(L, 1); +lpairs_group(lua_State *L) { + struct group_iter *iter = lua_touserdata(L, 1); lua_pushcfunction(L, leach_group); lua_pushvalue(L, 1); lua_createtable(L, 2, iter->nkey); int i; int opt = 0; struct field *f = iter->f; - for (i = 0; i < iter->nkey; i++) - { + for (i=0;inkey;i++) { struct group_key *k = &iter->k[i]; create_key_cache(L, k, f); f += k->field_n; if (k->attrib & COMPONENT_OPTIONAL) ++opt; } - if (opt) - { + if (opt) { // create backup table in metatable lua_createtable(L, 0, opt); - for (i = 0; i < iter->nkey; i++) - { + for (i=0;inkey;i++) { struct group_key *k = &iter->k[i]; - if (k->attrib & COMPONENT_OPTIONAL) - { + if (k->attrib & COMPONENT_OPTIONAL) { lua_getfield(L, -2, k->name); lua_setfield(L, -2, k->name); } @@ -1466,17 +1365,15 @@ lpairs_group(lua_State *L) } lua_pushinteger(L, 0); lua_rawseti(L, -2, 1); - lua_pushinteger(L, iter->k[0].id); // mainkey + lua_pushinteger(L, iter->k[0].id); // mainkey lua_rawseti(L, -2, 2); - return 3; + return 3; } static int -check_boolean(lua_State *L, const char *key) -{ +check_boolean(lua_State *L, const char * key) { int r = 0; - switch (lua_getfield(L, -1, key)) - { + switch (lua_getfield(L, -1, key)) { case LUA_TNIL: break; case LUA_TBOOLEAN: @@ -1490,10 +1387,8 @@ check_boolean(lua_State *L, const char *key) } static int -is_value(lua_State *L, struct field *f) -{ - switch (lua_getfield(L, -1, "type")) - { +is_value(lua_State *L, struct field *f) { + switch (lua_getfield(L, -1, "type")) { case LUA_TNIL: lua_pop(L, 1); return 0; @@ -1508,58 +1403,45 @@ is_value(lua_State *L, struct field *f) } static int -get_key(struct entity_world *w, lua_State *L, struct group_key *key, struct field *f) -{ - if (lua_getfield(L, -1, "id") != LUA_TNUMBER) - { +get_key(struct entity_world *w, lua_State *L, struct group_key *key, struct field *f) { + if (lua_getfield(L, -1, "id") != LUA_TNUMBER) { return luaL_error(L, "Invalid id"); } key->id = lua_tointeger(L, -1); lua_pop(L, 1); - if (key->id < 0 || key->id >= MAX_COMPONENT || w->c[key->id].cap == 0) - { + if (key->id < 0 || key->id >= MAX_COMPONENT || w->c[key->id].cap == 0) { return luaL_error(L, "Invalid id %d", key->id); } - if (lua_getfield(L, -1, "name") != LUA_TSTRING) - { + if (lua_getfield(L, -1, "name") != LUA_TSTRING) { return luaL_error(L, "Invalid component name"); } key->name = lua_tostring(L, -1); lua_pop(L, 1); int attrib = 0; - if (check_boolean(L, "r")) - { + if (check_boolean(L, "r")) { attrib |= COMPONENT_IN; } - if (check_boolean(L, "w")) - { + if (check_boolean(L, "w")) { attrib |= COMPONENT_OUT; } - if (check_boolean(L, "opt")) - { + if (check_boolean(L, "opt")) { attrib |= COMPONENT_OPTIONAL; } - if (check_boolean(L, "exist")) - { + if (check_boolean(L, "exist")) { attrib |= COMPONENT_EXIST; } key->attrib = attrib; - if (is_value(L, f)) - { + if (is_value(L, f)) { key->field_n = 1; return 1; - } - else - { + } else { int i = 0; int ttype; - while ((ttype = lua_geti(L, -1, i + 1)) != LUA_TNIL) - { - if (ttype != LUA_TTABLE) - { - return luaL_error(L, "Invalid field %d", i + 1); + while ((ttype = lua_geti(L, -1, i+1)) != LUA_TNIL) { + if (ttype != LUA_TTABLE) { + return luaL_error(L, "Invalid field %d", i+1); } - get_field(L, i + 1, &f[i]); + get_field(L, i+1, &f[i]); ++i; } key->field_n = i; @@ -1569,31 +1451,26 @@ get_key(struct entity_world *w, lua_State *L, struct group_key *key, struct fiel } static int -lgroupiter(lua_State *L) -{ +lgroupiter(lua_State *L) { struct entity_world *w = getW(L); luaL_checktype(L, 2, LUA_TTABLE); int nkey = get_len(L, 2); int field_n = 0; int i; - if (nkey == 0) - { + if (nkey == 0) { return luaL_error(L, "At least one key"); } - if (nkey > MAX_COMPONENT) - { + if (nkey > MAX_COMPONENT) { return luaL_error(L, "Too many keys"); } - for (i = 0; i < nkey; i++) - { - if (lua_geti(L, 2, i + 1) != LUA_TTABLE) - { + for (i=0;ireadonly = 1; struct field *f = (struct field *)((char *)iter + header_size); iter->f = f; - for (i = 0; i < nkey; i++) - { - lua_geti(L, 2, i + 1); + for (i=0; i< nkey; i++) { + lua_geti(L, 2, i+1); int n = get_key(w, L, &iter->k[i], f); struct component_pool *c = &w->c[iter->k[i].id]; f += n; lua_pop(L, 1); - if (c->stride == STRIDE_LUA) - { + if (c->stride == STRIDE_LUA) { if (n != 0) return luaL_error(L, ".%s is object component, no fields needed", iter->k[i].name); iter->k[i].attrib |= COMPONENT_OBJECT; - } - else if (c->stride == STRIDE_ORDER) - { - if (i != 0) - { + } else if (c->stride == STRIDE_ORDER) { + if (i != 0) { return luaL_error(L, ".%s is an order key, must be main key", iter->k[i].name); - } - else if (iter->k[0].attrib & COMPONENT_OUT) - { + } else if (iter->k[0].attrib & COMPONENT_OUT) { return luaL_error(L, ".%s is an order key, it should be readonly", iter->k[0].name); } } @@ -1640,16 +1510,13 @@ lgroupiter(lua_State *L) if (!readonly) iter->readonly = 0; } - if (iter->k[0].attrib & COMPONENT_OPTIONAL) - { + if (iter->k[0].attrib & COMPONENT_OPTIONAL) { return luaL_error(L, "The main key should not be optional"); } - if (is_temporary(iter->k[0].attrib)) - { + if (is_temporary(iter->k[0].attrib)) { return luaL_error(L, "The main key can't be temporary"); } - if (luaL_newmetatable(L, "ENTITY_GROUPITER")) - { + if (luaL_newmetatable(L, "ENTITY_GROUPITER")) { lua_pushcfunction(L, lpairs_group); lua_setfield(L, -2, "__call"); } @@ -1658,10 +1525,8 @@ lgroupiter(lua_State *L) } static int -get_integer(lua_State *L, int index, int i, const char *key) -{ - if (lua_rawgeti(L, index, i) != LUA_TNUMBER) - { +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); @@ -1672,8 +1537,7 @@ get_integer(lua_State *L, int index, int i, const char *key) } static int -lremove(lua_State *L) -{ +lremove(lua_State *L) { struct entity_world *w = getW(L); luaL_checktype(L, 2, LUA_TTABLE); int iter = get_integer(L, 2, 1, "index") - 1; @@ -1683,8 +1547,7 @@ lremove(lua_State *L) } static int -lsortkey(lua_State *L) -{ +lsortkey(lua_State *L) { struct entity_world *w = getW(L); int oid = luaL_checkinteger(L, 2); int cid = luaL_checkinteger(L, 3); @@ -1693,472 +1556,110 @@ lsortkey(lua_State *L) } static int -lsingleton(lua_State *L) -{ +lobject(lua_State *L) { struct group_iter *iter = luaL_checkudata(L, 1, "ENTITY_GROUPITER"); + int index = luaL_optinteger(L, 3, 1) - 1; int cid = iter->k[0].id; - struct entity_world *w = iter->world; - if (cid < 0 || cid >= MAX_COMPONENT) - { - return luaL_error(L, "Invalid singleton %d", cid); + struct entity_world * w = iter->world; + if (cid < 0 || cid >=MAX_COMPONENT) { + return luaL_error(L, "Invalid object %d", cid); } + lua_settop(L, 2); struct component_pool *c = &w->c[cid]; - if (c->n == 0) - { - return luaL_error(L, "No singleton %d", cid); - } - if (c->stride == STRIDE_LUA) - { - // lua singleton - lua_settop(L, 2); - if (lua_getiuservalue(L, 1, 1) != LUA_TUSERDATA) - { + if (c->n <= index) { + return luaL_error(L, "No object %d", cid); + } + if (c->stride == STRIDE_LUA) { + // lua object + if (lua_getiuservalue(L, 1, 1) != LUA_TUSERDATA) { return luaL_error(L, "No world"); } - if (lua_getiuservalue(L, -1, cid * 2 + 2) != LUA_TTABLE) - { + if (lua_getiuservalue(L, -1, cid * 2 + 2) != LUA_TTABLE) { return luaL_error(L, "Missing lua table for %d", cid); } - if (lua_isnil(L, 2)) - { - lua_rawgeti(L, -1, 1); - } - else - { + if (lua_isnil(L, 2)) { + lua_rawgeti(L, -1, index + 1); + } else { lua_pushvalue(L, 2); - lua_rawseti(L, -2, 1); + lua_rawseti(L, -2, index + 1); lua_settop(L, 2); } return 1; - } - else if (c->stride <= 0) - { - return luaL_error(L, "Invalid singleton %d", cid); + } else if (c->stride == 0) { + if (lua_type(L, 2) != LUA_TBOOLEAN) + return luaL_error(L, "%s is a tag, need boolean", iter->k[0].name); + if (!lua_toboolean(L, 2)) { + entity_disable_tag_(w, cid, index, cid); + } + return 1; + } else if (c->stride < 0) { + return luaL_error(L, "Invalid object %d", cid); } struct field *f = iter->f; - void *buffer = get_ptr(c, 0); - if (lua_isnoneornil(L, 2)) - { - // read singleton - lua_createtable(L, 0, iter->k[0].field_n); - if (f->key == NULL) - { + void * buffer = get_ptr(c, index); + if (lua_isnoneornil(L, 2)) { + // read object + if (f->key == NULL) { // value type read_value(L, f, buffer); + } else { + lua_createtable(L, 0, iter->k[0].field_n); + int lua_index = lua_gettop(L); + read_component(L, iter->k[0].field_n, f, lua_index, buffer); } - else - { - int index = lua_gettop(L); - read_component(L, iter->k[0].field_n, f, index, buffer); - } - } - else - { - // write singleton + } else { + // write object lua_pushvalue(L, 2); write_component_object(L, iter->k[0].field_n, f, buffer); } return 1; } -// reference object - -struct ecs_ref -{ - struct ecs_ref_i interface; - void *data; - lua_State *L; - int n; - int cap; - int stride; - int nkey; - int freelist; - struct field f[1]; -}; - -struct ref_freenode -{ - int freelist; -}; - -static void -init_fields(struct ecs_ref *R, lua_State *L, int index, int nkey) -{ - if (nkey == 0) - { - // lua object - R->stride = 0; - lua_newtable(R->L); - if (lua_gettop(R->L) != 1) - { - luaL_error(L, "Invalid ref context"); - } - } - else - { - if (lua_getfield(L, index, "size") != LUA_TNUMBER) - { - luaL_error(L, "need .size"); - } - R->stride = lua_tointeger(L, -1); - lua_pop(L, 1); - int i; - for (i = 0; i < nkey; i++) - { - struct field *f = &R->f[i]; - if (lua_geti(L, index, i + 1) != LUA_TTABLE) - { - luaL_error(L, "Invalid field %d, need table, it's %s", i + 1, lua_typename(L, lua_type(L, -1))); - } - if (lua_geti(L, -1, 1) != LUA_TNUMBER) - { - luaL_error(L, "Invalid type id in [%d]", i + 1); - } - f->type = lua_tointeger(L, -1); - lua_pop(L, 1); - if (lua_geti(L, -1, 2) != LUA_TSTRING) - { - if (lua_type(L, -1) == LUA_TNIL && i == 0) - { - f->key = NULL; - } - else - { - luaL_error(L, "Invalid key name in [%d]", i + 1); - } - } - else - { - f->key = lua_tostring(L, -1); - } - lua_pop(L, 1); - if (lua_geti(L, -1, 3) != LUA_TNUMBER) - { - luaL_error(L, "Invalid offset in [%d]", i + 1); - } - f->offset = lua_tointeger(L, -1); - if (f->offset >= R->stride) - { - luaL_error(L, "Invalid offset (%d/%d) in [%d]", f->offset, R->stride, i + 1); - } - lua_pop(L, 2); - } - } -} - -static inline void * -ref_index_ptr(struct ecs_ref *R, int index) -{ - return (void *)((char *)R->data + R->stride * index); -} - static int -alloc_id(struct ecs_ref *R) -{ - if (R->data == NULL) - { - lua_settop(R->L, 0); - R->data = lua_newuserdata(R->L, R->stride * R->cap); - R->n = 1; - return 1; - } - if (R->freelist) - { - int r = R->freelist - 1; - struct ref_freenode *node = (struct ref_freenode *)ref_index_ptr(R, r); - R->freelist = node->freelist; - return r; - } - if (R->n >= R->cap) - { - int newcap = R->cap * 3 / 2; - void *data = lua_newuserdata(R->L, R->stride * newcap); - memcpy(R->data, data, R->stride * R->n); - lua_replace(R->L, 1); - R->data = data; - R->cap = newcap; - } - return ++R->n; -} - -static int -lnew_object(lua_State *L) -{ - struct ecs_ref *R = (struct ecs_ref *)luaL_checkudata(L, 1, "ENTITY_REFOBJECT"); - int n; - if (R->stride == 0) - { - // lua object - if (!lua_istable(R->L, 1)) - { - return luaL_error(L, "Invalid ref context"); - } - n = lua_rawlen(R->L, 1); - lua_settop(L, 2); - lua_xmove(L, R->L, 1); - lua_rawseti(R->L, 1, n + 1); - lua_pushinteger(L, n + 1); - } - else - { - n = alloc_id(R); - void *buffer = ref_index_ptr(R, n - 1); - if (R->f[0].key == NULL) - { - write_value(L, R->f, buffer); - } - else - { - write_component(L, R->nkey, R->f, 2, buffer); - } - lua_pushinteger(L, n); - } - return 1; -} - -static void -release_object(struct ecs_ref *R, int id) -{ - if (R->stride == 0) - { - // lua object - if (!lua_istable(R->L, 1)) - { - luaL_error(R->L, "Invalid ref context"); - } - lua_pushnil(R->L); - lua_rawseti(R->L, 1, id); - } - else - { - if (id <= 0 || id > R->n) - luaL_error(R->L, "Invalid id %d", id); - if (id == R->n) - { - --R->n; - } - else - { - struct ref_freenode *node = (struct ref_freenode *)ref_index_ptr(R, id - 1); - node->freelist = R->freelist; - R->freelist = id; - } - } -} - -static void * -index_object(struct ecs_ref *R, int id) -{ - if (R->stride == 0) - { - luaL_error(R->L, "Can't index lua object"); - } - else if (id <= 0 || id > R->n) - { - luaL_error(R->L, "Invalid id %d", id); - } - return ref_index_ptr(R, id - 1); -} - -static int -ldelete_object(lua_State *L) -{ - struct ecs_ref *R = (struct ecs_ref *)luaL_checkudata(L, 1, "ENTITY_REFOBJECT"); - int id = luaL_checkinteger(L, 2); - release_object(R, id); - return 0; -} - -#define KEY(s) s, sizeof(""s) - -static int -iskey(const char *name, size_t sz, const char *keyname, size_t keysize) -{ - return (sz + 1 == keysize) && memcmp(name, keyname, sz) == 0; -} - -static inline int -method(lua_State *L, int index) -{ - size_t sz; - const char *name = lua_tolstring(L, index, &sz); - if (iskey(name, sz, KEY("new"))) - { - lua_pushcfunction(L, lnew_object); - } - else if (iskey(name, sz, KEY("delete"))) - { - lua_pushcfunction(L, ldelete_object); - } - else - { - return luaL_error(L, "Invalid method %s", name); - } - return 1; -} - -static inline int -index_ref(lua_State *L, int index) -{ - int id = lua_tointeger(L, index); - if (id <= 0) - { - return luaL_error(L, "Invalid index %d", id); - } - struct ecs_ref *R = (struct ecs_ref *)lua_touserdata(L, 1); - if (R->stride == 0) - { - // lua object - if (!lua_istable(R->L, 1)) - { - return luaL_error(L, "Invalid ref context"); - } - lua_rawgeti(R->L, 1, id); - lua_xmove(R->L, L, 1); - } - else - { - if (id <= 0 || id > R->n) - { - return luaL_error(L, "Invalid id %d\n", id); - } - void *buffer = ref_index_ptr(R, id - 1); - if (R->f->key == NULL) - { - read_value(L, R->f, buffer); - } - else - { - lua_createtable(L, 0, R->nkey); - int index = lua_gettop(L); - read_component(L, R->nkey, R->f, index, buffer); - } - } - return 1; -} - -static int -lread_ref(lua_State *L) -{ - switch (lua_type(L, 2)) - { - case LUA_TSTRING: - return method(L, 2); - case LUA_TNUMBER: - return index_ref(L, 2); - default: - return luaL_error(L, "Invalid key type %s", lua_typename(L, lua_type(L, -1))); - } -} - -static int -lwrite_ref(lua_State *L) -{ - struct ecs_ref *R = (struct ecs_ref *)lua_touserdata(L, 1); - int id = luaL_checkinteger(L, 2); - if (R->stride == 0) - { - // lua object - if (!lua_istable(R->L, 1)) - { - return luaL_error(L, "Invalid ref context"); - } - lua_xmove(L, R->L, 1); - lua_rawseti(R->L, 1, id); - } - if (id <= 0 && id > R->n) - return luaL_error(L, "Invalid id %d", id); - void *buffer = ref_index_ptr(R, id - 1); - write_component_object(L, R->nkey, R->f, buffer); +lrelease(lua_State *L) { + struct entity_world *w = getW(L); + int cid = luaL_checkinteger(L, 2); + int refid = luaL_checkinteger(L, 3) - 1; + int live_tag = cid + 1; + int dead_tag = cid + 2; + entity_disable_tag_(w, cid, refid, live_tag); + entity_enable_tag_(w, cid, refid, dead_tag, L, 1); return 0; } -static int -lnew_ref(lua_State *L) -{ - size_t sz; - int nkey; - if (lua_isnoneornil(L, 1)) - { - sz = offsetof(struct ecs_ref, f); - nkey = 0; - } - else - { - luaL_checktype(L, 1, LUA_TTABLE); - nkey = get_len(L, 1); - sz = sizeof(struct ecs_ref) + (nkey - 1) * sizeof(struct field); - } - struct ecs_ref *R = (struct ecs_ref *)lua_newuserdatauv(L, sz, 1); - static struct ecs_capi_ref apis = { - alloc_id, - release_object, - index_object, - }; - R->interface.api = &apis; - R->data = NULL; - R->n = 0; - R->cap = DEFAULT_SIZE; - R->nkey = nkey; - R->freelist = 0; - R->L = lua_newthread(L); - lua_setiuservalue(L, -2, 1); - init_fields(R, L, 1, nkey); - if (luaL_newmetatable(L, "ENTITY_REFOBJECT")) - { - luaL_Reg l[] = { - {"__index", lread_ref}, - {"__newindex", lwrite_ref}, - {NULL, NULL}, - }; - luaL_setfuncs(L, l, 0); - } - lua_setmetatable(L, -2); - return 1; -} - LUAMOD_API int -luaopen_ecs_core(lua_State *L) -{ +luaopen_ecs_core(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { - {"_world", lnew_world}, - {"_ref", lnew_ref}, - {"_MAXTYPE", NULL}, - {"_METHODS", NULL}, - {"_TYPEINT", NULL}, - {"_TYPEFLOAT", NULL}, - {"_TYPEBOOL", NULL}, - {NULL, NULL}, + { "_world", lnew_world }, + { NULL, NULL }, }; - luaL_newlib(L, l); - lua_pushinteger(L, MAX_COMPONENT - 1); + luaL_newlib(L,l); + lua_pushinteger(L, MAX_COMPONENT-1); lua_setfield(L, -2, "_MAXTYPE"); - if (luaL_newmetatable(L, "ENTITY_WORLD")) - { + if (luaL_newmetatable(L, "ENTITY_WORLD")) { luaL_Reg l[] = { - {"__index", NULL}, - {"memory", lcount_memory}, - {"collect", lcollect_memory}, - {"_newtype", lnew_type}, - {"_newentity", lnew_entity}, - {"_addcomponent", ladd_component}, - {"update", lupdate}, - {"_clear", lclear_type}, - {"_context", lcontext}, - {"_groupiter", lgroupiter}, - {"remove", lremove}, - {"_sortkey", lsortkey}, - {"_singleton", lsingleton}, - {"_sync", lsync}, - {NULL, NULL}, + { "__index", NULL }, + { "memory", lcount_memory }, + { "collect", lcollect_memory }, + { "_newtype",lnew_type }, + { "_newentity", lnew_entity }, + { "_addcomponent", ladd_component }, + { "update", lupdate }, + { "_clear", lclear_type }, + { "_context", lcontext }, + { "_groupiter", lgroupiter }, + { "remove", lremove }, + { "_sortkey", lsortkey }, + { "_object", lobject }, + { "_sync", lsync }, + { "_release", lrelease }, + { NULL, NULL }, }; - luaL_setfuncs(L, l, 0); + luaL_setfuncs(L,l,0); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); - } - else - { + } else { return luaL_error(L, "ENTITY_WORLD exist"); } lua_setfield(L, -2, "_METHODS"); @@ -2168,12 +1669,26 @@ luaopen_ecs_core(lua_State *L) lua_setfield(L, -2, "_TYPEFLOAT"); lua_pushinteger(L, TYPE_BOOL); lua_setfield(L, -2, "_TYPEBOOL"); + lua_pushinteger(L, TYPE_INT64); + lua_setfield(L, -2, "_TYPEINT64"); + lua_pushinteger(L, TYPE_DWORD); + lua_setfield(L, -2, "_TYPEDWORD"); + lua_pushinteger(L, TYPE_WORD); + lua_setfield(L, -2, "_TYPEWORD"); + lua_pushinteger(L, TYPE_BYTE); + lua_setfield(L, -2, "_TYPEBYTE"); + lua_pushinteger(L, TYPE_DOUBLE); + lua_setfield(L, -2, "_TYPEDOUBLE"); + lua_pushinteger(L, TYPE_USERDATA); + lua_setfield(L, -2, "_TYPEUSERDATA"); lua_pushinteger(L, STRIDE_LUA); lua_setfield(L, -2, "_LUAOBJECT"); lua_pushinteger(L, ENTITY_REMOVED); lua_setfield(L, -2, "_REMOVED"); lua_pushinteger(L, STRIDE_ORDER); lua_setfield(L, -2, "_ORDERKEY"); + lua_pushlightuserdata(L, NULL); + lua_setfield(L, -2, "NULL"); return 1; } @@ -2187,34 +1702,28 @@ luaopen_ecs_core(lua_State *L) #define COMPONENT_ID 3 #define SINGLETON_STRING 4 -struct vector2 -{ +struct vector2 { float x; float y; }; -struct id -{ +struct id { int v; }; static int -ltest(lua_State *L) -{ +ltest(lua_State *L) { struct ecs_context *ctx = lua_touserdata(L, 1); struct vector2 *v; int i; - for (i = 0; (v = (struct vector2 *)entity_iter(ctx, COMPONENT_VECTOR2, i)); i++) - { + for (i=0;(v=(struct vector2 *)entity_iter(ctx, COMPONENT_VECTOR2, i));i++) { printf("vector2 %d: x=%f y=%f\n", i, v->x, v->y); - struct id *id = (struct id *)entity_sibling(ctx, COMPONENT_VECTOR2, i, COMPONENT_ID); - if (id) - { + struct id * id = (struct id *)entity_sibling(ctx, COMPONENT_VECTOR2, i, COMPONENT_ID); + if (id) { printf("\tid = %d\n", id->v); } - void *mark = entity_sibling(ctx, COMPONENT_VECTOR2, i, TAG_MARK); - if (mark) - { + void * mark = entity_sibling(ctx, COMPONENT_VECTOR2, i, TAG_MARK); + if (mark) { printf("\tMARK\n"); } } @@ -2223,14 +1732,12 @@ ltest(lua_State *L) } static int -lsum(lua_State *L) -{ +lsum(lua_State *L) { struct ecs_context *ctx = lua_touserdata(L, 1); struct vector2 *v; int i; float s = 0; - for (i = 0; (v = (struct vector2 *)entity_iter(ctx, COMPONENT_VECTOR2, i)); i++) - { + for (i=0;(v=(struct vector2 *)entity_iter(ctx, COMPONENT_VECTOR2, i));i++) { s += v->x + v->y; } lua_pushnumber(L, s); @@ -2238,40 +1745,38 @@ lsum(lua_State *L) } static int -lget(lua_State *L) -{ +lget(lua_State *L) { struct ecs_context *ctx = lua_touserdata(L, 1); - const char *ret = (const char *)entity_iter_lua(ctx, SINGLETON_STRING, 0); - if (ret) - { + const char *ret = (const char *)entity_ref_object(ctx, SINGLETON_STRING, 1); + if (ret) { lua_pushfstring(L, "[string:%s]", ret); } return 1; } +struct userdata_t { + unsigned char a; + void *b; +}; + static int -ltestref(lua_State *L) -{ - struct ecs_ref_i *R = (struct ecs_ref_i *)lua_touserdata(L, 1); - int id = robject_create(R); - printf("create id = %d\n", id); - struct vector2 *vec = robject_index(R, id); - vec->x = 42.0f; - vec->y = 24.0f; - lua_pushinteger(L, id); - return 1; +ltestuserdata(lua_State *L) { + struct ecs_context *ctx = lua_touserdata(L, 1); + struct userdata_t *ud = entity_iter(ctx, 1, 0); + ud->a = 1 - ud->a; + ud->b = ctx; + return 0; } LUAMOD_API int -luaopen_ecs_ctest(lua_State *L) -{ +luaopen_ecs_ctest(lua_State *L) { luaL_checkversion(L); luaL_Reg l[] = { - {"test", ltest}, - {"sum", lsum}, - {"get", lget}, - {"testref", ltestref}, - {NULL, NULL}, + { "test", ltest }, + { "sum", lsum }, + { "get", lget }, + { "testuserdata", ltestuserdata }, + { NULL, NULL }, }; luaL_newlib(L, l); return 1; diff --git a/framework/lualib-src/lua-ecs/luaecs.h b/framework/lualib-src/lua-ecs/luaecs.h index d0d01c4..5bca81a 100644 --- a/framework/lualib-src/lua-ecs/luaecs.h +++ b/framework/lualib-src/lua-ecs/luaecs.h @@ -5,132 +5,149 @@ struct entity_world; -struct ecs_capi -{ - void *(*iter)(struct entity_world *w, int cid, int index); +struct ecs_capi { + void * (*iter)(struct entity_world *w, int cid, int index); void (*clear_type)(struct entity_world *w, int cid); - void *(*sibling)(struct entity_world *w, int cid, int index, int slibling_id); - void *(*add_sibling)(struct entity_world *w, int cid, int index, int slibling_id, const void *buffer, void *L, int world_index); + int (*sibling_id)(struct entity_world *w, int cid, int index, int slibling_id); + void* (*add_sibling)(struct entity_world *w, int cid, int index, int slibling_id, const void *buffer, void *L, int world_index); + int (*new_entity)(struct entity_world *w, int cid, const void *buffer, void *L, int world_index); void (*remove)(struct entity_world *w, int cid, int index, void *L, int world_index); void (*enable_tag)(struct entity_world *w, int cid, int index, int tag_id, void *L, int world_index); void (*disable_tag)(struct entity_world *w, int cid, int index, int tag_id); void (*sort_key)(struct entity_world *w, int orderid, int cid, void *L, int world_index); - void *(*iter_lua)(struct entity_world *w, int cid, int index, void *L); + void * (*iter_lua)(struct entity_world *w, int cid, int index, void *L, int world_index); + int (*assign_lua)(struct entity_world *w, int cid, int index, void *L, int world_index); }; -struct ecs_context -{ +struct ecs_context { struct ecs_capi *api; struct entity_world *world; - void *L; // for memory allocator + void *L; // for memory allocator int max_id; int cid[1]; }; static inline void -check_id_(struct ecs_context *ctx, int cid) -{ +check_id_(struct ecs_context *ctx, int cid) { assert(cid >= 0 && cid <= ctx->max_id); } static inline void * -entity_iter(struct ecs_context *ctx, int cid, int index) -{ +entity_iter(struct ecs_context *ctx, int cid, int index) { check_id_(ctx, cid); return ctx->api->iter(ctx->world, ctx->cid[cid], index); } +static inline void * +entity_ref_object(struct ecs_context *ctx, int cid, int index) { + if (index <= 0) + return NULL; + check_id_(ctx, cid); + return ctx->api->iter_lua(ctx->world, ctx->cid[cid], index - 1, ctx->L, 1); +} + static inline void -entity_clear_type(struct ecs_context *ctx, int cid) -{ +entity_clear_type(struct ecs_context *ctx, int cid) { check_id_(ctx, cid); ctx->api->clear_type(ctx->world, ctx->cid[cid]); } +static inline int +entity_sibling_id(struct ecs_context *ctx, int cid, int index, int sibling_id) { + check_id_(ctx, cid); + check_id_(ctx, sibling_id); + return ctx->api->sibling_id(ctx->world, ctx->cid[cid], index, ctx->cid[sibling_id]); +} + static inline void * -entity_sibling(struct ecs_context *ctx, int cid, int index, int slibling_id) -{ +entity_sibling(struct ecs_context *ctx, int cid, int index, int sibling_id) { check_id_(ctx, cid); - check_id_(ctx, slibling_id); - return ctx->api->sibling(ctx->world, ctx->cid[cid], index, ctx->cid[slibling_id]); + check_id_(ctx, sibling_id); + int id = ctx->api->sibling_id(ctx->world, ctx->cid[cid], index, ctx->cid[sibling_id]); + if (id == 0) { + return NULL; + } else { + return ctx->api->iter(ctx->world, ctx->cid[sibling_id], id-1); + } } static inline void * -entity_add_sibling(struct ecs_context *ctx, int cid, int index, int slibling_id, const void *buffer) -{ +entity_add_sibling(struct ecs_context *ctx, int cid, int index, int sibling_id, const void *buffer) { + check_id_(ctx, cid); + check_id_(ctx, sibling_id); + return ctx->api->add_sibling(ctx->world, ctx->cid[cid], index, ctx->cid[sibling_id], buffer, ctx->L, 1); +} + +static inline int +entity_new(struct ecs_context *ctx, int cid, const void *buffer) { check_id_(ctx, cid); - check_id_(ctx, slibling_id); - return ctx->api->add_sibling(ctx->world, ctx->cid[cid], index, ctx->cid[slibling_id], buffer, ctx->L, 1); + return ctx->api->new_entity(ctx->world, ctx->cid[cid], buffer, ctx->L, 1); } static inline void -entity_remove(struct ecs_context *ctx, int cid, int index) -{ +entity_remove(struct ecs_context *ctx, int cid, int index) { check_id_(ctx, cid); ctx->api->remove(ctx->world, ctx->cid[cid], index, ctx->L, 1); } static inline void -entity_enable_tag(struct ecs_context *ctx, int cid, int index, int tag_id) -{ +entity_enable_tag(struct ecs_context *ctx, int cid, int index, int tag_id) { check_id_(ctx, cid); check_id_(ctx, tag_id); ctx->api->enable_tag(ctx->world, ctx->cid[cid], index, ctx->cid[tag_id], ctx->L, 1); } static inline void -entity_disable_tag(struct ecs_context *ctx, int cid, int index, int tag_id) -{ +entity_disable_tag(struct ecs_context *ctx, int cid, int index, int tag_id) { check_id_(ctx, cid); check_id_(ctx, tag_id); ctx->api->disable_tag(ctx->world, ctx->cid[cid], index, ctx->cid[tag_id]); } static inline void -entity_sort_key(struct ecs_context *ctx, int orderid, int cid) -{ +entity_sort_key(struct ecs_context *ctx, int orderid, int cid) { check_id_(ctx, orderid); check_id_(ctx, cid); ctx->api->sort_key(ctx->world, ctx->cid[orderid], ctx->cid[cid], ctx->L, 1); } -static inline void * -entity_iter_lua(struct ecs_context *ctx, int cid, int index) -{ +static inline int +entity_assign_lua(struct ecs_context *ctx, int cid, int index) { check_id_(ctx, cid); - return ctx->api->iter_lua(ctx->world, ctx->cid[cid], index, ctx->L); + assert(index > 0); + return ctx->api->assign_lua(ctx->world, ctx->cid[cid], index-1, ctx->L, 1); } -struct ecs_ref_i -{ - struct ecs_capi_ref *api; -}; - -struct ecs_ref; - -struct ecs_capi_ref -{ - int (*create)(struct ecs_ref *); - void (*release)(struct ecs_ref *, int id); - void *(*index)(struct ecs_ref *, int id); -}; - static inline int -robject_create(struct ecs_ref_i *R) -{ - return R->api->create((struct ecs_ref *)R); +entity_new_ref(struct ecs_context *ctx, int cid) { + check_id_(ctx, cid); + int object_id = ctx->cid[cid]; + int live_tag = object_id + 1; + int dead_tag = object_id + 2; + int id; + if (ctx->api->iter(ctx->world, dead_tag, 0)) { + // reuse + id = ctx->api->sibling_id(ctx->world, dead_tag, 0, object_id); + assert(id > 0); + --id; + ctx->api->disable_tag(ctx->world, dead_tag, 0, dead_tag); + } else { + id = ctx->api->new_entity(ctx->world, object_id, NULL, ctx->L, 1); + } + ctx->api->enable_tag(ctx->world, object_id, id, live_tag, ctx->L, 1); + return id + 1; } static inline void -robject_release(struct ecs_ref_i *R, int id) -{ - R->api->release((struct ecs_ref *)R, id); -} - -static inline void * -robject_index(struct ecs_ref_i *R, int id) -{ - return R->api->index((struct ecs_ref *)R, id); +entity_release_ref(struct ecs_context *ctx, int cid, int id) { + if (id == 0) + return; + check_id_(ctx, cid); + int object_id = ctx->cid[cid]; + int live_tag = object_id + 1; + int dead_tag = object_id + 2; + ctx->api->disable_tag(ctx->world, object_id, id-1, live_tag); + ctx->api->enable_tag(ctx->world, object_id, id-1, dead_tag, ctx->L, 1); } #endif diff --git a/framework/lualib/3rd/zeus/ecs.lua b/framework/lualib/3rd/misc/ecs.lua similarity index 58% rename from framework/lualib/3rd/zeus/ecs.lua rename to framework/lualib/3rd/misc/ecs.lua index 5e4ab3d..a138f3d 100644 --- a/framework/lualib/3rd/zeus/ecs.lua +++ b/framework/lualib/3rd/misc/ecs.lua @@ -1,5 +1,3 @@ --- https://github.com/cloudwu/luaecs - local ecs = require "ecs.core" local function get_attrib(opt, inout) @@ -16,7 +14,7 @@ local function get_attrib(opt, inout) end if inout == "in" then desc.r = true - elseif inout == "out" then + elseif inout == "out" or inout == "new" then desc.w = true elseif inout == "update" then desc.r = true @@ -35,8 +33,30 @@ local function cache_world(obj, k) 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 = {} @@ -49,11 +69,25 @@ local function cache_world(obj, k) opt, inout = padding:match "^([:?])(%l+)$" assert(opt, "Invalid pattern") end - local tc = assert(typenames[key]) + local tc = typenames[key] + if tc == nil then + error("Unknown type " .. key) + end + if tc.ref and inout ~= "new" then + local live = typenames[key .. "_live"] + local a = { + exist = true, + name = live.name, + id = live.id, + } + 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 @@ -74,6 +108,17 @@ local function cache_world(obj, k) __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 @@ -85,17 +130,23 @@ 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), } local typesize = { [typeid.int] = 4, [typeid.float] = 4, [typeid.bool] = 1, -} - -local typepack = { - [typeid.int] = 'i4', - [typeid.float] = 'f', - [typeid.bool] = 'B', + [typeid.int64] = 8, + [typeid.dword] = 4, + [typeid.word] = 2, + [typeid.byte] = 1, + [typeid.double] = 8, + [typeid.userdata] = 8, } local M = ecs._METHODS @@ -103,30 +154,24 @@ local M = ecs._METHODS do -- newtype local function parse(s) -- s is "name:typename" - local name, typename = s:match "([%w_]+):(%l+)" - local tid = assert(typeid[typename]) - return {tid, name} + 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 size = c.size - if t == typeid.int or t == typeid.float then - local offset = ((size + 3) & ~3) - c.size = offset + 4 - field[3] = offset - elseif t == typeid.bool then - c.size = size + 1 - field[3] = size - else - error("Invalid type " .. t) - end + 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 == typeid.int or t == typeid.float then - c.size = ((c.size + 3) & ~3) + if t then + local s = typesize[t] - 1 + c.size = ((c.size + s) & ~s) end end @@ -152,18 +197,12 @@ do -- newtype c.islua = true elseif c.size > 0 then align_struct(c, typeclass[1][1]) - local pack = "!4=" - for i = 1, #c do - pack = pack .. typepack[c[i][1]] - end - c.pack = pack else -- size == 0, one value if ttype then local t = assert(typeid[typeclass.type]) c.type = t c.size = typesize[t] - c.pack = typepack[t] c[1] = {t, "v", 0} else c.tag = true @@ -171,35 +210,32 @@ do -- newtype end typenames[name] = c self:_newtype(id, c.size) + if typeclass.ref then + c.ref = true + self:register{ + name = name .. "_live", + } + self:register{ + name = name .. "_dead", + } + end end +end - local _ref = ecs._ref - function ecs.ref(typeclass) - local c = { - size = 0, - } - for i, v in ipairs(typeclass) do - c[i] = align(c, parse(v)) - end - if c.size == 0 and typeclass.type then - if typeclass.type ~= "lua" then - local id = assert(typeid[typeclass.type]) - c[1] = align(c, {id, nil, 0}) +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 - if c.size > 0 then - align_struct(c, c[1][1]) - end - return _ref(c) end end -local mapbool = { - [true] = 1, - [false] = 0, -} - function M:new(obj) + -- dump(obj) local eid = self:_newentity() local typenames = context[self].typenames for k, v in pairs(obj) do @@ -207,23 +243,44 @@ function M:new(obj) if not tc then error("Invalid key : " .. k) end - if tc.islua then - self:_addcomponent(eid, tc.id, v) - elseif tc.tag then - assert(tc.size == 0) - self:_addcomponent(eid, tc.id) - elseif tc.type then - self:_addcomponent(eid, tc.id, string.pack(tc.pack, mapbool[v] or v)) - else - local tmp = {} - for i, f in ipairs(tc) do - tmp[i] = v[f[2]] - end - self:_addcomponent(eid, tc.id, string.pack(tc.pack, table.unpack(tmp))) - end + local id = self:_addcomponent(eid, tc.id) + self:object(k, id, v) end end +local ref_key = setmetatable({}, { + __index = function(cache, key) + local select_key = string.format("%s_dead:out %s_live?out %s:new", key, key, key) + cache[key] = select_key + return select_key + end, +}) + +function M:ref(name, obj) + local ctx = context[self] + local typenames = ctx.typenames + local tc = assert(typenames[name]) + local live = name .. "_live" + local dead = name .. "_dead" + obj = obj or tc.tag + for v in self:select(dead) do + v[dead] = false + v[live] = true + v[name] = obj + return self:sync(ref_key[name], v) + end + local eid = self:_newentity() + local id = self:_addcomponent(eid, tc.id) + self:object(name, id, obj) + self:object(live, self:_addcomponent(eid, typenames[live].id), true) + return id +end + +function M:release(name, 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 = {} @@ -243,7 +300,7 @@ end function M:sync(pat, iter) local p = context[self].select[pat] - self:_sync(p, iter) + return self:_sync(p, iter) end function M:clear(name) @@ -276,10 +333,15 @@ function M:sort(sorted, name) end do - local _singleton = M._singleton + 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].select[name] - return _singleton(pat, v) + local pat = context[self].ref[name] + return _object(pat, v) end end diff --git a/framework/lualib/3rd/zeus/enum.lua b/framework/lualib/3rd/misc/enum.lua similarity index 100% rename from framework/lualib/3rd/zeus/enum.lua rename to framework/lualib/3rd/misc/enum.lua diff --git a/framework/lualib/3rd/zeus/fsm.lua b/framework/lualib/3rd/misc/fsm.lua similarity index 100% rename from framework/lualib/3rd/zeus/fsm.lua rename to framework/lualib/3rd/misc/fsm.lua diff --git a/framework/lualib/3rd/zeus/handler.lua b/framework/lualib/3rd/misc/handler.lua similarity index 100% rename from framework/lualib/3rd/zeus/handler.lua rename to framework/lualib/3rd/misc/handler.lua diff --git a/framework/lualib/3rd/zeus/hashids.lua b/framework/lualib/3rd/misc/hashids.lua similarity index 100% rename from framework/lualib/3rd/zeus/hashids.lua rename to framework/lualib/3rd/misc/hashids.lua diff --git a/framework/lualib/3rd/zeus/json.lua b/framework/lualib/3rd/misc/json.lua similarity index 100% rename from framework/lualib/3rd/zeus/json.lua rename to framework/lualib/3rd/misc/json.lua diff --git a/framework/lualib/3rd/zeus/lru.lua b/framework/lualib/3rd/misc/lru.lua similarity index 100% rename from framework/lualib/3rd/zeus/lru.lua rename to framework/lualib/3rd/misc/lru.lua diff --git a/framework/lualib/3rd/zeus/ltrace.lua b/framework/lualib/3rd/misc/ltrace.lua similarity index 100% rename from framework/lualib/3rd/zeus/ltrace.lua rename to framework/lualib/3rd/misc/ltrace.lua diff --git a/framework/lualib/3rd/zeus/middleclass.lua b/framework/lualib/3rd/misc/middleclass.lua similarity index 100% rename from framework/lualib/3rd/zeus/middleclass.lua rename to framework/lualib/3rd/misc/middleclass.lua diff --git a/framework/lualib/3rd/zeus/moses.lua b/framework/lualib/3rd/misc/moses.lua similarity index 100% rename from framework/lualib/3rd/zeus/moses.lua rename to framework/lualib/3rd/misc/moses.lua diff --git a/framework/lualib/3rd/zeus/nesting.lua b/framework/lualib/3rd/misc/nesting.lua similarity index 94% rename from framework/lualib/3rd/zeus/nesting.lua rename to framework/lualib/3rd/misc/nesting.lua index e940d54..611cdda 100644 --- a/framework/lualib/3rd/zeus/nesting.lua +++ b/framework/lualib/3rd/misc/nesting.lua @@ -1,4 +1,5 @@ -- 嵌套表 +local skynet = require "skynet" local class = class local select = select local next = next @@ -31,7 +32,7 @@ local function isKind(obj, strKind) end local function exception(e) - -- Log.e(e) + skynet.error(e) return e end @@ -57,7 +58,6 @@ end -- @param ... 多个键值 function NestingTable:add(item, k, ...) if not item or not k or select("#", k, ...) ~= self.m_deep then - -- Log.w("NestingTable add nil!") return end @@ -71,7 +71,6 @@ function NestingTable:add(item, k, ...) _item:add(item, ...) else self.m_items[k] = item - -- Log.d("NestingTable add", k, item) end end @@ -80,13 +79,11 @@ end -- @param ... 多个键值 function NestingTable:remove(k, ...) if not k or select("#", k, ...) ~= self.m_deep then - -- Log.w("NestingTable remove k nil!") return end local _item = self:get(k) if not ... then - -- Log.d("NestingTable remove", k, _item) self.m_items[k] = nil elseif _item then _item:remove(...) diff --git a/framework/lualib/3rd/zeus/option.lua b/framework/lualib/3rd/misc/option.lua similarity index 100% rename from framework/lualib/3rd/zeus/option.lua rename to framework/lualib/3rd/misc/option.lua diff --git a/framework/lualib/3rd/zeus/promise.lua b/framework/lualib/3rd/misc/promise.lua similarity index 100% rename from framework/lualib/3rd/zeus/promise.lua rename to framework/lualib/3rd/misc/promise.lua diff --git a/framework/lualib/3rd/misc/readme.txt b/framework/lualib/3rd/misc/readme.txt new file mode 100644 index 0000000..f622718 --- /dev/null +++ b/framework/lualib/3rd/misc/readme.txt @@ -0,0 +1 @@ +有用的 独立 基础 lua 库 \ No newline at end of file diff --git a/framework/lualib/3rd/zeus/singleton.lua b/framework/lualib/3rd/misc/singleton.lua similarity index 100% rename from framework/lualib/3rd/zeus/singleton.lua rename to framework/lualib/3rd/misc/singleton.lua diff --git a/framework/lualib/3rd/zeus/skewheap.lua b/framework/lualib/3rd/misc/skewheap.lua similarity index 100% rename from framework/lualib/3rd/zeus/skewheap.lua rename to framework/lualib/3rd/misc/skewheap.lua diff --git a/framework/lualib/3rd/zeus/stateful.lua b/framework/lualib/3rd/misc/stateful.lua similarity index 100% rename from framework/lualib/3rd/zeus/stateful.lua rename to framework/lualib/3rd/misc/stateful.lua diff --git a/framework/lualib/3rd/zeus/traceable.lua b/framework/lualib/3rd/misc/traceable.lua similarity index 100% rename from framework/lualib/3rd/zeus/traceable.lua rename to framework/lualib/3rd/misc/traceable.lua diff --git a/framework/lualib/3rd/zeus/try.lua b/framework/lualib/3rd/misc/try.lua similarity index 100% rename from framework/lualib/3rd/zeus/try.lua rename to framework/lualib/3rd/misc/try.lua diff --git a/framework/lualib/3rd/zeus/vararg.lua b/framework/lualib/3rd/misc/vararg.lua similarity index 100% rename from framework/lualib/3rd/zeus/vararg.lua rename to framework/lualib/3rd/misc/vararg.lua diff --git a/framework/lualib/3rd/misc/weighted_random.lua b/framework/lualib/3rd/misc/weighted_random.lua new file mode 100644 index 0000000..97a55d4 --- /dev/null +++ b/framework/lualib/3rd/misc/weighted_random.lua @@ -0,0 +1,118 @@ +-- tbl_weight = { +-- [xx] = { id = xx, weight = xx }, +-- ... +-- } + +-- https://github.com/kinbei/lua-misc/blob/master/weighted_random.lua + +return function(tbl_weight, random_func, id, weight) + random_func = random_func or math.random + id = id or "id" + weight = weight or "weight" + + local t = {} + local total_index = #tbl_weight + local total_weight = 0 + + for _, v in pairs(tbl_weight) do + assert(type(v[weight]) == "number") + + total_weight = total_weight + v[weight] + table.insert(t, { + [id] = v[id], + [weight] = v[weight], + }) + end + + return function() + local rand_index + + while true do + rand_index = random_func(1, total_index) + if random_func(1, total_weight) < t[rand_index].weight then + return t[rand_index][id] + end + end + end +end + +-- ---------------------------------------------------------------------------------------- +-- math.randomseed( os.time() ) + +-- local function test_case_1() +-- print("test_case_1") + +-- local t = {} +-- table.insert(t, { id = 1, weight = 400 } ) +-- table.insert(t, { id = 2, weight = 30 } ) +-- table.insert(t, { id = 3, weight = 100 } ) +-- table.insert(t, { id = 4, weight = 8 } ) +-- table.insert(t, { id = 5, weight = 30 } ) +-- table.insert(t, { id = 6, weight = 500 } ) +-- table.insert(t, { id = 7, weight = 20 } ) +-- table.insert(t, { id = 8, weight = 200 } ) +-- table.insert(t, { id = 9, weight = 40 } ) +-- table.insert(t, { id = 10, weight = 70 } ) +-- table.insert(t, { id = 11, weight = 300 } ) +-- table.insert(t, { id = 12, weight = 500 } ) +-- table.insert(t, { id = 13, weight = 350 } ) +-- table.insert(t, { id = 14, weight = 20 } ) +-- table.insert(t, { id = 15, weight = 480 } ) +-- table.insert(t, { id = 16, weight = 250 } ) +-- table.insert(t, { id = 17, weight = 500 } ) +-- table.insert(t, { id = 18, weight = 50 } ) +-- table.insert(t, { id = 19, weight = 300 } ) +-- table.insert(t, { id = 20, weight = 500 } ) + +-- local f = weighted_random(t) + +-- local result = {} +-- for i = 1, 4648 do +-- local id = f() +-- result[id] = result[id] or 0 +-- result[id] = result[id] + 1 +-- end + +-- local r = {} +-- for k, v in pairs(result) do +-- table.insert(r, { id = k, times = v }) +-- end + +-- table.sort(r, function(a, b) return a.times > b.times end) +-- for _, v in ipairs(r) do +-- print(v.id, v.times) +-- end +-- end + +-- local function test_case_2() +-- print("test_case_2") + +-- local t = {} +-- t[1] = { weight = 2000, id = 1 } +-- t[2] = { weight = 2000, id = 2 } +-- t[3] = { weight = 30, id = 3 } +-- t[4] = { weight = 40, id = 4 } +-- t[5] = { weight = 50, id = 5 } + +-- local f = weighted_random(t) + +-- local result = {} +-- for i = 1, 4120 do +-- local id = f() +-- result[id] = result[id] or 0 +-- result[id] = result[id] + 1 +-- end + +-- local r = {} +-- for k, v in pairs(result) do +-- table.insert(r, { id = k, times = v }) +-- end + +-- table.sort(r, function(a, b) return a.times > b.times end) +-- for _, v in ipairs(r) do +-- print(v.id, v.times) +-- end +-- end + +-- test_case_1() +-- test_case_2() diff --git a/framework/lualib/3rd/zeus/zset.lua b/framework/lualib/3rd/misc/zset.lua similarity index 100% rename from framework/lualib/3rd/zeus/zset.lua rename to framework/lualib/3rd/misc/zset.lua diff --git a/framework/lualib/zeus/storage/entity_pool.lua b/framework/lualib/zeus/storage/entity_pool.lua index 03bd953..0118aae 100644 --- a/framework/lualib/zeus/storage/entity_pool.lua +++ b/framework/lualib/zeus/storage/entity_pool.lua @@ -1,6 +1,6 @@ -local single_entity = require "single_entity" -local multi_entity = require "multi_entity" -local util = require "store_util" +local single_entity = require "storage.single_entity" +local multi_entity = require "storage.multi_entity" +local util = require "storage.util" local traceback = debug.traceback @@ -73,12 +73,12 @@ function mt:flush() entity:collect_dirty(rediscmds, sqls) end - for addr, cmds in pairs(rediscmds) do - xpcall(util.redis_execute, traceback, addr, cmds) + for addr, elements in pairs(rediscmds) do + xpcall(util.redis_execute, traceback, addr, elements) end - for addr, sqls in pairs(sqls) do - xpcall(util.mysql_execute, traceback, addr, sqls) + for addr, elements in pairs(sqls) do + xpcall(util.mysql_execute, traceback, addr, elements) end end diff --git a/framework/lualib/zeus/storage/initdb.lua b/framework/lualib/zeus/storage/initdb.lua deleted file mode 100644 index 21f0cd8..0000000 --- a/framework/lualib/zeus/storage/initdb.lua +++ /dev/null @@ -1,6 +0,0 @@ -local skynet = require "skynet" - -return function(dbconf) - local addr = skynet.uniqueservice("dbmgr") - return skynet.call(addr, "lua", "init", dbconf) -end diff --git a/framework/lualib/zeus/storage/multi_entity.lua b/framework/lualib/zeus/storage/multi_entity.lua index 2977635..8bf7aa1 100644 --- a/framework/lualib/zeus/storage/multi_entity.lua +++ b/framework/lualib/zeus/storage/multi_entity.lua @@ -1,4 +1,4 @@ -local util = require "store_util" +local util = require "storage.util" local strformat = string.format local tinsert = table.insert diff --git a/framework/lualib/3rd/mysqlauto/db.lua b/framework/lualib/zeus/storage/mysqlauto/db.lua similarity index 100% rename from framework/lualib/3rd/mysqlauto/db.lua rename to framework/lualib/zeus/storage/mysqlauto/db.lua diff --git a/framework/lualib/3rd/mysqlauto/file.lua b/framework/lualib/zeus/storage/mysqlauto/file.lua similarity index 100% rename from framework/lualib/3rd/mysqlauto/file.lua rename to framework/lualib/zeus/storage/mysqlauto/file.lua diff --git a/framework/lualib/3rd/mysqlauto/mysqlauto.lua b/framework/lualib/zeus/storage/mysqlauto/mysqlauto.lua similarity index 100% rename from framework/lualib/3rd/mysqlauto/mysqlauto.lua rename to framework/lualib/zeus/storage/mysqlauto/mysqlauto.lua diff --git a/framework/lualib/zeus/storage/single_entity.lua b/framework/lualib/zeus/storage/single_entity.lua index fd56fdd..077438f 100644 --- a/framework/lualib/zeus/storage/single_entity.lua +++ b/framework/lualib/zeus/storage/single_entity.lua @@ -1,4 +1,4 @@ -local util = require "store_util" +local util = require "storage.util" local strformat = string.format local tinsert = table.insert diff --git a/framework/lualib/zeus/storage/store.lua b/framework/lualib/zeus/storage/storage.lua similarity index 74% rename from framework/lualib/zeus/storage/store.lua rename to framework/lualib/zeus/storage/storage.lua index c6fcf27..0fa8714 100644 --- a/framework/lualib/zeus/storage/store.lua +++ b/framework/lualib/zeus/storage/storage.lua @@ -1,5 +1,5 @@ local skynet = require "skynet" -local entity_pool = requier "entity_pool" +local entity_pool = require "storage.entity_pool" local _store = {} local inited = false @@ -19,7 +19,7 @@ local function open(flush_interval) pool:flush() skynet.yield() end - skynet.sleep(flush_interval*100) + skynet.sleep(flush_interval * 100) end end) end @@ -33,8 +33,10 @@ local function close() inited = false end -local store = setmetatable(_store, {__index = function(self, name) - error(("can not find entity pool [%s]"):format(name)) -end}) +local store = setmetatable(_store, { + __index = function(self, name) + error(("can not find entity pool [%s]"):format(name)) + end, +}) return store, add_pool, open, close diff --git a/framework/lualib/zeus/storage/store_util.lua b/framework/lualib/zeus/storage/util.lua similarity index 89% rename from framework/lualib/zeus/storage/store_util.lua rename to framework/lualib/zeus/storage/util.lua index 1515018..965daee 100644 --- a/framework/lualib/zeus/storage/store_util.lua +++ b/framework/lualib/zeus/storage/util.lua @@ -10,6 +10,7 @@ local mysqld_service_num = {} local redisd_service_num = {} local guid_generator_addrs + local M = {} function M.config(opts) @@ -51,7 +52,7 @@ function M.balance_mysqld_addr(dbkey, id) mysqld_service_num[dbkey] = num end assert(num) - local sname = M.mysqld_sname(dbkey, (id % num) + 1) + local sname = M.mysqld_sname(dbkey, (id%num)+1) return skynet.localname(sname) end @@ -62,7 +63,7 @@ function M.balance_redisd_addr(dbkey, id) redisd_service_num[dbkey] = num end assert(num) - local sname = M.redis_sname(dbkey, (id % num) + 1) + local sname = M.redis_sname(dbkey, (id%num)+1) return skynet.localname(sname) end @@ -72,25 +73,21 @@ function M.guid() end assert(guid_generator_addrs, ".dbmgr must be init") local num = #guid_generator_addrs - return skynet.call(guid_generator_addrs[random(1, num)], "lua") + return skynet.call(guid_generator_addrs[random(1,num)], "lua") end function M.encode(val) - if not val then - return - end + if not val then return end local ok, ret = xpcall(json.encode, traceback, val) if not ok then - assert(false, strformat("encode error. val=[%s] ret=[%s]", tostring(val), tostring(ret))) + assert(false, strformat("encode error. val=[%s] ret=[%s]",tostring(val), tostring(ret))) return end return ret end function M.decode(val) - if not val then - return - end + if not val then return end local ok, ret = xpcall(json.decode, traceback, val) if not ok then assert(false, strformat("decode error. val=[%s] ret=[%s]", tostring(val), tostring(ret))) @@ -111,14 +108,12 @@ local escape_map = { ['"'] = '\\"', } -function M.quote_sql_str(str) +function M.quote_sql_str( str) return strformat("'%s'", strgsub(str, "[\0\b\n\r\t\26\\\'\"]", escape_map)) end function M.redis_key_field(conf, id) - if not conf.redisd_addr then - return - end + if not conf.redisd_addr then return end local key, field if id then key = conf.tbl .. ":" .. conf.id @@ -146,4 +141,4 @@ function M.redis_execute(addr, cmd, ...) end end -return M +return M \ No newline at end of file diff --git a/framework/lualib/zeus/zlog/log.lua b/framework/lualib/zeus/zlog/log.lua deleted file mode 100644 index c462610..0000000 --- a/framework/lualib/zeus/zlog/log.lua +++ /dev/null @@ -1,76 +0,0 @@ -local skynet = require "skynet" -local log_define = require "zlog.log_define" - -local getinfo = debug.getinfo -local LOG_LEVEL = log_define.LOG_LEVEL -local DEFAULT_CATEGORY = log_define.DEFAULT_CATEGORY -local log_format = log_define.format - -local category_addr = {} - -local function get_service(category) - local addr = category_addr[category] - if addr then - return addr - end - - local root_addr = skynet.localname(".logger") - if not root_addr then - -- no logger config - root_addr = skynet.uniqueservice("logger") - end - - addr = skynet.call(root_addr, "lua", "get_service", category) - category_addr[category] = addr - return addr -end - -local function sendlog(category, level, ...) - local di = getinfo(3, "Sl") - local msg = log_format(skynet.self(), level, di, ...) - skynet.call(get_service(category), "lua", "log", level, msg) -end - -local M = {} - -function M.d(...) - sendlog(DEFAULT_CATEGORY, LOG_LEVEL.DEBUG, ...) -end - -function M.d2(category, ...) - sendlog(category, LOG_LEVEL.DEBUG, ...) -end - -function M.i(...) - sendlog(DEFAULT_CATEGORY, LOG_LEVEL.INFO, ...) -end - -function M.i2(category, ...) - sendlog(category, LOG_LEVEL.INFO, ...) -end - -function M.w(...) - sendlog(DEFAULT_CATEGORY, LOG_LEVEL.WARN, ...) -end - -function M.w2(category, ...) - sendlog(category, LOG_LEVEL.WARN, ...) -end - -function M.e(...) - sendlog(DEFAULT_CATEGORY, LOG_LEVEL.ERROR, ...) -end - -function M.e2(category, ...) - sendlog(category, LOG_LEVEL.ERROR, ...) -end - -function M.f(...) - sendlog(DEFAULT_CATEGORY, LOG_LEVEL.FATAL, ...) -end - -function M.f2(category, ...) - sendlog(category, LOG_LEVEL.FATAL, ...) -end - -return M diff --git a/framework/lualib/zeus/zlog/log_define.lua b/framework/lualib/zeus/zlog/log_define.lua deleted file mode 100644 index 523977e..0000000 --- a/framework/lualib/zeus/zlog/log_define.lua +++ /dev/null @@ -1,77 +0,0 @@ -local string_format = string.format -local tconcat = table.concat -local os_date = os.date -local string_sub = string.sub -local os_clock = os.clock - -local ESC = string.char(27, 91) -local RESET = ESC .. '0m' - -local M = {} - -M.LOG_LEVEL = { - DEBUG = 1, - INFO = 2, - WARN = 3, - ERROR = 4, - FATAL = 5, -} - -M.LOG_LEVEL_NAME = { - [1] = "DEBUG", - [2] = "INFO ", - [3] = "WARN ", - [4] = "ERROR", - [5] = "FATAL", -} - -M.LOG_COLOR = { - [1] = ESC .. '34m', - [2] = ESC .. '32m', - [3] = ESC .. '33m', - [4] = ESC .. '31m', - [5] = ESC .. '35m', -} - -M.DEFAULT_CATEGORY = "root" - -function M.log_dir(log_root, date) - return string_format("%s/%04d-%02d-%02d", log_root or ".", date.year, date.month, date.day) -end - -function M.log_path(dir, prefix, category, date) - return string_format("%s/%s%s_%04d-%02d-%02d.log", dir or ".", prefix or "", category or M.DEFAULT_CATEGORY, - date.year, date.month, date.day) -end - -function M.format(addr, level, di, ...) - local param = {...} - local date = os_date("*t") - local ms = string_sub(os_clock(), 3, 6) - - local time = string_format("%02d:%02d:%02d.%02d", date.hour, date.min, date.sec, ms) - - local fileline = "" - if di then - fileline = (" [%s:%d]"):format(di.short_src, di.currentline) - end - - for k, v in pairs(param) do - param[k] = tostring(v) - end - - local msg = - string_format("[:%08x][%s][%s] %s%s", addr, M.LOG_LEVEL_NAME[level], time, tconcat(param, " "), fileline) - - return msg -end - -function M.color(level, msg) - local c = M.LOG_COLOR[level] - if not c then - return msg - end - return c .. msg .. RESET -end - -return M diff --git a/framework/service/dbmgr.lua b/framework/service/dbmgr.lua new file mode 100644 index 0000000..fefc1b3 --- /dev/null +++ b/framework/service/dbmgr.lua @@ -0,0 +1,75 @@ +local skynet = require "skynet" +require "skynet.manager" + +local dbconf + +local CMD = {} + +function CMD.init(cconf) + assert(not dbconf, "dbmgr has been initialized.") + dbconf = cconf -- init is allowed only once + + local redisconf = dbconf.redis + for dbkey, conf in pairs(redisconf) do + for index = 1, conf.service_num do + local addr = skynet.newservice("redisd", dbkey, index) + local ok = skynet.call(addr, "lua", "init", conf) + if not ok then + assert(false, ("redisd init failed. [dbkey] %s [id] %d"):format(dbkey, index)) + end + end + end + + local mysqlconf = dbconf.mysql + for dbkey, conf in pairs(mysqlconf) do + for index = 1, conf.service_num do + local addr = skynet.newservice("mysqld", dbkey, index) + local ok = skynet.call(addr, "lua", "init", conf) + if not ok then + assert(false, ("mysqld init failed. [dbkey] %s [id] %d"):format(dbkey, index)) + end + end + end + + return true +end + +function CMD.mysql_service_num(dbkey) + if not dbconf then + return + end + local mysqlconf = dbconf.mysql + if not mysqlconf then + return + end + local conf = mysqlconf[dbkey] + if not conf then + return + end + return conf.service_num +end + +function CMD.redis_service_num(dbkey) + if not dbconf then + return + end + local redisconf = dbconf.redis + if not redisconf then + return + end + local conf = redisconf[dbkey] + if not conf then + return + end + return conf.service_num +end + +skynet.start(function() + skynet.dispatch("lua", function(_, _, cmd, ...) + local f = CMD[cmd] + assert(f, cmd) + skynet.retpack(f(...)) + end) +end) + +skynet.register(".dbmgr") diff --git a/framework/service/gdd.lua b/framework/service/gdd.lua deleted file mode 100644 index 1be0d27..0000000 --- a/framework/service/gdd.lua +++ /dev/null @@ -1,34 +0,0 @@ -local skynet = require "skynet" -local st = require "skynet.sharetable" -local mc = require "skynet.multicast" - -local channel - -local CMD = {} - -function CMD.query(filename) - assert(channel) - return st.query(filename) -end - -function CMD.loadfiles(filenames) - assert(type(filenames) == "table") - for _, filename in pairs(filenames) do - st.loadfile(filename) - end - channel:publish(filenames) -end - -function CMD.channel() - return channel.channel -end - -skynet.start(function() - channel = mc.new() - skynet.dispatch("lua", function(_, _, cmd, ...) - local f = CMD[cmd] - assert(f, cmd) - skynet.retpack(f(...)) - end) -end) - diff --git a/framework/service/logger.lua b/framework/service/logger.lua deleted file mode 100644 index 1309d5b..0000000 --- a/framework/service/logger.lua +++ /dev/null @@ -1,212 +0,0 @@ -local skynet = require "skynet" -local log_define = require "zlog.log_define" -local queue = require "skynet.queue" -require "skynet.manager" - -local LOG_LEVEL = log_define.LOG_LEVEL -local DEFAULT_CATEGORY = log_define.DEFAULT_CATEGORY -local log_format = log_define.format -local color = log_define.color -local string_match = string.match - -local skynet_env = require("skynet.env") -local nodeid = skynet_env.get("nodeid") - -local zenv = require("zenv.init") -local define = zenv.Logger - -local log_root = define.log_root -local log_level = define.log_level or LOG_LEVEL.INFO -local log_console = define.log_console - -local name = zenv.get_node_conf(nodeid).name -local log_prefix = name .. "_" - -local last_day = -1 -local category = ... -local is_master = not category -local category_addr = {} -local lock = queue() -local file - -local function close_file() - if not file then - return - end - file:close() - file = nil -end - -local function open_file(date) - date = date or os.date("*t") - - local dir = log_define.log_dir(log_root, date) - if not os.rename(dir, dir) then - os.execute("mkdir -p " .. dir) - end - - if file then - close_file() - end - - local path = log_define.log_path(dir, log_prefix, category, date) - local f, e = io.open(path, "a") - if not f then - print("logger error:", tostring(e)) - return - end - - file = f - last_day = date.day -end - -local CMD = {} - -function CMD.console(level, msg) - print(color(level, msg)) -end - -function CMD.log(level, msg) - if level < log_level then - return - end - - msg = msg or "" - local date = os.date("*t") - if not file or date.day ~= last_day then - open_file(date) - end - - file:write(msg .. '\n') - file:flush() - - if log_console then - if is_master then - CMD.console(level, msg) - else - skynet.call(".logger", "lua", "console", level, msg) - end - end -end - -function CMD.set_console(is_open) - log_console = is_open - if is_master then - for _, addr in pairs(category_addr) do - skynet.call(addr, "lua", "set_console", is_open) - end - end -end - -function CMD.set_level(level) - log_level = level - if is_master then - for _, addr in pairs(category_addr) do - skynet.call(addr, "lua", "set_level", level) - end - end -end - -function CMD.get_service(cate) - if not is_master then - return - end - - local addr - lock(function() - addr = category_addr[cate] - if not addr then - addr = skynet.newservice("logger", cate) - category_addr[cate] = addr - end - end) - return addr -end - -if is_master then - skynet.info_func(function() - return { - log_console = log_console, - log_level = log_level, - } - end) - - skynet.register_protocol { - name = "text", - id = skynet.PTYPE_TEXT, - unpack = skynet.tostring, - dispatch = function(_, addr, msg) - local level = LOG_LEVEL.INFO - if string_match(msg, "maybe in an endless loop") then - level = LOG_LEVEL.WARN - end - if string_match(msg, "stack traceback:") then - level = LOG_LEVEL.ERROR - end - msg = log_format(addr, level, nil, msg) - CMD.log(level, msg) - end, - } - - local SIGHUP_CMD = {} - local function get_first_line(filename) - local f = io.open(filename, "r") - if not f then - return - end - - local first_line = f:read("l") - f:close() - return first_line - end - - local function get_sighup_cmd(sighup_file) - local cmd = get_first_line(sighup_file) - if not cmd then - return - end - return SIGHUP_CMD[cmd] - end - - local sighup_file = "./.sighup_file" - - -- 捕捉sighup信号(kill -1) - skynet.register_protocol { - name = "SYSTEM", - id = skynet.PTYPE_SYSTEM, - unpack = function(...) - return ... - end, - dispatch = function(_, addr) - -- https://blog.hanxi.cc/p/75/ - local cmd = get_sighup_cmd(sighup_file) - if cmd then - cmd = cmd:match("^%s*(.-)%s*$") - local func = SIGHUP_CMD[cmd] - if func then - func() - else - skynet.error( - string.format("unknow sighup cmd, need set sighup file. sighup_file: '%s'", sighup_file)) - end - else - local level = LOG_LEVEL.FATAL - local msg = log_format(addr, level, nil, "SIGHUP") - CMD.log(level, msg) - end - end, - } - - category_addr[DEFAULT_CATEGORY] = skynet.self() - skynet.register(".logger") -end - -open_file() - -skynet.start(function() - skynet.dispatch("lua", function(_, _, cmd, ...) - local f = CMD[cmd] - assert(f, cmd) - return skynet.retpack(f(...)) - end) -end) diff --git a/framework/service/mysqld.lua b/framework/service/mysqld.lua new file mode 100644 index 0000000..5988de4 --- /dev/null +++ b/framework/service/mysqld.lua @@ -0,0 +1,50 @@ +local skynet = require "skynet" +local mysql = require "skynet.db.mysql" +local util = require "store_util" +require "skynet.manager" + +local traceback = debug.traceback + +local dbkey, index = ... +local db + +local CMD = {} + +local function success(ret) + if not ret or ret.err or ret.badresult then + return false + end + return true +end + +function CMD.init(conf) + db = mysql.connect(conf) + db:query("set names utf8mb4") + return true +end + +function CMD.exec_one(sql) + local ok, ret = xpcall(db.query, traceback, db, sql) + if not ok or not success(ret) then + assert(false, ("sql=[%s] ret=[%s]"):format(sql, util.encode(ret))) + return + end + return ret +end + +function CMD.exec(sqls) + for i = 1, #sqls do + local sql = sqls[i] + CMD.exec_one(sql) + end +end + +skynet.start(function() + skynet.dispatch("lua", function(_, _, cmd, ...) + local f = CMD[cmd] + assert(f, cmd) + skynet.retpack(f(...)) + end) +end) + +skynet.register(util.mysql_sname(dbkey, index)) diff --git a/framework/service/redisd.lua b/framework/service/redisd.lua new file mode 100644 index 0000000..995339d --- /dev/null +++ b/framework/service/redisd.lua @@ -0,0 +1,42 @@ +local skynet = require "skynet" +local redis = require "skynet.db.redis" +local util = require "store_util" +require "skynet.manager" + +local traceback = debug.traceback +local tunpack = table.unpack +local tconcat = table.concat +local dbkey, index = ... +local db + +local CMD = {} + +function CMD.init(conf) + db = redis.connect(conf) + return true +end + +function CMD.exec_one(cmd, ...) + local ok, ret = xpcall(db[cmd], traceback, db, ...) + if not ok then + assert(false, ("cmd=[%s %s] ret=[%s]"):format(cmd, tconcat({...}, " "), ret)) + return + end + return ret +end + +function CMD.exec(cmds) + for _, cmd in pairs(cmds) do + xpcall(CMD.exec_one, traceback, tunpack(cmd)) + end +end + +skynet.start(function() + skynet.dispatch("lua", function(_, _, cmd, ...) + local f = CMD[cmd] + assert(f, cmd) + skynet.retpack(f(...)) + end) +end) + +skynet.register(util.redis_sname(dbkey, index)) diff --git a/framework/service/redlockd.lua b/framework/service/redlockd.lua deleted file mode 100644 index e525de4..0000000 --- a/framework/service/redlockd.lua +++ /dev/null @@ -1,198 +0,0 @@ -local skynet = require "skynet" -local redis = require "skynet.db.redis" -local crypt = require "skynet.crypt" - -local math_floor = math.floor -local math_ceil = math.ceil -local math_random = math.random - -local function hash(script) - local key = crypt.sha1(script) - return crypt.hexencode(key) -end - -local QUORUM - -local SCRIPT = { - LOCK = [[ - local key = KEYS[1] - if redis.call("exists", key) == 1 then - return 0 - end - redis.call("set", key, ARGV[1], "PX", ARGV[2]) - return 1 - ]], - UNLOCK = [[ - local key = KEYS[1] - if redis.call("get", key) == ARGV[1] then - redis.pcall("del", key) - return 1 - end - return 0 - ]], - EXTEND = [[ - local key = KEYS[1] - if redis.call("get", key) ~= ARGV[1] then - return 0 - end - redis.call("set", key, ARGV[1], "PX", ARGV[2]) - return 1 - ]], -} - -local SCRIPT_HASH = { - LOCK = hash(SCRIPT.LOCK), - UNLOCK = hash(SCRIPT.UNLOCK), - EXTEND = hash(SCRIPT.EXTEND), -} - -local conf -local dbs = {} -local sessions = {} - -local function execute_script(db, type, s) - local ok, ret = pcall(db["evalsha"], db, SCRIPT_HASH[type], 1, s.lockname, s.uuid, s.timeout) - if not ok and ret:find("NOSCRIPT") then - ok, ret = pcall(db["eval"], db, SCRIPT[type], 1, s.lockname, s.uuid, s.timeout) - end - if not ok then - skynet.error("redis execute_script err.", ret, s.lockname, s.uuid, s.timeout) - return false - end - if ret == 1 then - return true - end - return false -end - -local function execute_script_timeout(db, type, s) - local co = coroutine.running() - local ok, ret = false, "timeout" - - skynet.fork(function() - ok, ret = execute_script(db, type, s) - if co then - skynet.wakeup(co) - co = nil - end - end) - - skynet.sleep(conf.request_timeout / 10) - if co then - co = nil - end - return ok, ret -end - -local function calc_time(s) - local now = skynet.now() * 10 - local drift = math_floor(conf.drift_factor * s.timeout) + 2 - s.starttime = now - s.endtime = now + s.timeout - drift -end - -local function make_session(lockname, uuid, timeout) - local s = { - lockname = lockname, - uuid = uuid, - timeout = timeout, - attempts = 0, - starttime = 0, - endtime = 0, - } - calc_time(s) - return s -end - -local function unlock(s) - s.endtime = 0 - for _, db in pairs(dbs) do - execute_script(db, "UNLOCK", s) - end -end - -local function attempt(s, is_extend) - s.attempts = s.attempts + 1 - local votes = 0 - for _, db in pairs(dbs) do - local ok - if is_extend then - ok = execute_script_timeout(db, "EXTEND", s) - else - ok = execute_script_timeout(db, "LOCK", s) - end - if ok then - votes = votes + 1 - end - end - - local now = skynet.now() * 10 - if votes >= QUORUM and s.endtime > now then - local ti = s.timeout / 3 - (now - s.starttime) - ti = math_floor(ti / 10) - if ti < 0 then - ti = 0 - end - skynet.timeout(ti, function() - if s.endtime == 0 then - return - end - s.attempts = 0 - calc_time(s) - attempt(s, true) - end) - return true - else - unlock(s) - -- retry - if conf.retry_count == -1 or s.attempts <= conf.retry_count then - local t = conf.retry_delay + math_floor((math_random() * 2 - 1) * conf.retry_jitter) - skynet.sleep(math_ceil(t / 10)) - calc_time(s) - return attempt(s) - end - -- failed - sessions[s.uuid] = nil - return false, "timeout" - end -end - -local CMD = {} - -function CMD.lock(lockname, uuid, timeout) - timeout = timeout or conf.timeout - local s = sessions[uuid] - if s then - return false, "session exist" - end - s = make_session(lockname, uuid, timeout) - sessions[uuid] = s - - return attempt(s) -end - -function CMD.unlock(_, uuid) - local s = sessions[uuid] - if not s then - return false, "session not exist." - end - sessions[uuid] = nil - return unlock(s) -end - -skynet.init(function() - conf = require "redlock_conf" - for _, client in ipairs(conf.servers) do - table.insert(dbs, redis.connect(client)) - end - QUORUM = math_floor(#conf.servers / 2) + 1 -end) - -skynet.start(function() - skynet.dispatch("lua", function(_, _, cmd, ...) - local f = CMD[cmd] - assert(f, cmd) - skynet.retpack(f(...)) - end) -end) -