diff --git a/source/base/CMakeLists.txt b/source/base/CMakeLists.txt index e813e45..e77d9ff 100644 --- a/source/base/CMakeLists.txt +++ b/source/base/CMakeLists.txt @@ -18,7 +18,6 @@ SET (star_base_HEADERS StarMixer.hpp StarPackedAssetSource.hpp StarRootBase.hpp - StarVersion.hpp StarVersionOptionParser.hpp StarWorldGeometry.hpp scripting/StarImageLuaBindings.hpp @@ -40,8 +39,7 @@ SET (star_base_SOURCES scripting/StarImageLuaBindings.cpp ) -CONFIGURE_FILE (StarVersion.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp) -ADD_LIBRARY (star_base OBJECT ${star_base_SOURCES} ${star_base_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp) +ADD_LIBRARY (star_base OBJECT ${star_base_SOURCES} ${star_base_HEADERS}) IF(STAR_PRECOMPILED_HEADERS) TARGET_PRECOMPILE_HEADERS (star_base REUSE_FROM star_core) diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index bb8bd22..2f0c858 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -124,6 +124,7 @@ SET (star_core_HEADERS StarUnicode.hpp StarUuid.hpp StarVector.hpp + StarVersion.hpp StarVlqEncoding.hpp StarWeightedPool.hpp StarWorkerPool.hpp @@ -164,6 +165,7 @@ SET (star_core_SOURCES StarLua.cpp StarLuaConverters.cpp StarMemory.cpp + StarNetCompatibility.cpp StarNetElement.cpp StarNetElementBasicFields.cpp StarNetElementGroup.cpp @@ -219,7 +221,8 @@ ELSEIF (STAR_SYSTEM_FAMILY_WINDOWS) ENDIF () -ADD_LIBRARY (star_core OBJECT ${star_core_SOURCES} ${star_core_HEADERS}) +CONFIGURE_FILE (StarVersion.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp) +ADD_LIBRARY (star_core OBJECT ${star_core_SOURCES} ${star_core_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp) IF(STAR_PRECOMPILED_HEADERS) TARGET_PRECOMPILE_HEADERS (star_core PUBLIC StarPch.hpp) diff --git a/source/core/StarDataStream.cpp b/source/core/StarDataStream.cpp index 1224f54..3a4ed0c 100644 --- a/source/core/StarDataStream.cpp +++ b/source/core/StarDataStream.cpp @@ -36,10 +36,7 @@ void DataStream::setStreamCompatibilityVersion(unsigned streamCompatibilityVersi } void DataStream::setStreamCompatibilityVersion(NetCompatibilityRules const& rules) { - if (rules.isLegacy) - m_streamCompatibilityVersion = 1; - else - m_streamCompatibilityVersion = CurrentStreamVersion; + m_streamCompatibilityVersion = rules.version(); } ByteArray DataStream::readBytes(size_t len) { diff --git a/source/core/StarNetCompatibility.cpp b/source/core/StarNetCompatibility.cpp new file mode 100644 index 0000000..fdd53fb --- /dev/null +++ b/source/core/StarNetCompatibility.cpp @@ -0,0 +1,7 @@ +#include "StarNetCompatibility.hpp" + +namespace Star { + +VersionNumber const OpenProtocolVersion = 2; + +} \ No newline at end of file diff --git a/source/core/StarNetCompatibility.hpp b/source/core/StarNetCompatibility.hpp index 730546e..4b950ab 100644 --- a/source/core/StarNetCompatibility.hpp +++ b/source/core/StarNetCompatibility.hpp @@ -1,40 +1,54 @@ #pragma once -#include "StarDataStream.hpp" +#include "StarVersion.hpp" +#include "StarHash.hpp" namespace Star { +extern VersionNumber const OpenProtocolVersion; -enum class NetCompatibilityFilter { - None = 0, - Old = 1, - New = 2 -}; +constexpr VersionNumber AnyVersion = 0xFFFFFFFF; +constexpr VersionNumber LegacyVersion = 0; -struct NetCompatibilityRules { - NetCompatibilityRules() = default; +class NetCompatibilityRules { +public: + NetCompatibilityRules(); NetCompatibilityRules(uint64_t) = delete; - NetCompatibilityRules(bool legacy); + NetCompatibilityRules(VersionNumber version); - bool checkFilter(NetCompatibilityFilter const& filter) const; + VersionNumber version() const; + void setVersion(VersionNumber version); + bool isLegacy() const; - bool isLegacy = false; + bool operator==(NetCompatibilityRules const& a) const; + +private: + VersionNumber m_version = OpenProtocolVersion; }; -inline NetCompatibilityRules::NetCompatibilityRules(bool legacy) : isLegacy(legacy) {} +inline NetCompatibilityRules::NetCompatibilityRules() : m_version(OpenProtocolVersion) {} -inline bool NetCompatibilityRules::checkFilter(NetCompatibilityFilter const& filter) const { - if (filter == NetCompatibilityFilter::None) - return true; - else if (isLegacy) - return filter == NetCompatibilityFilter::Old; - else - return filter == NetCompatibilityFilter::New; +inline NetCompatibilityRules::NetCompatibilityRules(VersionNumber v) : m_version(v) {} + +inline VersionNumber NetCompatibilityRules::version() const { + return m_version; +} + +inline void NetCompatibilityRules::setVersion(VersionNumber version) { + m_version = version; +} + +inline bool NetCompatibilityRules::isLegacy() const { + return m_version == LegacyVersion; +} + +inline bool NetCompatibilityRules::operator==(NetCompatibilityRules const& a) const { + return m_version == a.m_version; } template <> struct hash { size_t operator()(NetCompatibilityRules const& s) const { - return s.isLegacy; + return s.version(); } }; diff --git a/source/core/StarNetElement.hpp b/source/core/StarNetElement.hpp index 393dd3d..7d73b85 100644 --- a/source/core/StarNetElement.hpp +++ b/source/core/StarNetElement.hpp @@ -55,23 +55,25 @@ public: // received even if no deltas are produced, so no extrapolation takes place. virtual void blankNetDelta(float interpolationTime); - NetCompatibilityFilter netCompatibilityFilter() const; - void setNetCompatibilityFilter(NetCompatibilityFilter netFilter); + VersionNumber compatibilityVersion() const; + void setCompatibilityVersion(VersionNumber version); bool checkWithRules(NetCompatibilityRules const& rules) const; private: - NetCompatibilityFilter m_netCompatibilityFilter = NetCompatibilityFilter::None; + VersionNumber m_netCompatibilityVersion = AnyVersion; }; -inline NetCompatibilityFilter NetElement::netCompatibilityFilter() const { - return m_netCompatibilityFilter; +inline VersionNumber NetElement::compatibilityVersion() const { + return m_netCompatibilityVersion; } -inline void NetElement::setNetCompatibilityFilter(NetCompatibilityFilter netFilter) { - m_netCompatibilityFilter = netFilter; +inline void NetElement::setCompatibilityVersion(VersionNumber version) { + m_netCompatibilityVersion = version; } inline bool NetElement::checkWithRules(NetCompatibilityRules const& rules) const { - return rules.checkFilter(m_netCompatibilityFilter); + if (m_netCompatibilityVersion != AnyVersion) + return rules.version() >= m_netCompatibilityVersion; + return true; } } diff --git a/source/base/StarVersion.cpp.in b/source/core/StarVersion.cpp.in similarity index 100% rename from source/base/StarVersion.cpp.in rename to source/core/StarVersion.cpp.in diff --git a/source/base/StarVersion.hpp b/source/core/StarVersion.hpp similarity index 100% rename from source/base/StarVersion.hpp rename to source/core/StarVersion.hpp diff --git a/source/game/StarNetPackets.cpp b/source/game/StarNetPackets.cpp index dd80d76..b8605ed 100644 --- a/source/game/StarNetPackets.cpp +++ b/source/game/StarNetPackets.cpp @@ -5,7 +5,6 @@ namespace Star { VersionNumber const StarProtocolVersion = 747; -VersionNumber const OpenProtocolVersion = 1; EnumMap const PacketTypeNames{ {PacketType::ProtocolRequest, "ProtocolRequest"}, diff --git a/source/game/StarNetPackets.hpp b/source/game/StarNetPackets.hpp index e68a045..87a01cf 100644 --- a/source/game/StarNetPackets.hpp +++ b/source/game/StarNetPackets.hpp @@ -23,7 +23,6 @@ STAR_STRUCT(Packet); STAR_EXCEPTION(StarPacketException, IOException); extern VersionNumber const StarProtocolVersion; -extern VersionNumber const OpenProtocolVersion; // Packet types sent between the client and server over a NetSocket. Does not // correspond to actual packets, simply logical portions of NetSocket data. diff --git a/source/game/StarStatusController.cpp b/source/game/StarStatusController.cpp index a2a5e9c..325fc17 100644 --- a/source/game/StarStatusController.cpp +++ b/source/game/StarStatusController.cpp @@ -21,15 +21,15 @@ StatusController::StatusController(Json const& config) : m_statCollection(config m_statusProperties.reset(config.getObject("statusProperties", {})); m_statusProperties.setOverrides( [&](DataStream& ds, NetCompatibilityRules rules) { - if (rules.isLegacy) ds << m_statusProperties.baseMap(); + if (rules.version() <= 1) ds << m_statusProperties.baseMap(); else m_statusProperties.NetElementHashMap::netStore(ds, rules); }, [&](DataStream& ds, NetCompatibilityRules rules) { - if (rules.isLegacy) m_statusProperties.reset(ds.read()); + if (rules.version() <= 1) m_statusProperties.reset(ds.read()); else m_statusProperties.NetElementHashMap::netLoad(ds, rules); }, [&](DataStream& ds, uint64_t fromVersion, NetCompatibilityRules rules) { - if (rules.isLegacy) { + if (rules.version() <= 1) { if (m_statusProperties.shouldWriteNetDelta(fromVersion, rules)) { ds << m_statusProperties.baseMap(); return true; @@ -39,7 +39,7 @@ StatusController::StatusController(Json const& config) : m_statCollection(config return m_statusProperties.NetElementHashMap::writeNetDelta(ds, fromVersion, rules); }, [&](DataStream& ds, float interp, NetCompatibilityRules rules) { - if (rules.isLegacy) m_statusProperties.reset(ds.read()); + if (rules.version() <= 1) m_statusProperties.reset(ds.read()); else m_statusProperties.NetElementHashMap::readNetDelta(ds, interp, rules); } ); diff --git a/source/game/StarUniverseClient.cpp b/source/game/StarUniverseClient.cpp index 023140c..6038901 100644 --- a/source/game/StarUniverseClient.cpp +++ b/source/game/StarUniverseClient.cpp @@ -94,20 +94,27 @@ Maybe UniverseClient::connect(UniverseConnection connection, bool allowA else if (!protocolResponsePacket->allowed) return String(strf("Join failed! Server does not support connections with protocol version {}", StarProtocolVersion)); + NetCompatibilityRules compatibilityRules; + compatibilityRules.setVersion(LegacyVersion); bool legacyServer = protocolResponsePacket->compressionMode() != PacketCompressionMode::Enabled; if (!legacyServer) { - if (auto compressedSocket = as(&connection.packetSocket())) { - if (protocolResponsePacket->info) { - auto compressionName = protocolResponsePacket->info.getString("compression", "None"); + auto compressedSocket = as(&connection.packetSocket()); + if (protocolResponsePacket->info) { + compatibilityRules.setVersion(protocolResponsePacket->info.getUInt("openProtocolVersion", 1)); + auto compressionName = protocolResponsePacket->info.getString("compression", "None"); + if (compressedSocket) { auto compressionMode = NetCompressionModeNames.maybeLeft(compressionName); if (!compressionMode) return String(strf("Join failed! Unknown net stream connection type '{}'", compressionName)); Logger::info("UniverseClient: Using '{}' network stream compression", NetCompressionModeNames.getRight(*compressionMode)); compressedSocket->setCompressionStreamEnabled(compressionMode == NetCompressionMode::Zstd); - } else { + } + } else { + compatibilityRules.setVersion(1); // A version of 1 is OpenStarbound prior to the NetElement compatibility stuff + if (compressedSocket) { Logger::info("UniverseClient: Defaulting to Zstd network stream compression (older server version)"); - compressedSocket->setCompressionStreamEnabled(true);// old OpenSB server version always expects it! + compressedSocket->setCompressionStreamEnabled(true); } } } @@ -115,7 +122,10 @@ Maybe UniverseClient::connect(UniverseConnection connection, bool allowA auto clientConnect = make_shared(Root::singleton().assets()->digest(), allowAssetsMismatch, m_mainPlayer->uuid(), m_mainPlayer->name(), m_mainPlayer->species(), m_playerStorage->loadShipData(m_mainPlayer->uuid()), m_mainPlayer->shipUpgrades(), m_mainPlayer->log()->introComplete(), account); - clientConnect->info = JsonObject{ {"brand", "OpenStarbound"} }; + clientConnect->info = JsonObject{ + {"brand", "OpenStarbound"}, + {"openProtocolVersion", OpenProtocolVersion } + }; connection.pushSingle(std::move(clientConnect)); connection.sendAll(timeout); @@ -134,9 +144,6 @@ Maybe UniverseClient::connect(UniverseConnection connection, bool allowA packet = connection.pullSingle(); } - NetCompatibilityRules compatibilityRules; - compatibilityRules.isLegacy = legacyServer; - if (auto success = as(packet)) { m_universeClock = make_shared(); m_clientContext = make_shared(success->serverUuid, m_mainPlayer->uuid()); diff --git a/source/game/StarUniverseServer.cpp b/source/game/StarUniverseServer.cpp index 09cfdc8..6961ce4 100644 --- a/source/game/StarUniverseServer.cpp +++ b/source/game/StarUniverseServer.cpp @@ -1577,7 +1577,8 @@ void UniverseServer::acceptConnection(UniverseConnection connection, Maybeinfo = JsonObject{ - {"compression", NetCompressionModeNames.getRight(compressionMode)} + {"compression", NetCompressionModeNames.getRight(compressionMode)}, + {"openProtocolVersion", OpenProtocolVersion} }; } connection.pushSingle(protocolResponse); @@ -1674,7 +1675,10 @@ void UniverseServer::acceptConnection(UniverseConnection connection, MaybeplayerName, remoteAddressString); + NetCompatibilityRules netRules(legacyClient ? LegacyVersion : 1); if (Json& info = clientConnect->info) { + if (auto openProtocolVersion = info.optUInt("openProtocolVersion")) + netRules.setVersion(*openProtocolVersion); if (Json brand = info.get("brand", "custom")) connectionLog += strf(" ({} client)", brand.toString()); if (info.getBool("legacy", false)) @@ -1701,7 +1705,6 @@ void UniverseServer::acceptConnection(UniverseConnection connection, Maybe(clientId, remoteAddress, netRules, clientConnect->playerUuid, clientConnect->playerName, clientConnect->playerSpecies, administrator, clientConnect->shipChunks); m_clients.add(clientId, clientContext); diff --git a/source/game/StarWorldClient.cpp b/source/game/StarWorldClient.cpp index aecb77a..b18127e 100644 --- a/source/game/StarWorldClient.cpp +++ b/source/game/StarWorldClient.cpp @@ -1230,7 +1230,7 @@ void WorldClient::update(float dt) { queueUpdatePackets(m_entityUpdateTimer.wrapTick(dt)); - if ((!m_clientState.netCompatibilityRules().isLegacy && m_currentStep % 3 == 0) || m_pingTime.isNothing()) { + if ((!m_clientState.netCompatibilityRules().isLegacy() && m_currentStep % 3 == 0) || m_pingTime.isNothing()) { m_pingTime = Time::monotonicMilliseconds(); m_outgoingPackets.append(make_shared(*m_pingTime)); } diff --git a/source/game/StarWorldServer.cpp b/source/game/StarWorldServer.cpp index a2df77b..fbc23a9 100644 --- a/source/game/StarWorldServer.cpp +++ b/source/game/StarWorldServer.cpp @@ -692,7 +692,6 @@ void WorldServer::update(float dt) { queueUpdatePackets(pair.first, sendRemoteUpdates); } m_netStateCache.clear(); - m_legacyNetStateCache.clear(); for (auto& pair : m_clientInfo) pair.second->pendingForward = false; @@ -1872,7 +1871,7 @@ void WorldServer::queueUpdatePackets(ConnectionId clientId, bool sendRemoteUpdat if (auto version = clientInfo->clientSlavesNetVersion.ptr(entityId)) { if (auto updateSetPacket = updateSetPackets.value(connectionId)) { auto pair = make_pair(entityId, *version); - auto& cache = netRules.isLegacy ? m_legacyNetStateCache : m_netStateCache; + auto& cache = m_netStateCache[netRules]; auto i = cache.find(pair); if (i == cache.end()) i = cache.insert(pair, monitoredEntity->writeNetState(*version, netRules)).first; diff --git a/source/game/StarWorldServer.hpp b/source/game/StarWorldServer.hpp index a87f72d..ea650ac 100644 --- a/source/game/StarWorldServer.hpp +++ b/source/game/StarWorldServer.hpp @@ -374,8 +374,7 @@ private: CollisionGenerator m_collisionGenerator; List m_workingCollisionBlocks; - HashMap, pair> m_netStateCache; - HashMap, pair> m_legacyNetStateCache; + HashMap, pair>> m_netStateCache; OrderedHashMap> m_clientInfo; GameTimer m_entityUpdateTimer;