diff --git a/Makefile b/Makefile index 83d9603..f15ff06 100644 --- a/Makefile +++ b/Makefile @@ -45,6 +45,9 @@ CXXSRC=\ src/servers/Monitor.cpp\ src/lua/LuaManager.cpp\ src/lua/EventWrapper.cpp\ + src/lua/WorldWrapper.cpp\ + src/lua/EntityWrapper.cpp\ + src/lua/PlayerWrapper.cpp\ src/db/init.cpp\ src/db/login.cpp\ src/db/shard.cpp\ @@ -91,6 +94,9 @@ CXXHDR=\ src/lua/LuaManager.hpp\ src/lua/LuaWrapper.hpp\ src/lua/EventWrapper.hpp\ + src/lua/WorldWrapper.hpp\ + src/lua/EntityWrapper.hpp\ + src/lua/PlayerWrapper.hpp\ src/db/Database.hpp\ src/db/internal.hpp\ vendor/bcrypt/BCrypt.hpp\ diff --git a/scripts/test.lua b/scripts/test.lua index 0371c5c..607fc2d 100644 --- a/scripts/test.lua +++ b/scripts/test.lua @@ -1,3 +1,8 @@ print("Hello world!") + +World.onPlayerAdded:listen(function(plr) + print(plr.type .. " " .. plr.name .. " joined from LUA!!") +end) + wait(2) -print("Hello world ~2 seconds later!") \ No newline at end of file +print("Hello world ~2 seconds later! running protcol version " .. World.version) \ No newline at end of file diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index c817f7e..08efdfe 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -18,6 +18,8 @@ #include "settings.hpp" +#include "lua/LuaManager.hpp" + #include #include @@ -40,12 +42,18 @@ static void addPlayer(CNSocket* key, Player plr) { std::cout << getPlayerName(p) << " has joined!" << std::endl; std::cout << players.size() << " players" << std::endl; + + // call events + LuaManager::playerAdded(key); } void PlayerManager::removePlayer(CNSocket* key) { Player* plr = getPlayer(key); uint64_t fromInstance = plr->instanceID; + // call events + LuaManager::playerRemoved(key); + Groups::groupKickPlayer(plr); // remove player's bullets diff --git a/src/lua/EntityWrapper.cpp b/src/lua/EntityWrapper.cpp new file mode 100644 index 0000000..bdb5474 --- /dev/null +++ b/src/lua/EntityWrapper.cpp @@ -0,0 +1,174 @@ +#include "lua/LuaWrapper.hpp" +#include "lua/LuaManager.hpp" +#include "lua/EntityWrapper.hpp" + +#include "Entities.hpp" + +#define LIBNAME "Entity" +#define SUPERTBL "__entSUPERCLASSES" + +#define ENTYGONESTR "Entity doesn't exist anymore!" + +EntityRef* grabBaseEntityRef(lua_State *state, int indx) { + // first, make sure its a userdata + luaL_checktype(state, indx, LUA_TUSERDATA); + + // grab the super class table + lua_getfield(state, LUA_REGISTRYINDEX, SUPERTBL); + + // grab the userdata + EntityRef *data = (EntityRef*)lua_touserdata(state, indx); + + // check if it doesn't have a metatable + if (!lua_getmetatable(state, indx)) { + luaL_typerror(state, indx, LIBNAME); + return NULL; + } + + // index the super class table + lua_gettable(state, -2); + + // if the index was nil, it doesn't exist + if (lua_isnil(state, -1)) { + lua_pop(state, 1); + luaL_typerror(state, indx, LIBNAME); + return NULL; + } + + // it's good :) + lua_pop(state, 1); + return data; +} + +// check at index +EntityRef* grabEntityRef(lua_State *state, int indx) { + EntityRef *ref = grabBaseEntityRef(state, indx); + + if (ref == NULL || !ref->isValid()) + return NULL; + + return ref; +} + +// =============================================== [[ GETTERS ]] =============================================== + +static int ent_getX(lua_State *state) { + EntityRef *ref = grabEntityRef(state, 1); + + if (ref == NULL) + return 0; + + lua_pushnumber(state, ref->getEntity()->x); + return 1; +} + +static int ent_getY(lua_State *state) { + EntityRef *ref = grabEntityRef(state, 1); + + if (ref == NULL) + return 0; + + lua_pushnumber(state, ref->getEntity()->y); + return 1; +} + +static int ent_getZ(lua_State *state) { + EntityRef *ref = grabEntityRef(state, 1); + + if (ref == NULL) + return 0; + + lua_pushnumber(state, ref->getEntity()->z); + return 1; +} + +static int ent_getType(lua_State *state) { + EntityRef *ref = grabEntityRef(state, 1); + + if (ref == NULL) + return 0; + + // push the type string + switch(ref->type) { + case EntityType::PLAYER: + lua_pushstring(state, "Player"); + break; + case EntityType::MOB: + lua_pushstring(state, "Mob"); + break; + case EntityType::EGG: + lua_pushstring(state, "Egg"); + break; + case EntityType::BUS: + lua_pushstring(state, "Bus"); + break; + default: // INVALID, COMBAT_NPC, SIMPLE_NPC + lua_pushstring(state, "Entity"); + break; + } + return 1; +} + +static luaL_Reg ent_getters[] = { + {"x", ent_getX}, + {"y", ent_getY}, + {"z", ent_getZ}, + {"type", ent_getType}, + {0, 0} +}; + +// =============================================== [[ METHODS ]] =============================================== + +static int ent_exists(lua_State *state) { + EntityRef *data = (EntityRef*)grabBaseEntityRef(state, 1); + + lua_pushboolean(state, data == NULL || !data->isValid()); + return 1; +} + +static luaL_Reg ent_methods[] = { + {"exists", ent_exists}, + {0, 0} +}; + +void LuaManager::Entity::init(lua_State *state) { + // register our library as a global (and leave it on the stack) + luaL_register(state, LIBNAME, ent_methods); + lua_pop(state, 1); // pop library table + + // will hold our super classes + lua_pushstring(state, SUPERTBL); + lua_newtable(state); + lua_rawset(state, LUA_REGISTRYINDEX); +} + +void LuaManager::Entity::registerSuper(lua_State *state, const char *tname) { + // grab the super class table + lua_getfield(state, LUA_REGISTRYINDEX, SUPERTBL); + + // grab the metatable + lua_getfield(state, LUA_REGISTRYINDEX, tname); + lua_pushboolean(state, 1); + + // finally, set the index + lua_rawset(state, -3); + lua_pop(state, 1); // pop the super class table +} + +void LuaManager::Entity::addGetters(lua_State *state) { + luaL_register(state, NULL, ent_getters); +} + +void LuaManager::Entity::addMethods(lua_State *state) { + luaL_register(state, NULL, ent_methods); +} + +void LuaManager::Entity::push(lua_State *state, EntityRef ref, const char *tname) { + // creates the udata and copies the reference to the udata + EntityRef *ent = (EntityRef*)lua_newuserdata(state, sizeof(EntityRef)); + *ent = ref; + + // attaches our metatable from the registry to the udata + luaL_getmetatable(state, tname); + lua_setmetatable(state, -2); +} \ No newline at end of file diff --git a/src/lua/EntityWrapper.hpp b/src/lua/EntityWrapper.hpp new file mode 100644 index 0000000..b2f9525 --- /dev/null +++ b/src/lua/EntityWrapper.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "lua/LuaWrapper.hpp" +#include "lua/LuaManager.hpp" + +#include "Entities.hpp" + +namespace LuaManager { + namespace Entity { + void init(lua_State *state); + + void registerSuper(lua_State *state, const char *tname); + + void addGetters(lua_State *state); + void addMethods(lua_State *state); + + void push(lua_State *state, EntityRef ref, const char *tname); + } +} \ No newline at end of file diff --git a/src/lua/EventWrapper.cpp b/src/lua/EventWrapper.cpp index 9a22230..cee137c 100644 --- a/src/lua/EventWrapper.cpp +++ b/src/lua/EventWrapper.cpp @@ -7,8 +7,8 @@ #include -#define LIBNAME "event" -#define LISTNR "listener" +#define LIBNAME "Event" +#define LISTNR "Listener" typedef lEvent* eventData; diff --git a/src/lua/LuaManager.cpp b/src/lua/LuaManager.cpp index cab6ee7..2dbcc4d 100644 --- a/src/lua/LuaManager.cpp +++ b/src/lua/LuaManager.cpp @@ -1,6 +1,8 @@ #include "lua/LuaManager.hpp" #include "lua/LuaWrapper.hpp" #include "lua/EventWrapper.hpp" +#include "lua/WorldWrapper.hpp" +#include "lua/PlayerWrapper.hpp" #include "servers/CNShardServer.hpp" #include "settings.hpp" @@ -113,6 +115,9 @@ void LuaManager::init() { // register our libraries Event::init(global); + World::init(global); + Entity::init(global); + Player::init(global); activeScripts = std::map(); @@ -155,4 +160,12 @@ void LuaManager::loadScripts() { void LuaManager::clearState(lua_State *state) { // TODO +} + +void LuaManager::playerAdded(CNSocket *sock) { + World::playerAdded(sock); +} + +void LuaManager::playerRemoved(CNSocket *sock) { + World::playerRemoved(sock); } \ No newline at end of file diff --git a/src/lua/LuaManager.hpp b/src/lua/LuaManager.hpp index 9d09646..baadbaa 100644 --- a/src/lua/LuaManager.hpp +++ b/src/lua/LuaManager.hpp @@ -23,4 +23,6 @@ namespace LuaManager { // unregisters the events tied to this state with all wrappers void clearState(lua_State *state); + void playerAdded(CNSocket *sock); + void playerRemoved(CNSocket *sock); } diff --git a/src/lua/LuaWrapper.hpp b/src/lua/LuaWrapper.hpp index a05c68e..5d9d46a 100644 --- a/src/lua/LuaWrapper.hpp +++ b/src/lua/LuaWrapper.hpp @@ -10,6 +10,7 @@ #include #include "lua/LuaManager.hpp" +#include "lua/PlayerWrapper.hpp" #define yieldCall(state, nargs) \ int _retCode = lua_resume(state, nargs); \ @@ -29,6 +30,7 @@ inline static int lua_autoPush(lua_State* state, int nargs) { char* or const char* : LUA_TSTRING bool : LUA_TBOOLEAN lRegistry : grabs the object from the lua registry and pushes it onto the stack + CNSocket* : Pushes the Player Entity */ template inline static int lua_autoPush(lua_State* state, int nargs, T arg, Rest... rest) { @@ -40,6 +42,8 @@ inline static int lua_autoPush(lua_State* state, int nargs, T arg, Rest... rest) } else if constexpr(std::is_same::value) { // grab the value from the registry lua_rawgeti(state, LUA_REGISTRYINDEX, (int)arg); + } else if constexpr(std::is_same::value) { // pushes a Player Entity + LuaManager::Player::push(state, arg); } else if constexpr(std::is_same::value) { lua_pushboolean(state, arg); } diff --git a/src/lua/PlayerWrapper.cpp b/src/lua/PlayerWrapper.cpp new file mode 100644 index 0000000..3c55c91 --- /dev/null +++ b/src/lua/PlayerWrapper.cpp @@ -0,0 +1,171 @@ +#include "lua/EntityWrapper.hpp" +#include "lua/PlayerWrapper.hpp" + +#include "core/CNProtocol.hpp" +#include "Player.hpp" +#include "PlayerManager.hpp" + +#define LIBNAME "Player" +#define PLRGONESTR "Player doesn't exist anymore, they left!" +#define GETTERTBL "__plrGETTERS" +#define SETTERTBL "__plrSETTERS" +#define METHODTBL "__plrMETHODS" + +static Player* grabPlayer(lua_State *state, int indx) { + // first, make sure its a userdata + luaL_checktype(state, indx, LUA_TUSERDATA); + + // now, check and make sure its our library's metatable attached to this userdata + EntityRef *ref = (EntityRef*)luaL_checkudata(state, indx, LIBNAME); + if (ref == NULL) { + luaL_typerror(state, indx, LIBNAME); + return NULL; + } + + // check if the player exists still & return NULL if it doesn't + if (!ref->isValid()) { + luaL_argerror(state, indx, PLRGONESTR); + return NULL; + } + + return (Player*)ref->getEntity(); +} + +static CNSocket* grabSock(lua_State *state, int indx) { + // first, make sure its a userdata + luaL_checktype(state, indx, LUA_TUSERDATA); + + // now, check and make sure its our library's metatable attached to this userdata + EntityRef *ref = (EntityRef*)luaL_checkudata(state, indx, LIBNAME); + if (ref == NULL) { + luaL_typerror(state, indx, LIBNAME); + return NULL; + } + + // check if the player exists still & return NULL if it doesn't + if (!ref->isValid()) { + luaL_argerror(state, indx, PLRGONESTR); + return NULL; + } + + return ref->sock; +} + +// =============================================== [[ GETTERS ]] =============================================== + +static int plr_getName(lua_State *state) { + Player *plr = grabPlayer(state, 1); + + if (plr == NULL) + return 0; + + lua_pushstring(state, PlayerManager::getPlayerName(plr).c_str()); + return 1; +} + +static const luaL_Reg plr_getters[] = { + {"name", plr_getName}, + {0, 0} +}; + +// =============================================== [[ SETTERS ]] =============================================== + +static const luaL_Reg plr_setters[] = { + {0, 0} +}; + +// =============================================== [[ METHODS ]] =============================================== + +static const luaL_Reg plr_methods[] = { + {0, 0} +}; + +// in charge of calling the correct getter method +static int plr_index(lua_State *state) { + // grab the function from the getters lookup table + lua_pushstring(state, GETTERTBL); + lua_rawget(state, LUA_REGISTRYINDEX); + lua_pushvalue(state, 2); + lua_rawget(state, -2); + + // if it's not nil, call it and run the getter method + if (!lua_isnil(state, -1)) { + // push userdata & call the function + lua_pushvalue(state, 1); + lua_call(state, 1, 1); + + // return # of results + return 1; + } + + // grab the function from the methods lookup table + lua_pop(state, 1); + lua_pushstring(state, METHODTBL); + lua_rawget(state, LUA_REGISTRYINDEX); + lua_pushvalue(state, 2); + lua_rawget(state, -2); + + // return result + return 1; +} + +// in charge of calling the correct setter method +static int plr_newindex(lua_State *state) { + // grab the function from the getters lookup table + lua_pushstring(state, SETTERTBL); + lua_rawget(state, LUA_REGISTRYINDEX); + lua_pushvalue(state, 2); + lua_rawget(state, -2); + + // if it's nil return + if (lua_isnil(state, -1)) + return 0; + + // push userdata & call the function + lua_pushvalue(state, 1); + lua_call(state, 1, 0); + + // return # of results + return 0; +} + +void LuaManager::Player::init(lua_State *state) { + // register our library as a global (and leave it on the stack) + luaL_register(state, LIBNAME, plr_methods); + + // create the meta table and populate it with our functions + luaL_newmetatable(state, LIBNAME); + lua_pushstring(state, "__index"); + lua_pushcfunction(state, plr_index); + lua_rawset(state, -3); // sets meta.__index = plr_index + lua_pushstring(state, "__newindex"); + lua_pushcfunction(state, plr_newindex); + lua_rawset(state, -3); // sets meta.__newindex = plr_newindex + lua_pop(state, 2); // pop meta & library table + + // create the methods table + lua_pushstring(state, METHODTBL); + lua_newtable(state); + Entity::addMethods(state); // register the base Entity methods + luaL_register(state, NULL, plr_methods); + lua_rawset(state, LUA_REGISTRYINDEX); + + // create the getters table + lua_pushstring(state, GETTERTBL); + lua_newtable(state); + Entity::addGetters(state); // register the base Entity getters + luaL_register(state, NULL, plr_getters); + lua_rawset(state, LUA_REGISTRYINDEX); + + // create the setters table + lua_pushstring(state, SETTERTBL); + lua_newtable(state); + luaL_register(state, NULL, plr_setters); + lua_rawset(state, LUA_REGISTRYINDEX); + + LuaManager::Entity::registerSuper(state, LIBNAME); +} + +void LuaManager::Player::push(lua_State *state, CNSocket *sock) { + Entity::push(state, EntityRef(sock), LIBNAME); +} \ No newline at end of file diff --git a/src/lua/PlayerWrapper.hpp b/src/lua/PlayerWrapper.hpp new file mode 100644 index 0000000..55a47c4 --- /dev/null +++ b/src/lua/PlayerWrapper.hpp @@ -0,0 +1,11 @@ +#include "lua/LuaWrapper.hpp" +#include "lua/LuaManager.hpp" +#include "lua/EntityWrapper.hpp" + +namespace LuaManager { + namespace Player { + void init(lua_State *state); + + void push(lua_State *state, CNSocket *sock); + } +} \ No newline at end of file diff --git a/src/lua/WorldWrapper.cpp b/src/lua/WorldWrapper.cpp new file mode 100644 index 0000000..7ad261e --- /dev/null +++ b/src/lua/WorldWrapper.cpp @@ -0,0 +1,130 @@ +#include "lua/LuaManager.hpp" +#include "lua/LuaWrapper.hpp" +#include "lua/EventWrapper.hpp" +#include "lua/WorldWrapper.hpp" +#include "core/CNStructs.hpp" + +#include "PlayerManager.hpp" + +static lEvent *addedEvent; +static lEvent *removedEvent; + +#define LIBNAME "World" +#define GETTERTBL "__wrldGETTERS" +#define METHODTBL "__wrldMETHODS" + +// =============================================== [[ GETTERS ]] =============================================== + +int wrld_getPlrAdded(lua_State *state) { + LuaManager::Event::push(state, addedEvent); + return 1; +} + +int wrld_getPlrRemoved(lua_State *state) { + LuaManager::Event::push(state, removedEvent); + return 1; +} + +int wrld_getVersion(lua_State *state) { + lua_pushnumber(state, PROTOCOL_VERSION); + return 1; +} + +int wrld_getPlayers(lua_State *state) { + // create a new lua table and push it onto the stack + int entries = 0; + lua_newtable(state); + + // walk through the current list of players and add them to the table + for (auto pair : PlayerManager::players) { + lua_pushinteger(state, ++entries); + LuaManager::Player::push(state, pair.first); + lua_rawset(state, -3); + } + + // returns the player table :) + return 1; +} + +// =============================================== [[ METHODS ]] =============================================== + +int wrld_index(lua_State *state) { + // grab the function from the getters lookup table + lua_pushstring(state, GETTERTBL); + lua_rawget(state, LUA_REGISTRYINDEX); + lua_pushvalue(state, 2); + lua_rawget(state, -2); + + // if it's not nil, call it and run the getter method + if (!lua_isnil(state, -1)) { + // push userdata & call the function + lua_pushvalue(state, 1); + lua_call(state, 1, 1); + + // return # of results + return 1; + } + + // grab the function from the methods lookup table + lua_pop(state, 1); + lua_pushstring(state, METHODTBL); + lua_rawget(state, LUA_REGISTRYINDEX); + lua_pushvalue(state, 2); + lua_rawget(state, -2); + + // return result + return 1; +} + +static const luaL_Reg getters[] { + {"onPlayerAdded", wrld_getPlrAdded}, + {"onPlayerRemoved", wrld_getPlrRemoved}, + {"players", wrld_getPlayers}, + {"version", wrld_getVersion}, + {0, 0} +}; + +// TODO +static const luaL_Reg methods[] = { + //{"getNearbyPlayers", wrld_getNPlrs}, + {0, 0} +}; + + +void LuaManager::World::init(lua_State *state) { + lua_newtable(state); + luaL_newmetatable(state, LIBNAME); + lua_pushstring(state, "__index"); + lua_pushcfunction(state, wrld_index); + lua_rawset(state, -3); // sets meta.__index = wrld_index + lua_setmetatable(state, -2); // sets world.__metatable = meta + lua_setglobal(state, LIBNAME); + + // setup the __wrldGETTERS table in the registry + lua_pushstring(state, GETTERTBL); + lua_newtable(state); + luaL_register(state, NULL, getters); + lua_rawset(state, LUA_REGISTRYINDEX); + + // setup the __wrldMETHODS table in the registry + lua_pushstring(state, METHODTBL); + lua_newtable(state); + luaL_register(state, NULL, methods); + lua_rawset(state, LUA_REGISTRYINDEX); + + addedEvent = new lEvent(); + removedEvent = new lEvent(); +} + +void LuaManager::World::clearState(lua_State *state) { + addedEvent->clear(state); + removedEvent->clear(state); +} + +void LuaManager::World::playerAdded(CNSocket *sock) { + addedEvent->call(sock); +} + +void LuaManager::World::playerRemoved(CNSocket *sock) { + removedEvent->call(sock); +} \ No newline at end of file diff --git a/src/lua/WorldWrapper.hpp b/src/lua/WorldWrapper.hpp new file mode 100644 index 0000000..8a36f14 --- /dev/null +++ b/src/lua/WorldWrapper.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "lua/LuaManager.hpp" + +namespace LuaManager { + namespace World { + void init(lua_State *state); + + void clearState(lua_State *state); + void playerAdded(CNSocket *sock); + void playerRemoved(CNSocket *sock); + } +} \ No newline at end of file