diff --git a/premake5.lua b/premake5.lua index ca294e8f..a24be07f 100644 --- a/premake5.lua +++ b/premake5.lua @@ -111,6 +111,7 @@ workspace "iw4x" buildoptions { "/wd4100", -- "Unused formal parameter" "/wd6011", -- "Dereferencing NULL pointer" + "/wd4125", -- "Decimal digit terminates octal escape sequence" } defines { "_SCL_SECURE_NO_WARNINGS", diff --git a/src/Components/Modules/AssetInterfaces/IMaterial.cpp b/src/Components/Modules/AssetInterfaces/IMaterial.cpp index 79a30eab..4d1e5e0f 100644 --- a/src/Components/Modules/AssetInterfaces/IMaterial.cpp +++ b/src/Components/Modules/AssetInterfaces/IMaterial.cpp @@ -102,7 +102,7 @@ namespace Assets textureList.push_back(textureDef); } - if (textureList.size()) + if (!textureList.empty()) { Game::MaterialTextureDef* textureTable = builder->GetAllocator()->AllocateArray(textureList.size()); diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index 6e00ad9b..5e5bb07d 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -74,7 +74,7 @@ namespace Components Logger::Print("Rotating map...\n"); // if nothing, just restart - if (!Dvar::Var("sv_mapRotation").Get().size()) + if (Dvar::Var("sv_mapRotation").Get().empty()) { Logger::Print("No rotation defined, restarting map.\n"); Command::Execute(Utils::VA("map %s", Dvar::Var("mapname").Get()), true); @@ -82,7 +82,7 @@ namespace Components } // first, check if the string contains nothing - if (!Dvar::Var("sv_mapRotationCurrent").Get().size()) + if (Dvar::Var("sv_mapRotationCurrent").Get().empty()) { Logger::Print("Current map rotation has finished, reloading...\n"); Dvar::Var("sv_mapRotationCurrent").Set(Dvar::Var("sv_mapRotation").Get()); diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index 93f236e3..fe61872f 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -69,7 +69,7 @@ namespace Components bool Download::HasReceivedPacket(Download::Container::DownloadCL* download, int packet) { - if (download->parts.size()) + if (!download->parts.empty()) { for (auto i = download->parts.begin(); i != download->parts.end(); ++i) { @@ -256,7 +256,7 @@ namespace Components void Download::RequestMissingPackets(Download::Container::DownloadCL* download, std::vector packets) { - if (packets.size()) + if (!packets.empty()) { download->lastPing = Game::Com_Milliseconds(); @@ -274,7 +274,7 @@ namespace Components void Download::MarkPacketAsDirty(Download::Container::DownloadSV* download, int packet) { - if (download->sentParts.size()) + if (!download->sentParts.empty()) { for (auto i = download->sentParts.begin(); i != download->sentParts.end(); ++i) { @@ -313,7 +313,7 @@ namespace Components void Download::Frame() { - if (Download::DataContainer.ClientDownloads.size()) + if (!Download::DataContainer.ClientDownloads.empty()) { for (auto i = Download::DataContainer.ClientDownloads.begin(); i != Download::DataContainer.ClientDownloads.end(); ++i) { @@ -341,7 +341,7 @@ namespace Components } } - if (Download::DataContainer.ServerDownloads.size()) + if (!Download::DataContainer.ServerDownloads.empty()) { for (auto i = Download::DataContainer.ServerDownloads.begin(); i != Download::DataContainer.ServerDownloads.end(); ++i) { diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index 1c9cd4d6..8752e7b6 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -218,7 +218,7 @@ namespace Components { std::vector menus = Menus::LoadMenu(Utils::VA("ui_mp\\%s.menu", menudef->window.name)); - if (!menus.size()) + if (menus.empty()) { // Try loading the original menu, if we can't load our custom one Game::menuDef_t* originalMenu = AssetHandler::FindOriginalAsset(Game::XAssetType::ASSET_TYPE_MENU, menudef->window.name).menu; @@ -239,7 +239,7 @@ namespace Components Game::MenuList* Menus::LoadScriptMenu(const char* menu) { std::vector menus = Menus::LoadMenu(menu); - if (!menus.size()) return nullptr; + if (menus.empty()) return nullptr; // Allocate new menu list Game::MenuList* newList = Utils::Memory::AllocateArray(1); diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index 530088b5..46db971e 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -81,6 +81,17 @@ namespace Components return false; } + void Network::Address::Serialize(Proto::Network::Address* protoAddress) + { + protoAddress->set_ip(this->GetIP().full); + protoAddress->set_port(htons(this->GetPort())); + } + void Network::Address::Deserialize(const Proto::Network::Address& protoAddress) + { + this->SetIP({ protoAddress.ip() }); + this->SetPort(ntohs(static_cast(protoAddress.port()))); + this->SetType(Game::netadrtype_t::NA_IP); + } void Network::Handle(std::string packet, Network::Callback* callback) { diff --git a/src/Components/Modules/Network.hpp b/src/Components/Modules/Network.hpp index 2efbe26b..4dac4fda 100644 --- a/src/Components/Modules/Network.hpp +++ b/src/Components/Modules/Network.hpp @@ -30,6 +30,9 @@ namespace Components bool IsLocal(); bool IsSelf(); + void Serialize(Proto::Network::Address* protoAddress); + void Deserialize(const Proto::Network::Address& protoAddress); + private: Game::netadr_t address; }; diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp index fa48c972..3cd6b51d 100644 --- a/src/Components/Modules/News.cpp +++ b/src/Components/Modules/News.cpp @@ -54,7 +54,7 @@ namespace Components std::string data = Utils::WebIO("IW4x", "https://iw4xcachep26muba.onion.to/iw4/motd.txt").SetTimeout(5000)->Get(); - if (data.size()) + if (!data.empty()) { Localization::Set("MPUI_MOTD_TEXT", data.data()); } diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index c6c597f0..95a710c4 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -9,16 +9,16 @@ namespace Components void Node::LoadNodes() { std::string nodes = Utils::ReadFile("players/nodes.dat"); + if (nodes.empty()) return; - // Invalid - if (!nodes.size() || nodes.size() % 6) return; + Proto::Node::List list; + list.ParseFromString(nodes); - unsigned int size = (nodes.size() / sizeof(Node::AddressEntry)); - - Node::AddressEntry* addresses = reinterpret_cast(const_cast(nodes.data())); - for (unsigned int i = 0; i < size; ++i) + for (int i = 0; i < list.address_size(); ++i) { - Node::AddNode(addresses[i].toNetAddress()); + Network::Address address; + address.Deserialize(list.address(i)); + Node::AddNode(address); } } void Node::StoreNodes(bool force) @@ -29,23 +29,18 @@ namespace Components if ((Game::Com_Milliseconds() - lastStorage) < NODE_STORE_INTERVAL && !force) return; lastStorage = Game::Com_Milliseconds(); - std::vector entries; + Proto::Node::List list; for (auto node : Node::Nodes) { if (node.state == Node::STATE_VALID && node.registered) { - Node::AddressEntry thisAddress; - thisAddress.fromNetAddress(node.address); - - entries.push_back(thisAddress); + node.address.Serialize(list.add_address()); } } - std::string nodeStream(reinterpret_cast(entries.data()), entries.size() * sizeof(Node::AddressEntry)); - CreateDirectoryW(L"players", NULL); - Utils::WriteFile("players/nodes.dat", nodeStream); + Utils::WriteFile("players/nodes.dat", list.SerializeAsString()); } Node::NodeEntry* Node::FindNode(Network::Address address) @@ -107,35 +102,27 @@ namespace Components { if (address.IsSelf()) return; - std::vector entries; + Proto::Node::List list; + list.set_is_dedi(Dedicated::IsDedicated()); - for (auto entry : Node::Nodes) + for (auto node : Node::Nodes) { - if (entry.state == Node::STATE_VALID && entry.registered) + if (node.state == Node::STATE_VALID && node.registered) { - Node::AddressEntry thisAddress; - thisAddress.fromNetAddress(entry.address); - - entries.push_back(thisAddress); + node.address.Serialize(list.add_address()); } - if (entries.size() >= NODE_PACKET_LIMIT) + if (list.address_size() >= NODE_PACKET_LIMIT) { - std::string packet; - packet.append((Dedicated::IsDedicated() ? "\x01" : "\0"), 1); - packet.append(reinterpret_cast(entries.data()), entries.size() * sizeof(Node::AddressEntry)); - - Network::SendCommand(address, "nodeListResponse", packet); - - entries.clear(); + Network::SendCommand(address, "nodeListResponse", list.SerializeAsString()); + list.clear_address(); } } - std::string packet; - packet.append((Dedicated::IsDedicated() ? "\x01" : "\0"), 1); - packet.append(reinterpret_cast(entries.data()), entries.size() * sizeof(Node::AddressEntry)); - - Network::SendCommand(address, "nodeListResponse", packet); + if (list.address_size() > 0) + { + Network::SendCommand(address, "nodeListResponse", list.SerializeAsString()); + } } void Node::DeleteInvalidSessions() @@ -228,13 +215,11 @@ namespace Components { node.challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt()); - std::string data; - Proto::NodePacket packet; + Proto::Node::Packet packet; packet.set_challenge(node.challenge); - packet.SerializeToString(&data); Logger::Print("Sending registration request to %s\n", node.address.GetString()); - Network::SendCommand(node.address, "nodeRegisterRequest", data); + Network::SendCommand(node.address, "nodeRegisterRequest", packet.SerializeAsString()); } else { @@ -291,8 +276,6 @@ namespace Components Node::Node() { - Assert_Size(Node::AddressEntry, 6); - // ZoneBuilder doesn't require node stuff if (ZoneBuilder::IsEnabled()) return; @@ -311,17 +294,15 @@ namespace Components { QuickPatch::OnShutdown([] () { - std::string data, challenge; - challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt()); + std::string challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt()); - Proto::NodePacket packet; + Proto::Node::Packet packet; packet.set_challenge(challenge); packet.set_signature(Utils::Cryptography::ECDSA::SignMessage(Node::SignatureKey, challenge)); - packet.SerializeToString(&data); for (auto node : Node::Nodes) { - Network::SendCommand(node.address, "nodeDeregister", data); + Network::SendCommand(node.address, "nodeDeregister", packet.SerializeAsString()); } }); @@ -341,11 +322,10 @@ namespace Components Logger::Print("Received registration request from %s\n", address.GetString()); - Proto::NodePacket packet; + Proto::Node::Packet packet; if (!packet.ParseFromString(data)) return; - if (!packet.challenge().size()) return; + if (packet.challenge().empty()) return; - std::string response; std::string signature = Utils::Cryptography::ECDSA::SignMessage(Node::SignatureKey, packet.challenge()); std::string challenge = Utils::VA("%X", Utils::Cryptography::Rand::GenerateInt()); @@ -353,13 +333,12 @@ namespace Components packet.set_challenge(challenge); packet.set_signature(signature); packet.set_publickey(Node::SignatureKey.GetPublicKey()); - packet.SerializeToString(&response); entry->lastTime = Game::Com_Milliseconds(); entry->challenge = challenge; entry->state = Node::STATE_NEGOTIATING; - Network::SendCommand(address, "nodeRegisterSynchronize", response); + Network::SendCommand(address, "nodeRegisterSynchronize", packet.SerializeAsString()); }); Network::Handle("nodeRegisterSynchronize", [] (Network::Address address, std::string data) @@ -369,11 +348,11 @@ namespace Components Logger::Print("Received synchronization data for registration from %s!\n", address.GetString()); - Proto::NodePacket packet; + Proto::Node::Packet packet; if (!packet.ParseFromString(data)) return; - if (!packet.challenge().size()) return; - if (!packet.publickey().size()) return; - if (!packet.signature().size()) return; + if (packet.challenge().empty()) return; + if (packet.publickey().empty()) return; + if (packet.signature().empty()) return; std::string challenge = packet.challenge(); std::string publicKey = packet.publickey(); @@ -397,16 +376,14 @@ namespace Components Logger::Print("Node %s registered\n", address.GetString()); // Build response - data.clear(); publicKey = Node::SignatureKey.GetPublicKey(); signature = Utils::Cryptography::ECDSA::SignMessage(Node::SignatureKey, challenge); packet.Clear(); packet.set_signature(signature); packet.set_publickey(publicKey); - packet.SerializeToString(&data); - Network::SendCommand(address, "nodeRegisterAcknowledge", data); + Network::SendCommand(address, "nodeRegisterAcknowledge", packet.SerializeAsString()); }); Network::Handle("nodeRegisterAcknowledge", [] (Network::Address address, std::string data) @@ -417,10 +394,10 @@ namespace Components Logger::Print("Received acknowledgment from %s\n", address.GetString()); - Proto::NodePacket packet; + Proto::Node::Packet packet; if (!packet.ParseFromString(data)) return; - if (!packet.signature().size()) return; - if (!packet.publickey().size()) return; + if (packet.signature().empty()) return; + if (packet.publickey().empty()) return; std::string publicKey = packet.publickey(); std::string signature = packet.signature(); @@ -483,10 +460,10 @@ namespace Components Node::NodeEntry* entry = Node::FindNode(address); if (!entry || !entry->registered) return; - Proto::NodePacket packet; + Proto::Node::Packet packet; if (!packet.ParseFromString(data)) return; - if (!packet.challenge().size()) return; - if (!packet.signature().size()) return; + if (packet.challenge().empty()) return; + if (packet.signature().empty()) return; std::string challenge = packet.challenge(); std::string signature = packet.signature(); @@ -573,31 +550,31 @@ namespace Components Network::Handle("nodeListResponse", [] (Network::Address address, std::string data) { - if (data.size() % sizeof(Node::AddressEntry) != 1) + Proto::Node::List list; + + if (data.empty() || !list.ParseFromString(data)) { Logger::Print("Received invalid node list from %s!\n", address.GetString()); return; } - unsigned int size = ((data.size() - 1) / sizeof(Node::AddressEntry)); - Node::AddressEntry* addresses = reinterpret_cast(const_cast(data.data() + 1)); - bool isDedicated = (*data.data() != 0); - Node::NodeEntry* entry = Node::FindNode(address); if (entry) { if (entry->registered) { - Logger::Print("Received valid node list with %d entries from %s\n", size, address.GetString()); + Logger::Print("Received valid node list with %i entries from %s\n", list.address_size(), address.GetString()); - entry->isDedi = isDedicated; + entry->isDedi = list.is_dedi(); entry->state = Node::STATE_VALID; entry->lastTime = Game::Com_Milliseconds(); entry->lastListQuery = Game::Com_Milliseconds(); - for (unsigned int i = 0; i < size; ++i) + for (int i = 0; i < list.address_size(); ++i) { - Node::AddNode(addresses[i].toNetAddress()); + Network::Address addr; + addr.Deserialize(list.address(i)); + Node::AddNode(addr); } } } @@ -610,9 +587,11 @@ namespace Components { session->lastTime = Game::Com_Milliseconds(); - for (unsigned int i = 0; i < size; ++i) + for (int i = 0; i < list.address_size(); ++i) { - Node::AddNode(addresses[i].toNetAddress()); + Network::Address addr; + addr.Deserialize(list.address(i)); + Node::AddNode(addr); } } } diff --git a/src/Components/Modules/Node.hpp b/src/Components/Modules/Node.hpp index f33fd9ab..611f23b3 100644 --- a/src/Components/Modules/Node.hpp +++ b/src/Components/Modules/Node.hpp @@ -6,9 +6,6 @@ #define NODE_STORE_INTERVAL 1000 * 60* 1 // Store nodes every minute #define SESSION_TIMEOUT 1000 * 10 // 10 seconds session timeout -// Protobuf -#include "proto/node.pb.h" - namespace Components { class Node : public Component @@ -56,31 +53,6 @@ namespace Components int lastTime; }; -#pragma pack(push, 1) - struct AddressEntry - { - Game::netIP_t ip; - unsigned short port; - - Network::Address toNetAddress() - { - Network::Address address; - - address.SetIP(this->ip); - address.SetPort(ntohs(this->port)); - address.SetType(Game::netadrtype_t::NA_IP); - - return address; - } - - void fromNetAddress(Network::Address address) - { - this->ip = address.GetIP(); - this->port = htons(address.GetPort()); - } - }; -#pragma pack(pop) - static Utils::Cryptography::ECDSA::Key SignatureKey; static std::vector Nodes; diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 21e361af..dc9b8d90 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -285,7 +285,7 @@ namespace Components info.Set("hc", (Dvar::Var("g_hardcore").Get() ? "1" : "0")); // Ensure mapname is set - if (!info.Get("mapname").size()) + if (info.Get("mapname").empty()) { info.Set("mapname", Dvar::Var("ui_mapname").Get()); } diff --git a/src/Components/Modules/ServerInfo.cpp b/src/Components/Modules/ServerInfo.cpp index aa8ab538..f0c2524f 100644 --- a/src/Components/Modules/ServerInfo.cpp +++ b/src/Components/Modules/ServerInfo.cpp @@ -106,7 +106,7 @@ namespace Components info.Set("isPrivate", (Dvar::Var("g_password").Get().size() ? "1" : "0")); // Ensure mapname is set - if (!info.Get("mapname").size()) + if (info.Get("mapname").empty()) { info.Set("mapname", Dvar::Var("ui_mapname").Get()); } diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index aad33ccc..c934af32 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -236,7 +236,7 @@ namespace Components zoneHeader.assetList.assets = reinterpret_cast(-1); // Increment ScriptStrings count (for empty script string) if available - if (ZoneBuilder::Zone::ScriptStrings.size()) + if (!ZoneBuilder::Zone::ScriptStrings.empty()) { zoneHeader.assetList.stringList.count = ZoneBuilder::Zone::ScriptStrings.size() + 1; zoneHeader.assetList.stringList.strings = reinterpret_cast(-1); @@ -247,7 +247,7 @@ namespace Components ZoneBuilder::Zone::Buffer.PushBlock(Game::XFILE_BLOCK_VIRTUAL); // Push main stream onto the stream stack // Write ScriptStrings, if available - if (ZoneBuilder::Zone::ScriptStrings.size()) + if (!ZoneBuilder::Zone::ScriptStrings.empty()) { ZoneBuilder::Zone::Buffer.SaveNull(4); // Empty script string? // This actually represents a NULL string, but as scriptString. @@ -361,7 +361,7 @@ namespace Components // Might optimize that later if (!gameIndex) { - if (!ZoneBuilder::Zone::ScriptStrings.size()) + if (ZoneBuilder::Zone::ScriptStrings.empty()) { ZoneBuilder::Zone::ScriptStrings.push_back(""); } diff --git a/src/Proto/network.proto b/src/Proto/network.proto new file mode 100644 index 00000000..22f66543 --- /dev/null +++ b/src/Proto/network.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; + +package Proto.Network; + +// TODO: Add support for IPv6, once the game supports it (I assume we'll implement it :P) +message Address +{ + uint32 ip = 1; + uint32 port = 2; // Actually only 16 bits, but apparently protobuf handles that (https://groups.google.com/d/msg/protobuf/Er39mNGnRWU/x6Srz_GrZPgJ) +} diff --git a/src/Proto/node.proto b/src/Proto/node.proto index a320e25c..f8a231b5 100644 --- a/src/Proto/node.proto +++ b/src/Proto/node.proto @@ -1,10 +1,17 @@ syntax = "proto3"; -package Proto; +package Proto.Node; +import "network.proto"; -message NodePacket +message Packet { bytes challenge = 1; bytes signature = 2; - bytes publicKey = 3; + bytes publickey = 3; +} + +message List +{ + bool is_dedi = 1; + repeated Network.Address address = 2; } diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index b46e0deb..4cc0d276 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -61,6 +61,10 @@ #include #include +// Protobuf +#include "proto/network.pb.h" +#include "proto/node.pb.h" + #pragma warning(pop) // Version number diff --git a/src/Utils/CSV.cpp b/src/Utils/CSV.cpp index 2870a5ce..628380f2 100644 --- a/src/Utils/CSV.cpp +++ b/src/Utils/CSV.cpp @@ -78,7 +78,7 @@ namespace Utils buffer = file; } - if (buffer.size()) + if (!buffer.empty()) { auto rows = Utils::Explode(buffer, '\n'); diff --git a/src/Utils/Stream.cpp b/src/Utils/Stream.cpp index 5f465135..0bbb5ec3 100644 --- a/src/Utils/Stream.cpp +++ b/src/Utils/Stream.cpp @@ -146,7 +146,7 @@ namespace Utils bool Stream::PopBlock() { - if (Stream::StreamStack.size()) + if (!Stream::StreamStack.empty()) { Stream::StreamStack.pop_back(); return true; @@ -175,7 +175,7 @@ namespace Utils Game::XFILE_BLOCK_TYPES Stream::GetCurrentBlock() { - if (Stream::StreamStack.size()) + if (!Stream::StreamStack.empty()) { return Stream::StreamStack[Stream::StreamStack.size() - 1]; } diff --git a/src/Utils/WebIO.cpp b/src/Utils/WebIO.cpp index e71f953c..bd95d615 100644 --- a/src/Utils/WebIO.cpp +++ b/src/Utils/WebIO.cpp @@ -121,7 +121,7 @@ namespace Utils std::string key = param->first; std::string value = param->second; - if (body.size()) body.append("&"); + if (!body.empty()) body.append("&"); body.append(key); body.append("=");