diff --git a/aura.cfg b/aura.cfg index a80ed5a9..d0e6a314 100644 --- a/aura.cfg +++ b/aura.cfg @@ -9,6 +9,12 @@ bot_war3path = C:\Program Files\Warcraft III +### whether to act as Warcraft III: The Frozen Throne or not +### set this to 0 to act as Warcraft III: Reign of Chaos (you WILL NOT need to enter a TFT cd key to login to battle.net) +### set this to 1 to act as Warcraft III: The Frozen Throne (you WILL need to enter a TFT cd key to login to battle.net) + +bot_tft = 0 + ### the address Aura will bind to when hosting games (leave it blank to bind to all available addresses) ### if you don't know what this is just leave it blank diff --git a/src/aura.cpp b/src/aura.cpp index 13e1d283..cc058127 100644 --- a/src/aura.cpp +++ b/src/aura.cpp @@ -200,6 +200,13 @@ CAura::CAura(CConfig* CFG) m_UDPSocket->SetBroadcastTarget(CFG->GetString("udp_broadcasttarget", string())); m_UDPSocket->SetDontRoute(CFG->GetInt("udp_dontroute", 0) == 0 ? false : true); + m_TFT = CFG->GetInt("bot_tft", 1) == 0 ? false : true; + + if (m_TFT) + Print("[GHOST] acting as Warcraft III: The Frozen Throne"); + else + Print("[GHOST] acting as Warcraft III: Reign of Chaos"); + m_ReconnectPort = CFG->GetInt("bot_reconnectport", 6113); if (m_ReconnectSocket->Listen(m_BindAddress, m_ReconnectPort)) @@ -317,6 +324,24 @@ CAura::CAura(CConfig* CFG) if (Server.empty()) break; + if (CDKeyROC.empty()) + { + Print("[AURA] missing " + Prefix + "cdkeyroc, skipping this battle.net connection"); + break; + } + + if (m_TFT && CDKeyTFT.empty()) + { + Print("[AURA] missing " + Prefix + "cdkeytft, skipping this battle.net connection"); + break; + } + + if (UserName.empty()) + { + Print("[AURA] missing " + Prefix + "username, skipping this battle.net connection"); + break; + } + Print("[AURA] found battle.net connection #" + to_string(i) + " for server [" + Server + "]"); if (Locale == "system") diff --git a/src/aura.h b/src/aura.h index 307f7da9..e3535d61 100644 --- a/src/aura.h +++ b/src/aura.h @@ -86,6 +86,7 @@ class CAura bool m_AutoLock; // config value: auto lock games when the owner is present bool m_Ready; // indicates if there's lacking configuration info so we can quit bool m_LCPings; // config value: use LC style pings (divide actual pings by two) + bool m_TFT; // config value: TFT enabled or not explicit CAura(CConfig* CFG); ~CAura(); diff --git a/src/bncsutilinterface.cpp b/src/bncsutilinterface.cpp index f320cb03..910a3e63 100644 --- a/src/bncsutilinterface.cpp +++ b/src/bncsutilinterface.cpp @@ -74,7 +74,7 @@ inline static std::string CaseInsensitiveFileExists(const std::string& path, std return ""; } -bool CBNCSUtilInterface::HELP_SID_AUTH_CHECK(const string& war3Path, const string& keyROC, const string& keyTFT, const string& valueStringFormula, const string& mpqFileName, const std::vector& clientToken, const std::vector& serverToken, const uint8_t war3Version) +bool CBNCSUtilInterface::HELP_SID_AUTH_CHECK(bool TFT, const string& war3Path, const string& keyROC, const string& keyTFT, const string& valueStringFormula, const string& mpqFileName, const std::vector& clientToken, const std::vector& serverToken, const uint8_t war3Version) { const string FileWar3EXE = [&]() { if (war3Version >= 28) @@ -105,16 +105,18 @@ bool CBNCSUtilInterface::HELP_SID_AUTH_CHECK(const string& war3Path, const strin m_EXEVersion = CreateByteArray(EXEVersion, false); m_EXEVersionHash = CreateByteArray(EXEVersionHash, false); m_KeyInfoROC = CreateKeyInfo(keyROC, ByteArrayToUInt32(clientToken, false), ByteArrayToUInt32(serverToken, false)); - m_KeyInfoTFT = CreateKeyInfo(keyTFT, ByteArrayToUInt32(clientToken, false), ByteArrayToUInt32(serverToken, false)); - if (m_KeyInfoROC.size() == 36 && m_KeyInfoTFT.size() == 36) + if (TFT) + m_KeyInfoTFT = CreateKeyInfo(keyTFT, ByteArrayToUInt32(clientToken, false), ByteArrayToUInt32(serverToken, false)); + + if (m_KeyInfoROC.size() == 36 && (!TFT || m_KeyInfoTFT.size() == 36)) return true; else { if (m_KeyInfoROC.size() != 36) Print("[BNCSUI] unable to create ROC key info - invalid ROC key"); - if (m_KeyInfoTFT.size() != 36) + if (TFT && m_KeyInfoTFT.size() != 36) Print("[BNCSUI] unable to create TFT key info - invalid TFT key"); } } diff --git a/src/bncsutilinterface.h b/src/bncsutilinterface.h index fddca682..031014bc 100644 --- a/src/bncsutilinterface.h +++ b/src/bncsutilinterface.h @@ -61,7 +61,7 @@ class CBNCSUtilInterface void Reset(const std::string& userName, const std::string& userPassword); - bool HELP_SID_AUTH_CHECK(const std::string& war3Path, const std::string& keyROC, const std::string& keyTFT, const std::string& valueStringFormula, const std::string& mpqFileName, const std::vector& clientToken, const std::vector& serverToken, const uint8_t war3Version); + bool HELP_SID_AUTH_CHECK(bool TFT, const std::string& war3Path, const std::string& keyROC, const std::string& keyTFT, const std::string& valueStringFormula, const std::string& mpqFileName, const std::vector& clientToken, const std::vector& serverToken, const uint8_t war3Version); bool HELP_SID_AUTH_ACCOUNTLOGON(); bool HELP_SID_AUTH_ACCOUNTLOGONPROOF(const std::vector& salt, const std::vector& serverKey); bool HELP_PvPGNPasswordHash(const std::string& userPassword); diff --git a/src/bnet.cpp b/src/bnet.cpp index cda11ce7..59950d3d 100644 --- a/src/bnet.cpp +++ b/src/bnet.cpp @@ -244,7 +244,7 @@ bool CBNET::Update(void* fd, void* send_fd) if (m_Protocol->RECEIVE_SID_AUTH_INFO(Data)) { - if (m_BNCSUtil->HELP_SID_AUTH_CHECK(m_Aura->m_Warcraft3Path, m_CDKeyROC, m_CDKeyTFT, m_Protocol->GetValueStringFormulaString(), m_Protocol->GetIX86VerFileNameString(), m_Protocol->GetClientToken(), m_Protocol->GetServerToken(), m_War3Version)) + if (m_BNCSUtil->HELP_SID_AUTH_CHECK(m_Aura->m_TFT, m_Aura->m_Warcraft3Path, m_CDKeyROC, m_CDKeyTFT, m_Protocol->GetValueStringFormulaString(), m_Protocol->GetIX86VerFileNameString(), m_Protocol->GetClientToken(), m_Protocol->GetServerToken(), m_War3Version)) { // override the exe information generated by bncsutil if specified in the config file // apparently this is useful for pvpgn users @@ -261,9 +261,12 @@ bool CBNET::Update(void* fd, void* send_fd) m_BNCSUtil->SetEXEVersionHash(m_EXEVersionHash); } - Print("[BNET: " + m_ServerAlias + "] attempting to auth as Warcraft III: The Frozen Throne"); + if (m_Aura->m_TFT) + Print("[BNET: " + m_ServerAlias + "] attempting to auth as Warcraft III: The Frozen Throne"); + else + Print("[BNET: " + m_ServerAlias + "] attempting to auth as Warcraft III: Reign of Chaos"); - m_Socket->PutBytes(m_Protocol->SEND_SID_AUTH_CHECK(m_Protocol->GetClientToken(), m_BNCSUtil->GetEXEVersion(), m_BNCSUtil->GetEXEVersionHash(), m_BNCSUtil->GetKeyInfoROC(), m_BNCSUtil->GetKeyInfoTFT(), m_BNCSUtil->GetEXEInfo(), "Aura")); + m_Socket->PutBytes(m_Protocol->SEND_SID_AUTH_CHECK(m_Aura->m_TFT, m_Protocol->GetClientToken(), m_BNCSUtil->GetEXEVersion(), m_BNCSUtil->GetEXEVersionHash(), m_BNCSUtil->GetKeyInfoROC(), m_BNCSUtil->GetKeyInfoTFT(), m_BNCSUtil->GetEXEInfo(), "Aura")); } else { @@ -486,7 +489,7 @@ bool CBNET::Update(void* fd, void* send_fd) Print2("[BNET: " + m_ServerAlias + "] connected"); m_Socket->PutBytes(m_Protocol->SEND_PROTOCOL_INITIALIZE_SELECTOR()); - m_Socket->PutBytes(m_Protocol->SEND_SID_AUTH_INFO(m_War3Version, m_LocaleID, m_CountryAbbrev, m_Country)); + m_Socket->PutBytes(m_Protocol->SEND_SID_AUTH_INFO(m_War3Version, m_Aura->m_TFT, m_LocaleID, m_CountryAbbrev, m_Country)); m_Socket->DoSend(static_cast(send_fd)); m_LastNullTime = Time; m_LastOutPacketTicks = Ticks; @@ -1164,7 +1167,7 @@ void CBNET::ProcessChatEvent(const CIncomingChatEvent* chatEvent) // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) // note: we do not use m_Map->GetMapGameType because none of the filters are set when broadcasting to LAN (also as you might expect) - m_Aura->m_UDPSocket->SendTo(IP, Port, m_Aura->m_CurrentGame->GetProtocol()->SEND_W3GS_GAMEINFO(m_Aura->m_LANWar3Version, CreateByteArray(static_cast(MAPGAMETYPE_UNKNOWN0), false), m_Aura->m_CurrentGame->GetMap()->GetMapGameFlags(), m_Aura->m_CurrentGame->GetMap()->GetMapWidth(), m_Aura->m_CurrentGame->GetMap()->GetMapHeight(), m_Aura->m_CurrentGame->GetGameName(), "Clan 007", 0, m_Aura->m_CurrentGame->GetMap()->GetMapPath(), m_Aura->m_CurrentGame->GetMap()->GetMapCRC(), MAX_SLOTS, MAX_SLOTS, m_Aura->m_CurrentGame->GetHostPort(), m_Aura->m_CurrentGame->GetHostCounter() & 0x0FFFFFFF, m_Aura->m_CurrentGame->GetEntryKey())); + m_Aura->m_UDPSocket->SendTo(IP, Port, m_Aura->m_CurrentGame->GetProtocol()->SEND_W3GS_GAMEINFO(m_Aura->m_TFT, m_Aura->m_LANWar3Version, CreateByteArray(static_cast(MAPGAMETYPE_UNKNOWN0), false), m_Aura->m_CurrentGame->GetMap()->GetMapGameFlags(), m_Aura->m_CurrentGame->GetMap()->GetMapWidth(), m_Aura->m_CurrentGame->GetMap()->GetMapHeight(), m_Aura->m_CurrentGame->GetGameName(), "Clan 007", 0, m_Aura->m_CurrentGame->GetMap()->GetMapPath(), m_Aura->m_CurrentGame->GetMap()->GetMapCRC(), MAX_SLOTS, MAX_SLOTS, m_Aura->m_CurrentGame->GetHostPort(), m_Aura->m_CurrentGame->GetHostCounter() & 0x0FFFFFFF, m_Aura->m_CurrentGame->GetEntryKey())); } break; diff --git a/src/bnetprotocol.cpp b/src/bnetprotocol.cpp index 25374326..7777f9d2 100644 --- a/src/bnetprotocol.cpp +++ b/src/bnetprotocol.cpp @@ -558,10 +558,11 @@ std::vector CBNETProtocol::SEND_SID_NETGAMEPORT(uint16_t serverPort) return packet; } -std::vector CBNETProtocol::SEND_SID_AUTH_INFO(uint8_t ver, uint32_t localeID, const string& countryAbbrev, const string& country) +std::vector CBNETProtocol::SEND_SID_AUTH_INFO(uint8_t ver, bool TFT, uint32_t localeID, const string& countryAbbrev, const string& country) { const uint8_t ProtocolID[] = {0, 0, 0, 0}; const uint8_t PlatformID[] = {54, 56, 88, 73}; // "IX86" + const uint8_t ProductID_ROC[] = {51, 82, 65, 87}; // "WAR3" const uint8_t ProductID_TFT[] = {80, 88, 51, 87}; // "W3XP" const uint8_t Version[] = {ver, 0, 0, 0}; const uint8_t Language[] = {83, 85, 110, 101}; // "enUS" @@ -575,7 +576,12 @@ std::vector CBNETProtocol::SEND_SID_AUTH_INFO(uint8_t ver, uint32_t loc packet.push_back(0); // packet length will be assigned later AppendByteArray(packet, ProtocolID, 4); // Protocol ID AppendByteArray(packet, PlatformID, 4); // Platform ID - AppendByteArray(packet, ProductID_TFT, 4); // Product ID (TFT) + + if (TFT) + AppendByteArray(packet, ProductID_TFT, 4); // Product ID (TFT) + else + AppendByteArray(packet, ProductID_ROC, 4); // Product ID (ROC) + AppendByteArray(packet, Version, 4); // Version AppendByteArray(packet, Language, 4); // Language (hardcoded as enUS to ensure battle.net sends the bot messages in English) AppendByteArray(packet, LocalIP, 4); // Local IP for NAT compatibility @@ -589,7 +595,7 @@ std::vector CBNETProtocol::SEND_SID_AUTH_INFO(uint8_t ver, uint32_t loc return packet; } -std::vector CBNETProtocol::SEND_SID_AUTH_CHECK(const std::vector& clientToken, const std::vector& exeVersion, const std::vector& exeVersionHash, const std::vector& keyInfoROC, const std::vector& keyInfoTFT, const string& exeInfo, const string& keyOwnerName) +std::vector CBNETProtocol::SEND_SID_AUTH_CHECK(bool TFT, const std::vector& clientToken, const std::vector& exeVersion, const std::vector& exeVersionHash, const std::vector& keyInfoROC, const std::vector& keyInfoTFT, const string& exeInfo, const string& keyOwnerName) { std::vector packet; @@ -607,7 +613,10 @@ std::vector CBNETProtocol::SEND_SID_AUTH_CHECK(const std::vector(0), false); // boolean Using Spawn (32 bit) AppendByteArrayFast(packet, keyInfoROC); // ROC Key Info - AppendByteArrayFast(packet, keyInfoTFT); // TFT Key Info + + if (TFT) + AppendByteArrayFast(packet, keyInfoTFT); // TFT Key Info + AppendByteArrayFast(packet, exeInfo); // EXE Info AppendByteArrayFast(packet, keyOwnerName); // CD Key Owner Name AssignLength(packet); diff --git a/src/bnetprotocol.h b/src/bnetprotocol.h index a28d666c..d2fba697 100644 --- a/src/bnetprotocol.h +++ b/src/bnetprotocol.h @@ -154,8 +154,8 @@ class CBNETProtocol std::vector SEND_SID_PING(const std::vector& pingValue); std::vector SEND_SID_LOGONRESPONSE(const std::vector& clientToken, const std::vector& serverToken, const std::vector& passwordHash, const std::string& accountName); std::vector SEND_SID_NETGAMEPORT(uint16_t serverPort); - std::vector SEND_SID_AUTH_INFO(uint8_t ver, uint32_t localeID, const std::string& countryAbbrev, const std::string& country); - std::vector SEND_SID_AUTH_CHECK(const std::vector& clientToken, const std::vector& exeVersion, const std::vector& exeVersionHash, const std::vector& keyInfoROC, const std::vector& keyInfoTFT, const std::string& exeInfo, const std::string& keyOwnerName); + std::vector SEND_SID_AUTH_INFO(uint8_t ver, bool TFT, uint32_t localeID, const std::string& countryAbbrev, const std::string& country); + std::vector SEND_SID_AUTH_CHECK(bool TFT, const std::vector& clientToken, const std::vector& exeVersion, const std::vector& exeVersionHash, const std::vector& keyInfoROC, const std::vector& keyInfoTFT, const std::string& exeInfo, const std::string& keyOwnerName); std::vector SEND_SID_AUTH_ACCOUNTLOGON(const std::vector& clientPublicKey, const std::string& accountName); std::vector SEND_SID_AUTH_ACCOUNTLOGONPROOF(const std::vector& clientPasswordProof); std::vector SEND_SID_FRIENDLIST(); diff --git a/src/game.cpp b/src/game.cpp index 5a7fb95f..f9a42e5b 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -345,7 +345,7 @@ bool CGame::Update(void* fd, void* send_fd) // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) // note: we do not use m_Map->GetMapGameType because none of the filters are set when broadcasting to LAN (also as you might expect) - m_Aura->m_UDPSocket->Broadcast(6112, m_Protocol->SEND_W3GS_GAMEINFO(m_Aura->m_LANWar3Version, CreateByteArray(static_cast(MAPGAMETYPE_UNKNOWN0), false), m_Map->GetMapGameFlags(), m_Map->GetMapWidth(), m_Map->GetMapHeight(), m_GameName, "Clan 007", 0, m_Map->GetMapPath(), m_Map->GetMapCRC(), MAX_SLOTS, MAX_SLOTS, m_HostPort, m_HostCounter & 0x0FFFFFFF, m_EntryKey)); + m_Aura->m_UDPSocket->Broadcast(6112, m_Protocol->SEND_W3GS_GAMEINFO(m_Aura->m_TFT, m_Aura->m_LANWar3Version, CreateByteArray(static_cast(MAPGAMETYPE_UNKNOWN0), false), m_Map->GetMapGameFlags(), m_Map->GetMapWidth(), m_Map->GetMapHeight(), m_GameName, "Clan 007", 0, m_Map->GetMapPath(), m_Map->GetMapCRC(), MAX_SLOTS, MAX_SLOTS, m_HostPort, m_HostCounter & 0x0FFFFFFF, m_EntryKey)); } m_LastPingTime = Time; @@ -2686,8 +2686,8 @@ bool CGame::EventPlayerBotCommand(CGamePlayer* player, string& command, string& // note: the PrivateGame flag is not set when broadcasting to LAN (as you might expect) // note: we do not use m_Map->GetMapGameType because none of the filters are set when broadcasting to LAN (also as you might expect) - - m_Aura->m_UDPSocket->SendTo(IP, Port, m_Protocol->SEND_W3GS_GAMEINFO(m_Aura->m_LANWar3Version, CreateByteArray(static_cast(MAPGAMETYPE_UNKNOWN0), false), m_Map->GetMapGameFlags(), m_Map->GetMapWidth(), m_Map->GetMapHeight(), m_GameName, "Clan 007", 0, m_Map->GetMapPath(), m_Map->GetMapCRC(), MAX_SLOTS, MAX_SLOTS, m_HostPort, m_HostCounter & 0x0FFFFFFF, m_EntryKey)); + + m_Aura->m_UDPSocket->SendTo(IP, Port, m_Protocol->SEND_W3GS_GAMEINFO(m_Aura->m_TFT, m_Aura->m_LANWar3Version, CreateByteArray(static_cast(MAPGAMETYPE_UNKNOWN0), false), m_Map->GetMapGameFlags(), m_Map->GetMapWidth(), m_Map->GetMapHeight(), m_GameName, "Clan 007", 0, m_Map->GetMapPath(), m_Map->GetMapCRC(), MAX_SLOTS, MAX_SLOTS, m_HostPort, m_HostCounter & 0x0FFFFFFF, m_EntryKey)); } break; diff --git a/src/gameprotocol.cpp b/src/gameprotocol.cpp index b577e490..ee44411a 100644 --- a/src/gameprotocol.cpp +++ b/src/gameprotocol.cpp @@ -469,10 +469,13 @@ std::vector CGameProtocol::SEND_W3GS_STOP_LAG(CGamePlayer* player) return packet; } -std::vector CGameProtocol::SEND_W3GS_GAMEINFO(uint8_t war3Version, const std::vector& mapGameType, const std::vector& mapFlags, const std::vector& mapWidth, const std::vector& mapHeight, const string& gameName, const string& hostName, uint32_t upTime, const string& mapPath, const std::vector& mapCRC, uint32_t slotsTotal, uint32_t slotsOpen, uint16_t port, uint32_t hostCounter, uint32_t entryKey) +std::vector CGameProtocol::SEND_W3GS_GAMEINFO(bool TFT, uint8_t war3Version, const std::vector& mapGameType, const std::vector& mapFlags, const std::vector& mapWidth, const std::vector& mapHeight, const string& gameName, const string& hostName, uint32_t upTime, const string& mapPath, const std::vector& mapCRC, uint32_t slotsTotal, uint32_t slotsOpen, uint16_t port, uint32_t hostCounter, uint32_t entryKey) { if (mapGameType.size() == 4 && mapFlags.size() == 4 && mapWidth.size() == 2 && mapHeight.size() == 2 && !gameName.empty() && !hostName.empty() && !mapPath.empty() && mapCRC.size() == 4) { + const uint8_t ProductID_ROC[] = {51, 82, 65, 87}; // "WAR3" + const uint8_t ProductID_TFT[] = {80, 88, 51, 87}; // "W3XP" + const uint8_t Version[] = {war3Version, 0, 0, 0}; const uint8_t Unknown2[] = {1, 0, 0, 0}; // make the stat string @@ -489,8 +492,14 @@ std::vector CGameProtocol::SEND_W3GS_GAMEINFO(uint8_t war3Version, cons StatString = EncodeStatString(StatString); // make the rest of the packet + std::vector packet = {W3GS_HEADER_CONSTANT, W3GS_GAMEINFO, 0, 0}; - std::vector packet = {W3GS_HEADER_CONSTANT, W3GS_GAMEINFO, 0, 0, 80, 88, 51, 87, war3Version, 0, 0, 0}; + if (TFT) + AppendByteArray(packet, ProductID_TFT, 4); // Product ID (TFT) + else + AppendByteArray(packet, ProductID_ROC, 4); // Product ID (ROC) + + AppendByteArray(packet, Version, 4); AppendByteArray(packet, hostCounter, false); // Host Counter AppendByteArray(packet, entryKey, false); // Entry Key AppendByteArrayFast(packet, gameName); // Game Name @@ -511,9 +520,24 @@ std::vector CGameProtocol::SEND_W3GS_GAMEINFO(uint8_t war3Version, cons return std::vector(); } -std::vector CGameProtocol::SEND_W3GS_CREATEGAME(uint8_t war3Version) +std::vector CGameProtocol::SEND_W3GS_CREATEGAME(bool TFT, uint8_t war3Version) { - return std::vector{W3GS_HEADER_CONSTANT, W3GS_CREATEGAME, 16, 0, 80, 88, 51, 87, war3Version, 0, 0, 0, 1, 0, 0, 0}; + const uint8_t ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" + const uint8_t ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" + const uint8_t Version[] = { war3Version, 0, 0, 0 }; + const uint8_t Unknown2[] = { 1, 0, 0, 0 }; + + std::vector packet = {W3GS_HEADER_CONSTANT, W3GS_CREATEGAME, 16, 0}; + + if (TFT) + AppendByteArray(packet, ProductID_TFT, 4); // Product ID (TFT) + else + AppendByteArray(packet, ProductID_ROC, 4); // Product ID (ROC) + + AppendByteArray(packet, Version, 4); + AppendByteArray(packet, Unknown2, 4); + + return packet; } std::vector CGameProtocol::SEND_W3GS_REFRESHGAME(uint32_t players, uint32_t playerSlots) diff --git a/src/gameprotocol.h b/src/gameprotocol.h index fab7b982..23023979 100644 --- a/src/gameprotocol.h +++ b/src/gameprotocol.h @@ -135,8 +135,8 @@ class CGameProtocol std::vector SEND_W3GS_CHAT_FROM_HOST(uint8_t fromPID, const std::vector& toPIDs, uint8_t flag, const std::vector& flagExtra, const std::string& message); std::vector SEND_W3GS_START_LAG(std::vector players); std::vector SEND_W3GS_STOP_LAG(CGamePlayer* player); - std::vector SEND_W3GS_GAMEINFO(uint8_t war3Version, const std::vector& mapGameType, const std::vector& mapFlags, const std::vector& mapWidth, const std::vector& mapHeight, const std::string& gameName, const std::string& hostName, uint32_t upTime, const std::string& mapPath, const std::vector& mapCRC, uint32_t slotsTotal, uint32_t slotsOpen, uint16_t port, uint32_t hostCounter, uint32_t entryKey); - std::vector SEND_W3GS_CREATEGAME(uint8_t war3Version); + std::vector SEND_W3GS_GAMEINFO(bool TFT, uint8_t war3Version, const std::vector& mapGameType, const std::vector& mapFlags, const std::vector& mapWidth, const std::vector& mapHeight, const std::string& gameName, const std::string& hostName, uint32_t upTime, const std::string& mapPath, const std::vector& mapCRC, uint32_t slotsTotal, uint32_t slotsOpen, uint16_t port, uint32_t hostCounter, uint32_t entryKey); + std::vector SEND_W3GS_CREATEGAME(bool TFT, uint8_t war3Version); std::vector SEND_W3GS_REFRESHGAME(uint32_t players, uint32_t playerSlots); std::vector SEND_W3GS_DECREATEGAME(); std::vector SEND_W3GS_MAPCHECK(const std::string& mapPath, const std::vector& mapSize, const std::vector& mapInfo, const std::vector& mapCRC, const std::vector& mapSHA1);