diff --git a/res/scripts/classes.lua b/res/scripts/classes.lua index e63d5a5a..c50443f8 100644 --- a/res/scripts/classes.lua +++ b/res/scripts/classes.lua @@ -72,6 +72,38 @@ local _tcp_client_callbacks = {} local _udp_server_callbacks = {} local _udp_client_datagram_callbacks = {} local _udp_client_open_callbacks = {} +local _http_response_callbacks = {} +local _http_error_callbacks = {} + +network.get = function(url, callback, errorCallback, headers) + local id = network.__get(url, headers) + if callback then + _http_response_callbacks[id] = callback + end + if errorCallback then + _http_error_callbacks[id] = errorCallback + end +end + +network.get_binary = function(url, callback, errorCallback, headers) + local id = network.__get_binary(url, headers) + if callback then + _http_response_callbacks[id] = callback + end + if errorCallback then + _http_error_callbacks[id] = errorCallback + end +end + +network.post = function(url, data, callback, errorCallback, headers) + local id = network.__post(url, data, headers) + if callback then + _http_response_callbacks[id] = callback + end + if errorCallback then + _http_error_callbacks[id] = errorCallback + end +end network.tcp_open = function (port, handler) local socket = setmetatable({id=network.__open_tcp(port)}, ServerSocket) @@ -133,6 +165,7 @@ network.__process_events = function() local CLIENT_CONNECTED = 1 local CONNECTED_TO_SERVER = 2 local DATAGRAM = 3 + local RESPONSE = 4 local ON_SERVER = 1 local ON_CLIENT = 2 @@ -158,6 +191,22 @@ network.__process_events = function() elseif side == ON_SERVER then _udp_server_callbacks[sid](addr, port, data) end + elseif etype == RESPONSE then + if event[2] / 100 == 2 then + local callback = _http_response_callbacks[event[3]] + _http_response_callbacks[event[3]] = nil + _http_error_callbacks[event[3]] = nil + if callback then + callback(event[4]) + end + else + local callback = _http_error_callbacks[event[3]] + _http_response_callbacks[event[3]] = nil + _http_error_callbacks[event[3]] = nil + if callback then + callback(event[2]) + end + end end -- remove dead servers diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index e260ebd7..1527d98b 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -288,6 +288,7 @@ void ContentLoader::loadContent(const dv::value& root) { item.iconType = ItemIconType::BLOCK; item.icon = def.name; item.placingBlock = def.name; + item.tags = def.tags; for (uint j = 0; j < 4; j++) { item.emission[j] = def.emission[j]; diff --git a/src/items/ItemDef.cpp b/src/items/ItemDef.cpp index 1d362ebd..236efc6b 100644 --- a/src/items/ItemDef.cpp +++ b/src/items/ItemDef.cpp @@ -19,4 +19,5 @@ void ItemDef::cloneTo(ItemDef& dst) { dst.modelName = modelName; dst.uses = uses; dst.usesDisplay = usesDisplay; + dst.tags = tags; } diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index 18d26644..c41a32d8 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -3,8 +3,70 @@ #include "engine/Engine.hpp" #include "network/Network.hpp" +#include +#include + using namespace scripting; +enum NetworkEventType { + CLIENT_CONNECTED = 1, + CONNECTED_TO_SERVER, + DATAGRAM, + RESPONSE, +}; + +struct ConnectionEventDto { + u64id_t server; + u64id_t client; +}; + +struct ResponseEventDto { + int status; + bool binary; + int requestId; + std::vector bytes; +}; + +enum NetworkDatagramSide { + ON_SERVER = 1, + ON_CLIENT +}; + +struct NetworkDatagramEventDto { + NetworkDatagramSide side; + u64id_t server; + u64id_t client; + std::string addr; + int port; + std::vector buffer; +}; + +struct NetworkEvent { + using Payload = std::variant< + ConnectionEventDto, + ResponseEventDto, + NetworkDatagramEventDto + >; + NetworkEventType type; + + Payload payload; + + NetworkEvent( + NetworkEventType type, + Payload payload + ) : type(type), payload(std::move(payload)) {} + + virtual ~NetworkEvent() = default; +}; + +static std::vector events_queue {}; +static std::mutex events_queue_mutex; + +static void push_event(NetworkEvent&& event) { + std::lock_guard lock(events_queue_mutex); + events_queue.push_back(std::move(event)); +} + static std::vector read_headers(lua::State* L, int index) { std::vector headers; if (lua::istable(L, index)) { @@ -18,76 +80,50 @@ static std::vector read_headers(lua::State* L, int index) { return headers; } -static int l_get(lua::State* L, network::Network& network) { +static int request_id = 1; + +static int perform_get(lua::State* L, network::Network& network, bool binary) { std::string url(lua::require_lstring(L, 1)); + auto headers = read_headers(L, 2); - lua::pushvalue(L, 2); - auto onResponse = lua::create_lambda_nothrow(L); + int currentRequestId = request_id++; - network::OnReject onReject = nullptr; - if (!lua::isnoneornil(L, 3)) { - lua::pushvalue(L, 3); - auto callback = lua::create_lambda_nothrow(L); - onReject = [callback](int code) { - callback({code}); - }; - } + network.get(url, [currentRequestId, binary](std::vector bytes) { + push_event(NetworkEvent( + RESPONSE, + ResponseEventDto { + 200, + binary, + currentRequestId, + std::move(bytes) + } + )); + }, [currentRequestId](int code) { + push_event(NetworkEvent( + RESPONSE, + ResponseEventDto { + code, + false, + currentRequestId, + {} + } + )); + }, std::move(headers)); + return lua::pushinteger(L, currentRequestId); +} - auto headers = read_headers(L, 4); - - network.get(url, [onResponse](std::vector bytes) { - engine->postRunnable([=]() { - onResponse({std::string(bytes.data(), bytes.size())}); - }); - }, std::move(onReject), std::move(headers)); - return 0; +static int l_get(lua::State* L, network::Network& network) { + return perform_get(L, network, false); } static int l_get_binary(lua::State* L, network::Network& network) { - std::string url(lua::require_lstring(L, 1)); - - lua::pushvalue(L, 2); - auto onResponse = lua::create_lambda_nothrow(L); - - network::OnReject onReject = nullptr; - if (!lua::isnoneornil(L, 3)) { - lua::pushvalue(L, 3); - auto callback = lua::create_lambda_nothrow(L); - onReject = [callback](int code) { - callback({code}); - }; - } - - auto headers = read_headers(L, 4); - - network.get(url, [onResponse](std::vector bytes) { - auto buffer = std::make_shared>( - reinterpret_cast(bytes.data()), bytes.size() - ); - engine->postRunnable([=]() { - onResponse({buffer}); - }); - }, std::move(onReject), std::move(headers)); - - return 0; + return perform_get(L, network, true); } static int l_post(lua::State* L, network::Network& network) { std::string url(lua::require_lstring(L, 1)); auto data = lua::tovalue(L, 2); - lua::pushvalue(L, 3); - auto onResponse = lua::create_lambda_nothrow(L); - - network::OnReject onReject = nullptr; - if (!lua::isnoneornil(L, 4)) { - lua::pushvalue(L, 4); - auto callback = lua::create_lambda_nothrow(L); - onReject = [callback](int code) { - callback({code}); - }; - } - std::string string; if (data.isString()) { string = data.asString(); @@ -95,17 +131,33 @@ static int l_post(lua::State* L, network::Network& network) { string = json::stringify(data, false); } - auto headers = read_headers(L, 5); + auto headers = read_headers(L, 3); + int currentRequestId = request_id++; - engine->getNetwork().post(url, string, [onResponse](std::vector bytes) { - auto buffer = std::make_shared>( - reinterpret_cast(bytes.data()), bytes.size() - ); - engine->postRunnable([=]() { - onResponse({std::string(bytes.data(), bytes.size())}); - }); - }, std::move(onReject), std::move(headers)); - return 0; + engine->getNetwork().post( + url, + string, + [currentRequestId](std::vector bytes) { + auto buffer = std::make_shared>( + reinterpret_cast(bytes.data()), bytes.size() + ); + push_event(NetworkEvent( + RESPONSE, + ResponseEventDto { + 200, + false, + currentRequestId, + std::vector(buffer->begin(), buffer->end())} + )); + }, + [currentRequestId](int code) { + push_event(NetworkEvent( + RESPONSE, ResponseEventDto {code, false, currentRequestId, {}} + )); + }, + std::move(headers) + ); + return lua::pushinteger(L, currentRequestId); } static int l_close(lua::State* L, network::Network& network) { @@ -230,69 +282,14 @@ static int l_available(lua::State* L, network::Network& network) { return 0; } -enum NetworkEventType { - CLIENT_CONNECTED = 1, - CONNECTED_TO_SERVER, - DATAGRAM -}; - -struct NetworkEvent { - NetworkEventType type; - u64id_t server; - u64id_t client; - - NetworkEvent( - NetworkEventType type, - u64id_t server, - u64id_t client - ) { - this->type = type; - this->server = server; - this->client = client; - } - - virtual ~NetworkEvent() = default; -}; - -enum NetworkDatagramSide { - ON_SERVER = 1, - ON_CLIENT -}; - -struct NetworkDatagramEvent : NetworkEvent { - NetworkDatagramSide side; - std::string addr; - int port; - const char* buffer; - size_t length; - - NetworkDatagramEvent( - NetworkEventType datagram, - u64id_t sid, - u64id_t cid, - NetworkDatagramSide side, - const std::string& addr, - int port, - const char* data, - size_t length - ) : NetworkEvent(DATAGRAM, sid, cid) { - this->side = side; - this->addr = addr; - this->port = port; - - buffer = data; - - this->length = length; - } -}; - -static std::vector> events_queue {}; - static int l_connect_tcp(lua::State* L, network::Network& network) { std::string address = lua::require_string(L, 1); int port = lua::tointeger(L, 2); u64id_t id = network.connectTcp(address, port, [](u64id_t cid) { - events_queue.push_back(std::make_unique(CONNECTED_TO_SERVER, 0, cid)); + push_event(NetworkEvent( + CONNECTED_TO_SERVER, + ConnectionEventDto {0, cid} + )); }); return lua::pushinteger(L, id); } @@ -300,7 +297,10 @@ static int l_connect_tcp(lua::State* L, network::Network& network) { static int l_open_tcp(lua::State* L, network::Network& network) { int port = lua::tointeger(L, 1); u64id_t id = network.openTcpServer(port, [](u64id_t sid, u64id_t id) { - events_queue.push_back(std::make_unique(CLIENT_CONNECTED, sid, id)); + push_event(NetworkEvent( + CLIENT_CONNECTED, + ConnectionEventDto {sid, id} + )); }); return lua::pushinteger(L, id); } @@ -309,18 +309,22 @@ static int l_connect_udp(lua::State* L, network::Network& network) { std::string address = lua::require_string(L, 1); int port = lua::tointeger(L, 2); u64id_t id = network.connectUdp(address, port, [](u64id_t cid) { - events_queue.push_back(std::make_unique(CONNECTED_TO_SERVER, 0, cid)); + push_event(NetworkEvent( + CONNECTED_TO_SERVER, + ConnectionEventDto {0, cid} + )); }, [address, port]( u64id_t cid, const char* buffer, size_t length ) { - events_queue.push_back( - std::make_unique( - DATAGRAM, 0, cid, ON_CLIENT, - address, port, buffer, length - ) - ); + push_event(NetworkEvent( + DATAGRAM, + NetworkDatagramEventDto { + ON_CLIENT, 0, cid, + address, port, std::vector(buffer, buffer + length) + } + )); }); return lua::pushinteger(L, id); } @@ -333,10 +337,13 @@ static int l_open_udp(lua::State* L, network::Network& network) { int port, const char* buffer, size_t length) { - events_queue.push_back( - std::make_unique( - DATAGRAM, sid, 0, ON_SERVER, - addr, port, buffer, length + push_event( + NetworkEvent( + DATAGRAM, + NetworkDatagramEventDto { + ON_SERVER, sid, 0, + addr, port, std::vector(buffer, buffer + length) + } ) ); }); @@ -403,39 +410,78 @@ static int l_get_total_download(lua::State* L, network::Network& network) { } static int l_pull_events(lua::State* L, network::Network& network) { - lua::createtable(L, events_queue.size(), 0); + std::vector local_queue; + { + std::lock_guard lock(events_queue_mutex); + local_queue.swap(events_queue); + } - for (size_t i = 0; i < events_queue.size(); i++) { - const auto* datagramEvent = dynamic_cast(events_queue[i].get()); + lua::createtable(L, local_queue.size(), 0); - lua::createtable(L, datagramEvent ? 7 : 3, 0); + for (size_t i = 0; i < local_queue.size(); i++) { + lua::createtable(L, 7, 0); - lua::pushinteger(L, events_queue[i]->type); - lua::rawseti(L, 1); + const auto& event = local_queue[i]; + switch (event.type) { + case CLIENT_CONNECTED: + case CONNECTED_TO_SERVER: { + const auto& dto = std::get(event.payload); + lua::pushinteger(L, event.type); + lua::rawseti(L, 1); - lua::pushinteger(L, events_queue[i]->server); - lua::rawseti(L, 2); + lua::pushinteger(L, dto.server); + lua::rawseti(L, 2); - lua::pushinteger(L, events_queue[i]->client); - lua::rawseti(L, 3); + lua::pushinteger(L, dto.client); + lua::rawseti(L, 3); + break; + } + case DATAGRAM: { + const auto& dto = std::get(event.payload); + lua::pushinteger(L, event.type); + lua::rawseti(L, 1); - if (datagramEvent) { - lua::pushstring(L, datagramEvent->addr); - lua::rawseti(L, 4); + lua::pushinteger(L, dto.server); + lua::rawseti(L, 2); - lua::pushinteger(L, datagramEvent->port); - lua::rawseti(L, 5); + lua::pushinteger(L, dto.client); + lua::rawseti(L, 3); - lua::pushinteger(L, datagramEvent->side); - lua::rawseti(L, 6); + lua::pushstring(L, dto.addr); + lua::rawseti(L, 4); - lua::create_bytearray(L, datagramEvent->buffer, datagramEvent->length); - lua::rawseti(L, 7); + lua::pushinteger(L, dto.port); + lua::rawseti(L, 5); + + lua::pushinteger(L, dto.side); + lua::rawseti(L, 6); + + lua::create_bytearray(L, dto.buffer.data(), dto.buffer.size()); + lua::rawseti(L, 7); + break; + } + case RESPONSE: { + const auto& dto = std::get(event.payload); + lua::pushinteger(L, event.type); + lua::rawseti(L, 1); + + lua::pushinteger(L, dto.status); + lua::rawseti(L, 2); + + lua::pushinteger(L, dto.requestId); + lua::rawseti(L, 3); + + if (dto.binary) { + lua::create_bytearray(L, dto.bytes.data(), dto.bytes.size()); + } else { + lua::pushlstring(L, std::string_view(dto.bytes.data(), dto.bytes.size())); + } + lua::rawseti(L, 4); + break; + } } - lua::rawseti(L, i + 1); } - events_queue.clear(); return 1; } @@ -457,9 +503,9 @@ int wrap(lua_State* L) { } const luaL_Reg networklib[] = { - {"get", wrap}, - {"get_binary", wrap}, - {"post", wrap}, + {"__get", wrap}, + {"__get_binary", wrap}, + {"__post", wrap}, {"get_total_upload", wrap}, {"get_total_download", wrap}, {"__pull_events", wrap}, diff --git a/src/network/Network.cpp b/src/network/Network.cpp index 76636b2d..d60dcb67 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -642,19 +642,19 @@ public: ) { SOCKET descriptor = socket(AF_INET, SOCK_DGRAM, 0); if (descriptor == -1) { - throw std::runtime_error("could not create UDP socket"); + throw std::runtime_error("could not create udp socket"); } sockaddr_in serverAddr{}; serverAddr.sin_family = AF_INET; if (inet_pton(AF_INET, address.c_str(), &serverAddr.sin_addr) <= 0) { closesocket(descriptor); - throw std::runtime_error("invalid UDP address: " + address); + throw std::runtime_error("invalid udp address: " + address); } serverAddr.sin_port = htons(port); if (::connect(descriptor, (sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { - auto err = handle_socket_error("UDP connect failed"); + auto err = handle_socket_error("udp connect failed"); closesocket(descriptor); throw err; } @@ -809,7 +809,7 @@ public: u64id_t id, Network* network, int port, const ServerDatagramCallback& handler ) { SOCKET descriptor = socket(AF_INET, SOCK_DGRAM, 0); - if (descriptor == -1) throw std::runtime_error("Could not create UDP socket"); + if (descriptor == -1) throw std::runtime_error("could not create udp socket"); sockaddr_in address{}; address.sin_family = AF_INET; @@ -818,7 +818,7 @@ public: if (bind(descriptor, (sockaddr*)&address, sizeof(address)) < 0) { closesocket(descriptor); - throw std::runtime_error("Could not bind UDP port " + std::to_string(port)); + throw std::runtime_error("could not bind udp port " + std::to_string(port)); } auto server = std::make_shared(id, network, descriptor, port); diff --git a/src/voxels/Block.cpp b/src/voxels/Block.cpp index 4685dfb6..17a3acc4 100644 --- a/src/voxels/Block.cpp +++ b/src/voxels/Block.cpp @@ -155,6 +155,7 @@ void Block::cloneTo(Block& dst) { dst.tickInterval = tickInterval; dst.overlayTexture = overlayTexture; dst.translucent = translucent; + dst.tags = tags; if (particles) { dst.particles = std::make_unique(*particles); }