diff --git a/res/scripts/classes.lua b/res/scripts/classes.lua index 0741c89b..9ab70132 100644 --- a/res/scripts/classes.lua +++ b/res/scripts/classes.lua @@ -60,8 +60,37 @@ local ServerSocket = {__index={ get_port=function(self) return network.__get_serverport(self.id) end, }} -network.tcp_open = function(port, handler) - return setmetatable({id=network.__open(port, function(id) + +local _tcp_server_callbacks = {} + +network.tcp_open = function (port, handler) + local socket = setmetatable({id=network.__open(port)}, ServerSocket) + + _tcp_server_callbacks[socket.id] = function(id) handler(setmetatable({id=id}, Socket)) - end)}, ServerSocket) + end + return socket +end + +network.__pull_events = function() + local cleaned = false + local connections = network.__pull_connections() + for i, pair in ipairs(connections) do + local sid, cid = unpack(pair) + local callback = _tcp_server_callbacks[sid] + + if callback then + callback(cid) + end + + -- remove dead servers + if not cleaned then + for sid, callback in pairs(_tcp_server_callbacks) do + if not network.__is_serveropen(sid) then + _tcp_server_callbacks[sid] = nil + end + end + cleaned = true + end + end end diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 0765199e..6eb2bbca 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -34,7 +34,10 @@ local function complete_app_lib(app) app.reconfig_packs = core.reconfig_packs app.get_setting = core.get_setting app.set_setting = core.set_setting - app.tick = coroutine.yield + app.tick = function() + coroutine.yield() + network.__pull_events() + end app.get_version = core.get_version app.get_setting_info = core.get_setting_info app.load_content = function() diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 8f8683da..eb7f29f7 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -44,11 +44,11 @@ public: }; struct CoreParameters { - bool headless = false; + bool headless = true; bool testMode = false; std::filesystem::path resFolder = "res"; std::filesystem::path userFolder = "."; - std::filesystem::path scriptFile; + std::filesystem::path scriptFile = "res/content/remp/remp_server.lua"; std::filesystem::path projectFolder; }; diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index dc3b5731..66a82681 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -182,14 +182,17 @@ static int l_available(lua::State* L, network::Network& network) { return 0; } +struct ConnectionEvent { + u64id_t server; + u64id_t client; +}; + +static std::vector clients_queue {}; + static int l_open(lua::State* L, network::Network& network) { int port = lua::tointeger(L, 1); - lua::pushvalue(L, 2); - auto callback = lua::create_lambda_nothrow(L); - u64id_t id = network.openServer(port, [callback](u64id_t id) { - engine->postRunnable([=]() { - callback({id}); - }); + u64id_t id = network.openServer(port, [](u64id_t sid, u64id_t id) { + clients_queue.push_back({sid, id}); }); return lua::pushinteger(L, id); } @@ -250,6 +253,23 @@ static int l_get_total_download(lua::State* L, network::Network& network) { return lua::pushinteger(L, network.getTotalDownload()); } +static int l_pull_connections(lua::State* L, network::Network& network) { + lua::createtable(L, clients_queue.size(), 0); + for (size_t i = 0; i < clients_queue.size(); i++) { + lua::createtable(L, 2, 0); + + lua::pushinteger(L, clients_queue[i].server); + lua::rawseti(L, 1); + + lua::pushinteger(L, clients_queue[i].client); + lua::rawseti(L, 2); + + lua::rawseti(L, i + 1); + } + clients_queue.clear(); + return 1; +} + template int wrap(lua_State* L) { int result = 0; @@ -267,13 +287,13 @@ int wrap(lua_State* L) { return result; } - const luaL_Reg networklib[] = { {"get", wrap}, {"get_binary", wrap}, {"post", wrap}, {"get_total_upload", wrap}, {"get_total_download", wrap}, + {"__pull_connections", wrap}, {"__open", wrap}, {"__closeserver", wrap}, {"__connect", wrap}, diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 2d95fdaa..f766f29d 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -90,7 +90,7 @@ public: } void update() override { - if (id == 0) { + if (!alive || id == 0) { return; } if (lua::requireglobal(L, "__vc_resume_coroutine")) { diff --git a/src/network/Network.cpp b/src/network/Network.cpp index b88aeed9..8936adc6 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -477,6 +477,7 @@ public: }; class SocketTcpSServer : public TcpServer { + u64id_t id; Network* network; SOCKET descriptor; std::vector clients; @@ -485,14 +486,14 @@ class SocketTcpSServer : public TcpServer { std::unique_ptr thread = nullptr; int port; public: - SocketTcpSServer(Network* network, SOCKET descriptor, int port) - : network(network), descriptor(descriptor), port(port) {} + SocketTcpSServer(u64id_t id, Network* network, SOCKET descriptor, int port) + : id(id), network(network), descriptor(descriptor), port(port) {} ~SocketTcpSServer() { closeSocket(); } - void startListen(consumer handler) override { + void startListen(ConnectCallback handler) override { thread = std::make_unique([this, handler]() { while (open) { logger.info() << "listening for connections"; @@ -518,7 +519,7 @@ public: std::lock_guard lock(clientsMutex); clients.push_back(id); } - handler(id); + handler(this->id, id); } }); } @@ -558,7 +559,7 @@ public: } static std::shared_ptr openServer( - Network* network, int port, consumer handler + u64id_t id, Network* network, int port, ConnectCallback handler ) { SOCKET descriptor = socket( AF_INET, SOCK_STREAM, 0 @@ -585,7 +586,7 @@ public: } logger.info() << "opened server at port " << port; auto server = - std::make_shared(network, descriptor, port); + std::make_shared(id, network, descriptor, port); server->startListen(std::move(handler)); return server; } @@ -645,9 +646,9 @@ u64id_t Network::connect(const std::string& address, int port, consumer return id; } -u64id_t Network::openServer(int port, consumer handler) { +u64id_t Network::openServer(int port, ConnectCallback handler) { u64id_t id = nextServer++; - auto server = SocketTcpSServer::openServer(this, port, handler); + auto server = SocketTcpSServer::openServer(id, this, port, handler); servers[id] = std::move(server); return id; } diff --git a/src/network/Network.hpp b/src/network/Network.hpp index 33461e05..934642fa 100644 --- a/src/network/Network.hpp +++ b/src/network/Network.hpp @@ -12,6 +12,7 @@ namespace network { using OnResponse = std::function)>; using OnReject = std::function; + using ConnectCallback = std::function; class Requests { public: @@ -64,7 +65,7 @@ namespace network { class TcpServer { public: virtual ~TcpServer() {} - virtual void startListen(consumer handler) = 0; + virtual void startListen(ConnectCallback handler) = 0; virtual void close() = 0; virtual bool isOpen() = 0; virtual int getPort() const = 0; @@ -106,7 +107,7 @@ namespace network { u64id_t connect(const std::string& address, int port, consumer callback); - u64id_t openServer(int port, consumer handler); + u64id_t openServer(int port, ConnectCallback handler); u64id_t addConnection(const std::shared_ptr& connection);