2005-07-24 14:12:37 +00:00
/* $Id$ */
2008-05-06 15:11:33 +00:00
/** @file network_server.cpp Server part of the network protocol. */
2006-10-12 14:13:39 +00:00
# ifdef ENABLE_NETWORK
2007-01-02 17:34:03 +00:00
# include "../stdafx.h"
# include "../openttd.h" // XXX StringID
# include "../debug.h"
2007-12-21 19:49:27 +00:00
# include "../strings_func.h"
2008-05-30 18:20:26 +00:00
# include "network_internal.h"
2007-01-02 17:34:03 +00:00
# include "core/tcp.h"
2008-01-13 22:27:06 +00:00
# include "../vehicle_base.h"
# include "../vehicle_func.h"
2007-12-26 13:50:40 +00:00
# include "../date_func.h"
2004-12-04 17:54:56 +00:00
# include "network_server.h"
2004-12-15 20:10:34 +00:00
# include "network_udp.h"
2008-05-24 10:15:06 +00:00
# include "../console_func.h"
2007-12-21 21:50:46 +00:00
# include "../command_func.h"
2007-01-02 17:34:03 +00:00
# include "../saveload.h"
2008-03-31 00:06:17 +00:00
# include "../station_base.h"
2007-01-02 17:34:03 +00:00
# include "../variables.h"
# include "../genworld.h"
2007-12-25 09:48:53 +00:00
# include "../core/alloc_func.hpp"
2008-08-31 10:50:05 +00:00
# include "../fileio_func.h"
2008-01-07 14:23:25 +00:00
# include "../string_func.h"
2008-01-12 14:10:35 +00:00
# include "../player_base.h"
# include "../player_func.h"
# include "../player_gui.h"
2008-01-13 14:37:30 +00:00
# include "../settings_type.h"
2004-12-04 17:54:56 +00:00
2008-01-13 01:21:35 +00:00
# include "table/strings.h"
2004-12-04 17:54:56 +00:00
// This file handles all the server-commands
2007-01-12 20:19:49 +00:00
static void NetworkHandleCommandQueue ( NetworkTCPSocketHandler * cs ) ;
2004-12-19 10:17:26 +00:00
2004-12-04 17:54:56 +00:00
// **********
// Sending functions
2007-01-12 20:19:49 +00:00
// DEF_SERVER_SEND_COMMAND has parameter: NetworkTCPSocketHandler *cs
2004-12-04 17:54:56 +00:00
// **********
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_CLIENT_INFO ) ( NetworkTCPSocketHandler * cs , NetworkClientInfo * ci )
2004-12-04 17:54:56 +00:00
{
//
// Packet: SERVER_CLIENT_INFO
// Function: Sends info about a client
// Data:
// uint16: The index of the client (always unique on a server. 1 = server)
// uint8: As which player the client is playing
// String: The name of the client
//
if ( ci - > client_index ! = NETWORK_EMPTY_INDEX ) {
2006-10-17 23:34:12 +00:00
Packet * p = NetworkSend_Init ( PACKET_SERVER_CLIENT_INFO ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint16 ( ci - > client_index ) ;
p - > Send_uint8 ( ci - > client_playas ) ;
p - > Send_string ( ci - > client_name ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
}
DEF_SERVER_SEND_COMMAND ( PACKET_SERVER_COMPANY_INFO )
{
//
// Packet: SERVER_COMPANY_INFO
// Function: Sends info about the companies
// Data:
//
int i ;
Player * player ;
Packet * p ;
2006-01-31 22:16:15 +00:00
byte active = ActivePlayerCount ( ) ;
2004-12-04 17:54:56 +00:00
if ( active = = 0 ) {
2006-10-17 23:34:12 +00:00
p = NetworkSend_Init ( PACKET_SERVER_COMPANY_INFO ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( NETWORK_COMPANY_INFO_VERSION ) ;
p - > Send_uint8 ( active ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
return ;
}
NetworkPopulateCompanyInfo ( ) ;
FOR_ALL_PLAYERS ( player ) {
p = NetworkSend_Init ( PACKET_SERVER_COMPANY_INFO ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( NETWORK_COMPANY_INFO_VERSION ) ;
p - > Send_uint8 ( active ) ;
p - > Send_uint8 ( player - > index ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:26:44 +00:00
p - > Send_string ( _network_player_info [ player - > index ] . company_name ) ;
p - > Send_uint32 ( _network_player_info [ player - > index ] . inaugurated_year ) ;
p - > Send_uint64 ( _network_player_info [ player - > index ] . company_value ) ;
p - > Send_uint64 ( _network_player_info [ player - > index ] . money ) ;
p - > Send_uint64 ( _network_player_info [ player - > index ] . income ) ;
p - > Send_uint16 ( _network_player_info [ player - > index ] . performance ) ;
2004-12-04 17:54:56 +00:00
2005-01-14 21:47:35 +00:00
/* Send 1 if there is a passord for the company else send 0 */
2007-04-27 20:50:49 +00:00
p - > Send_bool ( ! StrEmpty ( _network_player_info [ player - > index ] . password ) ) ;
2005-01-14 21:47:35 +00:00
2006-06-27 21:25:53 +00:00
for ( i = 0 ; i < NETWORK_VEHICLE_TYPES ; i + + ) {
2007-02-01 23:26:44 +00:00
p - > Send_uint16 ( _network_player_info [ player - > index ] . num_vehicle [ i ] ) ;
2006-06-27 21:25:53 +00:00
}
2004-12-04 17:54:56 +00:00
2006-06-27 21:25:53 +00:00
for ( i = 0 ; i < NETWORK_STATION_TYPES ; i + + ) {
2007-02-01 23:26:44 +00:00
p - > Send_uint16 ( _network_player_info [ player - > index ] . num_station [ i ] ) ;
2006-06-27 21:25:53 +00:00
}
2004-12-04 17:54:56 +00:00
2006-06-27 21:25:53 +00:00
if ( _network_player_info [ player - > index ] . players [ 0 ] = = ' \0 ' ) {
2007-02-01 23:26:44 +00:00
p - > Send_string ( " <none> " ) ;
2006-06-27 21:25:53 +00:00
} else {
2007-02-01 23:26:44 +00:00
p - > Send_string ( _network_player_info [ player - > index ] . players ) ;
2006-06-27 21:25:53 +00:00
}
2004-12-04 17:54:56 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
2004-12-20 16:02:01 +00:00
p = NetworkSend_Init ( PACKET_SERVER_COMPANY_INFO ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( NETWORK_COMPANY_INFO_VERSION ) ;
p - > Send_uint8 ( 0 ) ;
2004-12-20 16:02:01 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_ERROR ) ( NetworkTCPSocketHandler * cs , NetworkErrorCode error )
2004-12-04 17:54:56 +00:00
{
//
// Packet: SERVER_ERROR
// Function: The client made an error
// Data:
// uint8: ErrorID (see network_data.h, NetworkErrorCode)
//
2004-12-19 15:14:55 +00:00
char str [ 100 ] ;
2004-12-04 17:54:56 +00:00
Packet * p = NetworkSend_Init ( PACKET_SERVER_ERROR ) ;
2006-04-02 12:41:01 +00:00
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( error ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
2006-10-21 23:31:34 +00:00
GetNetworkErrorMsg ( str , error , lastof ( str ) ) ;
2006-01-25 18:11:06 +00:00
2004-12-04 17:54:56 +00:00
// Only send when the current client was in game
if ( cs - > status > STATUS_AUTH ) {
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2006-10-17 23:34:12 +00:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 17:54:56 +00:00
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
2006-12-26 17:36:18 +00:00
DEBUG ( net , 1 , " '%s' made an error and has been disconnected. Reason: '%s' " , client_name , str ) ;
2004-12-04 17:54:56 +00:00
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " %s " , str ) ;
2004-12-04 17:54:56 +00:00
FOR_ALL_CLIENTS ( new_cs ) {
if ( new_cs - > status > STATUS_AUTH & & new_cs ! = cs ) {
// Some errors we filter to a more general error. Clients don't have to know the real
// reason a joining failed.
if ( error = = NETWORK_ERROR_NOT_AUTHORIZED | | error = = NETWORK_ERROR_NOT_EXPECTED | | error = = NETWORK_ERROR_WRONG_REVISION )
error = NETWORK_ERROR_ILLEGAL_PACKET ;
SEND_COMMAND ( PACKET_SERVER_ERROR_QUIT ) ( new_cs , cs - > index , error ) ;
}
}
} else {
2006-12-26 17:36:18 +00:00
DEBUG ( net , 1 , " Client %d made an error and has been disconnected. Reason: '%s' " , cs - > index , str ) ;
2004-12-04 17:54:56 +00:00
}
2006-10-17 23:34:12 +00:00
cs - > has_quit = true ;
2004-12-04 17:54:56 +00:00
// Make sure the data get's there before we close the connection
2007-02-01 23:50:15 +00:00
cs - > Send_Packets ( ) ;
2004-12-04 17:54:56 +00:00
// The client made a mistake, so drop his connection now!
2004-12-19 10:17:26 +00:00
NetworkCloseClient ( cs ) ;
2004-12-04 17:54:56 +00:00
}
2007-01-30 17:22:56 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_CHECK_NEWGRFS ) ( NetworkTCPSocketHandler * cs )
{
//
// Packet: PACKET_SERVER_CHECK_NEWGRFS
// Function: Sends info about the used GRFs to the client
// Data:
// uint8: Amount of GRFs
// And then for each GRF:
// uint32: GRF ID
// 16 * uint8: MD5 checksum of the GRF
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_CHECK_NEWGRFS ) ;
const GRFConfig * c ;
uint grf_count = 0 ;
2007-07-03 16:14:29 +00:00
for ( c = _grfconfig ; c ! = NULL ; c = c - > next ) {
2007-11-19 21:02:30 +00:00
if ( ! HasBit ( c - > flags , GCF_STATIC ) ) grf_count + + ;
2007-07-03 16:14:29 +00:00
}
2007-01-30 17:22:56 +00:00
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( grf_count ) ;
2007-01-30 17:22:56 +00:00
for ( c = _grfconfig ; c ! = NULL ; c = c - > next ) {
2007-11-19 21:02:30 +00:00
if ( ! HasBit ( c - > flags , GCF_STATIC ) ) cs - > Send_GRFIdentifier ( p , c ) ;
2007-01-30 17:22:56 +00:00
}
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2007-01-30 17:22:56 +00:00
}
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_NEED_PASSWORD ) ( NetworkTCPSocketHandler * cs , NetworkPasswordType type )
2004-12-04 17:54:56 +00:00
{
//
// Packet: SERVER_NEED_PASSWORD
// Function: Indication to the client that the server needs a password
// Data:
// uint8: Type of password
//
2007-03-06 22:00:42 +00:00
/* Invalid packet when status is AUTH or higher */
if ( cs - > status > = STATUS_AUTH ) return ;
cs - > status = STATUS_AUTHORIZING ;
2004-12-04 17:54:56 +00:00
Packet * p = NetworkSend_Init ( PACKET_SERVER_NEED_PASSWORD ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( type ) ;
2008-05-29 15:13:28 +00:00
p - > Send_uint32 ( _settings_game . game_creation . generation_seed ) ;
2008-05-29 20:21:28 +00:00
p - > Send_string ( _settings_client . network . network_id ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_SEND_COMMAND ( PACKET_SERVER_WELCOME )
{
//
// Packet: SERVER_WELCOME
// Function: The client is joined and ready to receive his map
// Data:
// uint16: Own ClientID
//
Packet * p ;
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 17:54:56 +00:00
// Invalid packet when status is AUTH or higher
2006-01-25 18:11:06 +00:00
if ( cs - > status > = STATUS_AUTH ) return ;
2004-12-04 17:54:56 +00:00
cs - > status = STATUS_AUTH ;
_network_game_info . clients_on + + ;
p = NetworkSend_Init ( PACKET_SERVER_WELCOME ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint16 ( cs - > index ) ;
2008-05-29 15:13:28 +00:00
p - > Send_uint32 ( _settings_game . game_creation . generation_seed ) ;
2008-05-29 20:21:28 +00:00
p - > Send_string ( _settings_client . network . network_id ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
// Transmit info about all the active clients
FOR_ALL_CLIENTS ( new_cs ) {
if ( new_cs ! = cs & & new_cs - > status > STATUS_AUTH )
SEND_COMMAND ( PACKET_SERVER_CLIENT_INFO ) ( cs , DEREF_CLIENT_INFO ( new_cs ) ) ;
}
// Also send the info of the server
SEND_COMMAND ( PACKET_SERVER_CLIENT_INFO ) ( cs , NetworkFindClientInfoFromIndex ( NETWORK_SERVER_INDEX ) ) ;
}
DEF_SERVER_SEND_COMMAND ( PACKET_SERVER_WAIT )
{
//
// Packet: PACKET_SERVER_WAIT
// Function: The client can not receive the map at the moment because
// someone else is already receiving the map
// Data:
// uint8: Clients awaiting map
//
int waiting = 0 ;
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 17:54:56 +00:00
Packet * p ;
// Count how many players are waiting in the queue
FOR_ALL_CLIENTS ( new_cs ) {
2006-06-27 21:25:53 +00:00
if ( new_cs - > status = = STATUS_MAP_WAIT ) waiting + + ;
2004-12-04 17:54:56 +00:00
}
p = NetworkSend_Init ( PACKET_SERVER_WAIT ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( waiting ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
// This sends the map to the client
DEF_SERVER_SEND_COMMAND ( PACKET_SERVER_MAP )
{
//
// Packet: SERVER_MAP
// Function: Sends the map to the client, or a part of it (it is splitted in
// a lot of multiple packets)
// Data:
// uint8: packet-type (MAP_PACKET_START, MAP_PACKET_NORMAL and MAP_PACKET_END)
// if MAP_PACKET_START:
// uint32: The current FrameCounter
// if MAP_PACKET_NORMAL:
// piece of the map (till max-size of packet)
// if MAP_PACKET_END:
// uint32: seed0 of player
// uint32: seed1 of player
// last 2 are repeated MAX_PLAYERS time
//
static FILE * file_pointer ;
static uint sent_packets ; // How many packets we did send succecfully last time
if ( cs - > status < STATUS_AUTH ) {
// Illegal call, return error and ignore the packet
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_AUTHORIZED ) ;
return ;
}
2006-10-17 23:34:12 +00:00
2004-12-04 17:54:56 +00:00
if ( cs - > status = = STATUS_AUTH ) {
2007-06-17 15:48:57 +00:00
const char * filename = " network_server.tmp " ;
2004-12-04 17:54:56 +00:00
Packet * p ;
// Make a dump of the current game
2008-06-05 20:54:52 +00:00
if ( SaveOrLoad ( filename , SL_SAVE , AUTOSAVE_DIR ) ! = SL_OK ) usererror ( " network savedump failed " ) ;
2004-12-04 17:54:56 +00:00
2007-06-17 15:48:57 +00:00
file_pointer = FioFOpenFile ( filename , " rb " , AUTOSAVE_DIR ) ;
2004-12-04 17:54:56 +00:00
fseek ( file_pointer , 0 , SEEK_END ) ;
2008-06-05 20:54:52 +00:00
if ( ftell ( file_pointer ) = = 0 ) usererror ( " network savedump failed - zero sized savegame? " ) ;
2007-01-17 00:01:55 +00:00
2004-12-04 17:54:56 +00:00
// Now send the _frame_counter and how many packets are coming
p = NetworkSend_Init ( PACKET_SERVER_MAP ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( MAP_PACKET_START ) ;
p - > Send_uint32 ( _frame_counter ) ;
p - > Send_uint32 ( ftell ( file_pointer ) ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
fseek ( file_pointer , 0 , SEEK_SET ) ;
sent_packets = 4 ; // We start with trying 4 packets
cs - > status = STATUS_MAP ;
2005-03-29 19:10:13 +00:00
/* Mark the start of download */
cs - > last_frame = _frame_counter ;
cs - > last_frame_server = _frame_counter ;
2004-12-04 17:54:56 +00:00
}
if ( cs - > status = = STATUS_MAP ) {
uint i ;
int res ;
for ( i = 0 ; i < sent_packets ; i + + ) {
Packet * p = NetworkSend_Init ( PACKET_SERVER_MAP ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( MAP_PACKET_NORMAL ) ;
2006-08-20 12:09:32 +00:00
res = ( int ) fread ( p - > buffer + p - > size , 1 , SEND_MTU - p - > size , file_pointer ) ;
2006-10-17 23:34:12 +00:00
2008-06-05 20:54:52 +00:00
if ( ferror ( file_pointer ) ) usererror ( " Error reading temporary network savegame! " ) ;
2006-10-17 23:34:12 +00:00
2004-12-04 17:54:56 +00:00
p - > size + = res ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
if ( feof ( file_pointer ) ) {
// Done reading!
2006-03-02 02:22:15 +00:00
Packet * p = NetworkSend_Init ( PACKET_SERVER_MAP ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( MAP_PACKET_END ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
// Set the status to DONE_MAP, no we will wait for the client
// to send it is ready (maybe that happens like never ;))
cs - > status = STATUS_DONE_MAP ;
fclose ( file_pointer ) ;
{
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 17:54:56 +00:00
bool new_map_client = false ;
// Check if there is a client waiting for receiving the map
// and start sending him the map
FOR_ALL_CLIENTS ( new_cs ) {
if ( new_cs - > status = = STATUS_MAP_WAIT ) {
// Check if we already have a new client to send the map to
if ( ! new_map_client ) {
// If not, this client will get the map
new_cs - > status = STATUS_AUTH ;
new_map_client = true ;
SEND_COMMAND ( PACKET_SERVER_MAP ) ( new_cs ) ;
} else {
// Else, send the other clients how many clients are in front of them
SEND_COMMAND ( PACKET_SERVER_WAIT ) ( new_cs ) ;
}
}
}
}
// There is no more data, so break the for
break ;
}
}
// Send all packets (forced) and check if we have send it all
2007-02-01 23:50:15 +00:00
cs - > Send_Packets ( ) ;
if ( cs - > IsPacketQueueEmpty ( ) ) {
2004-12-04 17:54:56 +00:00
// All are sent, increase the sent_packets
sent_packets * = 2 ;
} else {
// Not everything is sent, decrease the sent_packets
if ( sent_packets > 1 ) sent_packets / = 2 ;
}
}
}
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_JOIN ) ( NetworkTCPSocketHandler * cs , uint16 client_index )
2004-12-04 17:54:56 +00:00
{
//
// Packet: SERVER_JOIN
// Function: A client is joined (all active clients receive this after a
// PACKET_CLIENT_MAP_OK) Mostly what directly follows is a
// PACKET_SERVER_CLIENT_INFO
// Data:
// uint16: Client-Index
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_JOIN ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint16 ( client_index ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_SEND_COMMAND ( PACKET_SERVER_FRAME )
{
//
// Packet: SERVER_FRAME
// Function: Sends the current frame-counter to the client
// Data:
// uint32: Frame Counter
// uint32: Frame Counter Max (how far may the client walk before the server?)
// [uint32: general-seed-1]
// [uint32: general-seed-2]
// (last two depends on compile-settings, and are not default settings)
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_FRAME ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint32 ( _frame_counter ) ;
p - > Send_uint32 ( _frame_counter_max ) ;
2004-12-04 17:54:56 +00:00
# ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
2007-02-01 23:26:44 +00:00
p - > Send_uint32 ( _sync_seed_1 ) ;
2004-12-04 17:54:56 +00:00
# ifdef NETWORK_SEND_DOUBLE_SEED
2007-02-01 23:26:44 +00:00
p - > Send_uint32 ( _sync_seed_2 ) ;
2004-12-04 17:54:56 +00:00
# endif
# endif
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_SEND_COMMAND ( PACKET_SERVER_SYNC )
{
//
// Packet: SERVER_SYNC
// Function: Sends a sync-check to the client
// Data:
// uint32: Frame Counter
// uint32: General-seed-1
// [uint32: general-seed-2]
// (last one depends on compile-settings, and are not default settings)
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_SYNC ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint32 ( _frame_counter ) ;
p - > Send_uint32 ( _sync_seed_1 ) ;
2004-12-04 17:54:56 +00:00
# ifdef NETWORK_SEND_DOUBLE_SEED
2007-02-01 23:26:44 +00:00
p - > Send_uint32 ( _sync_seed_2 ) ;
2004-12-04 17:54:56 +00:00
# endif
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_COMMAND ) ( NetworkTCPSocketHandler * cs , CommandPacket * cp )
2004-12-04 17:54:56 +00:00
{
//
// Packet: SERVER_COMMAND
// Function: Sends a DoCommand to the client
// Data:
// uint8: PlayerID (0..MAX_PLAYERS-1)
// uint32: CommandID (see command.h)
// uint32: P1 (free variables used in DoCommand)
// uint32: P2
// uint32: Tile
2005-05-15 18:50:55 +00:00
// string: text
2004-12-04 17:54:56 +00:00
// uint8: CallBackID (see callback_table.c)
// uint32: Frame of execution
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_COMMAND ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( cp - > player ) ;
p - > Send_uint32 ( cp - > cmd ) ;
p - > Send_uint32 ( cp - > p1 ) ;
p - > Send_uint32 ( cp - > p2 ) ;
p - > Send_uint32 ( cp - > tile ) ;
p - > Send_string ( cp - > text ) ;
p - > Send_uint8 ( cp - > callback ) ;
p - > Send_uint32 ( cp - > frame ) ;
2007-07-10 20:59:41 +00:00
p - > Send_bool ( cp - > my_cmd ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_CHAT ) ( NetworkTCPSocketHandler * cs , NetworkAction action , uint16 client_index , bool self_send , const char * msg )
2004-12-04 17:54:56 +00:00
{
//
// Packet: SERVER_CHAT
// Function: Sends a chat-packet to the client
// Data:
// uint8: ActionID (see network_data.h, NetworkAction)
// uint16: Client-index
2008-08-11 22:07:26 +00:00
// String: Message (max NETWORK_CHAT_LENGTH)
2004-12-04 17:54:56 +00:00
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_CHAT ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint8 ( action ) ;
p - > Send_uint16 ( client_index ) ;
2007-02-02 23:16:58 +00:00
p - > Send_bool ( self_send ) ;
2007-02-01 23:26:44 +00:00
p - > Send_string ( msg ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_ERROR_QUIT ) ( NetworkTCPSocketHandler * cs , uint16 client_index , NetworkErrorCode errorno )
2004-12-04 17:54:56 +00:00
{
//
// Packet: SERVER_ERROR_QUIT
// Function: One of the clients made an error and is quiting the game
// This packet informs the other clients of that.
// Data:
// uint16: Client-index
// uint8: ErrorID (see network_data.h, NetworkErrorCode)
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_ERROR_QUIT ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint16 ( client_index ) ;
p - > Send_uint8 ( errorno ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_QUIT ) ( NetworkTCPSocketHandler * cs , uint16 client_index , const char * leavemsg )
2004-12-04 17:54:56 +00:00
{
//
// Packet: SERVER_ERROR_QUIT
// Function: A client left the game, and this packets informs the other clients
// of that.
// Data:
// uint16: Client-index
// String: leave-message
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_QUIT ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint16 ( client_index ) ;
p - > Send_string ( leavemsg ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_SEND_COMMAND ( PACKET_SERVER_SHUTDOWN )
{
//
// Packet: SERVER_SHUTDOWN
// Function: Let the clients know that the server is closing
// Data:
// <none>
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_SHUTDOWN ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_SEND_COMMAND ( PACKET_SERVER_NEWGAME )
{
//
// Packet: PACKET_SERVER_NEWGAME
// Function: Let the clients know that the server is loading a new map
// Data:
// <none>
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_NEWGAME ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2004-12-04 17:54:56 +00:00
}
2007-01-12 20:19:49 +00:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_RCON ) ( NetworkTCPSocketHandler * cs , uint16 color , const char * command )
2005-01-15 20:09:16 +00:00
{
Packet * p = NetworkSend_Init ( PACKET_SERVER_RCON ) ;
2007-02-01 23:26:44 +00:00
p - > Send_uint16 ( color ) ;
p - > Send_string ( command ) ;
2007-02-01 23:50:15 +00:00
cs - > Send_Packet ( p ) ;
2005-01-15 20:09:16 +00:00
}
2004-12-04 17:54:56 +00:00
// **********
// Receiving functions
2007-01-12 20:19:49 +00:00
// DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkTCPSocketHandler *cs, Packet *p
2004-12-04 17:54:56 +00:00
// **********
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_COMPANY_INFO )
{
SEND_COMMAND ( PACKET_SERVER_COMPANY_INFO ) ( cs ) ;
}
2007-01-30 17:22:56 +00:00
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_NEWGRFS_CHECKED )
{
2008-06-08 08:44:19 +00:00
if ( cs - > status ! = STATUS_INACTIVE ) {
/* Illegal call, return error and ignore the packet */
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
return ;
}
2007-01-30 17:22:56 +00:00
NetworkClientInfo * ci = DEREF_CLIENT_INFO ( cs ) ;
/* We now want a password from the client else we do not allow him in! */
2008-06-03 08:04:35 +00:00
if ( ! StrEmpty ( _settings_client . network . server_password ) ) {
2007-01-30 17:22:56 +00:00
SEND_COMMAND ( PACKET_SERVER_NEED_PASSWORD ) ( cs , NETWORK_GAME_PASSWORD ) ;
} else {
2008-07-17 20:13:01 +00:00
if ( IsValidPlayerID ( ci - > client_playas ) & & _network_player_info [ ci - > client_playas ] . password [ 0 ] ! = ' \0 ' ) {
2007-01-30 17:22:56 +00:00
SEND_COMMAND ( PACKET_SERVER_NEED_PASSWORD ) ( cs , NETWORK_COMPANY_PASSWORD ) ;
} else {
SEND_COMMAND ( PACKET_SERVER_WELCOME ) ( cs ) ;
}
}
}
2004-12-04 17:54:56 +00:00
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_JOIN )
{
2008-06-08 08:44:19 +00:00
if ( cs - > status ! = STATUS_INACTIVE ) {
/* Illegal call, return error and ignore the packet */
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
return ;
}
2006-04-22 09:46:31 +00:00
char name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2007-10-30 11:29:01 +00:00
char unique_id [ NETWORK_UNIQUE_ID_LENGTH ] ;
2004-12-04 17:54:56 +00:00
NetworkClientInfo * ci ;
2007-01-10 18:56:51 +00:00
PlayerID playas ;
2004-12-04 17:54:56 +00:00
NetworkLanguage client_lang ;
char client_revision [ NETWORK_REVISION_LENGTH ] ;
2007-02-01 23:26:44 +00:00
p - > Recv_string ( client_revision , sizeof ( client_revision ) ) ;
2004-12-04 17:54:56 +00:00
2004-12-15 00:31:08 +00:00
// Check if the client has revision control enabled
2007-03-01 00:58:09 +00:00
if ( ! IsNetworkCompatibleVersion ( client_revision ) ) {
2006-06-27 21:25:53 +00:00
// Different revisions!!
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_WRONG_REVISION ) ;
return ;
2004-12-04 17:54:56 +00:00
}
2007-02-01 23:26:44 +00:00
p - > Recv_string ( name , sizeof ( name ) ) ;
playas = ( Owner ) p - > Recv_uint8 ( ) ;
client_lang = ( NetworkLanguage ) p - > Recv_uint8 ( ) ;
p - > Recv_string ( unique_id , sizeof ( unique_id ) ) ;
2005-01-05 14:39:48 +00:00
2006-10-17 23:34:12 +00:00
if ( cs - > has_quit ) return ;
2004-12-04 17:54:56 +00:00
2006-01-25 18:11:06 +00:00
// join another company does not affect these values
switch ( playas ) {
2006-10-15 23:48:34 +00:00
case PLAYER_NEW_COMPANY : /* New company */
2008-06-03 08:04:35 +00:00
if ( ActivePlayerCount ( ) > = _settings_client . network . max_companies ) {
2006-01-25 18:11:06 +00:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_FULL ) ;
return ;
}
break ;
2006-10-14 15:49:43 +00:00
case PLAYER_SPECTATOR : /* Spectator */
2008-06-03 08:04:35 +00:00
if ( NetworkSpectatorCount ( ) > = _settings_client . network . max_spectators ) {
2006-01-25 18:11:06 +00:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_FULL ) ;
return ;
}
break ;
2006-10-17 22:16:46 +00:00
default : /* Join another company (companies 1-8 (index 0-7)) */
2008-07-17 20:13:01 +00:00
if ( ! IsValidPlayerID ( playas ) ) {
2006-10-15 23:48:34 +00:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_PLAYER_MISMATCH ) ;
return ;
}
break ;
2004-12-04 17:54:56 +00:00
}
2006-01-25 18:11:06 +00:00
// We need a valid name.. make it Player
2006-04-22 09:46:31 +00:00
if ( * name = = ' \0 ' ) ttd_strlcpy ( name , " Player " , sizeof ( name ) ) ;
2006-01-25 18:11:06 +00:00
if ( ! NetworkFindName ( name ) ) { // Change name if duplicate
2004-12-04 17:54:56 +00:00
// We could not create a name for this player
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NAME_IN_USE ) ;
return ;
}
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-04-22 09:46:31 +00:00
ttd_strlcpy ( ci - > client_name , name , sizeof ( ci - > client_name ) ) ;
ttd_strlcpy ( ci - > unique_id , unique_id , sizeof ( ci - > unique_id ) ) ;
2004-12-04 17:54:56 +00:00
ci - > client_playas = playas ;
ci - > client_lang = client_lang ;
2006-10-17 22:16:46 +00:00
/* Make sure companies to which people try to join are not autocleaned */
2008-07-17 20:13:01 +00:00
if ( IsValidPlayerID ( playas ) ) _network_player_info [ playas ] . months_empty = 0 ;
2007-01-30 17:22:56 +00:00
if ( _grfconfig = = NULL ) {
RECEIVE_COMMAND ( PACKET_CLIENT_NEWGRFS_CHECKED ) ( cs , NULL ) ;
} else {
SEND_COMMAND ( PACKET_SERVER_CHECK_NEWGRFS ) ( cs ) ;
}
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_PASSWORD )
{
NetworkPasswordType type ;
char password [ NETWORK_PASSWORD_LENGTH ] ;
2006-10-17 23:34:12 +00:00
const NetworkClientInfo * ci ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:26:44 +00:00
type = ( NetworkPasswordType ) p - > Recv_uint8 ( ) ;
p - > Recv_string ( password , sizeof ( password ) ) ;
2004-12-04 17:54:56 +00:00
2007-03-08 09:46:44 +00:00
if ( cs - > status = = STATUS_AUTHORIZING & & type = = NETWORK_GAME_PASSWORD ) {
2004-12-04 17:54:56 +00:00
// Check game-password
2008-06-03 08:04:35 +00:00
if ( strcmp ( password , _settings_client . network . server_password ) ! = 0 ) {
2004-12-04 17:54:56 +00:00
// Password is invalid
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_WRONG_PASSWORD ) ;
return ;
}
ci = DEREF_CLIENT_INFO ( cs ) ;
2008-07-17 20:13:01 +00:00
if ( IsValidPlayerID ( ci - > client_playas ) & & _network_player_info [ ci - > client_playas ] . password [ 0 ] ! = ' \0 ' ) {
2004-12-04 17:54:56 +00:00
SEND_COMMAND ( PACKET_SERVER_NEED_PASSWORD ) ( cs , NETWORK_COMPANY_PASSWORD ) ;
return ;
}
// Valid password, allow user
SEND_COMMAND ( PACKET_SERVER_WELCOME ) ( cs ) ;
return ;
2007-03-08 09:46:44 +00:00
} else if ( cs - > status = = STATUS_AUTHORIZING & & type = = NETWORK_COMPANY_PASSWORD ) {
2004-12-04 17:54:56 +00:00
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-10-17 22:16:46 +00:00
if ( strcmp ( password , _network_player_info [ ci - > client_playas ] . password ) ! = 0 ) {
2004-12-04 17:54:56 +00:00
// Password is invalid
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_WRONG_PASSWORD ) ;
return ;
}
SEND_COMMAND ( PACKET_SERVER_WELCOME ) ( cs ) ;
return ;
}
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
return ;
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_GETMAP )
{
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 17:54:56 +00:00
// The client was never joined.. so this is impossible, right?
// Ignore the packet, give the client a warning, and close his connection
2006-10-17 23:34:12 +00:00
if ( cs - > status < STATUS_AUTH | | cs - > has_quit ) {
2004-12-04 17:54:56 +00:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_AUTHORIZED ) ;
return ;
}
// Check if someone else is receiving the map
FOR_ALL_CLIENTS ( new_cs ) {
if ( new_cs - > status = = STATUS_MAP ) {
// Tell the new client to wait
cs - > status = STATUS_MAP_WAIT ;
SEND_COMMAND ( PACKET_SERVER_WAIT ) ( cs ) ;
return ;
}
}
// We receive a request to upload the map.. give it to the client!
SEND_COMMAND ( PACKET_SERVER_MAP ) ( cs ) ;
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_MAP_OK )
{
// Client has the map, now start syncing
2006-10-17 23:34:12 +00:00
if ( cs - > status = = STATUS_DONE_MAP & & ! cs - > has_quit ) {
2004-12-23 20:33:57 +00:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 17:54:56 +00:00
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( NETWORK_ACTION_JOIN , CC_DEFAULT , false , client_name , " " ) ;
2004-12-04 17:54:56 +00:00
// Mark the client as pre-active, and wait for an ACK
// so we know he is done loading and in sync with us
cs - > status = STATUS_PRE_ACTIVE ;
NetworkHandleCommandQueue ( cs ) ;
SEND_COMMAND ( PACKET_SERVER_FRAME ) ( cs ) ;
SEND_COMMAND ( PACKET_SERVER_SYNC ) ( cs ) ;
// This is the frame the client receives
// we need it later on to make sure the client is not too slow
cs - > last_frame = _frame_counter ;
cs - > last_frame_server = _frame_counter ;
FOR_ALL_CLIENTS ( new_cs ) {
if ( new_cs - > status > STATUS_AUTH ) {
SEND_COMMAND ( PACKET_SERVER_CLIENT_INFO ) ( new_cs , DEREF_CLIENT_INFO ( cs ) ) ;
SEND_COMMAND ( PACKET_SERVER_JOIN ) ( new_cs , cs - > index ) ;
}
}
2005-03-29 19:10:13 +00:00
2008-05-29 20:21:28 +00:00
if ( _settings_client . network . pause_on_join ) {
2005-03-29 19:10:13 +00:00
/* Now pause the game till the client is in sync */
DoCommandP ( 0 , 1 , 0 , NULL , CMD_PAUSE ) ;
2008-05-30 18:20:26 +00:00
NetworkServerSendChat ( NETWORK_ACTION_SERVER_MESSAGE , DESTTYPE_BROADCAST , 0 , " Game paused (incoming client) " , NETWORK_SERVER_INDEX ) ;
2005-03-29 19:10:13 +00:00
}
2004-12-04 17:54:56 +00:00
} else {
// Wrong status for this packet, give a warning to client, and close connection
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
}
}
2005-05-14 19:25:18 +00:00
/** Enforce the command flags.
* Eg a server - only command can only be executed by a server , etc .
* @ param * cp the commandpacket that is going to be checked
* @ param * ci client information for debugging output to console
*/
static bool CheckCommandFlags ( const CommandPacket * cp , const NetworkClientInfo * ci )
{
byte flags = GetCommandFlags ( cp - > cmd ) ;
if ( flags & CMD_SERVER & & ci - > client_index ! = NETWORK_SERVER_INDEX ) {
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_ERROR , " WARNING: server only command from client %d (IP: %s), kicking... " , ci - > client_index , GetPlayerIP ( ci ) ) ;
2005-05-14 19:25:18 +00:00
return false ;
}
if ( flags & CMD_OFFLINE ) {
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_ERROR , " WARNING: offline only command from client %d (IP: %s), kicking... " , ci - > client_index , GetPlayerIP ( ci ) ) ;
2005-05-14 19:25:18 +00:00
return false ;
}
2006-10-17 23:34:12 +00:00
2008-07-17 20:13:01 +00:00
if ( cp - > cmd ! = CMD_PLAYER_CTRL & & ! IsValidPlayerID ( cp - > player ) & & ci - > client_index ! = NETWORK_SERVER_INDEX ) {
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_ERROR , " WARNING: spectator issueing command from client %d (IP: %s), kicking... " , ci - > client_index , GetPlayerIP ( ci ) ) ;
2007-08-30 19:20:15 +00:00
return false ;
}
2005-05-14 19:25:18 +00:00
return true ;
}
/** The client has done a command and wants us to handle it
* @ param * cs the connected client that has sent the command
* @ param * p the packet in which the command was sent
*/
2004-12-04 17:54:56 +00:00
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_COMMAND )
{
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2005-05-14 19:25:18 +00:00
const NetworkClientInfo * ci ;
byte callback ;
2004-12-04 17:54:56 +00:00
// The client was never joined.. so this is impossible, right?
// Ignore the packet, give the client a warning, and close his connection
2006-10-17 23:34:12 +00:00
if ( cs - > status < STATUS_DONE_MAP | | cs - > has_quit ) {
2004-12-04 17:54:56 +00:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
return ;
}
2007-06-09 04:01:40 +00:00
CommandPacket * cp = MallocT < CommandPacket > ( 1 ) ;
2007-02-01 23:26:44 +00:00
cp - > player = ( Owner ) p - > Recv_uint8 ( ) ;
cp - > cmd = p - > Recv_uint32 ( ) ;
cp - > p1 = p - > Recv_uint32 ( ) ;
cp - > p2 = p - > Recv_uint32 ( ) ;
cp - > tile = p - > Recv_uint32 ( ) ;
p - > Recv_string ( cp - > text , lengthof ( cp - > text ) ) ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:26:44 +00:00
callback = p - > Recv_uint8 ( ) ;
2005-01-05 14:39:48 +00:00
2007-06-09 04:01:40 +00:00
if ( cs - > has_quit ) {
free ( cp ) ;
return ;
}
2005-05-14 19:25:18 +00:00
ci = DEREF_CLIENT_INFO ( cs ) ;
2005-01-05 14:39:48 +00:00
/* Check if cp->cmd is valid */
if ( ! IsValidCommand ( cp - > cmd ) ) {
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_ERROR , " WARNING: invalid command from client %d (IP: %s). " , ci - > client_index , GetPlayerIP ( ci ) ) ;
2005-01-05 14:39:48 +00:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
2007-06-09 04:01:40 +00:00
free ( cp ) ;
2005-01-05 14:39:48 +00:00
return ;
}
2004-12-04 17:54:56 +00:00
2005-05-14 19:25:18 +00:00
if ( ! CheckCommandFlags ( cp , ci ) ) {
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_KICKED ) ;
2007-06-09 04:01:40 +00:00
free ( cp ) ;
2005-05-14 19:25:18 +00:00
return ;
}
/** Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
* to match the player in the packet . If it doesn ' t , the client has done
* something pretty naughty ( or a bug ) , and will be kicked
*/
2008-07-17 15:14:42 +00:00
if ( ! ( cp - > cmd = = CMD_PLAYER_CTRL & & cp - > p1 = = 0 & & ci - > client_playas = = PLAYER_NEW_COMPANY ) & & ci - > client_playas ! = cp - > player ) {
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_ERROR , " WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking... " ,
2006-10-17 22:16:46 +00:00
ci - > client_playas + 1 , GetPlayerIP ( ci ) , cp - > player + 1 ) ;
2004-12-04 17:54:56 +00:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_PLAYER_MISMATCH ) ;
2007-06-09 04:01:40 +00:00
free ( cp ) ;
2004-12-04 17:54:56 +00:00
return ;
}
2005-05-14 19:25:18 +00:00
/** @todo CMD_PLAYER_CTRL with p1 = 0 announces a new player to the server. To give the
* player the correct ID , the server injects p2 and executes the command . Any other p1
* is prohibited . Pretty ugly and should be redone together with its function .
* @ see CmdPlayerCtrl ( ) players . c : 655
*/
if ( cp - > cmd = = CMD_PLAYER_CTRL ) {
if ( cp - > p1 ! = 0 ) {
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_CHEATER ) ;
2007-06-09 04:01:40 +00:00
free ( cp ) ;
2005-05-14 19:25:18 +00:00
return ;
}
2006-10-17 23:34:12 +00:00
/* XXX - Execute the command as a valid player. Normally this would be done by a
* spectator , but that is not allowed any commands . So do an impersonation . The drawback
* of this is that the first company ' s last_built_tile is also updated . . . */
2007-01-10 18:56:51 +00:00
cp - > player = OWNER_BEGIN ;
2006-10-17 23:34:12 +00:00
cp - > p2 = cs - _clients ; // XXX - UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl
2005-05-14 19:25:18 +00:00
}
2004-12-04 17:54:56 +00:00
// The frame can be executed in the same frame as the next frame-packet
// That frame just before that frame is saved in _frame_counter_max
cp - > frame = _frame_counter_max + 1 ;
2005-01-05 14:39:48 +00:00
cp - > next = NULL ;
2004-12-04 17:54:56 +00:00
// Queue the command for the clients (are send at the end of the frame
// if they can handle it ;))
FOR_ALL_CLIENTS ( new_cs ) {
2006-12-26 18:27:40 +00:00
if ( new_cs - > status > = STATUS_MAP ) {
2004-12-04 17:54:56 +00:00
// Callbacks are only send back to the client who sent them in the
// first place. This filters that out.
2005-05-14 19:25:18 +00:00
cp - > callback = ( new_cs ! = cs ) ? 0 : callback ;
2007-07-10 20:59:41 +00:00
cp - > my_cmd = ( new_cs = = cs ) ;
2004-12-04 17:54:56 +00:00
NetworkAddCommandQueue ( new_cs , cp ) ;
}
}
cp - > callback = 0 ;
2007-07-10 20:59:41 +00:00
cp - > my_cmd = false ;
2004-12-04 17:54:56 +00:00
// Queue the command on the server
if ( _local_command_queue = = NULL ) {
_local_command_queue = cp ;
} else {
// Find last packet
CommandPacket * c = _local_command_queue ;
while ( c - > next ! = NULL ) c = c - > next ;
c - > next = cp ;
}
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_ERROR )
{
// This packets means a client noticed an error and is reporting this
// to us. Display the error and report it to the other clients
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2004-12-19 15:14:55 +00:00
char str [ 100 ] ;
2004-12-23 20:33:57 +00:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2007-02-01 23:26:44 +00:00
NetworkErrorCode errorno = ( NetworkErrorCode ) p - > Recv_uint8 ( ) ;
2004-12-04 17:54:56 +00:00
// The client was never joined.. thank the client for the packet, but ignore it
2006-10-17 23:34:12 +00:00
if ( cs - > status < STATUS_DONE_MAP | | cs - > has_quit ) {
cs - > has_quit = true ;
2004-12-04 17:54:56 +00:00
return ;
}
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
2006-10-21 23:31:34 +00:00
GetNetworkErrorMsg ( str , errorno , lastof ( str ) ) ;
2004-12-04 17:54:56 +00:00
2006-12-26 17:36:18 +00:00
DEBUG ( net , 2 , " '%s' reported an error and is closing its connection (%s) " , client_name , str ) ;
2004-12-04 17:54:56 +00:00
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " %s " , str ) ;
2004-12-04 17:54:56 +00:00
FOR_ALL_CLIENTS ( new_cs ) {
if ( new_cs - > status > STATUS_AUTH ) {
SEND_COMMAND ( PACKET_SERVER_ERROR_QUIT ) ( new_cs , cs - > index , errorno ) ;
}
}
2006-10-17 23:34:12 +00:00
cs - > has_quit = true ;
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_QUIT )
{
// The client wants to leave. Display this and report it to the other
// clients.
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2004-12-19 15:14:55 +00:00
char str [ 100 ] ;
2004-12-23 20:33:57 +00:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 17:54:56 +00:00
// The client was never joined.. thank the client for the packet, but ignore it
2006-10-17 23:34:12 +00:00
if ( cs - > status < STATUS_DONE_MAP | | cs - > has_quit ) {
cs - > has_quit = true ;
2004-12-04 17:54:56 +00:00
return ;
}
2007-02-01 23:26:44 +00:00
p - > Recv_string ( str , lengthof ( str ) ) ;
2004-12-04 17:54:56 +00:00
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " %s " , str ) ;
2004-12-04 17:54:56 +00:00
FOR_ALL_CLIENTS ( new_cs ) {
if ( new_cs - > status > STATUS_AUTH ) {
2004-12-19 15:14:55 +00:00
SEND_COMMAND ( PACKET_SERVER_QUIT ) ( new_cs , cs - > index , str ) ;
2004-12-04 17:54:56 +00:00
}
}
2006-10-17 23:34:12 +00:00
cs - > has_quit = true ;
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_ACK )
{
2008-06-08 08:44:19 +00:00
if ( cs - > status < STATUS_AUTH ) {
/* Illegal call, return error and ignore the packet */
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_AUTHORIZED ) ;
return ;
}
2007-02-01 23:26:44 +00:00
uint32 frame = p - > Recv_uint32 ( ) ;
2005-03-29 19:10:13 +00:00
/* The client is trying to catch up with the server */
if ( cs - > status = = STATUS_PRE_ACTIVE ) {
/* The client is not yet catched up? */
2006-10-17 23:34:12 +00:00
if ( frame + DAY_TICKS < _frame_counter ) return ;
2005-03-29 19:10:13 +00:00
/* Now he is! Unpause the game */
cs - > status = STATUS_ACTIVE ;
2008-05-29 20:21:28 +00:00
if ( _settings_client . network . pause_on_join ) {
2005-03-29 19:10:13 +00:00
DoCommandP ( 0 , 0 , 0 , NULL , CMD_PAUSE ) ;
2008-05-30 18:20:26 +00:00
NetworkServerSendChat ( NETWORK_ACTION_SERVER_MESSAGE , DESTTYPE_BROADCAST , 0 , " Game unpaused (client connected) " , NETWORK_SERVER_INDEX ) ;
2005-03-29 19:10:13 +00:00
}
2006-10-03 14:59:05 +00:00
2006-10-03 16:25:03 +00:00
CheckMinPlayers ( ) ;
2006-10-03 14:59:05 +00:00
/* Execute script for, e.g. MOTD */
IConsoleCmdExec ( " exec scripts/on_server_connect.scr 0 " ) ;
2005-03-29 19:10:13 +00:00
}
2004-12-04 17:54:56 +00:00
// The client received the frame, make note of it
2005-03-29 19:10:13 +00:00
cs - > last_frame = frame ;
2004-12-04 17:54:56 +00:00
// With those 2 values we can calculate the lag realtime
cs - > last_frame_server = _frame_counter ;
}
2008-05-30 18:20:26 +00:00
void NetworkServerSendChat ( NetworkAction action , DestType desttype , int dest , const char * msg , uint16 from_index )
2004-12-04 17:54:56 +00:00
{
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * cs ;
2006-10-17 23:34:12 +00:00
const NetworkClientInfo * ci , * ci_own , * ci_to ;
2004-12-04 17:54:56 +00:00
switch ( desttype ) {
case DESTTYPE_CLIENT :
2004-12-19 15:14:55 +00:00
/* Are we sending to the server? */
if ( dest = = NETWORK_SERVER_INDEX ) {
2004-12-04 17:54:56 +00:00
ci = NetworkFindClientInfoFromIndex ( from_index ) ;
2004-12-19 15:14:55 +00:00
/* Display the text locally, and that is it */
2004-12-04 17:54:56 +00:00
if ( ci ! = NULL )
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci - > client_playas ) , false , ci - > client_name , " %s " , msg ) ;
2004-12-04 17:54:56 +00:00
} else {
2004-12-19 15:14:55 +00:00
/* Else find the client to send the message to */
2004-12-04 17:54:56 +00:00
FOR_ALL_CLIENTS ( cs ) {
if ( cs - > index = = dest ) {
2004-12-19 15:14:55 +00:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , from_index , false , msg ) ;
2004-12-04 17:54:56 +00:00
break ;
}
}
}
// Display the message locally (so you know you have sent it)
if ( from_index ! = dest ) {
2004-12-19 15:14:55 +00:00
if ( from_index = = NETWORK_SERVER_INDEX ) {
2004-12-04 17:54:56 +00:00
ci = NetworkFindClientInfoFromIndex ( from_index ) ;
ci_to = NetworkFindClientInfoFromIndex ( dest ) ;
if ( ci ! = NULL & & ci_to ! = NULL )
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci - > client_playas ) , true , ci_to - > client_name , " %s " , msg ) ;
2004-12-04 17:54:56 +00:00
} else {
FOR_ALL_CLIENTS ( cs ) {
if ( cs - > index = = from_index ) {
2004-12-19 15:14:55 +00:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , dest , true , msg ) ;
2004-12-04 17:54:56 +00:00
break ;
}
}
}
}
break ;
2006-10-21 22:29:14 +00:00
case DESTTYPE_TEAM : {
2004-12-04 17:54:56 +00:00
bool show_local = true ; // If this is false, the message is already displayed
// on the client who did sent it.
2004-12-19 15:14:55 +00:00
/* Find all clients that belong to this player */
2004-12-20 15:26:19 +00:00
ci_to = NULL ;
2004-12-04 17:54:56 +00:00
FOR_ALL_CLIENTS ( cs ) {
ci = DEREF_CLIENT_INFO ( cs ) ;
if ( ci - > client_playas = = dest ) {
2004-12-19 15:14:55 +00:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , from_index , false , msg ) ;
2006-10-17 23:34:12 +00:00
if ( cs - > index = = from_index ) show_local = false ;
2004-12-20 15:26:19 +00:00
ci_to = ci ; // Remember a client that is in the company for company-name
2004-12-04 17:54:56 +00:00
}
}
2004-12-20 15:26:19 +00:00
2004-12-04 17:54:56 +00:00
ci = NetworkFindClientInfoFromIndex ( from_index ) ;
ci_own = NetworkFindClientInfoFromIndex ( NETWORK_SERVER_INDEX ) ;
if ( ci ! = NULL & & ci_own ! = NULL & & ci_own - > client_playas = = dest ) {
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci - > client_playas ) , false , ci - > client_name , " %s " , msg ) ;
2006-10-17 23:34:12 +00:00
if ( from_index = = NETWORK_SERVER_INDEX ) show_local = false ;
2005-05-17 18:22:59 +00:00
ci_to = ci_own ;
2004-12-04 17:54:56 +00:00
}
2004-12-20 15:26:19 +00:00
/* There is no such player */
2005-05-17 18:22:59 +00:00
if ( ci_to = = NULL ) break ;
2004-12-20 15:26:19 +00:00
2004-12-04 17:54:56 +00:00
// Display the message locally (so you know you have sent it)
if ( ci ! = NULL & & show_local ) {
if ( from_index = = NETWORK_SERVER_INDEX ) {
char name [ NETWORK_NAME_LENGTH ] ;
2008-07-17 20:13:01 +00:00
StringID str = IsValidPlayerID ( ci_to - > client_playas ) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS ;
2007-06-25 15:59:37 +00:00
SetDParam ( 0 , ci_to - > client_playas ) ;
2006-10-24 22:26:20 +00:00
GetString ( name , str , lastof ( name ) ) ;
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci_own - > client_playas ) , true , name , " %s " , msg ) ;
2004-12-04 17:54:56 +00:00
} else {
FOR_ALL_CLIENTS ( cs ) {
if ( cs - > index = = from_index ) {
2004-12-23 13:53:05 +00:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , ci_to - > client_index , true , msg ) ;
2004-12-04 17:54:56 +00:00
}
}
}
}
}
break ;
default :
2006-12-26 17:36:18 +00:00
DEBUG ( net , 0 , " [server] received unknown chat destination type %d. Doing broadcast instead " , desttype ) ;
2004-12-04 17:54:56 +00:00
/* fall-through to next case */
case DESTTYPE_BROADCAST :
FOR_ALL_CLIENTS ( cs ) {
2004-12-19 15:14:55 +00:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , from_index , false , msg ) ;
2004-12-04 17:54:56 +00:00
}
ci = NetworkFindClientInfoFromIndex ( from_index ) ;
if ( ci ! = NULL )
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci - > client_playas ) , false , ci - > client_name , " %s " , msg ) ;
2004-12-04 17:54:56 +00:00
break ;
}
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_CHAT )
{
2008-06-08 08:44:19 +00:00
if ( cs - > status < STATUS_AUTH ) {
/* Illegal call, return error and ignore the packet */
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_AUTHORIZED ) ;
return ;
}
2007-02-01 23:26:44 +00:00
NetworkAction action = ( NetworkAction ) p - > Recv_uint8 ( ) ;
DestType desttype = ( DestType ) p - > Recv_uint8 ( ) ;
2007-04-26 07:41:24 +00:00
int dest = p - > Recv_uint16 ( ) ;
2008-08-11 22:07:26 +00:00
char msg [ NETWORK_CHAT_LENGTH ] ;
2004-12-04 17:54:56 +00:00
2008-08-11 22:07:26 +00:00
p - > Recv_string ( msg , NETWORK_CHAT_LENGTH ) ;
2004-12-04 17:54:56 +00:00
2008-07-21 15:50:55 +00:00
const NetworkClientInfo * ci = DEREF_CLIENT_INFO ( cs ) ;
switch ( action ) {
case NETWORK_ACTION_GIVE_MONEY :
if ( ! IsValidPlayerID ( ci - > client_playas ) ) break ;
/* Fall-through */
case NETWORK_ACTION_CHAT :
case NETWORK_ACTION_CHAT_CLIENT :
case NETWORK_ACTION_CHAT_COMPANY :
NetworkServerSendChat ( action , desttype , dest , msg , cs - > index ) ;
break ;
default :
IConsolePrintF ( CC_ERROR , " WARNING: invalid chat action from client %d (IP: %s). " , ci - > client_index , GetPlayerIP ( ci ) ) ;
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
break ;
}
2004-12-04 17:54:56 +00:00
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_SET_PASSWORD )
{
2008-06-08 08:44:19 +00:00
if ( cs - > status ! = STATUS_ACTIVE ) {
/* Illegal call, return error and ignore the packet */
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
return ;
}
2004-12-04 17:54:56 +00:00
char password [ NETWORK_PASSWORD_LENGTH ] ;
2006-10-17 23:34:12 +00:00
const NetworkClientInfo * ci ;
2004-12-04 17:54:56 +00:00
2007-02-01 23:26:44 +00:00
p - > Recv_string ( password , sizeof ( password ) ) ;
2004-12-04 17:54:56 +00:00
ci = DEREF_CLIENT_INFO ( cs ) ;
2008-07-17 20:13:01 +00:00
if ( IsValidPlayerID ( ci - > client_playas ) ) {
2006-10-17 22:16:46 +00:00
ttd_strlcpy ( _network_player_info [ ci - > client_playas ] . password , password , sizeof ( _network_player_info [ 0 ] . password ) ) ;
2004-12-04 17:54:56 +00:00
}
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_SET_NAME )
{
2008-06-08 08:44:19 +00:00
if ( cs - > status ! = STATUS_ACTIVE ) {
/* Illegal call, return error and ignore the packet */
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
return ;
}
2004-12-23 20:33:57 +00:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 17:54:56 +00:00
NetworkClientInfo * ci ;
2007-02-01 23:26:44 +00:00
p - > Recv_string ( client_name , sizeof ( client_name ) ) ;
2004-12-04 17:54:56 +00:00
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-10-17 23:34:12 +00:00
if ( cs - > has_quit ) return ;
2005-01-05 14:39:48 +00:00
2004-12-04 17:54:56 +00:00
if ( ci ! = NULL ) {
// Display change
2004-12-23 20:33:57 +00:00
if ( NetworkFindName ( client_name ) ) {
2008-05-24 10:35:15 +00:00
NetworkTextMessage ( NETWORK_ACTION_NAME_CHANGE , CC_DEFAULT , false , ci - > client_name , " %s " , client_name ) ;
2004-12-23 20:33:57 +00:00
ttd_strlcpy ( ci - > client_name , client_name , sizeof ( ci - > client_name ) ) ;
2004-12-04 17:54:56 +00:00
NetworkUpdateClientInfo ( ci - > client_index ) ;
}
}
}
2005-01-15 20:09:16 +00:00
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_RCON )
{
char pass [ NETWORK_PASSWORD_LENGTH ] ;
char command [ NETWORK_RCONCOMMAND_LENGTH ] ;
2008-06-03 08:04:35 +00:00
if ( StrEmpty ( _settings_client . network . rcon_password ) ) return ;
2005-01-15 20:09:16 +00:00
2007-02-01 23:26:44 +00:00
p - > Recv_string ( pass , sizeof ( pass ) ) ;
p - > Recv_string ( command , sizeof ( command ) ) ;
2005-01-15 20:09:16 +00:00
2008-06-03 08:04:35 +00:00
if ( strcmp ( pass , _settings_client . network . rcon_password ) ! = 0 ) {
2006-12-26 17:36:18 +00:00
DEBUG ( net , 0 , " [rcon] wrong password from client-id %d " , cs - > index ) ;
2005-01-15 20:09:16 +00:00
return ;
}
2006-12-26 17:36:18 +00:00
DEBUG ( net , 0 , " [rcon] client-id %d executed: '%s' " , cs - > index , command ) ;
2005-01-15 20:09:16 +00:00
_redirect_console_to_client = cs - > index ;
IConsoleCmdExec ( command ) ;
_redirect_console_to_client = 0 ;
return ;
}
2004-12-04 17:54:56 +00:00
// The layout for the receive-functions by the server
2007-01-12 20:19:49 +00:00
typedef void NetworkServerPacket ( NetworkTCPSocketHandler * cs , Packet * p ) ;
2004-12-04 17:54:56 +00:00
// This array matches PacketType. At an incoming
// packet it is matches against this array
// and that way the right function to handle that
// packet is found.
static NetworkServerPacket * const _network_server_packet [ ] = {
NULL , /*PACKET_SERVER_FULL,*/
2005-01-02 12:03:43 +00:00
NULL , /*PACKET_SERVER_BANNED,*/
2004-12-04 17:54:56 +00:00
RECEIVE_COMMAND ( PACKET_CLIENT_JOIN ) ,
NULL , /*PACKET_SERVER_ERROR,*/
RECEIVE_COMMAND ( PACKET_CLIENT_COMPANY_INFO ) ,
NULL , /*PACKET_SERVER_COMPANY_INFO,*/
NULL , /*PACKET_SERVER_CLIENT_INFO,*/
NULL , /*PACKET_SERVER_NEED_PASSWORD,*/
RECEIVE_COMMAND ( PACKET_CLIENT_PASSWORD ) ,
NULL , /*PACKET_SERVER_WELCOME,*/
RECEIVE_COMMAND ( PACKET_CLIENT_GETMAP ) ,
NULL , /*PACKET_SERVER_WAIT,*/
NULL , /*PACKET_SERVER_MAP,*/
RECEIVE_COMMAND ( PACKET_CLIENT_MAP_OK ) ,
NULL , /*PACKET_SERVER_JOIN,*/
NULL , /*PACKET_SERVER_FRAME,*/
NULL , /*PACKET_SERVER_SYNC,*/
RECEIVE_COMMAND ( PACKET_CLIENT_ACK ) ,
RECEIVE_COMMAND ( PACKET_CLIENT_COMMAND ) ,
NULL , /*PACKET_SERVER_COMMAND,*/
RECEIVE_COMMAND ( PACKET_CLIENT_CHAT ) ,
NULL , /*PACKET_SERVER_CHAT,*/
RECEIVE_COMMAND ( PACKET_CLIENT_SET_PASSWORD ) ,
RECEIVE_COMMAND ( PACKET_CLIENT_SET_NAME ) ,
RECEIVE_COMMAND ( PACKET_CLIENT_QUIT ) ,
RECEIVE_COMMAND ( PACKET_CLIENT_ERROR ) ,
NULL , /*PACKET_SERVER_QUIT,*/
NULL , /*PACKET_SERVER_ERROR_QUIT,*/
NULL , /*PACKET_SERVER_SHUTDOWN,*/
NULL , /*PACKET_SERVER_NEWGAME,*/
2005-01-15 20:09:16 +00:00
NULL , /*PACKET_SERVER_RCON,*/
RECEIVE_COMMAND ( PACKET_CLIENT_RCON ) ,
2007-01-30 17:22:56 +00:00
NULL , /*PACKET_CLIENT_CHECK_NEWGRFS,*/
RECEIVE_COMMAND ( PACKET_CLIENT_NEWGRFS_CHECKED ) ,
2004-12-04 17:54:56 +00:00
} ;
// If this fails, check the array above with network_data.h
assert_compile ( lengthof ( _network_server_packet ) = = PACKET_END ) ;
// This update the company_info-stuff
2007-03-07 11:47:46 +00:00
void NetworkPopulateCompanyInfo ( )
2004-12-04 17:54:56 +00:00
{
char password [ NETWORK_PASSWORD_LENGTH ] ;
2006-10-17 23:34:12 +00:00
const Player * p ;
const Vehicle * v ;
const Station * s ;
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * cs ;
2006-10-17 23:34:12 +00:00
const NetworkClientInfo * ci ;
uint i ;
2004-12-16 13:59:23 +00:00
uint16 months_empty ;
2004-12-04 17:54:56 +00:00
2008-07-19 20:23:51 +00:00
for ( PlayerID pid = PLAYER_FIRST ; pid < MAX_PLAYERS ; pid + + ) {
if ( ! IsValidPlayerID ( pid ) ) memset ( & _network_player_info [ pid ] , 0 , sizeof ( NetworkPlayerInfo ) ) ;
}
2004-12-04 17:54:56 +00:00
2008-07-18 16:40:29 +00:00
FOR_ALL_PLAYERS ( p ) {
2004-12-04 17:54:56 +00:00
// Clean the info but not the password
ttd_strlcpy ( password , _network_player_info [ p - > index ] . password , sizeof ( password ) ) ;
2004-12-16 13:59:23 +00:00
months_empty = _network_player_info [ p - > index ] . months_empty ;
2004-12-04 17:54:56 +00:00
memset ( & _network_player_info [ p - > index ] , 0 , sizeof ( NetworkPlayerInfo ) ) ;
2004-12-16 13:59:23 +00:00
_network_player_info [ p - > index ] . months_empty = months_empty ;
2004-12-04 17:54:56 +00:00
ttd_strlcpy ( _network_player_info [ p - > index ] . password , password , sizeof ( _network_player_info [ p - > index ] . password ) ) ;
// Grap the company name
2007-06-25 15:59:37 +00:00
SetDParam ( 0 , p - > index ) ;
GetString ( _network_player_info [ p - > index ] . company_name , STR_COMPANY_NAME , lastof ( _network_player_info [ p - > index ] . company_name ) ) ;
2004-12-04 17:54:56 +00:00
// Check the income
2006-08-20 19:05:28 +00:00
if ( _cur_year - 1 = = p - > inaugurated_year ) {
2004-12-04 17:54:56 +00:00
// The player is here just 1 year, so display [2], else display[1]
2006-10-17 23:34:12 +00:00
for ( i = 0 ; i < lengthof ( p - > yearly_expenses [ 2 ] ) ; i + + ) {
2004-12-04 17:54:56 +00:00
_network_player_info [ p - > index ] . income - = p - > yearly_expenses [ 2 ] [ i ] ;
2006-06-27 21:25:53 +00:00
}
} else {
2006-10-17 23:34:12 +00:00
for ( i = 0 ; i < lengthof ( p - > yearly_expenses [ 1 ] ) ; i + + ) {
2004-12-04 17:54:56 +00:00
_network_player_info [ p - > index ] . income - = p - > yearly_expenses [ 1 ] [ i ] ;
2006-06-27 21:25:53 +00:00
}
}
2004-12-04 17:54:56 +00:00
// Set some general stuff
_network_player_info [ p - > index ] . inaugurated_year = p - > inaugurated_year ;
_network_player_info [ p - > index ] . company_value = p - > old_economy [ 0 ] . company_value ;
2007-06-18 21:00:14 +00:00
_network_player_info [ p - > index ] . money = p - > player_money ;
2004-12-04 17:54:56 +00:00
_network_player_info [ p - > index ] . performance = p - > old_economy [ 0 ] . performance_history ;
}
// Go through all vehicles and count the type of vehicles
FOR_ALL_VEHICLES ( v ) {
2008-07-17 20:13:01 +00:00
if ( ! IsValidPlayerID ( v - > owner ) | | ! v - > IsPrimaryVehicle ( ) ) continue ;
2008-01-13 22:27:06 +00:00
byte type = 0 ;
2006-06-27 21:25:53 +00:00
switch ( v - > type ) {
2008-01-13 22:27:06 +00:00
case VEH_TRAIN : type = 0 ; break ;
case VEH_ROAD : type = ( v - > cargo_type ! = CT_PASSENGERS ) ? 1 : 2 ; break ;
case VEH_AIRCRAFT : type = 3 ; break ;
case VEH_SHIP : type = 4 ; break ;
default : continue ;
2006-06-27 21:25:53 +00:00
}
2008-01-18 21:25:18 +00:00
_network_player_info [ v - > owner ] . num_vehicle [ type ] + + ;
2004-12-04 17:54:56 +00:00
}
// Go through all stations and count the types of stations
FOR_ALL_STATIONS ( s ) {
2008-07-17 20:13:01 +00:00
if ( IsValidPlayerID ( s - > owner ) ) {
2006-10-17 23:34:12 +00:00
NetworkPlayerInfo * npi = & _network_player_info [ s - > owner ] ;
2006-06-27 21:25:53 +00:00
if ( s - > facilities & FACIL_TRAIN ) npi - > num_station [ 0 ] + + ;
if ( s - > facilities & FACIL_TRUCK_STOP ) npi - > num_station [ 1 ] + + ;
if ( s - > facilities & FACIL_BUS_STOP ) npi - > num_station [ 2 ] + + ;
if ( s - > facilities & FACIL_AIRPORT ) npi - > num_station [ 3 ] + + ;
if ( s - > facilities & FACIL_DOCK ) npi - > num_station [ 4 ] + + ;
2004-12-04 17:54:56 +00:00
}
}
ci = NetworkFindClientInfoFromIndex ( NETWORK_SERVER_INDEX ) ;
// Register local player (if not dedicated)
2008-07-17 20:13:01 +00:00
if ( ci ! = NULL & & IsValidPlayerID ( ci - > client_playas ) )
2006-10-17 22:16:46 +00:00
ttd_strlcpy ( _network_player_info [ ci - > client_playas ] . players , ci - > client_name , sizeof ( _network_player_info [ 0 ] . players ) ) ;
2004-12-04 17:54:56 +00:00
FOR_ALL_CLIENTS ( cs ) {
2004-12-23 20:33:57 +00:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 17:54:56 +00:00
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
ci = DEREF_CLIENT_INFO ( cs ) ;
2008-07-17 20:13:01 +00:00
if ( ci ! = NULL & & IsValidPlayerID ( ci - > client_playas ) ) {
2007-01-13 15:00:16 +00:00
if ( ! StrEmpty ( _network_player_info [ ci - > client_playas ] . players ) ) {
2006-10-17 22:16:46 +00:00
ttd_strlcat ( _network_player_info [ ci - > client_playas ] . players , " , " , lengthof ( _network_player_info [ 0 ] . players ) ) ;
2007-01-13 15:00:16 +00:00
}
2004-12-15 20:10:34 +00:00
2006-10-17 22:16:46 +00:00
ttd_strlcat ( _network_player_info [ ci - > client_playas ] . players , client_name , lengthof ( _network_player_info [ 0 ] . players ) ) ;
2004-12-04 17:54:56 +00:00
}
}
}
// Send a packet to all clients with updated info about this client_index
void NetworkUpdateClientInfo ( uint16 client_index )
{
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * cs ;
2006-10-17 23:34:12 +00:00
NetworkClientInfo * ci = NetworkFindClientInfoFromIndex ( client_index ) ;
2004-12-04 17:54:56 +00:00
2006-06-27 21:25:53 +00:00
if ( ci = = NULL ) return ;
2004-12-14 20:27:00 +00:00
2004-12-04 17:54:56 +00:00
FOR_ALL_CLIENTS ( cs ) {
SEND_COMMAND ( PACKET_SERVER_CLIENT_INFO ) ( cs , ci ) ;
}
}
2004-12-23 17:37:26 +00:00
/* Check if we want to restart the map */
2007-03-07 11:47:46 +00:00
static void NetworkCheckRestartMap ( )
2004-12-23 17:37:26 +00:00
{
2008-05-29 20:21:28 +00:00
if ( _settings_client . network . restart_game_year ! = 0 & & _cur_year > = _settings_client . network . restart_game_year ) {
2006-12-26 17:36:18 +00:00
DEBUG ( net , 0 , " Auto-restarting map. Year %d reached " , _cur_year ) ;
2004-12-23 17:37:26 +00:00
(svn r5946) -Add: merged the TGP branch to mainline. TGP adds:
- New optional landscape generator (TerraGenesis Perlin)
- Load heightmaps (either BMP or PNG)
- Progress dialog while generating worlds (no longer a 'hanging' screen)
- New dialogs for NewGame, Create Scenario and Play Heightmap
- Easier to configure your landscape
- More things to configure (tree-placer, ..)
- Speedup of world generation
- New console command 'restart': restart the map EXACTLY as it was when you
first started it (needs a game made after or with this commit)
- New console command 'getseed': get the seed of your map and share it with
others (of course only works with generated maps)
- Many new, world generation related, things
- Many internal cleanups and rewrites
Many tnx to those people who helped making this:
Belugas, DaleStan, glx, KUDr, RichK67, Rubidium, and TrueLight (alfabetic)
Many tnx to those who helped testing:
Arnau, Bjarni, and tokai (alfabetic)
And to all other people who helped testing and sending comments / bugs
Stats: 673 lines changed, 3534 new lines, 79 new strings
2006-08-19 10:00:30 +00:00
StartNewGameWithoutGUI ( GENERATE_NEW_SEED ) ;
2004-12-23 17:37:26 +00:00
}
}
2004-12-16 13:59:23 +00:00
/* Check if the server has autoclean_companies activated
Two things happen :
1 ) If a company is not protected , it is closed after 1 year ( for example )
2 ) If a company is protected , protection is disabled after 3 years ( for example )
( and item 1. happens a year later ) */
2007-03-07 11:47:46 +00:00
static void NetworkAutoCleanCompanies ( )
2004-12-16 13:59:23 +00:00
{
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * cs ;
2006-10-17 23:34:12 +00:00
const NetworkClientInfo * ci ;
const Player * p ;
2004-12-16 13:59:23 +00:00
bool clients_in_company [ MAX_PLAYERS ] ;
2008-05-29 20:21:28 +00:00
if ( ! _settings_client . network . autoclean_companies ) return ;
2004-12-16 13:59:23 +00:00
memset ( clients_in_company , 0 , sizeof ( clients_in_company ) ) ;
/* Detect the active companies */
FOR_ALL_CLIENTS ( cs ) {
ci = DEREF_CLIENT_INFO ( cs ) ;
2008-07-17 20:13:01 +00:00
if ( IsValidPlayerID ( ci - > client_playas ) ) clients_in_company [ ci - > client_playas ] = true ;
2004-12-16 13:59:23 +00:00
}
2006-10-17 23:34:12 +00:00
2004-12-16 13:59:23 +00:00
if ( ! _network_dedicated ) {
ci = NetworkFindClientInfoFromIndex ( NETWORK_SERVER_INDEX ) ;
2008-07-17 20:13:01 +00:00
if ( IsValidPlayerID ( ci - > client_playas ) ) clients_in_company [ ci - > client_playas ] = true ;
2004-12-16 13:59:23 +00:00
}
/* Go through all the comapnies */
FOR_ALL_PLAYERS ( p ) {
/* Skip the non-active once */
2008-07-18 16:40:29 +00:00
if ( p - > is_ai ) continue ;
2004-12-16 13:59:23 +00:00
if ( ! clients_in_company [ p - > index ] ) {
/* The company is empty for one month more */
_network_player_info [ p - > index ] . months_empty + + ;
/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
2008-07-21 13:05:43 +00:00
if ( _settings_client . network . autoclean_unprotected ! = 0 & & _network_player_info [ p - > index ] . months_empty > _settings_client . network . autoclean_unprotected & & _network_player_info [ p - > index ] . password [ 0 ] = = ' \0 ' ) {
2004-12-16 13:59:23 +00:00
/* Shut the company down */
DoCommandP ( 0 , 2 , p - > index , NULL , CMD_PLAYER_CTRL ) ;
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_DEFAULT , " Auto-cleaned company #%d " , p - > index + 1 ) ;
2004-12-16 13:59:23 +00:00
}
/* Is the compnay empty for autoclean_protected-months, and there is a protection? */
2008-07-21 13:05:43 +00:00
if ( _settings_client . network . autoclean_protected ! = 0 & & _network_player_info [ p - > index ] . months_empty > _settings_client . network . autoclean_protected & & _network_player_info [ p - > index ] . password [ 0 ] ! = ' \0 ' ) {
2004-12-16 13:59:23 +00:00
/* Unprotect the company */
_network_player_info [ p - > index ] . password [ 0 ] = ' \0 ' ;
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_DEFAULT , " Auto-removed protection from company #%d " , p - > index + 1 ) ;
2004-12-16 13:59:23 +00:00
_network_player_info [ p - > index ] . months_empty = 0 ;
}
} else {
/* It is not empty, reset the date */
_network_player_info [ p - > index ] . months_empty = 0 ;
}
}
}
2004-12-04 17:54:56 +00:00
// This function changes new_name to a name that is unique (by adding #1 ...)
// and it returns true if that succeeded.
2004-12-23 20:33:57 +00:00
bool NetworkFindName ( char new_name [ NETWORK_CLIENT_NAME_LENGTH ] )
2004-12-04 17:54:56 +00:00
{
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 17:54:56 +00:00
bool found_name = false ;
byte number = 0 ;
2004-12-23 20:33:57 +00:00
char original_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 17:54:56 +00:00
2006-04-22 09:46:31 +00:00
// We use NETWORK_CLIENT_NAME_LENGTH in here, because new_name is really a pointer
2004-12-23 20:33:57 +00:00
ttd_strlcpy ( original_name , new_name , NETWORK_CLIENT_NAME_LENGTH ) ;
2004-12-04 17:54:56 +00:00
while ( ! found_name ) {
2006-10-17 23:34:12 +00:00
const NetworkClientInfo * ci ;
2004-12-04 17:54:56 +00:00
found_name = true ;
FOR_ALL_CLIENTS ( new_cs ) {
ci = DEREF_CLIENT_INFO ( new_cs ) ;
2006-06-14 13:22:30 +00:00
if ( strcmp ( ci - > client_name , new_name ) = = 0 ) {
2004-12-04 17:54:56 +00:00
// Name already in use
found_name = false ;
break ;
}
}
// Check if it is the same as the server-name
ci = NetworkFindClientInfoFromIndex ( NETWORK_SERVER_INDEX ) ;
if ( ci ! = NULL ) {
2006-10-17 23:34:12 +00:00
if ( strcmp ( ci - > client_name , new_name ) = = 0 ) found_name = false ; // name already in use
2004-12-04 17:54:56 +00:00
}
if ( ! found_name ) {
// Try a new name (<name> #1, <name> #2, and so on)
2004-12-29 13:13:29 +00:00
// Stop if we tried for more than 50 times..
2004-12-04 17:54:56 +00:00
if ( number + + > 50 ) break ;
2004-12-23 20:33:57 +00:00
snprintf ( new_name , NETWORK_CLIENT_NAME_LENGTH , " %s #%d " , original_name , number ) ;
2004-12-04 17:54:56 +00:00
}
}
return found_name ;
}
// Reads a packet from the stream
2007-01-12 20:19:49 +00:00
bool NetworkServer_ReadPackets ( NetworkTCPSocketHandler * cs )
2004-12-04 17:54:56 +00:00
{
Packet * p ;
NetworkRecvStatus res ;
2007-02-01 23:50:15 +00:00
while ( ( p = cs - > Recv_Packet ( & res ) ) ! = NULL ) {
2007-02-01 23:26:44 +00:00
byte type = p - > Recv_uint8 ( ) ;
2006-10-17 23:34:12 +00:00
if ( type < PACKET_END & & _network_server_packet [ type ] ! = NULL & & ! cs - > has_quit ) {
2004-12-04 17:54:56 +00:00
_network_server_packet [ type ] ( cs , p ) ;
2006-06-27 21:25:53 +00:00
} else {
2006-12-26 17:36:18 +00:00
DEBUG ( net , 0 , " [server] received invalid packet type %d " , type ) ;
2006-06-27 21:25:53 +00:00
}
2007-02-01 22:30:35 +00:00
delete p ;
2004-12-04 17:54:56 +00:00
}
return true ;
}
// Handle the local command-queue
2007-01-12 20:19:49 +00:00
static void NetworkHandleCommandQueue ( NetworkTCPSocketHandler * cs )
2006-01-05 12:40:50 +00:00
{
2005-07-16 15:05:52 +00:00
CommandPacket * cp ;
2004-12-04 17:54:56 +00:00
2005-07-16 15:05:52 +00:00
while ( ( cp = cs - > command_queue ) ! = NULL ) {
SEND_COMMAND ( PACKET_SERVER_COMMAND ) ( cs , cp ) ;
2004-12-04 17:54:56 +00:00
2005-07-16 15:05:52 +00:00
cs - > command_queue = cp - > next ;
free ( cp ) ;
2004-12-04 17:54:56 +00:00
}
}
// This is called every tick if this is a _network_server
2005-07-29 21:55:49 +00:00
void NetworkServer_Tick ( bool send_frame )
2004-12-04 17:54:56 +00:00
{
2007-01-12 20:19:49 +00:00
NetworkTCPSocketHandler * cs ;
2005-07-16 12:59:23 +00:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
bool send_sync = false ;
# endif
2004-12-04 17:54:56 +00:00
2005-07-16 12:59:23 +00:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
2008-05-29 20:21:28 +00:00
if ( _frame_counter > = _last_sync_frame + _settings_client . network . sync_freq ) {
2005-07-16 12:59:23 +00:00
_last_sync_frame = _frame_counter ;
send_sync = true ;
}
# endif
2004-12-04 17:54:56 +00:00
// Now we are done with the frame, inform the clients that they can
// do their frame!
FOR_ALL_CLIENTS ( cs ) {
// Check if the speed of the client is what we can expect from a client
if ( cs - > status = = STATUS_ACTIVE ) {
// 1 lag-point per day
int lag = NetworkCalculateLag ( cs ) / DAY_TICKS ;
if ( lag > 0 ) {
if ( lag > 3 ) {
// Client did still not report in after 4 game-day, drop him
// (that is, the 3 of above, + 1 before any lag is counted)
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_ERROR , " Client #%d is dropped because the client did not respond for more than 4 game-days " , cs - > index ) ;
2004-12-19 10:17:26 +00:00
NetworkCloseClient ( cs ) ;
2004-12-04 17:54:56 +00:00
continue ;
}
// Report once per time we detect the lag
if ( cs - > lag_test = = 0 ) {
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_WARNING , " [%d] Client #%d is slow, try increasing *net_frame_freq to a higher value! " , _frame_counter , cs - > index ) ;
2004-12-04 17:54:56 +00:00
cs - > lag_test = 1 ;
}
} else {
cs - > lag_test = 0 ;
}
2005-03-29 19:10:13 +00:00
} else if ( cs - > status = = STATUS_PRE_ACTIVE ) {
int lag = NetworkCalculateLag ( cs ) ;
2008-05-29 20:21:28 +00:00
if ( lag > _settings_client . network . max_join_time ) {
IConsolePrintF ( CC_ERROR , " Client #%d is dropped because it took longer than %d ticks for him to join " , cs - > index , _settings_client . network . max_join_time ) ;
2005-03-29 19:10:13 +00:00
NetworkCloseClient ( cs ) ;
}
2007-03-06 22:00:42 +00:00
} else if ( cs - > status = = STATUS_INACTIVE ) {
int lag = NetworkCalculateLag ( cs ) ;
if ( lag > 4 * DAY_TICKS ) {
2008-05-24 10:35:15 +00:00
IConsolePrintF ( CC_ERROR , " Client #%d is dropped because it took longer than %d ticks to start the joining process " , cs - > index , 4 * DAY_TICKS ) ;
2007-03-06 22:00:42 +00:00
NetworkCloseClient ( cs ) ;
}
2004-12-04 17:54:56 +00:00
}
2005-07-16 12:59:23 +00:00
if ( cs - > status > = STATUS_PRE_ACTIVE ) {
// Check if we can send command, and if we have anything in the queue
2004-12-04 17:54:56 +00:00
NetworkHandleCommandQueue ( cs ) ;
2005-07-16 12:59:23 +00:00
// Send an updated _frame_counter_max to the client
2006-10-17 23:34:12 +00:00
if ( send_frame ) SEND_COMMAND ( PACKET_SERVER_FRAME ) ( cs ) ;
2004-12-04 17:54:56 +00:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
2005-07-16 12:59:23 +00:00
// Send a sync-check packet
2006-10-17 23:34:12 +00:00
if ( send_sync ) SEND_COMMAND ( PACKET_SERVER_SYNC ) ( cs ) ;
2004-12-04 17:54:56 +00:00
# endif
2005-07-16 12:59:23 +00:00
}
}
2004-12-15 20:10:34 +00:00
/* See if we need to advertise */
NetworkUDPAdvertise ( ) ;
2004-12-04 17:54:56 +00:00
}
2007-03-07 11:47:46 +00:00
void NetworkServerYearlyLoop ( )
2004-12-23 17:37:26 +00:00
{
NetworkCheckRestartMap ( ) ;
}
2007-03-07 11:47:46 +00:00
void NetworkServerMonthlyLoop ( )
2004-12-16 13:59:23 +00:00
{
NetworkAutoCleanCompanies ( ) ;
}
2008-05-30 18:20:26 +00:00
void NetworkServerChangeOwner ( PlayerID current_player , PlayerID new_player )
{
/* The server has to handle all administrative issues, for example
* updating and notifying all clients of what has happened */
NetworkTCPSocketHandler * cs ;
NetworkClientInfo * ci = NetworkFindClientInfoFromIndex ( NETWORK_SERVER_INDEX ) ;
/* The server has just changed from player */
if ( current_player = = ci - > client_playas ) {
ci - > client_playas = new_player ;
NetworkUpdateClientInfo ( NETWORK_SERVER_INDEX ) ;
}
/* Find all clients that were in control of this company, and mark them as new_player */
FOR_ALL_CLIENTS ( cs ) {
ci = DEREF_CLIENT_INFO ( cs ) ;
if ( current_player = = ci - > client_playas ) {
ci - > client_playas = new_player ;
NetworkUpdateClientInfo ( ci - > client_index ) ;
}
}
}
const char * GetPlayerIP ( const NetworkClientInfo * ci )
{
struct in_addr addr ;
addr . s_addr = ci - > client_ip ;
return inet_ntoa ( addr ) ;
}
void NetworkServerShowStatusToConsole ( )
{
static const char * const stat_str [ ] = {
" inactive " ,
" authorizing " ,
" authorized " ,
" waiting " ,
" loading map " ,
" map done " ,
" ready " ,
" active "
} ;
NetworkTCPSocketHandler * cs ;
FOR_ALL_CLIENTS ( cs ) {
int lag = NetworkCalculateLag ( cs ) ;
const NetworkClientInfo * ci = DEREF_CLIENT_INFO ( cs ) ;
const char * status ;
status = ( cs - > status < ( ptrdiff_t ) lengthof ( stat_str ) ? stat_str [ cs - > status ] : " unknown " ) ;
IConsolePrintF ( CC_INFO , " Client #%1d name: '%s' status: '%s' frame-lag: %3d company: %1d IP: %s unique-id: '%s' " ,
cs - > index , ci - > client_name , status , lag ,
2008-07-17 20:13:01 +00:00
ci - > client_playas + ( IsValidPlayerID ( ci - > client_playas ) ? 1 : 0 ) ,
2008-05-30 18:20:26 +00:00
GetPlayerIP ( ci ) , ci - > unique_id ) ;
}
}
void NetworkServerSendRcon ( uint16 client_index , ConsoleColour colour_code , const char * string )
{
SEND_COMMAND ( PACKET_SERVER_RCON ) ( NetworkFindClientStateFromIndex ( client_index ) , colour_code , string ) ;
}
void NetworkServerSendError ( uint16 client_index , NetworkErrorCode error )
{
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( NetworkFindClientStateFromIndex ( client_index ) , error ) ;
}
bool NetworkCompanyHasPlayers ( PlayerID company )
{
const NetworkTCPSocketHandler * cs ;
const NetworkClientInfo * ci ;
FOR_ALL_CLIENTS ( cs ) {
ci = DEREF_CLIENT_INFO ( cs ) ;
if ( ci - > client_playas = = company ) return true ;
}
return false ;
}
2004-12-04 17:54:56 +00:00
# endif /* ENABLE_NETWORK */