From 38337fadd8922f2ff998e0717c98d3c3f77e3253 Mon Sep 17 00:00:00 2001 From: isplatonov Date: Sun, 10 Sep 2023 19:51:19 +0300 Subject: [PATCH] refactor, another way to store & transfer objects --- include/Actor.hpp | 6 +-- include/LinearAlgebra.hpp | 11 +++-- include/Multiplayer.hpp | 10 ++-- include/WorldMap.hpp | 3 +- src/Actor.cpp | 9 ++-- src/Controls.cpp | 99 +++++++++++++++++++++++++++++++++------ src/LinearAlgebra.cpp | 18 ------- src/Multiplayer.cpp | 78 ++++++++++++++++++++---------- src/Object.cpp | 4 +- src/WorldMap.cpp | 4 +- src/server/server.cpp | 6 +-- 11 files changed, 166 insertions(+), 82 deletions(-) diff --git a/include/Actor.hpp b/include/Actor.hpp index 08c6cc1..44ecbae 100644 --- a/include/Actor.hpp +++ b/include/Actor.hpp @@ -23,7 +23,7 @@ namespace Actor Actor(const Actor&); Actor(const sf::Vector2f& position, const std::unordered_map& inventory); Actor(sf::Vector2f&& position, std::unordered_map&& inventory); - sf::Vector2f&& move_dt(const sf::Vector2f& direction, const sf::Uint32& dt, const WorldMap::ObjectMap& ObjectMap = {}); + sf::Vector2f&& move_dt(const sf::Vector2f& direction, const sf::Uint32& dt, WorldMap::ObjectMap& ObjectMap); void check_direction(const sf::Vector2f&); const sf::Vector2f& getPosition() const; const sf::Sprite& getSprite() const; @@ -54,7 +54,7 @@ namespace Actor { public: using Actor::Actor; - void make_step(const sf::Uint32& dt, const WorldMap::ObjectMap& ObjectMap = {}); + void make_step(const sf::Uint32& dt, WorldMap::ObjectMap& ObjectMap); private: sf::Vector2f prev_move_direction = linalg::normalize(sf::Vector2f(std::rand() % 10 - 10 / 2, std::rand() % 10 - 10 / 2)); @@ -70,7 +70,7 @@ namespace Actor public: User(const sf::Vector2f& position, const std::unordered_map& inventory = {}); User(sf::Vector2f&& position, std::unordered_map&& inventory = {}); - sf::Vector2f&& move_dt(const sf::Vector2f& direction, const sf::Uint32& dt, const WorldMap::ObjectMap& ObjectMap = {}); + sf::Vector2f&& move_dt(const sf::Vector2f& direction, const sf::Uint32& dt, WorldMap::ObjectMap& ObjectMap); const sf::View& getView() const; const int& getIp() const; const int& getLocalIp() const; diff --git a/include/LinearAlgebra.hpp b/include/LinearAlgebra.hpp index e8dbcad..74ae31d 100644 --- a/include/LinearAlgebra.hpp +++ b/include/LinearAlgebra.hpp @@ -6,7 +6,14 @@ namespace linalg { - sf::Vector2f normalize(const sf::Vector2f& v); + inline float magnitude(const sf::Vector2f& v) { + return std::sqrt(v.x * v.x + v.y * v.y); + } + + + inline sf::Vector2f normalize(const sf::Vector2f& v) { + return v == sf::Vector2f(0.f, 0.f) ? v : v / magnitude(v); + } /*Vector2& rotateBy(float degrees, const Vector2& center=Vector2()) { @@ -47,6 +54,4 @@ namespace linalg else return 180.0+atan(-y/-x) * 180.f/3.14159f; }*/ - - float magnitude(const sf::Vector2f& v); } diff --git a/include/Multiplayer.hpp b/include/Multiplayer.hpp index ef0a31d..d455ced 100644 --- a/include/Multiplayer.hpp +++ b/include/Multiplayer.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -88,6 +89,7 @@ namespace Multiplayer ObjectData(sf::Vector2f position, sf::Uint32 time, Object::ObjectName object_name, Object::Passability passability); const Object::ObjectName& getName() const; const Object::Passability& getPassability() const; + inline bool operator ==(const ObjectData& object_data) const { return object_name == object_data.getName() && passability == object_data.getPassability(); } private: Object::ObjectName object_name; @@ -105,9 +107,10 @@ namespace Multiplayer sf::Socket::Status receive(); sf::Socket::Status send(sf::Packet& packet, const sf::IpAddress& dest_ip = sf::IpAddress()); const std::unordered_map& getPlayerDataPool() const; - const std::unordered_map& getObjectDataPool() const; + const std::unordered_map>& getObjectDataPool() const; + inline void clearObjectDataPool() { object_data_pool.clear();} std::unordered_map::iterator removePlayerById(const std::string& id); - std::unordered_map::iterator removeObjectByPoint(const sf::Vector2f& point); + std::unordered_map>::iterator removeObjectByPoint(const ObjectData& point); void addObject(const Object::Object& object); void addObject(const Multiplayer::ObjectData& object_data); ObjectData getRemovedObjectData(); @@ -123,7 +126,8 @@ namespace Multiplayer /*static*/ unsigned short port; /*static*/ unsigned short port_send; /*static*/ std::unordered_map player_data_pool; - /*static*/ std::unordered_map object_data_pool; + /*static*/ std::unordered_map> object_data_pool; + /*static*/ /* std::unordered_map terrain_data_pool; */ /*static*/ std::vector removed_object_data_list; /*static*/ std::vector objects_to_inventory_list; #ifndef CLIENT diff --git a/include/WorldMap.hpp b/include/WorldMap.hpp index 8a4f37d..06e3951 100644 --- a/include/WorldMap.hpp +++ b/include/WorldMap.hpp @@ -39,10 +39,9 @@ namespace WorldMap { public: ObjectMap(); - const std::unordered_map& getObjectMap(const Object::Passability&) const; + std::unordered_map& getObjectMap(const Object::Passability&); void addObject(const Multiplayer::ObjectData&); void removeObject(const Multiplayer::ObjectData&); - void removeObject(const Object::Object&); private: std::unordered_map background_objects; diff --git a/src/Actor.cpp b/src/Actor.cpp index af91a60..d35c749 100644 --- a/src/Actor.cpp +++ b/src/Actor.cpp @@ -51,11 +51,12 @@ namespace Actor } - sf::Vector2f&& Actor::move_dt(const sf::Vector2f& direction, const sf::Uint32& dt, const WorldMap::ObjectMap& ObjectMap) + sf::Vector2f&& Actor::move_dt(const sf::Vector2f& direction, const sf::Uint32& dt, WorldMap::ObjectMap& ObjectMap) { check_direction(direction); auto v = new sf::Vector2f(linalg::normalize(direction) * static_cast(dt) * Constants::getSTEP_SIZE_MULTIPLIER() * static_cast(Constants::getPIXEL_SIZE())); - for (const auto& object : ObjectMap.getObjectMap(Object::Passability::impassible)) + const auto& im = ObjectMap.getObjectMap(Object::Passability::impassible); + for (const auto& object : im) { object.second.check_collision(*v, this->getSprite().getGlobalBounds()); } @@ -109,7 +110,7 @@ namespace Actor } - sf::Vector2f&& User::move_dt(const sf::Vector2f& direction, const sf::Uint32& dt, const WorldMap::ObjectMap& ObjectMap) + sf::Vector2f&& User::move_dt(const sf::Vector2f& direction, const sf::Uint32& dt, WorldMap::ObjectMap& ObjectMap) { auto v = new sf::Vector2f(Actor::move_dt(direction, dt, ObjectMap)); view.move(*v); @@ -140,7 +141,7 @@ namespace Actor } - void Bot::make_step(const sf::Uint32& dt, const WorldMap::ObjectMap& ObjectMap) + void Bot::make_step(const sf::Uint32& dt, WorldMap::ObjectMap& ObjectMap) { prev_move_direction = linalg::normalize(linalg::normalize(sf::Vector2f(std::rand() % 11 - 11 / 2, std::rand() % 11 - 11 / 2)) * .2f + prev_move_direction * .8f); move_dt(prev_move_direction, dt, ObjectMap); diff --git a/src/Controls.cpp b/src/Controls.cpp index bb68f0a..72cdf17 100644 --- a/src/Controls.cpp +++ b/src/Controls.cpp @@ -134,7 +134,7 @@ void Controls::addEvent(const sf::Event& event) sf::Vector2f Controls::getDirection() { - return linalg::normalize(sf::Vector2f(right * 1.f - left * 1.f, down * 1.f - up * 1.f)); + return linalg::normalize(sf::Vector2f((right ? 1.f : 0.f) - (left ? 1.f : 0.f), (down ? 1.f : 0.f) - (up ? 1.f : 0.f))); } @@ -230,30 +230,32 @@ void Controls::handleFrameStep() // handling player_data_pool for (auto iter = udp_manager.getPlayerDataPool().begin(); iter != udp_manager.getPlayerDataPool().end();) { - auto time = (*iter).second.getTime(); + auto time = iter->second.getTime(); sf::Uint32 time_now = static_cast(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()); int ping = static_cast(time_now) - static_cast(time); - if (!player_pool.count((*iter).first)) + if (!player_pool.count(iter->first)) { - player_pool[(*iter).first] = Actor::Player((*iter).second); + player_pool[iter->first] = Actor::Player(iter->second); ++iter; continue; } else if (ping > Constants::getMAX_PING()) { - player_pool.erase((*iter).first); - udp_manager.removePlayerById((*iter++).first); + player_pool.erase(iter->first); + udp_manager.removePlayerById(iter++->first); continue; } else { - player_pool[(*iter).first] << (*iter).second; + player_pool[iter->first] << iter->second; ++iter; continue; } } - for (auto iter = udp_manager.getObjectDataPool().begin(); iter != udp_manager.getObjectDataPool().end(); ++iter) - Controls::object_map.addObject((*iter).second); + for (auto& pair : udp_manager.getObjectDataPool()) + for (auto& obj : pair.second) + object_map.addObject(obj); + Controls::udp_manager.clearObjectDataPool(); for (auto object_data = udp_manager.getRemovedObjectData(); object_data.getTime() != 0; object_data = udp_manager.getRemovedObjectData()) Controls::object_map.removeObject(object_data); for (auto object_data = udp_manager.getObjectToInventoryData(); object_data.getTime() != 0; object_data = udp_manager.getObjectToInventoryData()) @@ -270,15 +272,82 @@ void Controls::handleFrameStep() window.clear(); // Draw the sprite //window.draw(WorldMap::WorldMap::map); - for (auto iter : object_map.getObjectMap(Object::Passability::background)) - window.draw(iter.second); - for (auto iter : object_map.getObjectMap(Object::Passability::impassible)) - Controls::window.draw(iter.second); + auto& bm = object_map.getObjectMap(Object::Passability::background); + for (auto iter = bm.begin(); iter != bm.end();) { + const auto& position = iter->second.getPosition(); + const auto& it_size = iter->second.getSprite().getGlobalBounds().getSize(); + const auto& center = window.getView().getCenter(); + const auto& size = window.getView().getSize(); + if (position.x + it_size.x < center.x - size.x / 2.f || + position.x > center.x + size.x / 2.f || + position.y + it_size.y < center.y - size.y / 2.f || + position.y > center.y + size.y / 2.f) { + iter = bm.erase(iter); + continue; + } + /* auto text = sf::Text(std::to_string(static_cast(position.x / Constants::getPIXEL_SIZE())) + " " + std::to_string(static_cast(position.y / Constants::getPIXEL_SIZE())), font); + text.setFillColor(sf::Color::White); + text.setPosition(position + size / 2.f); + window.draw(text); */ + + window.draw(iter->second); + ++iter; + } + auto& im = object_map.getObjectMap(Object::Passability::impassible); + for (auto iter = im.begin(); iter != im.end();) { + const auto& position = iter->second.getPosition(); + const auto& it_size = iter->second.getSprite().getGlobalBounds().getSize(); + const auto& center = window.getView().getCenter(); + const auto& size = window.getView().getSize(); + if (position.x + it_size.x < center.x - size.x / 2.f || + position.x > center.x + size.x / 2.f || + position.y + it_size.y < center.y - size.y / 2.f || + position.y > center.y + size.y / 2.f) { + iter = im.erase(iter); + continue; + } + /* auto text = sf::Text(std::to_string(static_cast(position.x / Constants::getPIXEL_SIZE())) + " " + std::to_string(static_cast(position.y / Constants::getPIXEL_SIZE())), font); + text.setFillColor(sf::Color::White); + text.setPosition(position + size / 2.f); + window.draw(text); */ + + window.draw(iter->second); + ++iter; + } for (const auto& player : player_pool) Controls::window.draw(player.second.getSprite()); Controls::window.draw(user.getSprite()); - for (auto iter : object_map.getObjectMap(Object::Passability::foreground)) - window.draw(iter.second); + auto& fm = object_map.getObjectMap(Object::Passability::foreground); + for (auto iter = fm.begin(); iter != fm.end();) { + const auto& position = iter->second.getPosition(); + const auto& it_size = iter->second.getSprite().getGlobalBounds().getSize(); + const auto& center = window.getView().getCenter(); + const auto& size = window.getView().getSize(); + if (position.x + it_size.x < center.x - size.x / 2.f || + position.x > center.x + size.x / 2.f || + position.y + it_size.y < center.y - size.y / 2.f || + position.y > center.y + size.y / 2.f) { + iter = fm.erase(iter); + continue; + } + /* auto text = sf::Text(std::to_string(static_cast(position.x / Constants::getPIXEL_SIZE())) + " " + std::to_string(static_cast(position.y / Constants::getPIXEL_SIZE())), font); + text.setFillColor(sf::Color::White); + text.setPosition(position + size / 2.f); + window.draw(text); */ + + window.draw(iter->second); + ++iter; + } + { + const auto& bm = object_map.getObjectMap(Object::Passability::background); + const auto& im = object_map.getObjectMap(Object::Passability::impassible); + const auto& fm = object_map.getObjectMap(Object::Passability::foreground); + const auto& odp = udp_manager.getObjectDataPool(); + auto text = sf::Text(std::to_string(bm.size()) + " " + std::to_string(im.size()) + " " + std::to_string(fm.size()) + " " + std::to_string(odp.size()), font); + text.setFillColor(sf::Color::White); + text.setPosition(window.getView().getCenter() - window.getView().getSize() / 2.f); + window.draw(text); + } // Draw the string //window.draw(text); window.setView(user.getView()); diff --git a/src/LinearAlgebra.cpp b/src/LinearAlgebra.cpp index c2605cb..bf47b6c 100644 --- a/src/LinearAlgebra.cpp +++ b/src/LinearAlgebra.cpp @@ -1,20 +1,2 @@ #include "LinearAlgebra.hpp" - -sf::Vector2f linalg::normalize(const sf::Vector2f& v) -{ - float m = magnitude(v); - if (m == 0) - return v; - m = (1.f / m); - - return v * m; -} - - -float linalg::magnitude(const sf::Vector2f& v) -{ - auto x = static_cast(v.x); - auto y = static_cast(v.y); - return std::sqrt(x * x + y * y); -} diff --git a/src/Multiplayer.cpp b/src/Multiplayer.cpp index d73dc6d..998f3ac 100644 --- a/src/Multiplayer.cpp +++ b/src/Multiplayer.cpp @@ -278,12 +278,15 @@ namespace Multiplayer // send foreground objects on map for (auto iter : object_data_pool) { - if (iter.second.getPassability() != Object::Passability::foreground) - continue; - data.clear(); - data << DataType::Object << iter.second; - send(data, sf::IpAddress(player_data.getLocalIp())); - sf::sleep(sf::milliseconds(1)); + for (auto obj_data : iter.second) + { + if (obj_data.getPassability() != Object::Passability::foreground) + continue; + data.clear(); + data << DataType::Object << obj_data; + send(data, sf::IpAddress(player_data.getLocalIp())); + sf::sleep(sf::milliseconds(1)); + } } if (player_data.getInventory().empty() && !player_data_pool[id].getInventory().empty()) { @@ -334,12 +337,15 @@ namespace Multiplayer // send foreground objects for (auto iter : object_data_pool) { - if (iter.second.getPassability() != Object::Passability::foreground) - continue; - data.clear(); - data << DataType::Object << iter.second; - send(data, sf::IpAddress(player_data_pool[id].getLocalIp())); - sf::sleep(sf::milliseconds(1)); + for (auto object_data : iter.second) + { + if (object_data.getPassability() != Object::Passability::foreground) + continue; + data.clear(); + data << DataType::Object << object_data; + send(data, sf::IpAddress(player_data.getLocalIp())); + sf::sleep(sf::milliseconds(1)); + } } } break; @@ -374,7 +380,7 @@ namespace Multiplayer player_data_pool[id].setPosition(player_data.getPosition()); player_data_pool[id].setTime(player_data.getTime()); player_data_pool[id].addObject(object_data.getName()); - removeObjectByPoint(object_data.getPosition()); + removeObjectByPoint(object_data); data.clear(); data << DataType::Event << EventType::removeObject << object_data; for (auto iter = getPlayerDataPool().begin(); iter != getPlayerDataPool().end(); ++iter) @@ -402,7 +408,7 @@ namespace Multiplayer // receive object ObjectData object_data; data >> object_data; - removeObjectByPoint(object_data.getPosition()); + removeObjectByPoint(object_data); break; } default: @@ -438,7 +444,7 @@ namespace Multiplayer } - const std::unordered_map& UdpManager::getObjectDataPool() const + const std::unordered_map>& UdpManager::getObjectDataPool() const { return object_data_pool; } @@ -446,35 +452,53 @@ namespace Multiplayer std::unordered_map::iterator UdpManager::removePlayerById(const std::string& id) { - if (!player_data_pool.count(id)) + auto iter = player_data_pool.find(id); + if (iter == player_data_pool.end()) return std::unordered_map::iterator(); else - return player_data_pool.erase(player_data_pool.find(id)); + return player_data_pool.erase(iter); } - std::unordered_map::iterator UdpManager::removeObjectByPoint(const sf::Vector2f& point) + std::unordered_map>::iterator UdpManager::removeObjectByPoint(const ObjectData& obj_data) { - if (!object_data_pool.count(point)) - return std::unordered_map::iterator(); + auto iter = object_data_pool.find(obj_data.getPosition() - sf::Vector2f(std::fmod(obj_data.getPosition().x, 16.f), std::fmod(obj_data.getPosition().y, 16.f))); + auto oiter = std::find(iter->second.begin(), iter->second.end(), obj_data); + if (oiter == iter->second.end()) + return std::unordered_map>::iterator(); else { - removed_object_data_list.push_back((*object_data_pool.find(point)).second); - return object_data_pool.erase(object_data_pool.find(point)); + removed_object_data_list.push_back(*oiter); + iter->second.erase(oiter); + if (iter->second.empty()) + return object_data_pool.erase(iter); + else + return iter; } } void UdpManager::addObject(const Object::Object& object) { - ObjectData object_data(object.getPosition() / static_cast(Constants::getPIXEL_SIZE()), static_cast(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()), object.getName(), object.getPassability()); - object_data_pool[object_data.getPosition()] = object_data; + ObjectData object_data( object.getPosition() / static_cast(Constants::getPIXEL_SIZE()), + static_cast(std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()), + object.getName(), + object.getPassability()); + addObject(object_data); } void UdpManager::addObject(const Multiplayer::ObjectData& object_data) { - object_data_pool[object_data.getPosition()] = object_data; + auto iter = object_data_pool.find(object_data.getPosition() - sf::Vector2f(std::fmod(object_data.getPosition().x, 16.f), std::fmod(object_data.getPosition().y, 16.f))); + if (iter == object_data_pool.end()) + { + std::vector objects; + objects.push_back(object_data); + object_data_pool[object_data.getPosition() - sf::Vector2f(std::fmod(object_data.getPosition().x, 16.f), std::fmod(object_data.getPosition().y, 16.f))] = objects; + } + else + iter->second.push_back(object_data); } @@ -562,7 +586,9 @@ namespace Multiplayer for (auto x = -Constants::getVIEW_RADIUS(); x < Constants::getVIEW_RADIUS(); ++x) { addObjectByNoise(point + sf::Vector2f(x * 16., y * 16.)); - data << object_data_pool.at(point + sf::Vector2f(x * 16., y * 16.)); + for (auto object_data : object_data_pool.at(point + sf::Vector2f(x * 16., y * 16.))) { + data << object_data; + } } } return data; diff --git a/src/Object.cpp b/src/Object.cpp index 41417ee..caba98b 100644 --- a/src/Object.cpp +++ b/src/Object.cpp @@ -98,9 +98,7 @@ namespace Object bool Object::intersection(const sf::FloatRect& new_rect) const { - auto bounds = getSprite().getGlobalBounds(); - bool f = bounds.intersects(new_rect); - return f; + return getSprite().getGlobalBounds().intersects(new_rect); } diff --git a/src/WorldMap.cpp b/src/WorldMap.cpp index ab33d6a..fd8e6fa 100644 --- a/src/WorldMap.cpp +++ b/src/WorldMap.cpp @@ -102,7 +102,7 @@ namespace WorldMap } - const std::unordered_map& ObjectMap::getObjectMap(const Object::Passability& passability) const + std::unordered_map& ObjectMap::getObjectMap(const Object::Passability& passability) { switch (passability) { @@ -119,7 +119,7 @@ namespace WorldMap break; default: - throw; + throw std::invalid_argument("invalid passability"); break; } } diff --git a/src/server/server.cpp b/src/server/server.cpp index f8f6d99..0b57985 100644 --- a/src/server/server.cpp +++ b/src/server/server.cpp @@ -38,7 +38,7 @@ void UdpWorker(Multiplayer::UdpManager& UdpManager) for (auto dest_iter = UdpManager.getPlayerDataPool().begin(); dest_iter != UdpManager.getPlayerDataPool().end();) { //std::cout << "sending " << (*iter).first << " data to " << (*dest_iter).first << std::endl; - if ((*dest_iter).first == iter.first) + if (dest_iter->first == iter.first) { //std::cout << "*dest_iter == *iter" << std::endl; ++dest_iter; @@ -48,7 +48,7 @@ void UdpWorker(Multiplayer::UdpManager& UdpManager) sf::Packet data; data << Multiplayer::DataType::Player << iter.second; - UdpManager.send(data, sf::IpAddress((*dest_iter++).second.getLocalIp())); + UdpManager.send(data, sf::IpAddress(dest_iter++->second.getLocalIp())); //std::cout << "sent" << std::endl; } } @@ -66,7 +66,7 @@ std::vector load_terrain(const std::string& path) std::vector object_data_pool_init; std::ifstream infile(path); if (!infile.is_open()) - throw; + throw std::invalid_argument("invalid path"); int x, y; int name_enum, pass_enum; while (infile >> x >> y >> name_enum >> pass_enum)