2011-03-17 01:47:30 -04:00
# include "global.h"
# include "NetworkSyncManager.h"
# include "LuaManager.h"
# include "LocalizedString.h"
2011-03-27 17:28:44 -07:00
# include <errno.h>
2011-03-17 01:47:30 -04:00
NetworkSyncManager * NSMAN ;
2015-01-28 16:45:19 -06:00
// Aldo: version_num used by GetCurrentSMVersion()
// XXX: That's probably not what you want... --root
2015-10-22 21:21:47 -03:00
2015-01-28 16:45:19 -06:00
# include "ver.h"
2015-10-22 21:21:47 -03:00
2012-05-21 02:29:59 -05:00
2011-03-17 01:47:30 -04:00
# if defined(WITHOUT_NETWORKING)
NetworkSyncManager : : NetworkSyncManager ( LoadingWindow * ld ) { useSMserver = false ; isSMOnline = false ; }
NetworkSyncManager : : ~ NetworkSyncManager ( ) { }
void NetworkSyncManager : : CloseConnection ( ) { }
void NetworkSyncManager : : PostStartUp ( const RString & ServerIP ) { }
bool NetworkSyncManager : : Connect ( const RString & addy , unsigned short port ) { return false ; }
RString NetworkSyncManager : : GetServerName ( ) { return RString ( ) ; }
void NetworkSyncManager : : ReportNSSOnOff ( int i ) { }
void NetworkSyncManager : : ReportScore ( int playerID , int step , int score , int combo , float offset ) { }
2017-02-10 09:57:59 -03:00
void NetworkSyncManager : : ReportScore ( int playerID , int step , int score , int combo , float offset , int numNotes ) { }
2011-03-17 01:47:30 -04:00
void NetworkSyncManager : : ReportSongOver ( ) { }
void NetworkSyncManager : : ReportStyle ( ) { }
void NetworkSyncManager : : StartRequest ( short position ) { }
void NetworkSyncManager : : DisplayStartupStatus ( ) { }
void NetworkSyncManager : : Update ( float fDeltaTime ) { }
bool NetworkSyncManager : : ChangedScoreboard ( int Column ) { return false ; }
void NetworkSyncManager : : SendChat ( const RString & message ) { }
void NetworkSyncManager : : SelectUserSong ( ) { }
RString NetworkSyncManager : : MD5Hex ( const RString & sInput ) { return RString ( ) ; }
int NetworkSyncManager : : GetSMOnlineSalt ( ) { return 0 ; }
2012-05-21 02:29:59 -05:00
void NetworkSyncManager : : GetListOfLANServers ( vector < NetServerInfo > & AllServers ) { }
2015-10-02 20:02:55 -04:00
unsigned long NetworkSyncManager : : GetCurrentSMBuild ( LoadingWindow * ld ) { return 0 ; }
2011-03-17 01:47:30 -04:00
# else
# include "ezsockets.h"
# include "ProfileManager.h"
# include "RageLog.h"
# include "ScreenManager.h"
# include "Song.h"
# include "Course.h"
# include "GameState.h"
# include "StatsManager.h"
# include "Steps.h"
# include "ProductInfo.h"
# include "ScreenMessage.h"
# include "GameManager.h"
# include "MessageManager.h"
# include "arch/LoadingWindow/LoadingWindow.h"
# include "PlayerState.h"
# include "CryptManager.h"
AutoScreenMessage ( SM_AddToChat ) ;
AutoScreenMessage ( SM_ChangeSong ) ;
AutoScreenMessage ( SM_GotEval ) ;
AutoScreenMessage ( SM_UsersUpdate ) ;
2017-02-10 09:57:59 -03:00
AutoScreenMessage ( SM_FriendsUpdate ) ;
2011-03-17 01:47:30 -04:00
AutoScreenMessage ( SM_SMOnlinePack ) ;
int NetworkSyncManager : : GetSMOnlineSalt ( )
{
return m_iSalt ;
}
static LocalizedString INITIALIZING_CLIENT_NETWORK ( " NetworkSyncManager " , " Initializing Client Network... " ) ;
NetworkSyncManager : : NetworkSyncManager ( LoadingWindow * ld )
{
LANserver = NULL ; //So we know if it has been created yet
BroadcastReception = NULL ;
ld - > SetText ( INITIALIZING_CLIENT_NETWORK ) ;
NetPlayerClient = new EzSockets ;
NetPlayerClient - > blocking = false ;
m_ServerVersion = 0 ;
useSMserver = false ;
isSMOnline = false ;
FOREACH_PlayerNumber ( pn )
isSMOLoggedIn [ pn ] = false ;
m_startupStatus = 0 ; //By default, connection not tried.
m_ActivePlayers = 0 ;
StartUp ( ) ;
}
NetworkSyncManager : : ~ NetworkSyncManager ( )
{
//Close Connection to server nicely.
if ( useSMserver )
NetPlayerClient - > close ( ) ;
SAFE_DELETE ( NetPlayerClient ) ;
if ( BroadcastReception )
{
BroadcastReception - > close ( ) ;
SAFE_DELETE ( BroadcastReception ) ;
}
}
void NetworkSyncManager : : CloseConnection ( )
{
if ( ! useSMserver )
return ;
m_ServerVersion = 0 ;
useSMserver = false ;
isSMOnline = false ;
FOREACH_PlayerNumber ( pn )
isSMOLoggedIn [ pn ] = false ;
m_startupStatus = 0 ;
NetPlayerClient - > close ( ) ;
}
void NetworkSyncManager : : PostStartUp ( const RString & ServerIP )
{
RString sAddress ;
2011-03-27 19:06:15 -05:00
unsigned short iPort ;
2011-03-17 01:47:30 -04:00
size_t cLoc = ServerIP . find ( ' : ' ) ;
if ( ServerIP . find ( ' : ' ) ! = RString : : npos )
{
2011-03-27 19:19:31 -05:00
sAddress = ServerIP . substr ( 0 , cLoc ) ;
2011-03-27 19:06:15 -05:00
char * cEnd ;
2011-03-27 19:19:31 -05:00
errno = 0 ;
2011-03-27 19:06:15 -05:00
iPort = ( unsigned short ) strtol ( ServerIP . substr ( cLoc + 1 ) . c_str ( ) , & cEnd , 10 ) ;
2011-03-27 19:19:31 -05:00
if ( * cEnd ! = 0 | | errno ! = 0 )
{
m_startupStatus = 2 ;
LOG - > Warn ( " Invalid port " ) ;
return ;
}
2011-03-17 01:47:30 -04:00
}
else
{
iPort = 8765 ;
sAddress = ServerIP ;
}
2011-03-27 17:49:18 -05:00
LOG - > Info ( " Attempting to connect to: %s, Port: %i " , sAddress . c_str ( ) , iPort ) ;
2011-03-17 01:47:30 -04:00
CloseConnection ( ) ;
if ( ! Connect ( sAddress . c_str ( ) , iPort ) )
{
m_startupStatus = 2 ;
LOG - > Warn ( " Network Sync Manager failed to connect " ) ;
return ;
}
FOREACH_PlayerNumber ( pn )
isSMOLoggedIn [ pn ] = false ;
useSMserver = true ;
2011-03-27 19:19:31 -05:00
m_startupStatus = 1 ; // Connection attepmpt successful
2011-03-17 01:47:30 -04:00
// If network play is desired and the connection works,
// halt until we know what server version we're dealing with
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCHello ) ; //Hello Packet
m_packet . Write1 ( NETPROTOCOLVERSION ) ;
2015-01-28 19:21:24 -06:00
m_packet . WriteNT ( RString ( string ( PRODUCT_FAMILY ) + product_version ) ) ;
2011-03-17 01:47:30 -04:00
/* Block until response is received.
* Move mode to blocking in order to give CPU back to the system,
* and not wait.
*/
bool dontExit = true ;
NetPlayerClient - > blocking = true ;
// The following packet must get through, so we block for it.
// If we are serving, we do not block for this.
NetPlayerClient - > SendPack ( ( char * ) m_packet . Data , m_packet . Position ) ;
m_packet . ClearPacket ( ) ;
while ( dontExit )
{
m_packet . ClearPacket ( ) ;
if ( NetPlayerClient - > ReadPack ( ( char * ) & m_packet , NETMAXBUFFERSIZE ) < 1 )
dontExit = false ; // Also allow exit if there is a problem on the socket
if ( m_packet . Read1 ( ) = = NSServerOffset + NSCHello )
dontExit = false ;
// Only allow passing on handshake; otherwise scoreboard updates and
// such will confuse us.
}
NetPlayerClient - > blocking = false ;
m_ServerVersion = m_packet . Read1 ( ) ;
if ( m_ServerVersion > = 128 )
isSMOnline = true ;
m_ServerName = m_packet . ReadNT ( ) ;
m_iSalt = m_packet . Read4 ( ) ;
LOG - > Info ( " Server Version: %d %s " , m_ServerVersion , m_ServerName . c_str ( ) ) ;
}
void NetworkSyncManager : : StartUp ( )
{
RString ServerIP ;
if ( GetCommandlineArgument ( " netip " , & ServerIP ) )
PostStartUp ( ServerIP ) ;
BroadcastReception = new EzSockets ;
2017-05-24 01:23:22 -07:00
BroadcastReception - > create ( EZS_UDP ) ;
2011-03-17 01:47:30 -04:00
BroadcastReception - > bind ( 8765 ) ;
BroadcastReception - > blocking = false ;
}
bool NetworkSyncManager : : Connect ( const RString & addy , unsigned short port )
{
LOG - > Info ( " Beginning to connect " ) ;
NetPlayerClient - > create ( ) ; // Initialize Socket
2012-01-16 18:04:40 -05:00
LOG - > Info ( " Calling EzSockets:connect() " ) ;
2011-03-17 01:47:30 -04:00
useSMserver = NetPlayerClient - > connect ( addy , port ) ;
2012-01-16 18:04:40 -05:00
LOG - > Info ( " Back from ezsockets... " ) ;
2011-03-17 01:47:30 -04:00
return useSMserver ;
}
void NetworkSyncManager : : ReportNSSOnOff ( int i )
{
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCSMS ) ;
m_packet . Write1 ( ( uint8_t ) i ) ;
NetPlayerClient - > SendPack ( ( char * ) m_packet . Data , m_packet . Position ) ;
}
RString NetworkSyncManager : : GetServerName ( )
{
return m_ServerName ;
}
2017-02-10 09:57:59 -03:00
//Same as the one below except for ctr = uint8_t(STATSMAN->m_CurStageStats.m_player[playerID].GetGrade() * 16 + numNotes);
//Im keeping the old one because it's used for single tap notes
void NetworkSyncManager : : ReportScore ( int playerID , int step , int score , int combo , float offset , int numNotes )
{
if ( ! useSMserver ) //Make sure that we are using the network
return ;
LOG - > Trace ( " Player ID %i combo = %i " , playerID , combo ) ;
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCGSU ) ;
step = TranslateStepType ( step ) ;
uint8_t ctr = ( uint8_t ) ( playerID * 16 + step - ( SMOST_HITMINE - 1 ) ) ;
m_packet . Write1 ( ctr ) ;
ctr = uint8_t ( STATSMAN - > m_CurStageStats . m_player [ playerID ] . GetGrade ( ) * 16 + numNotes ) ;
if ( STATSMAN - > m_CurStageStats . m_player [ playerID ] . m_bFailed )
ctr = uint8_t ( 112 ) ; //Code for failed (failed constant seems not to work)
m_packet . Write1 ( ctr ) ;
m_packet . Write4 ( score ) ;
m_packet . Write2 ( ( uint16_t ) combo ) ;
m_packet . Write2 ( ( uint16_t ) m_playerLife [ playerID ] ) ;
// Offset Info
// Note: if a 0 is sent, then disregard data.
// ASSUMED: No step will be more than 16 seconds off center.
// If this assumption is false, read 16 seconds in either direction.
int iOffset = int ( ( offset + 16.384 ) * 2000.0f ) ;
if ( iOffset > 65535 )
iOffset = 65535 ;
if ( iOffset < 1 )
iOffset = 1 ;
// Report 0 if hold, or miss (don't forget mines should report)
if ( step = = SMOST_HITMINE | | step > SMOST_W1 )
iOffset = 0 ;
m_packet . Write2 ( ( uint16_t ) iOffset ) ;
NetPlayerClient - > SendPack ( ( char * ) m_packet . Data , m_packet . Position ) ;
}
2011-03-17 01:47:30 -04:00
void NetworkSyncManager : : ReportScore ( int playerID , int step , int score , int combo , float offset )
{
if ( ! useSMserver ) //Make sure that we are using the network
return ;
2011-06-12 03:12:44 -04:00
LOG - > Trace ( " Player ID %i combo = %i " , playerID , combo ) ;
2011-03-17 01:47:30 -04:00
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCGSU ) ;
step = TranslateStepType ( step ) ;
uint8_t ctr = ( uint8_t ) ( playerID * 16 + step - ( SMOST_HITMINE - 1 ) ) ;
m_packet . Write1 ( ctr ) ;
ctr = uint8_t ( STATSMAN - > m_CurStageStats . m_player [ playerID ] . GetGrade ( ) * 16 ) ;
if ( STATSMAN - > m_CurStageStats . m_player [ playerID ] . m_bFailed )
ctr = uint8_t ( 112 ) ; //Code for failed (failed constant seems not to work)
m_packet . Write1 ( ctr ) ;
m_packet . Write4 ( score ) ;
m_packet . Write2 ( ( uint16_t ) combo ) ;
m_packet . Write2 ( ( uint16_t ) m_playerLife [ playerID ] ) ;
// Offset Info
// Note: if a 0 is sent, then disregard data.
// ASSUMED: No step will be more than 16 seconds off center.
// If this assumption is false, read 16 seconds in either direction.
int iOffset = int ( ( offset + 16.384 ) * 2000.0f ) ;
if ( iOffset > 65535 )
iOffset = 65535 ;
if ( iOffset < 1 )
iOffset = 1 ;
// Report 0 if hold, or miss (don't forget mines should report)
if ( step = = SMOST_HITMINE | | step > SMOST_W1 )
iOffset = 0 ;
m_packet . Write2 ( ( uint16_t ) iOffset ) ;
NetPlayerClient - > SendPack ( ( char * ) m_packet . Data , m_packet . Position ) ;
}
void NetworkSyncManager : : ReportSongOver ( )
{
if ( ! useSMserver ) //Make sure that we are using the network
return ;
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCGON ) ;
NetPlayerClient - > SendPack ( ( char * ) & m_packet . Data , m_packet . Position ) ;
return ;
}
void NetworkSyncManager : : ReportStyle ( )
{
LOG - > Trace ( " Sending \" Style \" to server " ) ;
if ( ! useSMserver )
return ;
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCSU ) ;
m_packet . Write1 ( ( int8_t ) GAMESTATE - > GetNumPlayersEnabled ( ) ) ;
FOREACH_EnabledPlayer ( pn )
{
m_packet . Write1 ( ( uint8_t ) pn ) ;
m_packet . WriteNT ( GAMESTATE - > GetPlayerDisplayName ( pn ) ) ;
}
NetPlayerClient - > SendPack ( ( char * ) & m_packet . Data , m_packet . Position ) ;
}
void NetworkSyncManager : : StartRequest ( short position )
{
if ( ! useSMserver )
return ;
if ( GAMESTATE - > m_bDemonstrationOrJukebox )
return ;
LOG - > Trace ( " Requesting Start from Server. " ) ;
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCGSR ) ;
unsigned char ctr = 0 ;
Steps * tSteps ;
tSteps = GAMESTATE - > m_pCurSteps [ PLAYER_1 ] ;
if ( tSteps ! = NULL & & GAMESTATE - > IsPlayerEnabled ( PLAYER_1 ) )
ctr = uint8_t ( ctr + tSteps - > GetMeter ( ) * 16 ) ;
tSteps = GAMESTATE - > m_pCurSteps [ PLAYER_2 ] ;
if ( tSteps ! = NULL & & GAMESTATE - > IsPlayerEnabled ( PLAYER_2 ) )
ctr = uint8_t ( ctr + tSteps - > GetMeter ( ) ) ;
m_packet . Write1 ( ctr ) ;
ctr = 0 ;
tSteps = GAMESTATE - > m_pCurSteps [ PLAYER_1 ] ;
if ( tSteps ! = NULL & & GAMESTATE - > IsPlayerEnabled ( PLAYER_1 ) )
ctr = uint8_t ( ctr + ( int ) tSteps - > GetDifficulty ( ) * 16 ) ;
tSteps = GAMESTATE - > m_pCurSteps [ PLAYER_2 ] ;
if ( tSteps ! = NULL & & GAMESTATE - > IsPlayerEnabled ( PLAYER_2 ) )
ctr = uint8_t ( ctr + ( int ) tSteps - > GetDifficulty ( ) ) ;
m_packet . Write1 ( ctr ) ;
//Notify server if this is for sync or not.
ctr = char ( position * 16 ) ;
m_packet . Write1 ( ctr ) ;
if ( GAMESTATE - > m_pCurSong ! = NULL )
{
m_packet . WriteNT ( GAMESTATE - > m_pCurSong - > m_sMainTitle ) ;
m_packet . WriteNT ( GAMESTATE - > m_pCurSong - > m_sSubTitle ) ;
m_packet . WriteNT ( GAMESTATE - > m_pCurSong - > m_sArtist ) ;
}
else
{
m_packet . WriteNT ( " " ) ;
m_packet . WriteNT ( " " ) ;
m_packet . WriteNT ( " " ) ;
}
if ( GAMESTATE - > m_pCurCourse ! = NULL )
m_packet . WriteNT ( GAMESTATE - > m_pCurCourse - > GetDisplayFullTitle ( ) ) ;
else
m_packet . WriteNT ( RString ( ) ) ;
//Send Player (and song) Options
m_packet . WriteNT ( GAMESTATE - > m_SongOptions . GetCurrent ( ) . GetString ( ) ) ;
int players = 0 ;
FOREACH_PlayerNumber ( p )
{
+ + players ;
m_packet . WriteNT ( GAMESTATE - > m_pPlayerState [ p ] - > m_PlayerOptions . GetCurrent ( ) . GetString ( ) ) ;
}
for ( int i = 0 ; i < 2 - players ; + + i )
m_packet . WriteNT ( " " ) ; //Write a NULL if no player
2017-02-10 09:57:59 -03:00
//Send song hash/chartkey
if ( m_ServerVersion > = 129 ) {
tSteps = GAMESTATE - > m_pCurSteps [ PLAYER_1 ] ;
if ( tSteps ! = NULL & & GAMESTATE - > IsPlayerEnabled ( PLAYER_1 ) ) {
m_packet . WriteNT ( tSteps - > GetChartKey ( ) ) ;
}
else
{
m_packet . WriteNT ( " " ) ;
}
tSteps = GAMESTATE - > m_pCurSteps [ PLAYER_2 ] ;
if ( tSteps ! = NULL & & GAMESTATE - > IsPlayerEnabled ( PLAYER_2 ) ) {
m_packet . WriteNT ( tSteps - > GetChartKey ( ) ) ;
}
else
{
m_packet . WriteNT ( " " ) ;
}
int rate = ( int ) ( GAMESTATE - > m_SongOptions . GetCurrent ( ) . m_fMusicRate * 100 ) ;
m_packet . Write1 ( rate ) ;
m_packet . WriteNT ( GAMESTATE - > m_pCurSong - > GetFileHash ( ) ) ;
}
2011-03-17 01:47:30 -04:00
//This needs to be reset before ScreenEvaluation could possibly be called
m_EvalPlayerData . clear ( ) ;
//Block until go is recieved.
//Switch to blocking mode (this is the only
//way I know how to get precievably instantanious results
bool dontExit = true ;
NetPlayerClient - > blocking = true ;
//The following packet HAS to get through, so we turn blocking on for it as well
//Don't block if we are serving
NetPlayerClient - > SendPack ( ( char * ) & m_packet . Data , m_packet . Position ) ;
LOG - > Trace ( " Waiting for RECV " ) ;
m_packet . ClearPacket ( ) ;
while ( dontExit )
{
m_packet . ClearPacket ( ) ;
if ( NetPlayerClient - > ReadPack ( ( char * ) & m_packet , NETMAXBUFFERSIZE ) < 1 )
dontExit = false ; // Also allow exit if there is a problem on the socket
// Only do if we are not the server, otherwise the sync
// gets hosed up due to non blocking mode.
if ( m_packet . Read1 ( ) = = ( NSServerOffset + NSCGSR ) )
dontExit = false ;
// Only allow passing on Start request; otherwise scoreboard updates
// and such will confuse us.
}
NetPlayerClient - > blocking = false ;
}
static LocalizedString CONNECTION_SUCCESSFUL ( " NetworkSyncManager " , " Connection to '%s' successful. " ) ;
static LocalizedString CONNECTION_FAILED ( " NetworkSyncManager " , " Connection failed. " ) ;
void NetworkSyncManager : : DisplayStartupStatus ( )
{
RString sMessage ( " " ) ;
switch ( m_startupStatus )
{
case 0 :
//Networking wasn't attepmpted
return ;
case 1 :
sMessage = ssprintf ( CONNECTION_SUCCESSFUL . GetValue ( ) , m_ServerName . c_str ( ) ) ;
break ;
case 2 :
sMessage = CONNECTION_FAILED . GetValue ( ) ;
break ;
}
SCREENMAN - > SystemMessage ( sMessage ) ;
}
void NetworkSyncManager : : Update ( float fDeltaTime )
{
if ( useSMserver )
ProcessInput ( ) ;
PacketFunctions BroadIn ;
if ( BroadcastReception - > ReadPack ( ( char * ) & BroadIn . Data , 1020 ) )
{
NetServerInfo ThisServer ;
BroadIn . Position = 0 ;
if ( BroadIn . Read1 ( ) = = 141 ) // SMLS_Info?
{
ThisServer . Name = BroadIn . ReadNT ( ) ;
int port = BroadIn . Read2 ( ) ;
BroadIn . Read2 ( ) ; //Num players connected.
2017-05-24 01:23:22 -07:00
uint32_t addy = BroadcastReception - > getAddress ( ) ;
2011-03-17 01:47:30 -04:00
ThisServer . Address = ssprintf ( " %u.%u.%u.%u:%d " ,
( addy < < 0 ) > > 24 , ( addy < < 8 ) > > 24 , ( addy < < 16 ) > > 24 , ( addy < < 24 ) > > 24 , port ) ;
//It's fairly safe to assume that users will not be on networks with more than
//30 or 40 servers. Until this point, maps would be slower than vectors.
//So I am going to use a vector to store all of the servers.
//
//In this situation, I will traverse the vector to find the element that
//contains the corresponding server.
unsigned int i ;
for ( i = 0 ; i < m_vAllLANServers . size ( ) ; i + + )
{
if ( m_vAllLANServers [ i ] . Address = = ThisServer . Address )
{
m_vAllLANServers [ i ] . Name = ThisServer . Name ;
break ;
}
}
if ( i > = m_vAllLANServers . size ( ) )
m_vAllLANServers . push_back ( ThisServer ) ;
}
}
}
static LocalizedString CONNECTION_DROPPED ( " NetworkSyncManager " , " Connection to server dropped. " ) ;
void NetworkSyncManager : : ProcessInput ( )
{
//If we're disconnected, just exit
if ( ( NetPlayerClient - > state ! = NetPlayerClient - > skCONNECTED ) | |
NetPlayerClient - > IsError ( ) )
{
SCREENMAN - > SystemMessageNoAnimate ( CONNECTION_DROPPED ) ;
useSMserver = false ;
isSMOnline = false ;
FOREACH_PlayerNumber ( pn )
isSMOLoggedIn [ pn ] = false ;
NetPlayerClient - > close ( ) ;
return ;
}
// load new data into buffer
NetPlayerClient - > update ( ) ;
m_packet . ClearPacket ( ) ;
int packetSize ;
while ( ( packetSize = NetPlayerClient - > ReadPack ( ( char * ) & m_packet , NETMAXBUFFERSIZE ) ) > 0 )
{
m_packet . size = packetSize ;
int command = m_packet . Read1 ( ) ;
//Check to make sure command is valid from server
if ( command < NSServerOffset )
{
LOG - > Trace ( " CMD (below 128) Invalid> %d " , command ) ;
break ;
}
command = command - NSServerOffset ;
switch ( command )
{
case NSCPing : // Ping packet responce
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCPingR ) ;
NetPlayerClient - > SendPack ( ( char * ) m_packet . Data , m_packet . Position ) ;
break ;
case NSCPingR : // These are in response to when/if we send packet 0's
case NSCHello : // This is already taken care of by the blocking code earlier
case NSCGSR : // This is taken care of by the blocking start code
break ;
case NSCGON :
{
int PlayersInPack = m_packet . Read1 ( ) ;
m_EvalPlayerData . resize ( PlayersInPack ) ;
for ( int i = 0 ; i < PlayersInPack ; + + i )
m_EvalPlayerData [ i ] . name = m_packet . Read1 ( ) ;
for ( int i = 0 ; i < PlayersInPack ; + + i )
m_EvalPlayerData [ i ] . score = m_packet . Read4 ( ) ;
for ( int i = 0 ; i < PlayersInPack ; + + i )
m_EvalPlayerData [ i ] . grade = m_packet . Read1 ( ) ;
for ( int i = 0 ; i < PlayersInPack ; + + i )
m_EvalPlayerData [ i ] . difficulty = ( Difficulty ) m_packet . Read1 ( ) ;
for ( int j = 0 ; j < NETNUMTAPSCORES ; + + j )
for ( int i = 0 ; i < PlayersInPack ; + + i )
m_EvalPlayerData [ i ] . tapScores [ j ] = m_packet . Read2 ( ) ;
for ( int i = 0 ; i < PlayersInPack ; + + i )
m_EvalPlayerData [ i ] . playerOptions = m_packet . ReadNT ( ) ;
SCREENMAN - > SendMessageToTopScreen ( SM_GotEval ) ;
}
break ;
case NSCGSU : // Scoreboard Update
{ //Ease scope
int ColumnNumber = m_packet . Read1 ( ) ;
int NumberPlayers = m_packet . Read1 ( ) ;
RString ColumnData ;
switch ( ColumnNumber )
{
case NSSB_NAMES :
ColumnData = " Names \n " ;
for ( int i = 0 ; i < NumberPlayers ; + + i )
ColumnData + = m_PlayerNames [ m_packet . Read1 ( ) ] + " \n " ;
break ;
case NSSB_COMBO :
ColumnData = " Combo \n " ;
for ( int i = 0 ; i < NumberPlayers ; + + i )
ColumnData + = ssprintf ( " %d \n " , m_packet . Read2 ( ) ) ;
break ;
case NSSB_GRADE :
ColumnData = " Grade \n " ;
for ( int i = 0 ; i < NumberPlayers ; i + + )
ColumnData + = GradeToLocalizedString ( Grade ( m_packet . Read1 ( ) ) ) + " \n " ;
break ;
}
m_Scoreboard [ ColumnNumber ] = ColumnData ;
m_scoreboardchange [ ColumnNumber ] = true ;
/*
Message msg("ScoreboardUpdate");
msg.SetParam( "NumPlayers", NumberPlayers );
MESSAGEMAN->Broadcast( msg );
*/
}
break ;
case NSCSU : //System message from server
{
RString SysMSG = m_packet . ReadNT ( ) ;
SCREENMAN - > SystemMessage ( SysMSG ) ;
}
break ;
case NSCCM : //Chat message from server
{
m_sChatText + = m_packet . ReadNT ( ) + " \n " ;
//10000 chars backlog should be more than enough
m_sChatText = m_sChatText . Right ( 10000 ) ;
SCREENMAN - > SendMessageToTopScreen ( SM_AddToChat ) ;
}
break ;
case NSCRSG : //Select Song/Play song
{
m_iSelectMode = m_packet . Read1 ( ) ;
m_sMainTitle = m_packet . ReadNT ( ) ;
m_sArtist = m_packet . ReadNT ( ) ;
m_sSubTitle = m_packet . ReadNT ( ) ;
2017-02-10 09:57:59 -03:00
//Read songhash
if ( m_ServerVersion > = 129 ) {
m_sFileHash = m_packet . ReadNT ( ) ;
} else {
m_sFileHash = " " ;
}
2011-03-17 01:47:30 -04:00
SCREENMAN - > SendMessageToTopScreen ( SM_ChangeSong ) ;
}
break ;
case NSCUUL :
{
/*int ServerMaxPlayers=*/ m_packet . Read1 ( ) ;
int PlayersInThisPacket = m_packet . Read1 ( ) ;
m_ActivePlayer . clear ( ) ;
m_PlayerStatus . clear ( ) ;
m_PlayerNames . clear ( ) ;
m_ActivePlayers = 0 ;
for ( int i = 0 ; i < PlayersInThisPacket ; + + i )
{
int PStatus = m_packet . Read1 ( ) ;
if ( PStatus > 0 )
{
m_ActivePlayers + + ;
m_ActivePlayer . push_back ( i ) ;
}
m_PlayerStatus . push_back ( PStatus ) ;
m_PlayerNames . push_back ( m_packet . ReadNT ( ) ) ;
}
SCREENMAN - > SendMessageToTopScreen ( SM_UsersUpdate ) ;
}
break ;
case NSCSMS :
{
RString StyleName , GameName ;
GameName = m_packet . ReadNT ( ) ;
StyleName = m_packet . ReadNT ( ) ;
GAMESTATE - > SetCurGame ( GAMEMAN - > StringToGame ( GameName ) ) ;
2014-12-07 01:53:17 -07:00
GAMESTATE - > SetCurrentStyle ( GAMEMAN - > GameAndStringToStyle ( GAMESTATE - > m_pCurGame , StyleName ) , PLAYER_INVALID ) ;
2011-03-17 01:47:30 -04:00
SCREENMAN - > SetNewScreen ( " ScreenNetSelectMusic " ) ; //Should this be metric'd out?
}
break ;
case NSCSMOnline :
{
m_SMOnlinePacket . size = packetSize - 1 ;
m_SMOnlinePacket . Position = 0 ;
memcpy ( m_SMOnlinePacket . Data , ( m_packet . Data + 1 ) , packetSize - 1 ) ;
LOG - > Trace ( " Received SMOnline Command: %d, size:%d " , command , packetSize - 1 ) ;
SCREENMAN - > SendMessageToTopScreen ( SM_SMOnlinePack ) ;
}
break ;
case NSCAttack :
{
PlayerNumber iPlayerNumber = ( PlayerNumber ) m_packet . Read1 ( ) ;
if ( GAMESTATE - > IsPlayerEnabled ( iPlayerNumber ) ) // Only attack if the player can be attacked.
{
Attack a ;
a . fSecsRemaining = float ( m_packet . Read4 ( ) ) / 1000.0f ;
a . bGlobal = false ;
a . sModifiers = m_packet . ReadNT ( ) ;
GAMESTATE - > m_pPlayerState [ iPlayerNumber ] - > LaunchAttack ( a ) ;
}
m_packet . ClearPacket ( ) ;
}
break ;
2017-02-10 09:57:59 -03:00
case FLU :
{
int PlayersInThisPacket = m_packet . Read1 ( ) ;
fl_PlayerNames . clear ( ) ;
fl_PlayerStates . clear ( ) ;
for ( int i = 0 ; i < PlayersInThisPacket ; + + i )
{
int PStatus = m_packet . Read1 ( ) ;
fl_PlayerStates . push_back ( PStatus ) ;
fl_PlayerNames . push_back ( m_packet . ReadNT ( ) ) ;
}
SCREENMAN - > SendMessageToTopScreen ( SM_FriendsUpdate ) ;
}
break ;
2011-03-17 01:47:30 -04:00
}
m_packet . ClearPacket ( ) ;
}
}
bool NetworkSyncManager : : ChangedScoreboard ( int Column )
{
if ( ! m_scoreboardchange [ Column ] )
return false ;
m_scoreboardchange [ Column ] = false ;
return true ;
}
void NetworkSyncManager : : SendChat ( const RString & message )
{
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCCM ) ;
m_packet . WriteNT ( message ) ;
NetPlayerClient - > SendPack ( ( char * ) & m_packet . Data , m_packet . Position ) ;
}
void NetworkSyncManager : : ReportPlayerOptions ( )
{
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCUPOpts ) ;
FOREACH_PlayerNumber ( pn )
m_packet . WriteNT ( GAMESTATE - > m_pPlayerState [ pn ] - > m_PlayerOptions . GetCurrent ( ) . GetString ( ) ) ;
NetPlayerClient - > SendPack ( ( char * ) & m_packet . Data , m_packet . Position ) ;
}
2017-02-10 09:57:59 -03:00
int NetworkSyncManager : : GetServerVersion ( )
{
return m_ServerVersion ;
}
2011-03-17 01:47:30 -04:00
void NetworkSyncManager : : SelectUserSong ( )
{
m_packet . ClearPacket ( ) ;
m_packet . Write1 ( NSCRSG ) ;
m_packet . Write1 ( ( uint8_t ) m_iSelectMode ) ;
m_packet . WriteNT ( m_sMainTitle ) ;
m_packet . WriteNT ( m_sArtist ) ;
m_packet . WriteNT ( m_sSubTitle ) ;
2017-02-10 09:57:59 -03:00
//Send songhash
if ( m_ServerVersion > = 129 ) {
m_packet . WriteNT ( GAMESTATE - > m_pCurSong - > GetFileHash ( ) ) ;
}
2011-03-17 01:47:30 -04:00
NetPlayerClient - > SendPack ( ( char * ) & m_packet . Data , m_packet . Position ) ;
}
void NetworkSyncManager : : SendSMOnline ( )
{
m_packet . Position = m_SMOnlinePacket . Position + 1 ;
memcpy ( ( m_packet . Data + 1 ) , m_SMOnlinePacket . Data , m_SMOnlinePacket . Position ) ;
m_packet . Data [ 0 ] = NSCSMOnline ;
NetPlayerClient - > SendPack ( ( char * ) & m_packet . Data , m_packet . Position ) ;
}
SMOStepType NetworkSyncManager : : TranslateStepType ( int score )
{
/* Translate from Stepmania's constantly changing TapNoteScore
* to SMO's note scores */
switch ( score )
{
case TNS_HitMine :
return SMOST_HITMINE ;
case TNS_AvoidMine :
return SMOST_AVOIDMINE ;
case TNS_Miss :
return SMOST_MISS ;
case TNS_W5 :
return SMOST_W5 ;
case TNS_W4 :
return SMOST_W4 ;
case TNS_W3 :
return SMOST_W3 ;
case TNS_W2 :
return SMOST_W2 ;
case TNS_W1 :
return SMOST_W1 ;
case HNS_LetGo + TapNoteScore_Invalid :
return SMOST_LETGO ;
case HNS_Held + TapNoteScore_Invalid :
return SMOST_HELD ;
default :
return SMOST_UNUSED ;
}
}
// Packet functions
uint8_t PacketFunctions : : Read1 ( )
{
if ( Position > = NETMAXBUFFERSIZE )
return 0 ;
return Data [ Position + + ] ;
}
uint16_t PacketFunctions : : Read2 ( )
{
if ( Position > = NETMAXBUFFERSIZE - 1 )
return 0 ;
uint16_t Temp ;
memcpy ( & Temp , Data + Position , 2 ) ;
Position + = 2 ;
2017-05-24 01:23:22 -07:00
return EzSockets : : ntohs ( Temp ) ;
2011-03-17 01:47:30 -04:00
}
uint32_t PacketFunctions : : Read4 ( )
{
if ( Position > = NETMAXBUFFERSIZE - 3 )
return 0 ;
uint32_t Temp ;
memcpy ( & Temp , Data + Position , 4 ) ;
Position + = 4 ;
2017-05-24 01:23:22 -07:00
return EzSockets : : ntohl ( Temp ) ;
2011-03-17 01:47:30 -04:00
}
RString PacketFunctions : : ReadNT ( )
{
//int Orig=Packet.Position;
RString TempStr ;
while ( ( Position < NETMAXBUFFERSIZE ) & & ( ( ( char * ) Data ) [ Position ] ! = 0 ) )
TempStr = TempStr + ( char ) Data [ Position + + ] ;
+ + Position ;
return TempStr ;
}
void PacketFunctions : : Write1 ( uint8_t data )
{
if ( Position > = NETMAXBUFFERSIZE )
return ;
memcpy ( & Data [ Position ] , & data , 1 ) ;
+ + Position ;
}
void PacketFunctions : : Write2 ( uint16_t data )
{
if ( Position > = NETMAXBUFFERSIZE - 1 )
return ;
2017-05-24 01:23:22 -07:00
data = EzSockets : : htons ( data ) ;
2011-03-17 01:47:30 -04:00
memcpy ( & Data [ Position ] , & data , 2 ) ;
Position + = 2 ;
}
void PacketFunctions : : Write4 ( uint32_t data )
{
if ( Position > = NETMAXBUFFERSIZE - 3 )
return ;
2017-05-24 01:23:22 -07:00
data = EzSockets : : htonl ( data ) ;
2011-03-17 01:47:30 -04:00
memcpy ( & Data [ Position ] , & data , 4 ) ;
Position + = 4 ;
}
void PacketFunctions : : WriteNT ( const RString & data )
{
size_t index = 0 ;
while ( Position < NETMAXBUFFERSIZE & & index < data . size ( ) )
Data [ Position + + ] = ( unsigned char ) ( data . c_str ( ) [ index + + ] ) ;
Data [ Position + + ] = 0 ;
}
void PacketFunctions : : ClearPacket ( )
{
memset ( ( void * ) ( & Data ) , 0 , NETMAXBUFFERSIZE ) ;
Position = 0 ;
}
RString NetworkSyncManager : : MD5Hex ( const RString & sInput )
{
return BinaryToHex ( CryptManager : : GetMD5ForString ( sInput ) ) . MakeUpper ( ) ;
}
void NetworkSyncManager : : GetListOfLANServers ( vector < NetServerInfo > & AllServers )
{
AllServers = m_vAllLANServers ;
}
2012-05-21 02:29:59 -05:00
// Aldo: Please move this method to a new class, I didn't want to create new files because I don't know how to properly update the files for each platform.
// I preferred to misplace code rather than cause unneeded headaches to non-windows users, although it would be nice to have in the wiki which files to
// update when adding new files and how (Xcode/stepmania_xcode4.3.xcodeproj has a really crazy structure :/).
2015-10-22 21:21:47 -03:00
# if defined(CMAKE_POWERED)
2012-05-21 02:29:59 -05:00
unsigned long NetworkSyncManager : : GetCurrentSMBuild ( LoadingWindow * ld ) { return 0 ; }
# else
unsigned long NetworkSyncManager : : GetCurrentSMBuild ( LoadingWindow * ld )
{
// Aldo: Using my own host by now, upload update_check/check_sm5.php to an official URL and change the following constants accordingly:
const RString sHost = " aldo.mx " ;
const unsigned short uPort = 80 ;
const RString sResource = " /stepmania/check_sm5.php " ;
2012-05-21 17:59:06 -05:00
const RString sUserAgent = PRODUCT_ID ;
2012-05-21 02:29:59 -05:00
const RString sReferer = " http://aldo.mx/stepmania/ " ;
if ( ld )
{
ld - > SetIndeterminate ( true ) ;
ld - > SetText ( " Checking for updates... " ) ;
}
2015-10-02 20:02:55 -04:00
unsigned long uCurrentSMBuild = 0 ;
2012-05-21 02:29:59 -05:00
bool bSuccess = false ;
EzSockets * socket = new EzSockets ( ) ;
socket - > create ( ) ;
socket - > blocking = true ;
if ( socket - > connect ( sHost , uPort ) )
{
RString sHTTPRequest = ssprintf (
" GET %s HTTP/1.1 " " \r \n "
" Host: %s " " \r \n "
" User-Agent: %s " " \r \n "
" Cache-Control: no-cache " " \r \n "
" Referer: %s " " \r \n "
" X-SM-Build: %lu " " \r \n "
" \r \n " ,
sResource . c_str ( ) , sHost . c_str ( ) ,
sUserAgent . c_str ( ) , sReferer . c_str ( ) ,
2015-10-02 20:02:55 -04:00
0
2012-05-21 02:29:59 -05:00
) ;
socket - > SendData ( sHTTPRequest ) ;
// Aldo: EzSocket::pReadData() is a lower level function, I used it because I was having issues
// with EzSocket::ReadData() in 3.9, feel free to refactor this function, the low lever character
// manipulation might look scary to people not used to it.
char * cBuffer = new char [ NETMAXBUFFERSIZE ] ;
// Reading the first NETMAXBUFFERSIZE bytes (usually 1024), should be enough to get the HTTP Header only
int iBytes = socket - > pReadData ( cBuffer ) ;
if ( iBytes )
{
// \r\n\r\n = Separator from HTTP Header and Body
char * cBodyStart = strstr ( cBuffer , " \r \n \r \n " ) ;
if ( cBodyStart ! = NULL )
{
// Get the HTTP Header only
int iHeaderLength = cBodyStart - cBuffer ;
char * cHeader = new char [ iHeaderLength + 1 ] ;
strncpy ( cHeader , cBuffer , iHeaderLength ) ;
cHeader [ iHeaderLength ] = ' \0 ' ; // needed to make it a valid C String
RString sHTTPHeader ( cHeader ) ;
SAFE_DELETE ( cHeader ) ;
Trim ( sHTTPHeader ) ;
//LOG->Trace( sHTTPHeader.c_str() );
vector < RString > svResponse ;
split ( sHTTPHeader , " \r \n " , svResponse ) ;
// Check for 200 OK
if ( svResponse [ 0 ] . find ( " 200 " ) ! = RString : : npos )
{
// Iterate through every field until an X-SM-Build field is found
for ( unsigned h = 1 ; h < svResponse . size ( ) ; h + + )
{
RString : : size_type sFieldPos = svResponse [ h ] . find ( " : " ) ;
if ( sFieldPos ! = RString : : npos )
{
RString sFieldName = svResponse [ h ] . Left ( sFieldPos ) ,
sFieldValue = svResponse [ h ] . substr ( sFieldPos + 2 ) ;
Trim ( sFieldName ) ;
Trim ( sFieldValue ) ;
2015-10-07 19:00:16 -04:00
if ( 0 = = strcasecmp ( sFieldName , " X-SM-Build " ) )
2012-05-21 02:29:59 -05:00
{
bSuccess = true ;
uCurrentSMBuild = strtoul ( sFieldValue , NULL , 10 ) ;
break ;
}
}
}
} // if( svResponse[0].find("200") != RString::npos )
} // if( cBodyStart != NULL )
} // if( iBytes )
SAFE_DELETE ( cBuffer ) ;
} // if( socket->connect(sHost, uPort) )
socket - > close ( ) ;
SAFE_DELETE ( socket ) ;
if ( ld )
{
ld - > SetIndeterminate ( false ) ;
ld - > SetTotalWork ( 100 ) ;
if ( bSuccess )
{
ld - > SetProgress ( 100 ) ;
ld - > SetText ( " Checking for updates... OK " ) ;
}
else
{
ld - > SetProgress ( 0 ) ;
ld - > SetText ( " Checking for updates... ERROR " ) ;
}
}
return uCurrentSMBuild ;
}
# endif
2011-03-17 01:47:30 -04:00
static bool ConnectToServer ( const RString & t )
{
NSMAN - > PostStartUp ( t ) ;
NSMAN - > DisplayStartupStatus ( ) ;
return true ;
}
extern Preference < RString > g_sLastServer ;
LuaFunction ( ConnectToServer , ConnectToServer ( ( RString ( SArg ( 1 ) ) . length ( ) = = 0 ) ? RString ( g_sLastServer ) : RString ( SArg ( 1 ) ) ) )
# endif
static bool ReportStyle ( ) { NSMAN - > ReportStyle ( ) ; return true ; }
static bool CloseNetworkConnection ( ) { NSMAN - > CloseConnection ( ) ; return true ; }
LuaFunction ( IsSMOnlineLoggedIn , NSMAN - > isSMOLoggedIn [ Enum : : Check < PlayerNumber > ( L , 1 ) ] )
LuaFunction ( IsNetConnected , NSMAN - > useSMserver )
LuaFunction ( IsNetSMOnline , NSMAN - > isSMOnline )
LuaFunction ( ReportStyle , ReportStyle ( ) )
LuaFunction ( GetServerName , NSMAN - > GetServerName ( ) )
LuaFunction ( CloseConnection , CloseNetworkConnection ( ) )
/*
* (c) 2003-2004 Charles Lohr, Joshua Allen
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/