Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
815 lines (720 sloc) 28 KB
Index: default.cfg
===================================================================
--- default.cfg (revision 569)
+++ default.cfg (working copy)
@@ -354,6 +354,23 @@
db_mysql_botid = 1
+####################################
+# UDP COMMAND SOCKET CONFIGURATION #
+####################################
+
+### Enable the command socket or not?
+udp_cmdsocket = 0
+
+### The local ip and port to bind on
+### BE CAREFUL if you use a public ip!
+### Anyone can send commands and screw up your bot if you do that!
+udp_cmdbindip = 127.0.0.1
+udp_cmdbindport = 6969
+
+### The default realm to send commands to ( the server alias )
+### An empty string means the first bnet connection will be used
+udp_cmdrealm =
+
############################
# BATTLE.NET CONFIGURATION #
############################
Index: ghost/game.cpp
===================================================================
--- ghost/game.cpp (revision 569)
+++ ghost/game.cpp (working copy)
@@ -394,9 +394,10 @@
//
// !ADDBAN
// !BAN
+ // !B
//
- else if( ( Command == "addban" || Command == "ban" ) && !Payload.empty( ) && !m_GHost->m_BNETs.empty( ) )
+ else if( ( Command == "addban" || Command == "ban" || Command == "b" ) && !Payload.empty( ) && !m_GHost->m_BNETs.empty( ) )
{
// extract the victim and the reason
// e.g. "Varlock leaver after dying" -> victim: "Varlock", reason: "leaver after dying"
@@ -553,9 +554,10 @@
//
// !BANLAST
+ // !BL
//
- else if( Command == "banlast" && m_GameLoaded && !m_GHost->m_BNETs.empty( ) && m_DBBanLast )
+ else if( ( Command == "banlast" || Command == "bl" ) && m_GameLoaded && !m_GHost->m_BNETs.empty( ) && m_DBBanLast )
m_PairedBanAdds.push_back( PairedBanAdd( User, m_GHost->m_DB->ThreadedBanAdd( m_DBBanLast->GetServer( ), m_DBBanLast->GetName( ), m_DBBanLast->GetIP( ), m_GameName, User, Payload ) ) );
//
@@ -626,9 +628,10 @@
//
// !CLOSE (close slot)
+ // !C
//
- else if( Command == "close" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded )
+ else if( ( Command == "close" || Command == "c" ) && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded )
{
// close as many slots as specified, e.g. "5 10" closes slots 5 and 10
@@ -652,9 +655,10 @@
//
// !CLOSEALL
+ // !CA
//
- else if( Command == "closeall" && !m_GameLoading && !m_GameLoaded )
+ else if( ( Command == "closeall" || Command == "ca" ) && !m_GameLoading && !m_GameLoaded )
CloseAllSlots( );
//
@@ -980,9 +984,10 @@
//
// !FROM
+ // !F
//
- else if( Command == "from" )
+ else if( Command == "from" || Command == "f" )
{
string Froms;
@@ -991,6 +996,15 @@
// we reverse the byte order on the IP because it's stored in network byte order
Froms += (*i)->GetNameTerminated( );
+
+ // Show the joined realm
+ // GetJoinedRealm() returns something like "useast.battle.net"
+ if ( (*i)->GetJoinedRealm( ).substr( 0, 3 ) == "use" ) {
+ Froms += "@USEast";
+ } else if ( (*i)->GetJoinedRealm( ).substr( 0, 3 ) == "usw" ) {
+ Froms += "@USWest";
+ }
+
Froms += ": (";
Froms += m_GHost->m_DBLocal->FromCheck( UTIL_ByteArrayToUInt32( (*i)->GetExternalIP( ), true ) );
Froms += ")";
@@ -1040,9 +1054,10 @@
//
// !HOLD (hold a slot for someone)
+ // !H
//
- else if( Command == "hold" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded )
+ else if( ( Command == "hold" || Command == "h" ) && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded )
{
// hold as many players as specified, e.g. "Varlock Kilranin" holds players "Varlock" and "Kilranin"
@@ -1069,9 +1084,10 @@
//
// !KICK (kick a player)
+ // !K
//
- else if( Command == "kick" && !Payload.empty( ) )
+ else if( ( Command == "kick" || Command == "k" ) && !Payload.empty( ) )
{
CGamePlayer *LastMatch = NULL;
uint32_t Matches = GetPlayerFromNamePartial( Payload, &LastMatch );
@@ -1182,9 +1198,10 @@
//
// !OPEN (open slot)
+ // !O
//
- else if( Command == "open" && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded )
+ else if( ( Command == "open" || Command == "o" ) && !Payload.empty( ) && !m_GameLoading && !m_GameLoaded )
{
// open as many slots as specified, e.g. "5 10" opens slots 5 and 10
@@ -1208,9 +1225,10 @@
//
// !OPENALL
+ // !OA
//
- else if( Command == "openall" && !m_GameLoading && !m_GameLoaded )
+ else if( ( Command == "openall" || Command == "oa" ) && !m_GameLoading && !m_GameLoaded )
OpenAllSlots( );
//
@@ -1238,9 +1256,10 @@
//
// !PING
+ // !P
//
- else if( Command == "ping" )
+ else if( Command == "ping" || Command == "p" )
{
// kick players with ping higher than payload if payload isn't empty
// we only do this if the game hasn't started since we don't want to kick players from a game in progress
@@ -1260,6 +1279,15 @@
for( vector<CGamePlayer *> :: iterator i = SortedPlayers.begin( ); i != SortedPlayers.end( ); ++i )
{
Pings += (*i)->GetNameTerminated( );
+
+ // Show the joined realm
+ // GetJoinedRealm() returns something like "useast.battle.net"
+ if ( (*i)->GetJoinedRealm( ).substr( 0, 3 ) == "use" ) {
+ Pings += "@USEast";
+ } else if ( (*i)->GetJoinedRealm( ).substr( 0, 3 ) == "usw" ) {
+ Pings += "@USWest";
+ }
+
Pings += ": ";
if( (*i)->GetNumPings( ) > 0 )
@@ -1813,6 +1841,15 @@
SendAllChat( m_GHost->m_Language->VoteKickAcceptedNeedMoreVotes( m_KickVotePlayer, User, UTIL_ToString( VotesNeeded - Votes ) ) );
}
+ //
+ // !GN
+ //
+
+ else if( Command == "gn" )
+ {
+ SendChat( player, "Current game name is \"" + m_GameName + "\"" );
+ }
+
return HideCommand;
}
Index: ghost/Makefile
===================================================================
--- ghost/Makefile (revision 569)
+++ ghost/Makefile (working copy)
@@ -2,9 +2,9 @@
SYSTEM = $(shell uname)
C++ = g++
CC = gcc
-DFLAGS = -DGHOST_MYSQL
+DFLAGS =
OFLAGS = -O3
-LFLAGS = -L. -L../bncsutil/src/bncsutil/ -L../StormLib/stormlib/ -lbncsutil -lpthread -ldl -lz -lStorm -lmysqlclient_r -lboost_date_time-mt -lboost_thread-mt -lboost_system-mt -lboost_filesystem-mt
+LFLAGS = -L. -L../bncsutil/src/bncsutil/ -L../StormLib/stormlib/ -lbncsutil -lpthread -ldl -lz -lStorm -lboost_date_time-mt -lboost_thread-mt -lboost_system-mt -lboost_filesystem-mt
CFLAGS =
ifeq ($(SYSTEM),Darwin)
Index: ghost/game_base.cpp
===================================================================
--- ghost/game_base.cpp (revision 569)
+++ ghost/game_base.cpp (working copy)
@@ -1702,12 +1702,16 @@
SendAllChat( m_GHost->m_Language->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) );
m_IgnoredNames.insert( joinPlayer->GetName( ) );
}
-
+/* This code causes crashes sometimes...
// let banned players "join" the game with an arbitrary PID then immediately close the connection
// this causes them to be kicked back to the chat channel on battle.net
vector<CGameSlot> Slots = m_Map->GetSlots( );
potential->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( 1, potential->GetSocket( )->GetPort( ), potential->GetExternalIP( ), Slots, 0, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) );
+*/
+
+ // safer to just send game full
+ potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) );
potential->SetDeleteMe( true );
return;
}
@@ -1730,12 +1734,16 @@
SendAllChat( m_GHost->m_Language->UserWasBannedOnByBecause( Ban->GetServer( ), Ban->GetName( ), Ban->GetDate( ), Ban->GetAdmin( ), Ban->GetReason( ) ) );
m_IgnoredNames.insert( joinPlayer->GetName( ) );
}
-
+/* This code causes crashes sometimes...
// let banned players "join" the game with an arbitrary PID then immediately close the connection
// this causes them to be kicked back to the chat channel on battle.net
vector<CGameSlot> Slots = m_Map->GetSlots( );
potential->Send( m_Protocol->SEND_W3GS_SLOTINFOJOIN( 1, potential->GetSocket( )->GetPort( ), potential->GetExternalIP( ), Slots, 0, m_Map->GetMapLayoutStyle( ), m_Map->GetMapNumPlayers( ) ) );
+*/
+
+ // safer to just send game full
+ potential->Send( m_Protocol->SEND_W3GS_REJECTJOIN( REJECTJOIN_FULL ) );
potential->SetDeleteMe( true );
return;
}
@@ -1762,7 +1770,7 @@
for( vector<CBNET *> :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); ++i )
{
- if( (*i)->IsAdmin( joinPlayer->GetName( ) ) || (*i)->IsRootAdmin( joinPlayer->GetName( ) ) )
+ if( (*i)->IsAdmin( joinPlayer->GetName( ) ) || (*i)->IsRootAdmin( joinPlayer->GetName( ) ) || IsOwner( joinPlayer->GetName( ) ) )
{
AnyAdminCheck = true;
break;
@@ -1925,7 +1933,7 @@
// this problem is solved by setting the socket to NULL before deletion and handling the NULL case in the destructor
// we also have to be careful to not modify the m_Potentials vector since we're currently looping through it
- CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] joined the game" );
+ CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "@" + JoinedRealm + "|" + potential->GetExternalIPString( ) + "] joined the game" );
CGamePlayer *Player = new CGamePlayer( potential, m_SaveGame ? EnforcePID : GetNewPID( ), JoinedRealm, joinPlayer->GetName( ), joinPlayer->GetInternalIP( ), Reserved );
// consider LAN players to have already spoof checked since they can't
@@ -2078,7 +2086,8 @@
if( m_GHost->m_AutoLock && !m_Locked && IsOwner( joinPlayer->GetName( ) ) )
{
- SendAllChat( m_GHost->m_Language->GameLocked( ) );
+// Unnecessary spam...
+// SendAllChat( m_GHost->m_Language->GameLocked( ) );
m_Locked = true;
}
@@ -2134,7 +2143,7 @@
for( vector<CBNET *> :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); ++i )
{
- if( (*i)->IsAdmin( joinPlayer->GetName( ) ) || (*i)->IsRootAdmin( joinPlayer->GetName( ) ) )
+ if( (*i)->IsAdmin( joinPlayer->GetName( ) ) || (*i)->IsRootAdmin( joinPlayer->GetName( ) ) || IsOwner( joinPlayer->GetName( ) ) )
{
AnyAdminCheck = true;
break;
@@ -2334,7 +2343,7 @@
// this problem is solved by setting the socket to NULL before deletion and handling the NULL case in the destructor
// we also have to be careful to not modify the m_Potentials vector since we're currently looping through it
- CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "|" + potential->GetExternalIPString( ) + "] joined the game" );
+ CONSOLE_Print( "[GAME: " + m_GameName + "] player [" + joinPlayer->GetName( ) + "@" + JoinedRealm + "|" + potential->GetExternalIPString( ) + "] joined the game" );
CGamePlayer *Player = new CGamePlayer( potential, GetNewPID( ), JoinedRealm, joinPlayer->GetName( ), joinPlayer->GetInternalIP( ), false );
// consider LAN players to have already spoof checked since they can't
@@ -2490,7 +2499,8 @@
if( m_GHost->m_AutoLock && !m_Locked && IsOwner( joinPlayer->GetName( ) ) )
{
- SendAllChat( m_GHost->m_Language->GameLocked( ) );
+// Unnecessary spam...
+// SendAllChat( m_GHost->m_Language->GameLocked( ) );
m_Locked = true;
}
Index: ghost/includes.h
===================================================================
--- ghost/includes.h (revision 569)
+++ ghost/includes.h (working copy)
@@ -21,6 +21,10 @@
#ifndef INCLUDES_H
#define INCLUDES_H
+// define the boost filesystem version for compatibility
+// If you have a newer boost, you can set this to 3
+#define BOOST_FILESYSTEM_VERSION 2
+
// standard integer sizes for 64 bit compatibility
#ifdef WIN32
Index: ghost/ghostdbsqlite.cpp
===================================================================
--- ghost/ghostdbsqlite.cpp (revision 569)
+++ ghost/ghostdbsqlite.cpp (working copy)
@@ -32,8 +32,9 @@
CSQLITE3 :: CSQLITE3( string filename )
{
m_Ready = true;
-
- if( sqlite3_open_v2( filename.c_str( ), (sqlite3 **)&m_DB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL ) != SQLITE_OK )
+
+ // Use OPEN_FULLMUTEX to make sure only 1 thread can access the DB at the same time
+ if( sqlite3_open_v2( filename.c_str( ), (sqlite3 **)&m_DB, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL ) != SQLITE_OK )
m_Ready = false;
}
@@ -119,7 +120,10 @@
m_HasError = true;
m_Error = "error opening database";
return;
- }
+ }
+
+ // tweak default values
+ m_DB->Exec("PRAGMA default_cache_size=4000; PRAGMA synchronous=OFF; PRAGMA temp_store=2;");
// find the schema number so we can determine whether we need to upgrade or not
Index: ghost/game_admin.cpp
===================================================================
--- ghost/game_admin.cpp (revision 569)
+++ ghost/game_admin.cpp (working copy)
@@ -927,8 +927,16 @@
for( directory_iterator i( MapCFGPath ); i != EndIterator; ++i )
{
+#if BOOST_FILESYSTEM_VERSION == 3
string FileName = i->path( ).filename( ).string( );
string Stem = i->path( ).stem( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ string FileName = i->filename( );
+ string Stem = i->path( ).stem( );
+#else
+ #error "What BOOST version?"
+#endif
+
transform( FileName.begin( ), FileName.end( ), FileName.begin( ), (int(*)(int))tolower );
transform( Stem.begin( ), Stem.end( ), Stem.begin( ), (int(*)(int))tolower );
@@ -938,9 +946,17 @@
++Matches;
if( FoundMapConfigs.empty( ) )
+#if BOOST_FILESYSTEM_VERSION == 3
FoundMapConfigs = i->path( ).filename( ).string( );
else
FoundMapConfigs += ", " + i->path( ).filename( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ FoundMapConfigs = i->filename( );
+ else
+ FoundMapConfigs += ", " + i->filename( );
+#else
+ #error "What BOOST version?"
+#endif
// if the pattern matches the filename exactly, with or without extension, stop any further matching
@@ -956,7 +972,13 @@
SendChat( player, m_GHost->m_Language->NoMapConfigsFound( ) );
else if( Matches == 1 )
{
+#if BOOST_FILESYSTEM_VERSION == 3
string File = LastMatch.filename( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ string File = LastMatch.filename( );
+#else
+ #error "What BOOST version?"
+#endif
SendChat( player, m_GHost->m_Language->LoadingConfigFile( m_GHost->m_MapCFGPath + File ) );
CConfig MapCFG;
MapCFG.Read( LastMatch.string( ) );
@@ -1038,8 +1060,16 @@
for( directory_iterator i( MapPath ); i != EndIterator; ++i )
{
+#if BOOST_FILESYSTEM_VERSION == 3
string FileName = i->path( ).filename( ).string( );
string Stem = i->path( ).stem( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ string FileName = i->filename( );
+ string Stem = i->path( ).stem( );
+#else
+ #error "What BOOST version?"
+#endif
+
transform( FileName.begin( ), FileName.end( ), FileName.begin( ), (int(*)(int))tolower );
transform( Stem.begin( ), Stem.end( ), Stem.begin( ), (int(*)(int))tolower );
@@ -1049,9 +1079,17 @@
++Matches;
if( FoundMaps.empty( ) )
+#if BOOST_FILESYSTEM_VERSION == 3
FoundMaps = i->path( ).filename( ).string( );
else
FoundMaps += ", " + i->path( ).filename( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ FoundMaps = i->filename( );
+ else
+ FoundMaps += ", " + i->filename( );
+#else
+ #error "What BOOST version?"
+#endif
// if the pattern matches the filename exactly, with or without extension, stop any further matching
@@ -1067,7 +1105,14 @@
SendChat( player, m_GHost->m_Language->NoMapsFound( ) );
else if( Matches == 1 )
{
+#if BOOST_FILESYSTEM_VERSION == 3
string File = LastMatch.filename( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ string File = LastMatch.filename( );
+#else
+ #error "What BOOST version?"
+#endif
+
SendChat( player, m_GHost->m_Language->LoadingConfigFile( File ) );
// hackhack: create a config file in memory with the required information to load the map
Index: ghost/ghost.cpp
===================================================================
--- ghost/ghost.cpp (revision 569)
+++ ghost/ghost.cpp (working copy)
@@ -38,7 +38,8 @@
#include "gpsprotocol.h"
#include "game_base.h"
#include "game.h"
-#include "game_admin.h"
+#include "game_admin.h"
+#include "bnetprotocol.h"
#include <signal.h>
#include <stdlib.h>
@@ -486,7 +487,7 @@
m_Exiting = false;
m_ExitingNice = false;
m_Enabled = true;
- m_Version = "17.1";
+ m_Version = "17.1 ap0c";
m_HostCounter = 1;
m_AutoHostMaximumGames = CFG->GetInt( "autohost_maxgames", 0 );
m_AutoHostAutoStartPlayers = CFG->GetInt( "autohost_startplayers", 0 );
@@ -515,7 +516,19 @@
m_AdminGameMap = CFG->GetString( "admingame_map", string( ) );
m_LANWar3Version = CFG->GetInt( "lan_war3version", 26 );
m_ReplayWar3Version = CFG->GetInt( "replay_war3version", 26 );
- m_ReplayBuildNumber = CFG->GetInt( "replay_buildnumber", 6059 );
+ m_ReplayBuildNumber = CFG->GetInt( "replay_buildnumber", 6059 );
+
+ // UDPCommandSocket patch
+ m_UDPCommandSocketEnabled = CFG->GetInt( "udp_cmdsocket", 0 ) == 0 ? false : true;
+ if ( m_UDPCommandSocketEnabled ) {
+ m_UDPCommandRealm = CFG->GetString( "udp_cmdrealm", string( ) );
+ m_UDPCommandSocket = new CUDPServer();
+ string bindip = CFG->GetString( "udp_cmdbindip", "localhost" );
+ int bindport = CFG->GetInt( "udp_cmdbindport", 6969 );
+ m_UDPCommandSocket->Bind( bindip, bindport );
+ CONSOLE_Print( "[UDPCMDSOCK] Listening on " + bindip + ":" + UTIL_ToString( bindport ) );
+ }
+
SetConfigs( CFG );
// load the battle.net connections
@@ -691,7 +704,12 @@
}
CGHost :: ~CGHost( )
-{
+{
+ // UDPCommandSocket patch
+ if ( m_UDPCommandSocketEnabled ) {
+ delete m_UDPCommandSocket;
+ }
+
delete m_UDPSocket;
delete m_ReconnectSocket;
@@ -881,6 +899,14 @@
{
(*i)->SetFD( &fd, &send_fd, &nfds );
++NumFDs;
+ }
+
+ // 6. UDPCommandSocket socket(s)
+ if ( m_UDPCommandSocketEnabled ) {
+ m_UDPCommandSocket->SetFD( &fd, &send_fd, &nfds);
+
+ // SetFD of the UDPServer does not return the number of sockets belonging to it as it's obviously one
+ ++NumFDs;
}
// before we call select we need to determine how long to block for
@@ -988,6 +1014,58 @@
{
if( (*i)->Update( &fd, &send_fd ) )
BNETExit = true;
+ }
+
+ // process UDPCommandSocket clients
+ if ( m_UDPCommandSocketEnabled ) {
+ struct sockaddr_in recvAddr;
+ string udpcommand;
+ m_UDPCommandSocket->RecvFrom( &fd, &recvAddr, &udpcommand);
+ if ( udpcommand.size() ) {
+ // default server to relay the message to
+ string udptarget = m_UDPCommandRealm;
+ bool relayed = false;
+ string recvFrom = inet_ntoa( recvAddr.sin_addr );
+
+ // has the user specified a specific target the command should be sent to?
+ // looks for "<alias>" at the beginning of the received command,
+ // sets the target accordingly and strips it from the command
+ int pos;
+ if ( udpcommand.find("<") == 0 && (pos=udpcommand.find(">")) != string::npos ) {
+ udptarget = udpcommand.substr(1, pos - 1);
+ udpcommand.erase(0, pos + 1);
+
+ // remove any whitespace
+ pos = udpcommand.find_first_not_of(" ");
+ if ( pos != string::npos ) {
+ udpcommand.erase(0, pos);
+ }
+ }
+
+ // we expect commands not to start with the command trigger because this is a commandsocket,
+ // we only except commands and therefore know we received one and not some chatting
+ // this way the user sending the command does not have to have knowledge of the commandtrigger
+ // set in GHost's config file
+ udpcommand = m_CommandTrigger + udpcommand;
+
+ // loop through all connections to find the server the command should be issued on
+ for( vector<CBNET *> :: iterator i = m_BNETs.begin( ); i != m_BNETs.end( ); ++i ) {
+ // is this the right one or should we just send it to the first in list?
+ if ( udptarget.empty() || udptarget == (*i)->GetServerAlias( ) ) {
+ CONSOLE_Print("[UDPCMDSOCK] Relaying src[" + recvFrom + "] cmd [" + udpcommand + "] to server [" + udptarget + "]");
+
+ // spoof a whisper from the rootadmin belonging to this connection
+ CIncomingChatEvent *chatCommand = new CIncomingChatEvent( CBNETProtocol::EID_WHISPER, 0, (*i)->GetRootAdmin( ), udpcommand );
+ (*i)->ProcessChatEvent( chatCommand );
+ relayed = true;
+ break;
+ }
+ }
+
+ if ( ! relayed ) {
+ CONSOLE_Print("[UDPCMDSOCK] Could not relay src[" + recvFrom + "] cmd [" + udpcommand + "] to server [" + udptarget + "]: server unknown");
+ }
+ }
}
// update GProxy++ reliable reconnect sockets
Index: ghost/ghost.h
===================================================================
--- ghost/ghost.h (revision 569)
+++ ghost/ghost.h (working copy)
@@ -41,7 +41,10 @@
class CLanguage;
class CMap;
class CSaveGame;
-class CConfig;
+class CConfig;
+
+// UDPCommandSocket patch
+class CUDPServer;
class CGHost
{
@@ -132,7 +135,13 @@
uint32_t m_ReplayWar3Version; // config value: replay warcraft 3 version (for saving replays)
uint32_t m_ReplayBuildNumber; // config value: replay build number (for saving replays)
bool m_TCPNoDelay; // config value: use Nagle's algorithm or not
- uint32_t m_MatchMakingMethod; // config value: the matchmaking method
+ uint32_t m_MatchMakingMethod; // config value: the matchmaking method
+
+ // UDPCommandSocket patch
+ CUDPServer *m_UDPCommandSocket; // a UDP socket for receiving commands
+ bool m_UDPCommandSocketEnabled; // enable the UDP command socket ( udp_cmdsocket in cfg )
+ // also uses udp_cmdbindip and udp_cmdbindport in cfg
+ string m_UDPCommandRealm; // the realm to send udp received commands to ( udp_cmdrealm in cfg )
CGHost( CConfig *CFG );
~CGHost( );
Index: ghost/bnet.cpp
===================================================================
--- ghost/bnet.cpp (revision 569)
+++ ghost/bnet.cpp (working copy)
@@ -1025,9 +1025,10 @@
//
// !ADDBAN
// !BAN
+ // !B
//
- else if( ( Command == "addban" || Command == "ban" ) && !Payload.empty( ) )
+ else if( ( Command == "addban" || Command == "ban" || Command == "b" ) && !Payload.empty( ) )
{
// extract the victim and the reason
// e.g. "Varlock leaver after dying" -> victim: "Varlock", reason: "leaver after dying"
@@ -1323,9 +1324,10 @@
//
// !CLOSE (close slot)
+ // !C
//
- else if( Command == "close" && !Payload.empty( ) && m_GHost->m_CurrentGame )
+ else if( ( Command == "close" || Command == "c" ) && !Payload.empty( ) && m_GHost->m_CurrentGame )
{
if( !m_GHost->m_CurrentGame->GetLocked( ) )
{
@@ -1354,9 +1356,10 @@
//
// !CLOSEALL
+ // !CA
//
- else if( Command == "closeall" && m_GHost->m_CurrentGame )
+ else if( ( Command == "closeall" || Command == "ca" ) && m_GHost->m_CurrentGame )
{
if( !m_GHost->m_CurrentGame->GetLocked( ) )
m_GHost->m_CurrentGame->CloseAllSlots( );
@@ -1598,9 +1601,10 @@
//
// !HOLD (hold a slot for someone)
+ // !H
//
- else if( Command == "hold" && !Payload.empty( ) && m_GHost->m_CurrentGame )
+ else if( ( Command == "hold" || Command == "h" ) && !Payload.empty( ) && m_GHost->m_CurrentGame )
{
// hold as many players as specified, e.g. "Varlock Kilranin" holds players "Varlock" and "Kilranin"
@@ -1663,8 +1667,15 @@
for( directory_iterator i( MapCFGPath ); i != EndIterator; ++i )
{
+#if BOOST_FILESYSTEM_VERSION == 3
string FileName = i->path( ).filename( ).string( );
string Stem = i->path( ).stem( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ string FileName = i->filename( );
+ string Stem = i->path( ).stem( );
+#else
+ #error "What BOOST version?"
+#endif
transform( FileName.begin( ), FileName.end( ), FileName.begin( ), (int(*)(int))tolower );
transform( Stem.begin( ), Stem.end( ), Stem.begin( ), (int(*)(int))tolower );
@@ -1674,9 +1685,17 @@
++Matches;
if( FoundMapConfigs.empty( ) )
+#if BOOST_FILESYSTEM_VERSION == 3
FoundMapConfigs = i->path( ).filename( ).string( );
else
FoundMapConfigs += ", " + i->path( ).filename( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ FoundMapConfigs = i->filename( );
+ else
+ FoundMapConfigs += ", " + i->filename( );
+#else
+ #error "What BOOST version?"
+#endif
// if the pattern matches the filename exactly, with or without extension, stop any further matching
@@ -1692,7 +1711,14 @@
QueueChatCommand( m_GHost->m_Language->NoMapConfigsFound( ), User, Whisper );
else if( Matches == 1 )
{
+#if BOOST_FILESYSTEM_VERSION == 3
string File = LastMatch.filename( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ string File = LastMatch.filename( );
+#else
+ #error "What BOOST version?"
+#endif
+
QueueChatCommand( m_GHost->m_Language->LoadingConfigFile( m_GHost->m_MapCFGPath + File ), User, Whisper );
CConfig MapCFG;
MapCFG.Read( LastMatch.string( ) );
@@ -1774,8 +1800,16 @@
for( directory_iterator i( MapPath ); i != EndIterator; ++i )
{
+#if BOOST_FILESYSTEM_VERSION == 3
string FileName = i->path( ).filename( ).string( );
string Stem = i->path( ).stem( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ string FileName = i->filename( );
+ string Stem = i->path( ).stem( );
+#else
+ #error "What BOOST version?"
+#endif
+
transform( FileName.begin( ), FileName.end( ), FileName.begin( ), (int(*)(int))tolower );
transform( Stem.begin( ), Stem.end( ), Stem.begin( ), (int(*)(int))tolower );
@@ -1785,9 +1819,17 @@
++Matches;
if( FoundMaps.empty( ) )
+#if BOOST_FILESYSTEM_VERSION == 3
FoundMaps = i->path( ).filename( ).string( );
else
FoundMaps += ", " + i->path( ).filename( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ FoundMaps = i->filename( );
+ else
+ FoundMaps += ", " + i->filename( );
+#else
+ #error "What BOOST version?"
+#endif
// if the pattern matches the filename exactly, with or without extension, stop any further matching
@@ -1803,7 +1845,13 @@
QueueChatCommand( m_GHost->m_Language->NoMapsFound( ), User, Whisper );
else if( Matches == 1 )
{
+#if BOOST_FILESYSTEM_VERSION == 3
string File = LastMatch.filename( ).string( );
+#elif BOOST_FILESYSTEM_VERSION == 2
+ string File = LastMatch.filename( );
+#else
+ #error "What BOOST version?"
+#endif
QueueChatCommand( m_GHost->m_Language->LoadingConfigFile( File ), User, Whisper );
// hackhack: create a config file in memory with the required information to load the map
@@ -1827,9 +1875,10 @@
//
// !OPEN (open slot)
+ // !O
//
- else if( Command == "open" && !Payload.empty( ) && m_GHost->m_CurrentGame )
+ else if( ( Command == "open" || Command == "o" ) && !Payload.empty( ) && m_GHost->m_CurrentGame )
{
if( !m_GHost->m_CurrentGame->GetLocked( ) )
{
@@ -1858,9 +1907,10 @@
//
// !OPENALL
+ // !OA
//
- else if( Command == "openall" && m_GHost->m_CurrentGame )
+ else if( ( Command == "openall" || Command == "oa" ) && m_GHost->m_CurrentGame )
{
if( !m_GHost->m_CurrentGame->GetLocked( ) )
m_GHost->m_CurrentGame->OpenAllSlots( );
@@ -2048,6 +2098,18 @@
}
//
+ // !STARTN
+ //
+
+ else if( Command == "startn" && m_GHost->m_CurrentGame && !m_GHost->m_CurrentGame->GetCountDownStarted( ) && m_GHost->m_CurrentGame->GetNumHumanPlayers( ) > 0 )
+ {
+ if( !m_GHost->m_CurrentGame->GetLocked( ) )
+ m_GHost->m_CurrentGame->StartCountDown( true );
+ else
+ QueueChatCommand( m_GHost->m_Language->TheGameIsLockedBNET( ), User, Whisper );
+ }
+
+ //
// !SWAP (swap slots)
//