diff --git a/CMakeLists.txt b/CMakeLists.txt index 8edc205..1c98ce9 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ set(sources "src/main.cpp" "src/MainProgram.cpp" "src/DrawData.cpp" "src/FontData.cpp" + "src/ClientData.cpp" "src/GridManager.cpp" "src/WorldGrid.cpp" "src/TimePoint.cpp" @@ -53,8 +54,6 @@ set(sources "src/main.cpp" "src/ResourceDisplay/SvgResourceDisplay.cpp" "src/ResourceDisplay/ImageResourceDisplay.cpp" "src/ResourceDisplay/FileResourceDisplay.cpp" - "src/Server/MainServer.cpp" - "src/Server/ServerData.cpp" "src/RichText/TextBox.cpp" "src/RichText/TextStyleModifier.cpp" "src/RichText/ParagraphStyleData.cpp" diff --git a/include/Helpers/Networking/NetServer.hpp b/include/Helpers/Networking/NetServer.hpp index 7a259e1..67173e6 100644 --- a/include/Helpers/Networking/NetServer.hpp +++ b/include/Helpers/Networking/NetServer.hpp @@ -37,7 +37,7 @@ class NetServer : public std::enable_shared_from_this { }; std::unordered_map> messageQueues; - uint64_t customID; + std::array customID; void send_queued_messages(NetServer& server); void parse_received_messages(NetServer& server); diff --git a/include/Helpers/NetworkingObjects/NetObjManager.hpp b/include/Helpers/NetworkingObjects/NetObjManager.hpp index 4b81f34..20dff03 100644 --- a/include/Helpers/NetworkingObjects/NetObjManager.hpp +++ b/include/Helpers/NetworkingObjects/NetObjManager.hpp @@ -91,7 +91,6 @@ namespace NetworkingObjects { } template static void send_client_update(const NetObjTemporaryPtr& ptr, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { - assert(!isServer); if(ptr.get_obj_man()->client && !ptr.get_obj_man()->client->is_disconnected()) { auto ss(std::make_shared()); { @@ -104,7 +103,6 @@ namespace NetworkingObjects { } template static void send_server_update_to_client(const NetObjTemporaryPtr& ptr, const std::shared_ptr& clientToSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { - assert(isServer); if(ptr.get_obj_man()->server && !ptr.get_obj_man()->server->is_disconnected()) { auto ss(std::make_shared()); { @@ -117,7 +115,6 @@ namespace NetworkingObjects { } template static void send_server_update_to_all_clients_except(const NetObjTemporaryPtr& ptr, const std::shared_ptr& clientToNotSendTo, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { - assert(isServer); if(ptr.get_obj_man()->server && !ptr.get_obj_man()->server->is_disconnected()) { auto ss(std::make_shared()); { @@ -130,7 +127,6 @@ namespace NetworkingObjects { } template static void send_server_update_to_all_clients(const NetObjTemporaryPtr& ptr, const std::string& channel, std::function&, cereal::PortableBinaryOutputArchive&)> sendUpdateFunc) { - assert(isServer); if(ptr.get_obj_man()->server && !ptr.get_obj_man()->server->is_disconnected()) { auto ss(std::make_shared()); { diff --git a/include/Helpers/NetworkingObjects/NetObjUnorderedSet.hpp b/include/Helpers/NetworkingObjects/NetObjUnorderedSet.hpp index 326026d..1be67b8 100644 --- a/include/Helpers/NetworkingObjects/NetObjUnorderedSet.hpp +++ b/include/Helpers/NetworkingObjects/NetObjUnorderedSet.hpp @@ -47,7 +47,7 @@ namespace NetworkingObjects { } bool contains(const NetObjID& p) const { - return std::find_if(data.begin(), data.end(), [&p](const NetObjOwnerPtr& o){ o.get_net_id() == p; }) != data.end(); + return std::find_if(data.begin(), data.end(), [&p](const NetObjOwnerPtr& o){ return o.get_net_id() == p; }) != data.end(); } const std::vector>& get_data() const { return data; @@ -68,7 +68,7 @@ namespace NetworkingObjects { } bool erase_by_id(const NetObjTemporaryPtr>& l, const NetObjID& id) { - auto it = std::find_if(this->data.begin(), this->data.end(), [&id](const NetObjOwnerPtr& o){ o.get_net_id() == id; }); + auto it = std::find_if(this->data.begin(), this->data.end(), [&id](const NetObjOwnerPtr& o){ return o.get_net_id() == id; }); if(it == this->data.end()) return false; call_erase_callback(*it); @@ -77,14 +77,14 @@ namespace NetworkingObjects { return true; } - virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, NetObjOwnerPtr newObj) const = 0; + virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, const NetObjOwnerPtr& newObj) const = 0; virtual void erase_network(const NetObjTemporaryPtr>& l, const NetObjID& id) const = 0; virtual void read_update(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) = 0; void write_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryOutputArchive& a) { a(static_cast(data.size())); for(size_t i = 0; i < data.size(); i++) - data[i]->obj.write_create_message(a); + data[i].write_create_message(a); } void read_constructor(const NetObjTemporaryPtr>& l, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { @@ -128,7 +128,7 @@ namespace NetworkingObjects { public: NetObjUnorderedSetServer() {} protected: - virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, NetObjOwnerPtr newObj) const override { + virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr& clientInserting, const NetObjOwnerPtr& newObj) const override { l.send_server_update_to_all_clients_except(clientInserting, RELIABLE_COMMAND_CHANNEL, [&newObj](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrUnorderedSetCommand_StoC::INSERT_SINGLE_CONSTRUCT); newObj.write_create_message(a); @@ -144,13 +144,13 @@ namespace NetworkingObjects { a(command); switch(command) { case ObjPtrUnorderedSetCommand_CtoS::INSERT_SINGLE: { - insert(l, c, l.get_obj_man()->template read_create_message(a, c)); + NetObjUnorderedSet::insert(l, c, l.get_obj_man()->template read_create_message(a, c)); break; } case ObjPtrUnorderedSetCommand_CtoS::ERASE_SINGLE: { NetObjID idToErase; a(idToErase); - erase_by_id(l, idToErase); + NetObjUnorderedSet::erase_by_id(l, idToErase); break; } } @@ -161,7 +161,7 @@ namespace NetworkingObjects { public: NetObjUnorderedSetClient() {} protected: - virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr&, NetObjOwnerPtr newObj) const override { + virtual void insert_network(const NetObjTemporaryPtr>& l, const std::shared_ptr&, const NetObjOwnerPtr& newObj) const override { l.send_client_update(RELIABLE_COMMAND_CHANNEL, [&newObj](const NetObjTemporaryPtr>&, cereal::PortableBinaryOutputArchive& a) { a(ObjPtrUnorderedSetCommand_CtoS::INSERT_SINGLE); newObj.write_create_message(a); @@ -183,7 +183,7 @@ namespace NetworkingObjects { case ObjPtrUnorderedSetCommand_StoC::ERASE_SINGLE: { NetObjID id; a(id); - auto it = std::find_if(this->data.begin(), this->data.end(), [&id](const NetObjOwnerPtr& o){ o.get_net_id() == id; }); + auto it = std::find_if(this->data.begin(), this->data.end(), [&id](const NetObjOwnerPtr& o){ return o.get_net_id() == id; }); if(it != this->data.end()) this->data.erase(it); break; diff --git a/src/BookmarkManager.cpp b/src/BookmarkManager.cpp index 62eb375..15ee453 100644 --- a/src/BookmarkManager.cpp +++ b/src/BookmarkManager.cpp @@ -2,7 +2,6 @@ #include "Helpers/Networking/NetLibrary.hpp" #include "Helpers/NetworkingObjects/NetObjOrderedList.hpp" #include "World.hpp" -#include "Server/CommandList.hpp" #include "MainProgram.hpp" #include diff --git a/src/ClientData.cpp b/src/ClientData.cpp new file mode 100644 index 0000000..1faea93 --- /dev/null +++ b/src/ClientData.cpp @@ -0,0 +1,182 @@ +#include "ClientData.hpp" +#include "World.hpp" +#include +#include "MainProgram.hpp" + +using namespace NetworkingObjects; + +enum class ClientDataCommand : uint8_t { + SET_CURSOR_POS = 0, + SET_WINDOW_SIZE, + SET_CAM_COORDS, + SEND_CHAT_MESSAGE +}; + +ClientData::ClientData() { + set_from_init_struct(InitStruct()); +} + +ClientData::ClientData(const InitStruct& initStruct) { + set_from_init_struct(initStruct); +} + +void ClientData::set_from_init_struct(const InitStruct& initStruct) { + camCoords = initStruct.camCoords; + windowSize = initStruct.windowSize; + cursorPos = initStruct.cursorPos; + cursorColor = initStruct.cursorColor; + displayName = initStruct.displayName; +} + +void ClientData::register_class(World& world) { + world.netObjMan.register_class({ + .writeConstructorFuncClient = default_serialize_write_func, + .readConstructorFuncClient = default_serialize_read_constructor_func, + .readUpdateFuncClient = [&world](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr&) { + ClientDataCommand command; + a(command); + switch(command) { + case ClientDataCommand::SET_CURSOR_POS: + a(o->cursorPos); + break; + case ClientDataCommand::SET_WINDOW_SIZE: + a(o->windowSize); + break; + case ClientDataCommand::SET_CAM_COORDS: + a(o->camCoords); + break; + case ClientDataCommand::SEND_CHAT_MESSAGE: { + std::string chatMessage; + a(chatMessage); + world.add_chat_message(o->displayName, chatMessage, Toolbar::ChatMessage::Type::NORMAL); + } + } + }, + .writeConstructorFuncServer = default_serialize_write_func, + .readConstructorFuncServer = default_serialize_read_constructor_func, + .readUpdateFuncServer = [&world](const NetObjTemporaryPtr& o, cereal::PortableBinaryInputArchive& a, const std::shared_ptr& c) { + ClientDataCommand command; + a(command); + switch(command) { + case ClientDataCommand::SET_CURSOR_POS: + a(o->cursorPos); + o.send_server_update_to_all_clients_except(c, UNRELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive & a) { + a(ClientDataCommand::SET_CURSOR_POS, o->cursorPos); + }); + break; + case ClientDataCommand::SET_WINDOW_SIZE: + a(o->windowSize); + o.send_server_update_to_all_clients_except(c, RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive & a) { + a(ClientDataCommand::SET_WINDOW_SIZE, o->windowSize); + }); + break; + case ClientDataCommand::SET_CAM_COORDS: + a(o->camCoords); + o.send_server_update_to_all_clients_except(c, RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive & a) { + a(ClientDataCommand::SET_CAM_COORDS, o->camCoords); + }); + break; + case ClientDataCommand::SEND_CHAT_MESSAGE: { + std::string chatMessage; + a(chatMessage); + world.add_chat_message(o->displayName, chatMessage, Toolbar::ChatMessage::Type::NORMAL); + o.send_server_update_to_all_clients_except(c, RELIABLE_COMMAND_CHANNEL, [&chatMessage](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive & a) { + a(ClientDataCommand::SEND_CHAT_MESSAGE, chatMessage); + }); + break; + } + } + }, + }); +} + +void ClientData::set_cursor_pos(const NetworkingObjects::NetObjTemporaryPtr& o, Vector2f newPos) { + o->cursorPos = newPos; + o.send_update_to_all(UNRELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive & a) { + a(ClientDataCommand::SET_CURSOR_POS, o->cursorPos); + }); +} + +void ClientData::set_window_size(const NetworkingObjects::NetObjTemporaryPtr& o, Vector2f newWindowSize) { + if(o->windowSize != newWindowSize) { + o->windowSize = newWindowSize; + o.send_update_to_all(RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive & a) { + a(ClientDataCommand::SET_WINDOW_SIZE, o->windowSize); + }); + } +} + +void ClientData::set_camera_coords(const NetworkingObjects::NetObjTemporaryPtr& o, const CoordSpaceHelper& newCoords) { + if(o->camCoords != newCoords) { + o->camCoords = newCoords; + o.send_update_to_all(RELIABLE_COMMAND_CHANNEL, [](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive & a) { + a(ClientDataCommand::SET_CAM_COORDS, o->camCoords); + }); + } +} + +void ClientData::send_chat_message(const NetworkingObjects::NetObjTemporaryPtr& o, World& world, const std::string& chatMessage) { + world.add_chat_message(o->displayName, chatMessage, Toolbar::ChatMessage::Type::NORMAL); + o.send_update_to_all(RELIABLE_COMMAND_CHANNEL, [&chatMessage](const NetObjTemporaryPtr& o, cereal::PortableBinaryOutputArchive & a) { + a(ClientDataCommand::SEND_CHAT_MESSAGE, chatMessage); + }); +} + +void ClientData::set_display_name(const std::string& newDisplayName) { + displayName = newDisplayName; +} + +void ClientData::set_cursor_color(const Vector3f& newCursorColor) { + cursorColor = newCursorColor; +} + +const CoordSpaceHelper& ClientData::get_cam_coords() const { + return camCoords; +} + +const Vector2f& ClientData::get_window_size() const { + return windowSize; +} + +const Vector2f& ClientData::get_cursor_pos() const { + return cursorPos; +} + +const std::string& ClientData::get_display_name() const { + return displayName; +} + +const Vector3f& ClientData::get_cursor_color() const { + return cursorColor; +} + +void ClientData::draw_cursor(SkCanvas* canvas, const DrawData& drawData) const { + if((drawData.cam.c.inverseScale << 10) > camCoords.inverseScale && drawData.clampDrawMinimum < camCoords.inverseScale) { + canvas->save(); + camCoords.transform_sk_canvas(canvas, drawData); + + canvas->translate(cursorPos.x(), cursorPos.y()); + + SkPaint p(SkColor4f{cursorColor.x(), cursorColor.y(), cursorColor.z(), 0.2f}); + canvas->drawCircle(0.0f, 0.0f, 4.5f, p); + p.setStroke(true); + p.setStrokeWidth(1.0f); + p.setColor4f({cursorColor.x(), cursorColor.y(), cursorColor.z(), 0.7f}); + canvas->drawCircle(0.0f, 0.0f, 5.0f, p); + + SkFont f = drawData.main->toolbar.io->get_font(18.0f); + SkFontMetrics metrics; + f.getMetrics(&metrics); + + float nextText = f.measureText(displayName.c_str(), displayName.length(), SkTextEncoding::kUTF8, nullptr); + Vector2f bounds{nextText, - metrics.fAscent + metrics.fDescent}; + + SkPaint p2(SkColor4f{cursorColor.x(), cursorColor.y(), cursorColor.z(), 0.5f}); + canvas->drawSimpleText(displayName.c_str(), displayName.length(), SkTextEncoding::kUTF8, 6.0f, -metrics.fDescent, f, p2); + + SkPaint p3(color_mul_alpha(drawData.main->toolbar.io->theme->backColor1, 0.5f)); + canvas->drawRoundRect(SkRect::MakeXYWH(6.0f, -bounds.y(), bounds.x(), bounds.y()), 3.0f, 3.0f, p3); + + canvas->restore(); + } +} diff --git a/src/ClientData.hpp b/src/ClientData.hpp new file mode 100644 index 0000000..18b0102 --- /dev/null +++ b/src/ClientData.hpp @@ -0,0 +1,48 @@ +#pragma once +#include +#include "CoordSpaceHelper.hpp" +#include +#include + +class ClientData { + public: + struct InitStruct { + CoordSpaceHelper camCoords; + Vector2f windowSize = {1000.0f, 1000.0f}; + Vector2f cursorPos = {1.0f, 1.0f}; + + Vector3f cursorColor = {1.0f, 1.0f, 1.0f}; + std::string displayName; + }; + + ClientData(); + ClientData(const InitStruct& initStruct); + static void register_class(World& world); + static void set_cursor_pos(const NetworkingObjects::NetObjTemporaryPtr& o, Vector2f newPos); + static void set_window_size(const NetworkingObjects::NetObjTemporaryPtr& o, Vector2f newWindowSize); + static void set_camera_coords(const NetworkingObjects::NetObjTemporaryPtr& o, const CoordSpaceHelper& newCoords); + static void send_chat_message(const NetworkingObjects::NetObjTemporaryPtr& o, World& world, const std::string& chatMessage); + void set_display_name(const std::string& newDisplayName); + void set_cursor_color(const Vector3f& newCursorColor); + + const CoordSpaceHelper& get_cam_coords() const; + const Vector2f& get_window_size() const; + const Vector2f& get_cursor_pos() const; + const std::string& get_display_name() const; + const Vector3f& get_cursor_color() const; + + void draw_cursor(SkCanvas* canvas, const DrawData& drawData) const; + + template void serialize(Archive& a) { + a(camCoords, windowSize, cursorPos, cursorColor, displayName); + } + private: + void set_from_init_struct(const InitStruct& initStruct); + CoordSpaceHelper camCoords; + Vector2f windowSize; + Vector2f cursorPos; + + Vector3f cursorColor; + std::string displayName; +}; + diff --git a/src/Server/CommandList.hpp b/src/CommandList.hpp similarity index 73% rename from src/Server/CommandList.hpp rename to src/CommandList.hpp index 30f7c07..cb4222a 100644 --- a/src/Server/CommandList.hpp +++ b/src/CommandList.hpp @@ -7,11 +7,8 @@ enum ServerCommands : MessageCommandType { SERVER_KEEP_ALIVE, SERVER_INITIAL_DATA, SERVER_UPDATE_NETWORK_OBJECT, - SERVER_MOVE_CAMERA, - SERVER_MOVE_SCREEN_MOUSE, SERVER_NEW_RESOURCE_ID, - SERVER_NEW_RESOURCE_DATA, - SERVER_CHAT_MESSAGE + SERVER_NEW_RESOURCE_DATA }; enum ClientCommands : MessageCommandType { @@ -19,13 +16,8 @@ enum ClientCommands : MessageCommandType { CLIENT_KEEP_ALIVE, CLIENT_INITIAL_DATA, CLIENT_UPDATE_NETWORK_OBJECT, - CLIENT_USER_CONNECT, - CLIENT_USER_DISCONNECT, - CLIENT_MOVE_CAMERA, - CLIENT_MOVE_SCREEN_MOUSE, CLIENT_NEW_RESOURCE_ID, - CLIENT_NEW_RESOURCE_DATA, - CLIENT_CHAT_MESSAGE + CLIENT_NEW_RESOURCE_DATA }; // Arbitrary value. Higher scale up values lead to less scale up events (which can cause stuttering), but leads to larger numbers overall, which can cause a tiny bit of lag and increased memory usage diff --git a/src/ConnectionManager.cpp b/src/ConnectionManager.cpp index 932ec1e..c170bfd 100644 --- a/src/ConnectionManager.cpp +++ b/src/ConnectionManager.cpp @@ -1,16 +1,10 @@ #include "ConnectionManager.hpp" #include "Helpers/Networking/NetLibrary.hpp" -#include "Server/CommandList.hpp" +#include "CommandList.hpp" #include #include "World.hpp" #include -void ConnectionManager::init_local_p2p(World& initWorld, const std::string& serverLocalID) { - localServer = std::make_unique(initWorld, serverLocalID); - client = std::make_shared(*localServer->netServer); - lastKeepAliveTime = std::chrono::steady_clock::now(); -} - void ConnectionManager::connect_p2p(World& initWorld, const std::string& serverFullID) { client = std::make_shared(serverFullID); lastKeepAliveTime = std::chrono::steady_clock::now(); @@ -19,9 +13,6 @@ void ConnectionManager::connect_p2p(World& initWorld, const std::string& serverF } void ConnectionManager::update() { - if(localServer) { - localServer->update(); - } if(client) { client->update(); if(std::chrono::steady_clock::now() - lastKeepAliveTime > std::chrono::seconds(2)) { @@ -40,14 +31,6 @@ bool ConnectionManager::is_client_disconnected() { return client && client->is_disconnected(); } -bool ConnectionManager::is_host_disconnected() { - return localServer && localServer->netServer->is_disconnected(); -} - -bool ConnectionManager::host_exists() { - return localServer != nullptr; -} - bool ConnectionManager::client_exists() { return client != nullptr; } diff --git a/src/ConnectionManager.hpp b/src/ConnectionManager.hpp index 7261932..a541e6c 100644 --- a/src/ConnectionManager.hpp +++ b/src/ConnectionManager.hpp @@ -1,10 +1,10 @@ #pragma once -#include "Server/MainServer.hpp" #include +class World; + class ConnectionManager { public: - void init_local_p2p(World& initWorld, const std::string& serverLocalID); void connect_p2p(World& initWorld, const std::string& serverFullID); void update(); void client_add_recv_callback(uint32_t commandID, const NetClientRecvCallback &callback); @@ -13,11 +13,9 @@ class ConnectionManager { client->send_items_to_server(channel, items...); } bool is_client_disconnected(); - bool is_host_disconnected(); bool host_exists(); bool client_exists(); NetLibrary::DownloadProgress client_get_resource_retrieval_progress(); - std::unique_ptr localServer; private: std::shared_ptr client; std::chrono::steady_clock::time_point lastKeepAliveTime; diff --git a/src/DrawCamera.cpp b/src/DrawCamera.cpp index 95e89ce..6849f14 100755 --- a/src/DrawCamera.cpp +++ b/src/DrawCamera.cpp @@ -1,12 +1,9 @@ #include "DrawCamera.hpp" #include "DrawingProgram/DrawingProgramToolBase.hpp" #include "Helpers/FixedPoint.hpp" -#include "Helpers/MathExtras.hpp" #include "MainProgram.hpp" -#include "Server/CommandList.hpp" #include "World.hpp" #include "InputManager.hpp" -#include DrawCamera::DrawCamera(): c({0, 0}, WorldScalar(1000000), 0.0) diff --git a/src/DrawingProgram/DrawingProgram.cpp b/src/DrawingProgram/DrawingProgram.cpp index 2beda85..4c95cc3 100644 --- a/src/DrawingProgram/DrawingProgram.cpp +++ b/src/DrawingProgram/DrawingProgram.cpp @@ -8,7 +8,6 @@ #include "GridModifyTool.hpp" #include "../InputManager.hpp" #include "../SharedTypes.hpp" -#include "../Server/CommandList.hpp" #include #include #include @@ -80,13 +79,6 @@ void DrawingProgram::parallel_loop_all_components(std::functionget_data(), func); } -std::unordered_set DrawingProgram::get_used_resources() const { - std::unordered_set toRet; - //for(auto& c : components->get_data()) - // c->obj->get_used_resources(toRet); - return toRet; -} - void DrawingProgram::erase_component_set(const std::unordered_set& compsToErase) { std::unordered_set idsToErase; for(auto& c : compsToErase) diff --git a/src/DrawingProgram/DrawingProgram.hpp b/src/DrawingProgram/DrawingProgram.hpp index c587987..ec743f6 100644 --- a/src/DrawingProgram/DrawingProgram.hpp +++ b/src/DrawingProgram/DrawingProgram.hpp @@ -36,7 +36,6 @@ class DrawingProgram { void add_file_to_canvas_by_path(const std::filesystem::path& filePath, Vector2f dropPos, bool addInSameThread); void add_file_to_canvas_by_data(const std::string& fileName, std::string_view fileBuffer, Vector2f dropPos); - std::unordered_set get_used_resources() const; void load_file(cereal::PortableBinaryInputArchive& a, VersionNumber version); void save_file(cereal::PortableBinaryOutputArchive& a) const; World& world; diff --git a/src/DrawingProgram/EyeDropperTool.cpp b/src/DrawingProgram/EyeDropperTool.cpp index 921e40f..3c44646 100644 --- a/src/DrawingProgram/EyeDropperTool.cpp +++ b/src/DrawingProgram/EyeDropperTool.cpp @@ -1,6 +1,5 @@ #include "EyeDropperTool.hpp" #include "DrawingProgram.hpp" -#include "../Server/CommandList.hpp" #include "../MainProgram.hpp" #include "../DrawData.hpp" #include "DrawingProgramToolBase.hpp" diff --git a/src/DrawingProgram/ScreenshotTool.cpp b/src/DrawingProgram/ScreenshotTool.cpp index 2523f13..a1fc949 100644 --- a/src/DrawingProgram/ScreenshotTool.cpp +++ b/src/DrawingProgram/ScreenshotTool.cpp @@ -1,6 +1,5 @@ #include "ScreenshotTool.hpp" #include "DrawingProgram.hpp" -#include "../Server/CommandList.hpp" #include "../MainProgram.hpp" #include "../DrawData.hpp" #include "DrawingProgramToolBase.hpp" diff --git a/src/GridManager.cpp b/src/GridManager.cpp index 1e4bc14..2332604 100644 --- a/src/GridManager.cpp +++ b/src/GridManager.cpp @@ -1,10 +1,6 @@ #include "GridManager.hpp" -#include "Helpers/Networking/NetLibrary.hpp" -#include "Server/CommandList.hpp" -#include "SharedTypes.hpp" #include "World.hpp" #include "MainProgram.hpp" -#include GridManager::GridManager(World& w): world(w) {} diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 68f4742..1a458ea 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -5,8 +5,6 @@ #include -#include "Server/CommandList.hpp" - #ifdef __EMSCRIPTEN__ #include diff --git a/src/MainProgram.cpp b/src/MainProgram.cpp index bc86769..33105fe 100755 --- a/src/MainProgram.cpp +++ b/src/MainProgram.cpp @@ -16,7 +16,6 @@ #include #include #include "InputManager.hpp" -#include "Server/CommandList.hpp" #include #include #include @@ -137,7 +136,7 @@ void MainProgram::update() { void MainProgram::update_display_names() { for(auto& w : worlds) { if(!w->network_being_used()) - w->displayName = displayName; + w->ownClientData->set_display_name(displayName); } } diff --git a/src/MainProgram.hpp b/src/MainProgram.hpp index 9553176..4be0443 100644 --- a/src/MainProgram.hpp +++ b/src/MainProgram.hpp @@ -62,13 +62,6 @@ class MainProgram { SDL_Window* sdlWindow; } window; - struct Clipboard { - std::vector> components; - std::unordered_map resources; - WorldVec pos; - WorldScalar inverseScale; - } clipboard; - std::shared_ptr fonts; TimePoint deltaTime; Toolbar toolbar; diff --git a/src/ResourceManager.cpp b/src/ResourceManager.cpp index 1038d9f..c496a7b 100644 --- a/src/ResourceManager.cpp +++ b/src/ResourceManager.cpp @@ -3,7 +3,7 @@ #include #include #include "ResourceDisplay/SvgResourceDisplay.hpp" -#include "Server/CommandList.hpp" +#include "CommandList.hpp" #include "ResourceDisplay/ImageResourceDisplay.hpp" #include "ResourceDisplay/FileResourceDisplay.hpp" #include @@ -19,16 +19,14 @@ ResourceManager::ResourceManager(World& initWorld): void ResourceManager::init_client_callbacks() { world.con.client_add_recv_callback(SERVER_NEW_RESOURCE_ID, [&](cereal::PortableBinaryInputArchive& message) { - if(!world.con.host_exists()) { - NetworkingObjects::NetObjID idBeingRetrieved; - message(idBeingRetrieved); - // There is a scenario where the resource id and data messages can be sent twice for the same resource (a resource can be sent early before CLIENT_INITIAL_DATA is sent, and then resent with CLIENT_INITIAL_DATA), so check if resource already exists, and only keep track of the ID if the resource doesn't exist yet - if(!world.netObjMan.get_obj_temporary_ref_from_id(idBeingRetrieved)) - resourcesBeingRetrieved.emplace(idBeingRetrieved, 0); - } + NetworkingObjects::NetObjID idBeingRetrieved; + message(idBeingRetrieved); + // There is a scenario where the resource id and data messages can be sent twice for the same resource (a resource can be sent early before CLIENT_INITIAL_DATA is sent, and then resent with CLIENT_INITIAL_DATA), so check if resource already exists, and only keep track of the ID if the resource doesn't exist yet + if(!world.netObjMan.get_obj_temporary_ref_from_id(idBeingRetrieved)) + resourcesBeingRetrieved.emplace(idBeingRetrieved, std::weak_ptr()); }); world.con.client_add_recv_callback(SERVER_NEW_RESOURCE_DATA, [&](cereal::PortableBinaryInputArchive& message) { - if(!world.con.host_exists() && !resourcesBeingRetrieved.empty()) { // If the resource was sent for the second time, this will be empty, so we can ignore the message + if(!resourcesBeingRetrieved.empty()) { // If the resource was sent for the second time, this will be empty, so we can ignore the message ResourceData newResource; message(newResource); resourceList.emplace_back(world.netObjMan.make_obj_direct_with_specific_id(resourcesBeingRetrieved.begin()->first, newResource)); @@ -38,21 +36,21 @@ void ResourceManager::init_client_callbacks() { } void ResourceManager::init_server_callbacks() { - world.con.localServer->netServer->add_recv_callback(CLIENT_NEW_RESOURCE_ID, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { + world.netServer->add_recv_callback(CLIENT_NEW_RESOURCE_ID, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { NetworkingObjects::NetObjID idBeingRetrieved; message(idBeingRetrieved); - resourcesBeingRetrieved.emplace(idBeingRetrieved, client->customID); + resourcesBeingRetrieved.emplace(idBeingRetrieved, client); }); - world.con.localServer->netServer->add_recv_callback(CLIENT_NEW_RESOURCE_DATA, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { + world.netServer->add_recv_callback(CLIENT_NEW_RESOURCE_DATA, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { ResourceData newResource; message(newResource); auto it = std::find_if(resourcesBeingRetrieved.begin(), resourcesBeingRetrieved.end(), [&client](auto& p) { - return p.second == client->customID; + return (!p.second.expired() && p.second.lock() == client); }); resourceList.emplace_back(world.netObjMan.make_obj_direct_with_specific_id(it->first, newResource)); - world.con.localServer->netServer->send_items_to_all_clients_except(client, RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_ID, resourceList.back().get_net_id()); - world.con.localServer->netServer->send_items_to_all_clients_except(client, RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_DATA, newResource); - resourcesBeingRetrieved.erase(resourceList.back().get_net_id()); + world.netServer->send_items_to_all_clients_except(client, RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_ID, resourceList.back().get_net_id()); + world.netServer->send_items_to_all_clients_except(client, RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_DATA, newResource); + resourcesBeingRetrieved.erase(it); }); } @@ -60,18 +58,13 @@ float ResourceManager::get_resource_retrieval_progress(const NetworkingObjects:: auto resourceClientID = resourcesBeingRetrieved.find(id); if(resourceClientID == resourcesBeingRetrieved.end()) return 0.0f; - if(world.con.localServer) { - uint64_t clientIDToLookFor = resourceClientID->second; - - const std::vector>& clientListInNetServer = world.con.localServer->netServer->get_client_list(); - auto netClientIt = std::find_if(clientListInNetServer.begin(), clientListInNetServer.end(), [&clientIDToLookFor](auto& nC) { - return nC->customID == clientIDToLookFor; - }); - if(netClientIt == clientListInNetServer.end()) { - resourcesBeingRetrieved.erase(resourceClientID); // Client disconnected, remove it from the list + if(world.netServer) { + std::weak_ptr clientIDToLookFor = resourceClientID->second; + if(clientIDToLookFor.expired()) { + resourcesBeingRetrieved.erase(resourceClientID); return 0.0f; } - auto progressBytes = (*netClientIt)->get_progress_into_fragmented_message(RESOURCE_COMMAND_CHANNEL); + auto progressBytes = clientIDToLookFor.lock()->get_progress_into_fragmented_message(RESOURCE_COMMAND_CHANNEL); if(progressBytes.totalBytes == 0) return 0.0f; return static_cast(progressBytes.downloadedBytes) / static_cast(progressBytes.totalBytes); @@ -136,9 +129,9 @@ const NetworkingObjects::NetObjOwnerPtr& ResourceManager::add_reso return *it; } auto& resourceInsert = resourceList.emplace_back(world.netObjMan.make_obj_direct(resource)); - if(world.con.localServer) { - world.con.localServer->netServer->send_items_to_all_clients(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_ID, resourceInsert.get_net_id()); - world.con.localServer->netServer->send_items_to_all_clients(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_DATA, resource); + if(world.netServer) { + world.netServer->send_items_to_all_clients(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_ID, resourceInsert.get_net_id()); + world.netServer->send_items_to_all_clients(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_DATA, resource); } else { world.con.client_send_items_to_server(RESOURCE_COMMAND_CHANNEL, SERVER_NEW_RESOURCE_ID, resourceInsert.get_net_id()); diff --git a/src/ResourceManager.hpp b/src/ResourceManager.hpp index 33cd949..a3a5f5d 100644 --- a/src/ResourceManager.hpp +++ b/src/ResourceManager.hpp @@ -36,7 +36,7 @@ class ResourceManager { private: std::unordered_map> displays; - std::unordered_map resourcesBeingRetrieved; + std::unordered_map> resourcesBeingRetrieved; std::vector> resourceList; static std::array decoders; diff --git a/src/Server/ClientData.hpp b/src/Server/ClientData.hpp deleted file mode 100644 index 633f9cd..0000000 --- a/src/Server/ClientData.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once -#include "../SharedTypes.hpp" -#include -#include "../CoordSpaceHelper.hpp" -#include "../ResourceManager.hpp" -#include -#include - -class ClientData { - public: - CoordSpaceHelper camCoords; - Vector2f windowSize = {1000.0f, 1000.0f}; - Vector2f cursorPos = {1.0f, 1.0f}; - - Vector3f cursorColor = {1.0f, 1.0f, 1.0f}; - std::string displayName; - ServerPortionID serverID = 0; - - uint64_t canvasScale = 0; - - template void serialize(Archive& a) { - a(camCoords, windowSize, cursorPos, cursorColor, displayName); - } -}; - diff --git a/src/Server/MainServer.cpp b/src/Server/MainServer.cpp deleted file mode 100644 index 1235931..0000000 --- a/src/Server/MainServer.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "MainServer.hpp" -#include "CommandList.hpp" -#include "Helpers/HsvRgb.hpp" -#include "Helpers/Networking/NetLibrary.hpp" -#include "ServerData.hpp" -#include "../SharedTypes.hpp" -#include "../CoordSpaceHelper.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../World.hpp" - -MainServer::MainServer(World& initWorld, const std::string& serverLocalID): - world(initWorld) -{ - data.canvasScale = world.canvasScale; - - lastKeepAliveSent = std::chrono::steady_clock::now(); - - netServer = std::make_shared(serverLocalID); - NetLibrary::register_server(netServer); - - world.netObjMan.set_server(netServer, CLIENT_UPDATE_NETWORK_OBJECT); - - netServer->add_recv_callback(SERVER_INITIAL_DATA, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - bool isDirectConnect; - ClientData newClient; - Vector3f hsv; - hsv[0] = Random::get().real_range(0.0f, 360.0f); - hsv[1] = Random::get().real_range(0.3f, 0.7f); - hsv[2] = 1.0; - newClient.cursorColor = hsv_to_rgb(hsv); - newClient.canvasScale = data.canvasScale; - message(newClient.displayName, isDirectConnect); - ensure_display_name_unique(newClient.displayName); - - if(isDirectConnect) { - fileDisplayName = newClient.displayName; - message(newClient.camCoords, newClient.windowSize); - } - else { - auto& [randomClientServerID, randomClient] = *clients.begin(); - newClient.camCoords = randomClient.camCoords; - newClient.windowSize = randomClient.windowSize; - } - - newClient.serverID = Random::get().int_range(1, std::numeric_limits::max()); - client->customID = newClient.serverID; - netServer->send_items_to_all_clients_except(client, RELIABLE_COMMAND_CHANNEL, CLIENT_USER_CONNECT, newClient.serverID, newClient.displayName, newClient.cursorColor); - if(isDirectConnect) - netServer->send_items_to_client(client, RELIABLE_COMMAND_CHANNEL, CLIENT_INITIAL_DATA, isDirectConnect, newClient.serverID, newClient.cursorColor); - else { - auto ss(std::make_shared()); - { - cereal::PortableBinaryOutputArchive a(*ss); - a(CLIENT_INITIAL_DATA, isDirectConnect, newClient.serverID, newClient.cursorColor, newClient.displayName, newClient.camCoords, newClient.windowSize, fileDisplayName, clients, data); - world.bMan.bookmarks.write_create_message(a); - world.gridMan.grids.write_create_message(a); - world.drawProg.write_components_server(a); - world.canvasTheme.write_create_message(a); - } - netServer->send_string_stream_to_client(client, RELIABLE_COMMAND_CHANNEL, ss); - for(auto& r : world.rMan.resource_list()) { - netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_ID, r.get_net_id()); - netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_DATA, *r); - } - } - clients.emplace(newClient.serverID, newClient); - }); - netServer->add_recv_callback(SERVER_UPDATE_NETWORK_OBJECT, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - world.netObjMan.read_update_message(message, client); - }); - netServer->add_recv_callback(SERVER_MOVE_CAMERA, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - auto& c = clients[client->customID]; - message(c.camCoords, c.windowSize); - netServer->send_items_to_all_clients_except(client, RELIABLE_COMMAND_CHANNEL, CLIENT_MOVE_CAMERA, c.serverID, c.camCoords, c.windowSize); - }); - netServer->add_recv_callback(SERVER_MOVE_SCREEN_MOUSE, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - auto& c = clients[client->customID]; - message(c.cursorPos); - netServer->send_items_to_all_clients_except(client, UNRELIABLE_COMMAND_CHANNEL, CLIENT_MOVE_SCREEN_MOUSE, c.serverID, c.cursorPos); - }); - netServer->add_recv_callback(SERVER_KEEP_ALIVE, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - }); - netServer->add_disconnect_callback([&](std::shared_ptr client) { - auto it = clients.find(client->customID); - if(it != clients.end()) { - netServer->send_items_to_all_clients_except(client, RELIABLE_COMMAND_CHANNEL, CLIENT_USER_DISCONNECT, client->customID); - clients.erase(it); - } - }); -} - -void MainServer::ensure_display_name_unique(std::string& displayName) { - for(;;) { - bool isUnique = true; - for(auto& [id, client] : clients) { - if(client.displayName == displayName) { - size_t leftParenthesisIndex = displayName.find_last_of('('); - size_t rightParenthesisIndex = displayName.find_last_of(')'); - bool failToIncrement = true; - if(leftParenthesisIndex != std::string::npos && rightParenthesisIndex != std::string::npos && leftParenthesisIndex < rightParenthesisIndex) { - std::string numStr = displayName.substr(leftParenthesisIndex + 1, rightParenthesisIndex - leftParenthesisIndex - 1); - bool isAllDigits = true; - for(char c : numStr) { - if(!isdigit(c)) { - isAllDigits = false; - break; - } - } - if(isAllDigits) { - try { - int s = std::stoi(numStr); - s++; - displayName = displayName.substr(0, leftParenthesisIndex); - displayName += "(" + std::to_string(s) + ")"; - failToIncrement = false; - } - catch(...) {} - } - } - if(failToIncrement) - displayName += " (2)"; - isUnique = false; - break; - } - } - if(isUnique) - break; - } -} - -void MainServer::update() { - netServer->update(); - if(std::chrono::steady_clock::now() - lastKeepAliveSent > std::chrono::seconds(2)) { - netServer->send_items_to_all_clients(UNRELIABLE_COMMAND_CHANNEL, CLIENT_KEEP_ALIVE); - lastKeepAliveSent = std::chrono::steady_clock::now(); - } -} - -MainServer::~MainServer() { - //netServer->close_server(); -} diff --git a/src/Server/MainServer.hpp b/src/Server/MainServer.hpp deleted file mode 100644 index fc9a80e..0000000 --- a/src/Server/MainServer.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once -#include -#include -#include "ClientData.hpp" -#include "Helpers/Networking/NetLibrary.hpp" -#include "ServerData.hpp" - -class MainServer { - public: - MainServer(World& initWorld, const std::string& serverLocalID); - void update(); - ~MainServer(); - std::shared_ptr netServer; - std::unordered_map clients; - private: - World& world; - void ensure_display_name_unique(std::string& displayName); - ServerData data; - std::string fileDisplayName; - std::chrono::steady_clock::time_point lastKeepAliveSent; -}; diff --git a/src/Server/ServerData.cpp b/src/Server/ServerData.cpp deleted file mode 100644 index 9f9568d..0000000 --- a/src/Server/ServerData.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "ServerData.hpp" - -void ServerData::save(cereal::PortableBinaryOutputArchive& a) const { - a(canvasScale); -} - -void ServerData::load(cereal::PortableBinaryInputArchive& a) { - a(canvasScale); -} - -void ServerData::scale_up(const WorldScalar& scaleUpAmount) { -} diff --git a/src/Server/ServerData.hpp b/src/Server/ServerData.hpp deleted file mode 100644 index 95fec19..0000000 --- a/src/Server/ServerData.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include "cereal/archives/portable_binary.hpp" -#include "../SharedTypes.hpp" -#include "../ResourceManager.hpp" -#include "../WorldGrid.hpp" - -class DrawComponent; - -class ServerData { - public: - uint64_t canvasScale = 0; - - void save(cereal::PortableBinaryOutputArchive& a) const; - void load(cereal::PortableBinaryInputArchive& a); - void scale_up(const WorldScalar& scaleUpAmount); -}; diff --git a/src/SharedTypes.hpp b/src/SharedTypes.hpp index a218e7d..e254914 100644 --- a/src/SharedTypes.hpp +++ b/src/SharedTypes.hpp @@ -10,26 +10,7 @@ using namespace Eigen; typedef Vector WorldVec; -enum DrawComponentType : uint8_t { - DRAWCOMPONENT_BRUSHSTROKE = 0, - DRAWCOMPONENT_RECTANGLE, - DRAWCOMPONENT_ELLIPSE, - DRAWCOMPONENT_TEXTBOX, - DRAWCOMPONENT_IMAGE -}; - -typedef uint64_t ClientPortionID; -typedef uint64_t ServerPortionID; -typedef std::pair ServerClientID; - -template <> struct std::hash { - size_t operator()(const ServerClientID& v) const - { - uint64_t h = 0; - hash_combine(h, v.first, v.second); - return h; - } -}; +typedef uint64_t NetClientID; template std::ostream& operator<<(std::ostream& os, const std::pair& p) { os << p.first << ", " << p.second; diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index 2cd04f9..96927c3 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -1275,33 +1275,37 @@ void Toolbar::player_list() { gui.obstructing_window(); gui.push_id("client list"); gui.text_label_centered("Player List"); - gui.left_to_right_line_layout([&]() { - CLAY_AUTO_ID({ - .layout = { - .sizing = {.width = CLAY_SIZING_FIXED(20), .height = CLAY_SIZING_FIXED(20)} - }, - .backgroundColor = convert_vec4(SkColor4f{main.world->userColor.x(), main.world->userColor.y(), main.world->userColor.z(), 1.0f}), - .cornerRadius = CLAY_CORNER_RADIUS(3) - }) {} - gui.text_label(main.world->displayName); - }); - size_t num = 0; - for(auto& [id, client] : main.world->clients) { - gui.push_id(num++); + if(!main.world->clientStillConnecting) { gui.left_to_right_line_layout([&]() { CLAY_AUTO_ID({ .layout = { .sizing = {.width = CLAY_SIZING_FIXED(20), .height = CLAY_SIZING_FIXED(20)} }, - .backgroundColor = convert_vec4(SkColor4f{client.cursorColor.x(), client.cursorColor.y(), client.cursorColor.z(), 1.0f}), + .backgroundColor = convert_vec4(SkColor4f{main.world->ownClientData->get_cursor_color().x(), main.world->ownClientData->get_cursor_color().y(), main.world->ownClientData->get_cursor_color().z(), 1.0f}), .cornerRadius = CLAY_CORNER_RADIUS(3) }) {} - gui.text_label(client.displayName); - CLAY_AUTO_ID({.layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}}}) {} - if(gui.text_button("teleport button", "Jump To")) - main.world->drawData.cam.smooth_move_to(*main.world, client.camCoords, client.windowSize); + gui.text_label(main.world->ownClientData->get_display_name()); }); - gui.pop_id(); + size_t num = 0; + for(auto& client : main.world->clients->get_data()) { + if(client != main.world->ownClientData) { + gui.push_id(num++); + gui.left_to_right_line_layout([&]() { + CLAY_AUTO_ID({ + .layout = { + .sizing = {.width = CLAY_SIZING_FIXED(20), .height = CLAY_SIZING_FIXED(20)} + }, + .backgroundColor = convert_vec4(SkColor4f{client->get_cursor_color().x(), client->get_cursor_color().y(), client->get_cursor_color().z(), 1.0f}), + .cornerRadius = CLAY_CORNER_RADIUS(3) + }) {} + gui.text_label(client->get_display_name()); + CLAY_AUTO_ID({.layout = {.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)}}}) {} + if(gui.text_button("teleport button", "Jump To")) + main.world->drawData.cam.smooth_move_to(*main.world, client->get_cam_coords(), client->get_window_size()); + }); + gui.pop_id(); + } + } } if(gui.text_button_wide("close list", "Done")) playerMenuOpen = false; diff --git a/src/Toolbar.hpp b/src/Toolbar.hpp index c0ca6a9..a0810b6 100644 --- a/src/Toolbar.hpp +++ b/src/Toolbar.hpp @@ -2,7 +2,6 @@ #include "GUIStuff/GUIManager.hpp" #include "DrawData.hpp" #include "Helpers/FileDownloader.hpp" -#include "Server/CommandList.hpp" #include #include #include diff --git a/src/World.cpp b/src/World.cpp index ca8a888..a5c15fa 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -8,7 +8,9 @@ #include #include #include -#include "Server/CommandList.hpp" +#include "Helpers/NetworkingObjects/NetObjTemporaryPtr.decl.hpp" +#include "Helpers/NetworkingObjects/NetObjUnorderedSet.hpp" +#include "CommandList.hpp" #include "MainProgram.hpp" #include "SharedTypes.hpp" #include "Toolbar.hpp" @@ -42,13 +44,12 @@ World::World(MainProgram& initMain, OpenWorldInfo& worldInfo): canvasTheme(*this) { init_net_obj_type_list(); + init_client_data_list(); gridMan.init(); bMan.init(); drawProg.init(); canvasTheme.init(); - displayName = main.displayName; - netSource = worldInfo.netSource; if(worldInfo.conType == CONNECTIONTYPE_CLIENT || worldInfo.conType == CONNECTIONTYPE_SERVER) @@ -76,9 +77,36 @@ World::World(MainProgram& initMain, OpenWorldInfo& worldInfo): } } - rMan.init_client_callbacks(); init_client_callbacks(); - con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_INITIAL_DATA, displayName, false); + con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_INITIAL_DATA, main.displayName); +} + +void World::init_client_data_list() { + if(netObjMan.is_server()) { + clients = netObjMan.make_obj>(); + ownClientData = clients->emplace_direct(clients, ClientData::InitStruct{ + .cursorColor = get_random_cursor_color(), + .displayName = main.displayName + }); + init_client_data_list_callbacks(); + } +} + +Vector3f World::get_random_cursor_color() { + Vector3f hsv; + hsv[0] = Random::get().real_range(0.0f, 360.0f); + hsv[1] = Random::get().real_range(0.3f, 0.7f); + hsv[2] = 1.0; + return hsv_to_rgb(hsv); +} + +void World::init_client_data_list_callbacks() { + clients->set_insert_callback([&](const NetworkingObjects::NetObjOwnerPtr& objPtr) { + add_chat_message(objPtr->get_display_name(), "joined", Toolbar::ChatMessage::Type::JOIN); + }); + clients->set_erase_callback([&](const NetworkingObjects::NetObjOwnerPtr& objPtr) { + add_chat_message(objPtr->get_display_name(), "left", Toolbar::ChatMessage::Type::JOIN); + }); } void World::init_net_obj_type_list() { @@ -90,83 +118,74 @@ void World::init_net_obj_type_list() { CanvasComponentContainer::register_class(netObjMan); NetworkingObjects::register_ordered_list_class(netObjMan); canvasTheme.register_class(); + ClientData::register_class(*this); + NetworkingObjects::register_unordered_set_class(netObjMan); } void World::init_server_callbacks() { - con.localServer->netServer->add_recv_callback(SERVER_CHAT_MESSAGE, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { - std::string chatMessage; - message(chatMessage); - add_chat_message(clients[client->customID].displayName, chatMessage, Toolbar::ChatMessage::Type::NORMAL); - con.localServer->netServer->send_items_to_all_clients_except(client, RELIABLE_COMMAND_CHANNEL, CLIENT_CHAT_MESSAGE, client->customID, chatMessage); + rMan.init_server_callbacks(); + netServer->add_recv_callback(SERVER_INITIAL_DATA, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { + std::cout << "Received server init data" << std::endl; + ClientData::InitStruct newClientData; + newClientData.cursorColor = get_random_cursor_color(); + message(newClientData.displayName); + ensure_display_name_unique(newClientData.displayName); + + newClientData.camCoords = ownClientData->get_cam_coords(); + newClientData.windowSize = ownClientData->get_window_size(); + + NetworkingObjects::NetObjTemporaryPtr clientDataObjPtr = clients->emplace_direct(clients, newClientData); + client->customID = clientDataObjPtr.get_net_id().data; + auto ss(std::make_shared()); + { + cereal::PortableBinaryOutputArchive a(*ss); + a(CLIENT_INITIAL_DATA, name, clientDataObjPtr.get_net_id()); + bMan.bookmarks.write_create_message(a); + gridMan.grids.write_create_message(a); + drawProg.write_components_server(a); + canvasTheme.write_create_message(a); + clients.write_create_message(a); + } + netServer->send_string_stream_to_client(client, RELIABLE_COMMAND_CHANNEL, ss); + for(auto& r : rMan.resource_list()) { + netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_ID, r.get_net_id()); + netServer->send_items_to_client(client, RESOURCE_COMMAND_CHANNEL, CLIENT_NEW_RESOURCE_DATA, *r); + } + }); + netServer->add_recv_callback(SERVER_UPDATE_NETWORK_OBJECT, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { + netObjMan.read_update_message(message, client); + }); + netServer->add_recv_callback(SERVER_KEEP_ALIVE, [&](std::shared_ptr client, cereal::PortableBinaryInputArchive& message) { + }); + netServer->add_disconnect_callback([&](std::shared_ptr client) { + NetworkingObjects::NetObjID idToErase; + idToErase.data = client->customID; + clients->erase(clients, idToErase); }); } void World::init_client_callbacks() { + rMan.init_client_callbacks(); con.client_add_recv_callback(CLIENT_INITIAL_DATA, [&](cereal::PortableBinaryInputArchive& message) { - bool isDirectConnect; - message(isDirectConnect, ownID, userColor); - if(!isDirectConnect) { - std::string fileDisplayName; - CoordSpaceHelper camCoordsToMoveTo; - Vector2f windowSizeToMoveTo; - message(displayName); - message(camCoordsToMoveTo); - message(windowSizeToMoveTo); - message(fileDisplayName); - message(clients); - set_name(fileDisplayName); - drawData.cam.smooth_move_to(*main.world, camCoordsToMoveTo, windowSizeToMoveTo, true); - message(canvasScale); - bMan.bookmarks = netObjMan.read_create_message>(message, nullptr); - gridMan.grids = netObjMan.read_create_message>(message, nullptr); - drawProg.read_components_client(message); - canvasTheme.read_create_message(message); - } + std::cout << "Received client init data" << std::endl; + std::string fileDisplayName; + NetworkingObjects::NetObjID clientDataObjID; + message(fileDisplayName, clientDataObjID); + set_name(fileDisplayName); + bMan.bookmarks = netObjMan.read_create_message>(message, nullptr); + gridMan.grids = netObjMan.read_create_message>(message, nullptr); + drawProg.read_components_client(message); + canvasTheme.read_create_message(message); + + clients = netObjMan.read_create_message>(message, nullptr); + init_client_data_list_callbacks(); + ownClientData = netObjMan.get_obj_from_id(clientDataObjID); + drawData.cam.smooth_move_to(*main.world, ownClientData->get_cam_coords(), ownClientData->get_window_size(), true); + clientStillConnecting = false; }); - con.client_add_recv_callback(CLIENT_USER_CONNECT, [&](cereal::PortableBinaryInputArchive& message) { - ServerPortionID id; - std::string displayName; - Vector3f cursorColor; - message(id, displayName, cursorColor); - clients[id].displayName = displayName; - clients[id].cursorColor = cursorColor; - add_chat_message(clients[id].displayName, "joined", Toolbar::ChatMessage::Type::JOIN); - }); con.client_add_recv_callback(CLIENT_UPDATE_NETWORK_OBJECT, [&](cereal::PortableBinaryInputArchive& message) { - if(!con.host_exists() && !clientStillConnecting) // Dont update a direct connected client (which is just the server), and dont process these until the CLIENT_INITIAL_DATA message is received first - netObjMan.read_update_message(message, nullptr); - }); - con.client_add_recv_callback(CLIENT_USER_DISCONNECT, [&](cereal::PortableBinaryInputArchive& message) { - ServerPortionID id; - message(id); - auto it = clients.find(id); - if(it != clients.end()) { - add_chat_message(clients[id].displayName, "left", Toolbar::ChatMessage::Type::JOIN); - clients.erase(id); - } - }); - con.client_add_recv_callback(CLIENT_MOVE_CAMERA, [&](cereal::PortableBinaryInputArchive& message) { - ServerPortionID id; - message(id); - auto& c = clients[id]; - message(c.camCoords, c.windowSize); - }); - con.client_add_recv_callback(CLIENT_MOVE_SCREEN_MOUSE, [&](cereal::PortableBinaryInputArchive& message) { - ServerPortionID id; - message(id); - auto& c = clients[id]; - message(c.cursorPos); - }); - con.client_add_recv_callback(CLIENT_CHAT_MESSAGE, [&](cereal::PortableBinaryInputArchive& message) { - if(!con.host_exists() && !clientStillConnecting) { // Dont update a direct connected client (which is just the server), and dont process these until the CLIENT_INITIAL_DATA message is received first - ServerPortionID senderID; - std::string chatMessage; - message(senderID, chatMessage); - auto it = clients.find(senderID); - if(it != clients.end()) - add_chat_message(clients[senderID].displayName, chatMessage, Toolbar::ChatMessage::Type::NORMAL); - } + netObjMan.read_update_message(message, nullptr); }); con.client_add_recv_callback(CLIENT_KEEP_ALIVE, [&](cereal::PortableBinaryInputArchive& message) { }); @@ -175,11 +194,10 @@ void World::init_client_callbacks() { void World::focus_update() { con.update(); - if(con.is_host_disconnected()) { + if(netServer && netServer->is_disconnected()) { Logger::get().log("USERINFO", "Host connection failed"); - clientStillConnecting = false; - clients.clear(); netSource.clear(); + netServer = nullptr; conType = CONNECTIONTYPE_LOCAL; con = ConnectionManager(); } @@ -196,15 +214,10 @@ void World::focus_update() { timeToSendCameraData.update_time_since(); if(timeToSendCameraData.get_time_since() > SECONDS_TO_SEND_CAMERA_DATA) { timeToSendCameraData.update_time_point(); - if(!sentCameraData.has_value() || (sentCameraData.value().windowSize != main.window.size.cast().eval() || sentCameraData.value().camTransform != drawData.cam.c)) { - con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_MOVE_CAMERA, drawData.cam.c, main.window.size.cast().eval()); - sentCameraData = { - .camTransform = drawData.cam.c, - .windowSize = main.window.size.cast() - }; - } + ownClientData->set_window_size(ownClientData, main.window.size.cast().eval()); + ownClientData->set_camera_coords(ownClientData, drawData.cam.c); } - con.client_send_items_to_server(UNRELIABLE_COMMAND_CHANNEL, SERVER_MOVE_SCREEN_MOUSE, main.input.mouse.pos); + ownClientData->set_cursor_pos(ownClientData, main.input.mouse.pos); drawProg.update(); } @@ -237,16 +250,18 @@ void World::unfocus_update() { Logger::get().log("USERINFO", "Client connection failed"); setToDestroy = true; } + if(netServer) { + netServer->update(); + if(std::chrono::steady_clock::now() - lastKeepAliveSent > std::chrono::seconds(2)) { + netServer->send_items_to_all_clients(UNRELIABLE_COMMAND_CHANNEL, CLIENT_KEEP_ALIVE); + lastKeepAliveSent = std::chrono::steady_clock::now(); + } + } } void World::send_chat_message(const std::string& message) { - if(!clientStillConnecting) { - if(con.localServer) - con.localServer->netServer->send_items_to_all_clients(RELIABLE_COMMAND_CHANNEL, CLIENT_CHAT_MESSAGE, ownID, message); - else - con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_CHAT_MESSAGE, message); - add_chat_message(displayName, message, Toolbar::ChatMessage::Type::NORMAL); - } + if(!clientStillConnecting) + ownClientData->send_chat_message(ownClientData, *this, message); } void World::add_chat_message(const std::string& name, const std::string& message, Toolbar::ChatMessage::Type type) { @@ -279,18 +294,55 @@ void World::set_name(const std::string& n) { name = n; } +void World::ensure_display_name_unique(std::string& displayName) { + for(;;) { + bool isUnique = true; + for(auto& client : clients->get_data()) { + if(client->get_display_name() == displayName) { + size_t leftParenthesisIndex = displayName.find_last_of('('); + size_t rightParenthesisIndex = displayName.find_last_of(')'); + bool failToIncrement = true; + if(leftParenthesisIndex != std::string::npos && rightParenthesisIndex != std::string::npos && leftParenthesisIndex < rightParenthesisIndex) { + std::string numStr = displayName.substr(leftParenthesisIndex + 1, rightParenthesisIndex - leftParenthesisIndex - 1); + bool isAllDigits = true; + for(char c : numStr) { + if(!isdigit(c)) { + isAllDigits = false; + break; + } + } + if(isAllDigits) { + try { + int s = std::stoi(numStr); + s++; + displayName = displayName.substr(0, leftParenthesisIndex); + displayName += "(" + std::to_string(s) + ")"; + failToIncrement = false; + } + catch(...) {} + } + } + if(failToIncrement) + displayName += " (2)"; + isUnique = false; + break; + } + } + if(isUnique) + break; + } +} + void World::start_hosting(const std::string& initNetSource, const std::string& serverLocalID) { if(conType != CONNECTIONTYPE_LOCAL) return; main.init_net_library(); - con.init_local_p2p(*this, serverLocalID); - rMan.init_client_callbacks(); - rMan.init_server_callbacks(); - init_client_callbacks(); - con.client_send_items_to_server(RELIABLE_COMMAND_CHANNEL, SERVER_INITIAL_DATA, displayName, true, drawData.cam.c, main.window.size.cast().eval()); + netServer = std::make_shared(serverLocalID); + NetLibrary::register_server(netServer); + netObjMan.set_server(netServer, CLIENT_UPDATE_NETWORK_OBJECT); conType = CONNECTIONTYPE_SERVER; netSource = initNetSource; - clientStillConnecting = true; + init_server_callbacks(); } void World::save_to_file(const std::filesystem::path& filePathToSaveAt) { @@ -409,34 +461,10 @@ WorldScalar World::calculate_zoom_from_uniform_zoom(WorldScalar uniformZoom, Wor } void World::draw_other_player_cursors(SkCanvas* canvas, const DrawData& drawData) { - for(auto& [id, data] : clients) { - if((drawData.cam.c.inverseScale << 10) > data.camCoords.inverseScale && drawData.clampDrawMinimum < data.camCoords.inverseScale) { - canvas->save(); - data.camCoords.transform_sk_canvas(canvas, drawData); - - canvas->translate(data.cursorPos.x(), data.cursorPos.y()); - - SkPaint p(SkColor4f{data.cursorColor.x(), data.cursorColor.y(), data.cursorColor.z(), 0.2f}); - canvas->drawCircle(0.0f, 0.0f, 4.5f, p); - p.setStroke(true); - p.setStrokeWidth(1.0f); - p.setColor4f({data.cursorColor.x(), data.cursorColor.y(), data.cursorColor.z(), 0.7f}); - canvas->drawCircle(0.0f, 0.0f, 5.0f, p); - - SkFont f = main.toolbar.io->get_font(18.0f); - SkFontMetrics metrics; - f.getMetrics(&metrics); - - float nextText = f.measureText(data.displayName.c_str(), data.displayName.length(), SkTextEncoding::kUTF8, nullptr); - Vector2f bounds{nextText, - metrics.fAscent + metrics.fDescent}; - - SkPaint p2(SkColor4f{data.cursorColor.x(), data.cursorColor.y(), data.cursorColor.z(), 0.5f}); - canvas->drawSimpleText(data.displayName.c_str(), data.displayName.length(), SkTextEncoding::kUTF8, 6.0f, -metrics.fDescent, f, p2); - - SkPaint p3(color_mul_alpha(main.toolbar.io->theme->backColor1, 0.5f)); - canvas->drawRoundRect(SkRect::MakeXYWH(6.0f, -bounds.y(), bounds.x(), bounds.y()), 3.0f, 3.0f, p3); - - canvas->restore(); + if(clients) { + for(auto& clientDataPtr : clients->get_data()) { + if(clientDataPtr != ownClientData) + clientDataPtr->draw_cursor(canvas, drawData); } } } diff --git a/src/World.hpp b/src/World.hpp index 6044efb..b3f315e 100644 --- a/src/World.hpp +++ b/src/World.hpp @@ -1,6 +1,7 @@ #pragma once #include #include +#include "Helpers/NetworkingObjects/NetObjUnorderedSet.hpp" #include "UndoManager.hpp" #include "BookmarkManager.hpp" #include "ResourceManager.hpp" @@ -12,6 +13,7 @@ #include "GridManager.hpp" #include #include +#include "ClientData.hpp" class MainProgram; @@ -56,8 +58,6 @@ class World { std::deque chatMessages; std::string netSource; - - std::string displayName; void start_hosting(const std::string& initNetSource, const std::string& serverLocalID); @@ -86,39 +86,37 @@ class World { void undo_with_checks(); void redo_with_checks(); - ServerPortionID ownID = 0; - std::filesystem::path filePath; - Vector3f userColor = {0.0f, 0.0f, 0.0f}; std::string name; - std::unordered_map clients; + + NetworkingObjects::NetObjTemporaryPtr ownClientData; + NetworkingObjects::NetObjOwnerPtr> clients; CanvasTheme canvasTheme; void scale_up(const WorldScalar& scaleUpAmount); void scale_up_step(); - uint64_t canvasScale = 0; - bool setToDestroy = false; NetworkingObjects::DelayUpdateSerializedClassManager delayedUpdateObjectManager; - private: - void init_net_obj_type_list(); + std::shared_ptr netServer; + private: + Vector3f get_random_cursor_color(); + void init_client_data_list(); + void init_client_data_list_callbacks(); + void init_net_obj_type_list(); void init_client_callbacks(); void init_server_callbacks(); void set_name(const std::string& n); void draw_other_player_cursors(SkCanvas* canvas, const DrawData& drawData); + void ensure_display_name_unique(std::string& displayName); TimePoint timeToSendCameraData; - struct SentCameraData { - CoordSpaceHelper camTransform; - Vector2f windowSize; - }; - std::optional sentCameraData; - WorldVec mousePreviousWorldVec = {0, 0}; WorldVec mouseWorldMove = {0, 0}; + + std::chrono::steady_clock::time_point lastKeepAliveSent; };