2005-07-24 16:12:37 +02:00
/* $Id$ */
2008-05-06 17:11:33 +02:00
/** @file network_server.cpp Server part of the network protocol. */
2006-10-12 16:13:39 +02:00
# ifdef ENABLE_NETWORK
2007-01-02 18:34:03 +01:00
# include "../stdafx.h"
# include "../openttd.h" // XXX StringID
# include "../debug.h"
2007-12-21 20:49:27 +01:00
# include "../strings_func.h"
2004-12-04 18:54:56 +01:00
# include "network_data.h"
2007-01-02 18:34:03 +01:00
# include "core/tcp.h"
2008-01-13 23:27:06 +01:00
# include "../vehicle_base.h"
# include "../vehicle_func.h"
2007-12-26 14:50:40 +01:00
# include "../date_func.h"
2004-12-04 18:54:56 +01:00
# include "network_server.h"
2004-12-15 21:10:34 +01:00
# include "network_udp.h"
2008-05-24 12:15:06 +02:00
# include "../console_func.h"
2007-12-21 22:50:46 +01:00
# include "../command_func.h"
2007-01-02 18:34:03 +01:00
# include "../saveload.h"
2008-03-31 02:06:17 +02:00
# include "../station_base.h"
2007-01-02 18:34:03 +01:00
# include "../variables.h"
# include "../genworld.h"
2007-12-25 10:48:53 +01:00
# include "../core/alloc_func.hpp"
2007-06-17 17:48:57 +02:00
# include "../fileio.h"
2008-01-07 15:23:25 +01:00
# include "../string_func.h"
2008-01-12 15:10:35 +01:00
# include "../player_base.h"
# include "../player_func.h"
# include "../player_gui.h"
2008-01-13 15:37:30 +01:00
# include "../settings_type.h"
2004-12-04 18:54:56 +01:00
2008-01-13 02:21:35 +01:00
# include "table/strings.h"
2004-12-04 18:54:56 +01:00
// This file handles all the server-commands
2007-01-12 21:19:49 +01:00
static void NetworkHandleCommandQueue ( NetworkTCPSocketHandler * cs ) ;
2004-12-19 11:17:26 +01:00
2004-12-04 18:54:56 +01:00
// **********
// Sending functions
2007-01-12 21:19:49 +01:00
// DEF_SERVER_SEND_COMMAND has parameter: NetworkTCPSocketHandler *cs
2004-12-04 18:54:56 +01:00
// **********
2007-01-12 21:19:49 +01:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_CLIENT_INFO ) ( NetworkTCPSocketHandler * cs , NetworkClientInfo * ci )
2004-12-04 18:54:56 +01: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
2004-12-12 17:04:32 +01:00
// String: The unique id of the client
2004-12-04 18:54:56 +01:00
//
if ( ci - > client_index ! = NETWORK_EMPTY_INDEX ) {
2006-10-18 01:34:12 +02:00
Packet * p = NetworkSend_Init ( PACKET_SERVER_CLIENT_INFO ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint16 ( ci - > client_index ) ;
p - > Send_uint8 ( ci - > client_playas ) ;
p - > Send_string ( ci - > client_name ) ;
p - > Send_string ( ci - > unique_id ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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 23:16:15 +01:00
byte active = ActivePlayerCount ( ) ;
2004-12-04 18:54:56 +01:00
if ( active = = 0 ) {
2006-10-18 01:34:12 +02:00
p = NetworkSend_Init ( PACKET_SERVER_COMPANY_INFO ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( NETWORK_COMPANY_INFO_VERSION ) ;
p - > Send_uint8 ( active ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
return ;
}
NetworkPopulateCompanyInfo ( ) ;
FOR_ALL_PLAYERS ( player ) {
2006-06-27 23:25:53 +02:00
if ( ! player - > is_active ) continue ;
2004-12-04 18:54:56 +01:00
p = NetworkSend_Init ( PACKET_SERVER_COMPANY_INFO ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( NETWORK_COMPANY_INFO_VERSION ) ;
p - > Send_uint8 ( active ) ;
p - > Send_uint8 ( player - > index ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:26:44 +01: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 18:54:56 +01:00
2005-01-14 22:47:35 +01:00
/* Send 1 if there is a passord for the company else send 0 */
2007-04-27 22:50:49 +02:00
p - > Send_bool ( ! StrEmpty ( _network_player_info [ player - > index ] . password ) ) ;
2005-01-14 22:47:35 +01:00
2006-06-27 23:25:53 +02:00
for ( i = 0 ; i < NETWORK_VEHICLE_TYPES ; i + + ) {
2007-02-02 00:26:44 +01:00
p - > Send_uint16 ( _network_player_info [ player - > index ] . num_vehicle [ i ] ) ;
2006-06-27 23:25:53 +02:00
}
2004-12-04 18:54:56 +01:00
2006-06-27 23:25:53 +02:00
for ( i = 0 ; i < NETWORK_STATION_TYPES ; i + + ) {
2007-02-02 00:26:44 +01:00
p - > Send_uint16 ( _network_player_info [ player - > index ] . num_station [ i ] ) ;
2006-06-27 23:25:53 +02:00
}
2004-12-04 18:54:56 +01:00
2006-06-27 23:25:53 +02:00
if ( _network_player_info [ player - > index ] . players [ 0 ] = = ' \0 ' ) {
2007-02-02 00:26:44 +01:00
p - > Send_string ( " <none> " ) ;
2006-06-27 23:25:53 +02:00
} else {
2007-02-02 00:26:44 +01:00
p - > Send_string ( _network_player_info [ player - > index ] . players ) ;
2006-06-27 23:25:53 +02:00
}
2004-12-04 18:54:56 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
}
2004-12-20 17:02:01 +01:00
p = NetworkSend_Init ( PACKET_SERVER_COMPANY_INFO ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( NETWORK_COMPANY_INFO_VERSION ) ;
p - > Send_uint8 ( 0 ) ;
2004-12-20 17:02:01 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
}
2007-01-12 21:19:49 +01:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_ERROR ) ( NetworkTCPSocketHandler * cs , NetworkErrorCode error )
2004-12-04 18:54:56 +01:00
{
//
// Packet: SERVER_ERROR
// Function: The client made an error
// Data:
// uint8: ErrorID (see network_data.h, NetworkErrorCode)
//
2004-12-19 16:14:55 +01:00
char str [ 100 ] ;
2004-12-04 18:54:56 +01:00
Packet * p = NetworkSend_Init ( PACKET_SERVER_ERROR ) ;
2006-04-02 14:41:01 +02:00
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( error ) ;
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
2006-10-22 01:31:34 +02:00
GetNetworkErrorMsg ( str , error , lastof ( str ) ) ;
2006-01-25 19:11:06 +01:00
2004-12-04 18:54:56 +01:00
// Only send when the current client was in game
if ( cs - > status > STATUS_AUTH ) {
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2006-10-18 01:34:12 +02:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 18:54:56 +01:00
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
2006-12-26 18:36:18 +01:00
DEBUG ( net , 1 , " '%s' made an error and has been disconnected. Reason: '%s' " , client_name , str ) ;
2004-12-04 18:54:56 +01:00
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " %s " , str ) ;
2004-12-04 18:54:56 +01: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 18:36:18 +01:00
DEBUG ( net , 1 , " Client %d made an error and has been disconnected. Reason: '%s' " , cs - > index , str ) ;
2004-12-04 18:54:56 +01:00
}
2006-10-18 01:34:12 +02:00
cs - > has_quit = true ;
2004-12-04 18:54:56 +01:00
// Make sure the data get's there before we close the connection
2007-02-02 00:50:15 +01:00
cs - > Send_Packets ( ) ;
2004-12-04 18:54:56 +01:00
// The client made a mistake, so drop his connection now!
2004-12-19 11:17:26 +01:00
NetworkCloseClient ( cs ) ;
2004-12-04 18:54:56 +01:00
}
2007-01-30 18:22:56 +01: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 18:14:29 +02:00
for ( c = _grfconfig ; c ! = NULL ; c = c - > next ) {
2007-11-19 22:02:30 +01:00
if ( ! HasBit ( c - > flags , GCF_STATIC ) ) grf_count + + ;
2007-07-03 18:14:29 +02:00
}
2007-01-30 18:22:56 +01:00
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( grf_count ) ;
2007-01-30 18:22:56 +01:00
for ( c = _grfconfig ; c ! = NULL ; c = c - > next ) {
2007-11-19 22:02:30 +01:00
if ( ! HasBit ( c - > flags , GCF_STATIC ) ) cs - > Send_GRFIdentifier ( p , c ) ;
2007-01-30 18:22:56 +01:00
}
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2007-01-30 18:22:56 +01:00
}
2007-01-12 21:19:49 +01:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_NEED_PASSWORD ) ( NetworkTCPSocketHandler * cs , NetworkPasswordType type )
2004-12-04 18:54:56 +01:00
{
//
// Packet: SERVER_NEED_PASSWORD
// Function: Indication to the client that the server needs a password
// Data:
// uint8: Type of password
//
2007-03-06 23:00:42 +01:00
/* Invalid packet when status is AUTH or higher */
if ( cs - > status > = STATUS_AUTH ) return ;
cs - > status = STATUS_AUTHORIZING ;
2004-12-04 18:54:56 +01:00
Packet * p = NetworkSend_Init ( PACKET_SERVER_NEED_PASSWORD ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( type ) ;
2008-05-29 17:13:28 +02:00
p - > Send_uint32 ( _settings_game . game_creation . generation_seed ) ;
2008-05-29 22:21:28 +02:00
p - > Send_string ( _settings_client . network . network_id ) ;
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 18:54:56 +01:00
// Invalid packet when status is AUTH or higher
2006-01-25 19:11:06 +01:00
if ( cs - > status > = STATUS_AUTH ) return ;
2004-12-04 18:54:56 +01:00
cs - > status = STATUS_AUTH ;
_network_game_info . clients_on + + ;
p = NetworkSend_Init ( PACKET_SERVER_WELCOME ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint16 ( cs - > index ) ;
2008-05-29 17:13:28 +02:00
p - > Send_uint32 ( _settings_game . game_creation . generation_seed ) ;
2008-05-29 22:21:28 +02:00
p - > Send_string ( _settings_client . network . network_id ) ;
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 18:54:56 +01:00
Packet * p ;
// Count how many players are waiting in the queue
FOR_ALL_CLIENTS ( new_cs ) {
2006-06-27 23:25:53 +02:00
if ( new_cs - > status = = STATUS_MAP_WAIT ) waiting + + ;
2004-12-04 18:54:56 +01:00
}
p = NetworkSend_Init ( PACKET_SERVER_WAIT ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( waiting ) ;
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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-18 01:34:12 +02:00
2004-12-04 18:54:56 +01:00
if ( cs - > status = = STATUS_AUTH ) {
2007-06-17 17:48:57 +02:00
const char * filename = " network_server.tmp " ;
2004-12-04 18:54:56 +01:00
Packet * p ;
// Make a dump of the current game
2007-06-17 17:48:57 +02:00
if ( SaveOrLoad ( filename , SL_SAVE , AUTOSAVE_DIR ) ! = SL_OK ) error ( " network savedump failed " ) ;
2004-12-04 18:54:56 +01:00
2007-06-17 17:48:57 +02:00
file_pointer = FioFOpenFile ( filename , " rb " , AUTOSAVE_DIR ) ;
2004-12-04 18:54:56 +01:00
fseek ( file_pointer , 0 , SEEK_END ) ;
2007-01-17 01:01:55 +01:00
if ( ftell ( file_pointer ) = = 0 ) error ( " network savedump failed - zero sized savegame? " ) ;
2004-12-04 18:54:56 +01:00
// Now send the _frame_counter and how many packets are coming
p = NetworkSend_Init ( PACKET_SERVER_MAP ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( MAP_PACKET_START ) ;
p - > Send_uint32 ( _frame_counter ) ;
p - > Send_uint32 ( ftell ( file_pointer ) ) ;
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
fseek ( file_pointer , 0 , SEEK_SET ) ;
sent_packets = 4 ; // We start with trying 4 packets
cs - > status = STATUS_MAP ;
2005-03-29 21:10:13 +02:00
/* Mark the start of download */
cs - > last_frame = _frame_counter ;
cs - > last_frame_server = _frame_counter ;
2004-12-04 18:54:56 +01: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-02 00:26:44 +01:00
p - > Send_uint8 ( MAP_PACKET_NORMAL ) ;
2006-08-20 14:09:32 +02:00
res = ( int ) fread ( p - > buffer + p - > size , 1 , SEND_MTU - p - > size , file_pointer ) ;
2006-10-18 01:34:12 +02:00
if ( ferror ( file_pointer ) ) error ( " Error reading temporary network savegame! " ) ;
2004-12-04 18:54:56 +01:00
p - > size + = res ;
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
if ( feof ( file_pointer ) ) {
// Done reading!
2006-03-02 03:22:15 +01:00
Packet * p = NetworkSend_Init ( PACKET_SERVER_MAP ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( MAP_PACKET_END ) ;
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 18:54:56 +01: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-02 00:50:15 +01:00
cs - > Send_Packets ( ) ;
if ( cs - > IsPacketQueueEmpty ( ) ) {
2004-12-04 18:54:56 +01: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 21:19:49 +01:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_JOIN ) ( NetworkTCPSocketHandler * cs , uint16 client_index )
2004-12-04 18:54:56 +01: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-02 00:26:44 +01:00
p - > Send_uint16 ( client_index ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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-02 00:26:44 +01:00
p - > Send_uint32 ( _frame_counter ) ;
p - > Send_uint32 ( _frame_counter_max ) ;
2004-12-04 18:54:56 +01:00
# ifdef ENABLE_NETWORK_SYNC_EVERY_FRAME
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _sync_seed_1 ) ;
2004-12-04 18:54:56 +01:00
# ifdef NETWORK_SEND_DOUBLE_SEED
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _sync_seed_2 ) ;
2004-12-04 18:54:56 +01:00
# endif
# endif
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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-02 00:26:44 +01:00
p - > Send_uint32 ( _frame_counter ) ;
p - > Send_uint32 ( _sync_seed_1 ) ;
2004-12-04 18:54:56 +01:00
# ifdef NETWORK_SEND_DOUBLE_SEED
2007-02-02 00:26:44 +01:00
p - > Send_uint32 ( _sync_seed_2 ) ;
2004-12-04 18:54:56 +01:00
# endif
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
}
2007-01-12 21:19:49 +01:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_COMMAND ) ( NetworkTCPSocketHandler * cs , CommandPacket * cp )
2004-12-04 18:54:56 +01: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 20:50:55 +02:00
// string: text
2004-12-04 18:54:56 +01:00
// uint8: CallBackID (see callback_table.c)
// uint32: Frame of execution
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_COMMAND ) ;
2007-02-02 00:26:44 +01: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 22:59:41 +02:00
p - > Send_bool ( cp - > my_cmd ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
}
2007-01-12 21:19:49 +01: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 18:54:56 +01:00
{
//
// Packet: SERVER_CHAT
// Function: Sends a chat-packet to the client
// Data:
// uint8: ActionID (see network_data.h, NetworkAction)
// uint16: Client-index
// String: Message (max MAX_TEXT_MSG_LEN)
//
Packet * p = NetworkSend_Init ( PACKET_SERVER_CHAT ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint8 ( action ) ;
p - > Send_uint16 ( client_index ) ;
2007-02-03 00:16:58 +01:00
p - > Send_bool ( self_send ) ;
2007-02-02 00:26:44 +01:00
p - > Send_string ( msg ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
}
2007-01-12 21:19:49 +01:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_ERROR_QUIT ) ( NetworkTCPSocketHandler * cs , uint16 client_index , NetworkErrorCode errorno )
2004-12-04 18:54:56 +01: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-02 00:26:44 +01:00
p - > Send_uint16 ( client_index ) ;
p - > Send_uint8 ( errorno ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
}
2007-01-12 21:19:49 +01:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_QUIT ) ( NetworkTCPSocketHandler * cs , uint16 client_index , const char * leavemsg )
2004-12-04 18:54:56 +01: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-02 00:26:44 +01:00
p - > Send_uint16 ( client_index ) ;
p - > Send_string ( leavemsg ) ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01: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-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2004-12-04 18:54:56 +01:00
}
2007-01-12 21:19:49 +01:00
DEF_SERVER_SEND_COMMAND_PARAM ( PACKET_SERVER_RCON ) ( NetworkTCPSocketHandler * cs , uint16 color , const char * command )
2005-01-15 21:09:16 +01:00
{
Packet * p = NetworkSend_Init ( PACKET_SERVER_RCON ) ;
2007-02-02 00:26:44 +01:00
p - > Send_uint16 ( color ) ;
p - > Send_string ( command ) ;
2007-02-02 00:50:15 +01:00
cs - > Send_Packet ( p ) ;
2005-01-15 21:09:16 +01:00
}
2004-12-04 18:54:56 +01:00
// **********
// Receiving functions
2007-01-12 21:19:49 +01:00
// DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkTCPSocketHandler *cs, Packet *p
2004-12-04 18:54:56 +01:00
// **********
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_COMPANY_INFO )
{
SEND_COMMAND ( PACKET_SERVER_COMPANY_INFO ) ( cs ) ;
}
2007-01-30 18:22:56 +01:00
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_NEWGRFS_CHECKED )
{
NetworkClientInfo * ci = DEREF_CLIENT_INFO ( cs ) ;
/* We now want a password from the client else we do not allow him in! */
if ( _network_game_info . use_password ) {
SEND_COMMAND ( PACKET_SERVER_NEED_PASSWORD ) ( cs , NETWORK_GAME_PASSWORD ) ;
} else {
if ( IsValidPlayer ( ci - > client_playas ) & & _network_player_info [ ci - > client_playas ] . password [ 0 ] ! = ' \0 ' ) {
SEND_COMMAND ( PACKET_SERVER_NEED_PASSWORD ) ( cs , NETWORK_COMPANY_PASSWORD ) ;
} else {
SEND_COMMAND ( PACKET_SERVER_WELCOME ) ( cs ) ;
}
}
}
2004-12-04 18:54:56 +01:00
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_JOIN )
{
2006-04-22 11:46:31 +02:00
char name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2007-10-30 12:29:01 +01:00
char unique_id [ NETWORK_UNIQUE_ID_LENGTH ] ;
2004-12-04 18:54:56 +01:00
NetworkClientInfo * ci ;
2007-01-10 19:56:51 +01:00
PlayerID playas ;
2004-12-04 18:54:56 +01:00
NetworkLanguage client_lang ;
char client_revision [ NETWORK_REVISION_LENGTH ] ;
2007-02-02 00:26:44 +01:00
p - > Recv_string ( client_revision , sizeof ( client_revision ) ) ;
2004-12-04 18:54:56 +01:00
2004-12-16 16:35:19 +01:00
# if defined(WITH_REV) || defined(WITH_REV_HACK)
2004-12-15 01:31:08 +01:00
// Check if the client has revision control enabled
2007-03-01 01:58:09 +01:00
if ( ! IsNetworkCompatibleVersion ( client_revision ) ) {
2006-06-27 23:25:53 +02:00
// Different revisions!!
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_WRONG_REVISION ) ;
return ;
2004-12-04 18:54:56 +01:00
}
2004-12-15 17:51:55 +01:00
# endif
2004-12-04 18:54:56 +01:00
2007-02-02 00:26:44 +01: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 15:39:48 +01:00
2006-10-18 01:34:12 +02:00
if ( cs - > has_quit ) return ;
2004-12-04 18:54:56 +01:00
2006-01-25 19:11:06 +01:00
// join another company does not affect these values
switch ( playas ) {
2006-10-16 01:48:34 +02:00
case PLAYER_NEW_COMPANY : /* New company */
2006-01-31 23:16:15 +01:00
if ( ActivePlayerCount ( ) > = _network_game_info . companies_max ) {
2006-01-25 19:11:06 +01:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_FULL ) ;
return ;
}
break ;
2006-10-14 17:49:43 +02:00
case PLAYER_SPECTATOR : /* Spectator */
2006-01-31 23:16:15 +01:00
if ( NetworkSpectatorCount ( ) > = _network_game_info . spectators_max ) {
2006-01-25 19:11:06 +01:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_FULL ) ;
return ;
}
break ;
2006-10-18 00:16:46 +02:00
default : /* Join another company (companies 1-8 (index 0-7)) */
if ( ! IsValidPlayer ( playas ) ) {
2006-10-16 01:48:34 +02:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_PLAYER_MISMATCH ) ;
return ;
}
break ;
2004-12-04 18:54:56 +01:00
}
2006-01-25 19:11:06 +01:00
// We need a valid name.. make it Player
2006-04-22 11:46:31 +02:00
if ( * name = = ' \0 ' ) ttd_strlcpy ( name , " Player " , sizeof ( name ) ) ;
2006-01-25 19:11:06 +01:00
if ( ! NetworkFindName ( name ) ) { // Change name if duplicate
2004-12-04 18:54:56 +01: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 11:46:31 +02: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 18:54:56 +01:00
ci - > client_playas = playas ;
ci - > client_lang = client_lang ;
2006-10-18 00:16:46 +02:00
/* Make sure companies to which people try to join are not autocleaned */
if ( IsValidPlayer ( playas ) ) _network_player_info [ playas ] . months_empty = 0 ;
2007-01-30 18:22:56 +01:00
if ( _grfconfig = = NULL ) {
RECEIVE_COMMAND ( PACKET_CLIENT_NEWGRFS_CHECKED ) ( cs , NULL ) ;
} else {
SEND_COMMAND ( PACKET_SERVER_CHECK_NEWGRFS ) ( cs ) ;
}
2004-12-04 18:54:56 +01:00
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_PASSWORD )
{
NetworkPasswordType type ;
char password [ NETWORK_PASSWORD_LENGTH ] ;
2006-10-18 01:34:12 +02:00
const NetworkClientInfo * ci ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:26:44 +01:00
type = ( NetworkPasswordType ) p - > Recv_uint8 ( ) ;
p - > Recv_string ( password , sizeof ( password ) ) ;
2004-12-04 18:54:56 +01:00
2007-03-08 10:46:44 +01:00
if ( cs - > status = = STATUS_AUTHORIZING & & type = = NETWORK_GAME_PASSWORD ) {
2004-12-04 18:54:56 +01:00
// Check game-password
2006-06-14 15:22:30 +02:00
if ( strcmp ( password , _network_game_info . server_password ) ! = 0 ) {
2004-12-04 18:54:56 +01:00
// Password is invalid
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_WRONG_PASSWORD ) ;
return ;
}
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-10-18 00:16:46 +02:00
if ( IsValidPlayer ( ci - > client_playas ) & & _network_player_info [ ci - > client_playas ] . password [ 0 ] ! = ' \0 ' ) {
2004-12-04 18:54:56 +01: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 10:46:44 +01:00
} else if ( cs - > status = = STATUS_AUTHORIZING & & type = = NETWORK_COMPANY_PASSWORD ) {
2004-12-04 18:54:56 +01:00
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-10-18 00:16:46 +02:00
if ( strcmp ( password , _network_player_info [ ci - > client_playas ] . password ) ! = 0 ) {
2004-12-04 18:54:56 +01: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 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 18:54:56 +01: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-18 01:34:12 +02:00
if ( cs - > status < STATUS_AUTH | | cs - > has_quit ) {
2004-12-04 18:54:56 +01: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-18 01:34:12 +02:00
if ( cs - > status = = STATUS_DONE_MAP & & ! cs - > has_quit ) {
2004-12-23 21:33:57 +01:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 18:54:56 +01:00
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( NETWORK_ACTION_JOIN , CC_DEFAULT , false , client_name , " " ) ;
2004-12-04 18:54:56 +01: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 21:10:13 +02:00
2008-05-29 22:21:28 +02:00
if ( _settings_client . network . pause_on_join ) {
2005-03-29 21:10:13 +02:00
/* Now pause the game till the client is in sync */
DoCommandP ( 0 , 1 , 0 , NULL , CMD_PAUSE ) ;
2006-10-25 00:23:08 +02:00
NetworkServer_HandleChat ( NETWORK_ACTION_SERVER_MESSAGE , DESTTYPE_BROADCAST , 0 , " Game paused (incoming client) " , NETWORK_SERVER_INDEX ) ;
2005-03-29 21:10:13 +02:00
}
2004-12-04 18:54:56 +01: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 21:25:18 +02: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 12:35:15 +02:00
IConsolePrintF ( CC_ERROR , " WARNING: server only command from client %d (IP: %s), kicking... " , ci - > client_index , GetPlayerIP ( ci ) ) ;
2005-05-14 21:25:18 +02:00
return false ;
}
if ( flags & CMD_OFFLINE ) {
2008-05-24 12:35:15 +02:00
IConsolePrintF ( CC_ERROR , " WARNING: offline only command from client %d (IP: %s), kicking... " , ci - > client_index , GetPlayerIP ( ci ) ) ;
2005-05-14 21:25:18 +02:00
return false ;
}
2006-10-18 01:34:12 +02:00
2007-08-30 21:20:15 +02:00
if ( cp - > cmd ! = CMD_PLAYER_CTRL & & ! IsValidPlayer ( cp - > player ) & & ci - > client_index ! = NETWORK_SERVER_INDEX ) {
2008-05-24 12:35:15 +02:00
IConsolePrintF ( CC_ERROR , " WARNING: spectator issueing command from client %d (IP: %s), kicking... " , ci - > client_index , GetPlayerIP ( ci ) ) ;
2007-08-30 21:20:15 +02:00
return false ;
}
2005-05-14 21:25:18 +02: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 18:54:56 +01:00
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_COMMAND )
{
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2005-05-14 21:25:18 +02:00
const NetworkClientInfo * ci ;
byte callback ;
2004-12-04 18:54:56 +01: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-18 01:34:12 +02:00
if ( cs - > status < STATUS_DONE_MAP | | cs - > has_quit ) {
2004-12-04 18:54:56 +01:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
return ;
}
2007-06-09 06:01:40 +02:00
CommandPacket * cp = MallocT < CommandPacket > ( 1 ) ;
2007-02-02 00:26:44 +01: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 18:54:56 +01:00
2007-02-02 00:26:44 +01:00
callback = p - > Recv_uint8 ( ) ;
2005-01-05 15:39:48 +01:00
2007-06-09 06:01:40 +02:00
if ( cs - > has_quit ) {
free ( cp ) ;
return ;
}
2005-05-14 21:25:18 +02:00
ci = DEREF_CLIENT_INFO ( cs ) ;
2005-01-05 15:39:48 +01:00
/* Check if cp->cmd is valid */
if ( ! IsValidCommand ( cp - > cmd ) ) {
2008-05-24 12:35:15 +02:00
IConsolePrintF ( CC_ERROR , " WARNING: invalid command from client %d (IP: %s). " , ci - > client_index , GetPlayerIP ( ci ) ) ;
2005-01-05 15:39:48 +01:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_NOT_EXPECTED ) ;
2007-06-09 06:01:40 +02:00
free ( cp ) ;
2005-01-05 15:39:48 +01:00
return ;
}
2004-12-04 18:54:56 +01:00
2005-05-14 21:25:18 +02:00
if ( ! CheckCommandFlags ( cp , ci ) ) {
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_KICKED ) ;
2007-06-09 06:01:40 +02:00
free ( cp ) ;
2005-05-14 21:25:18 +02: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
*/
2006-10-18 00:16:46 +02:00
if ( ! ( cp - > cmd = = CMD_PLAYER_CTRL & & cp - > p1 = = 0 ) & & ci - > client_playas ! = cp - > player ) {
2008-05-24 12:35:15 +02:00
IConsolePrintF ( CC_ERROR , " WARNING: player %d (IP: %s) tried to execute a command as player %d, kicking... " ,
2006-10-18 00:16:46 +02:00
ci - > client_playas + 1 , GetPlayerIP ( ci ) , cp - > player + 1 ) ;
2004-12-04 18:54:56 +01:00
SEND_COMMAND ( PACKET_SERVER_ERROR ) ( cs , NETWORK_ERROR_PLAYER_MISMATCH ) ;
2007-06-09 06:01:40 +02:00
free ( cp ) ;
2004-12-04 18:54:56 +01:00
return ;
}
2005-05-14 21:25:18 +02: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 06:01:40 +02:00
free ( cp ) ;
2005-05-14 21:25:18 +02:00
return ;
}
2006-10-18 01:34:12 +02: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 19:56:51 +01:00
cp - > player = OWNER_BEGIN ;
2006-10-18 01:34:12 +02:00
cp - > p2 = cs - _clients ; // XXX - UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl
2005-05-14 21:25:18 +02:00
}
2004-12-04 18:54:56 +01: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 15:39:48 +01:00
cp - > next = NULL ;
2004-12-04 18:54:56 +01: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 19:27:40 +01:00
if ( new_cs - > status > = STATUS_MAP ) {
2004-12-04 18:54:56 +01:00
// Callbacks are only send back to the client who sent them in the
// first place. This filters that out.
2005-05-14 21:25:18 +02:00
cp - > callback = ( new_cs ! = cs ) ? 0 : callback ;
2007-07-10 22:59:41 +02:00
cp - > my_cmd = ( new_cs = = cs ) ;
2004-12-04 18:54:56 +01:00
NetworkAddCommandQueue ( new_cs , cp ) ;
}
}
cp - > callback = 0 ;
2007-07-10 22:59:41 +02:00
cp - > my_cmd = false ;
2004-12-04 18:54:56 +01: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 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2004-12-19 16:14:55 +01:00
char str [ 100 ] ;
2004-12-23 21:33:57 +01:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2007-02-02 00:26:44 +01:00
NetworkErrorCode errorno = ( NetworkErrorCode ) p - > Recv_uint8 ( ) ;
2004-12-04 18:54:56 +01:00
// The client was never joined.. thank the client for the packet, but ignore it
2006-10-18 01:34:12 +02:00
if ( cs - > status < STATUS_DONE_MAP | | cs - > has_quit ) {
cs - > has_quit = true ;
2004-12-04 18:54:56 +01:00
return ;
}
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
2006-10-22 01:31:34 +02:00
GetNetworkErrorMsg ( str , errorno , lastof ( str ) ) ;
2004-12-04 18:54:56 +01:00
2006-12-26 18:36:18 +01:00
DEBUG ( net , 2 , " '%s' reported an error and is closing its connection (%s) " , client_name , str ) ;
2004-12-04 18:54:56 +01:00
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " %s " , str ) ;
2004-12-04 18:54:56 +01: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-18 01:34:12 +02:00
cs - > has_quit = true ;
2004-12-04 18:54:56 +01: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 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2004-12-19 16:14:55 +01:00
char str [ 100 ] ;
2004-12-23 21:33:57 +01:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 18:54:56 +01:00
// The client was never joined.. thank the client for the packet, but ignore it
2006-10-18 01:34:12 +02:00
if ( cs - > status < STATUS_DONE_MAP | | cs - > has_quit ) {
cs - > has_quit = true ;
2004-12-04 18:54:56 +01:00
return ;
}
2007-02-02 00:26:44 +01:00
p - > Recv_string ( str , lengthof ( str ) ) ;
2004-12-04 18:54:56 +01:00
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( NETWORK_ACTION_LEAVE , CC_DEFAULT , false , client_name , " %s " , str ) ;
2004-12-04 18:54:56 +01:00
FOR_ALL_CLIENTS ( new_cs ) {
if ( new_cs - > status > STATUS_AUTH ) {
2004-12-19 16:14:55 +01:00
SEND_COMMAND ( PACKET_SERVER_QUIT ) ( new_cs , cs - > index , str ) ;
2004-12-04 18:54:56 +01:00
}
}
2006-10-18 01:34:12 +02:00
cs - > has_quit = true ;
2004-12-04 18:54:56 +01:00
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_ACK )
{
2007-02-02 00:26:44 +01:00
uint32 frame = p - > Recv_uint32 ( ) ;
2005-03-29 21:10:13 +02: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-18 01:34:12 +02:00
if ( frame + DAY_TICKS < _frame_counter ) return ;
2005-03-29 21:10:13 +02:00
/* Now he is! Unpause the game */
cs - > status = STATUS_ACTIVE ;
2008-05-29 22:21:28 +02:00
if ( _settings_client . network . pause_on_join ) {
2005-03-29 21:10:13 +02:00
DoCommandP ( 0 , 0 , 0 , NULL , CMD_PAUSE ) ;
2006-10-25 00:23:08 +02:00
NetworkServer_HandleChat ( NETWORK_ACTION_SERVER_MESSAGE , DESTTYPE_BROADCAST , 0 , " Game unpaused (client connected) " , NETWORK_SERVER_INDEX ) ;
2005-03-29 21:10:13 +02:00
}
2006-10-03 16:59:05 +02:00
2006-10-03 18:25:03 +02:00
CheckMinPlayers ( ) ;
2006-10-03 16:59:05 +02:00
/* Execute script for, e.g. MOTD */
IConsoleCmdExec ( " exec scripts/on_server_connect.scr 0 " ) ;
2005-03-29 21:10:13 +02:00
}
2004-12-04 18:54:56 +01:00
// The client received the frame, make note of it
2005-03-29 21:10:13 +02:00
cs - > last_frame = frame ;
2004-12-04 18:54:56 +01:00
// With those 2 values we can calculate the lag realtime
cs - > last_frame_server = _frame_counter ;
}
2005-01-01 17:34:54 +01:00
void NetworkServer_HandleChat ( NetworkAction action , DestType desttype , int dest , const char * msg , uint16 from_index )
2004-12-04 18:54:56 +01:00
{
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * cs ;
2006-10-18 01:34:12 +02:00
const NetworkClientInfo * ci , * ci_own , * ci_to ;
2004-12-04 18:54:56 +01:00
switch ( desttype ) {
case DESTTYPE_CLIENT :
2004-12-19 16:14:55 +01:00
/* Are we sending to the server? */
if ( dest = = NETWORK_SERVER_INDEX ) {
2004-12-04 18:54:56 +01:00
ci = NetworkFindClientInfoFromIndex ( from_index ) ;
2004-12-19 16:14:55 +01:00
/* Display the text locally, and that is it */
2004-12-04 18:54:56 +01:00
if ( ci ! = NULL )
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci - > client_playas ) , false , ci - > client_name , " %s " , msg ) ;
2004-12-04 18:54:56 +01:00
} else {
2004-12-19 16:14:55 +01:00
/* Else find the client to send the message to */
2004-12-04 18:54:56 +01:00
FOR_ALL_CLIENTS ( cs ) {
if ( cs - > index = = dest ) {
2004-12-19 16:14:55 +01:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , from_index , false , msg ) ;
2004-12-04 18:54:56 +01:00
break ;
}
}
}
// Display the message locally (so you know you have sent it)
if ( from_index ! = dest ) {
2004-12-19 16:14:55 +01:00
if ( from_index = = NETWORK_SERVER_INDEX ) {
2004-12-04 18:54:56 +01:00
ci = NetworkFindClientInfoFromIndex ( from_index ) ;
ci_to = NetworkFindClientInfoFromIndex ( dest ) ;
if ( ci ! = NULL & & ci_to ! = NULL )
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci - > client_playas ) , true , ci_to - > client_name , " %s " , msg ) ;
2004-12-04 18:54:56 +01:00
} else {
FOR_ALL_CLIENTS ( cs ) {
if ( cs - > index = = from_index ) {
2004-12-19 16:14:55 +01:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , dest , true , msg ) ;
2004-12-04 18:54:56 +01:00
break ;
}
}
}
}
break ;
2006-10-22 00:29:14 +02:00
case DESTTYPE_TEAM : {
2004-12-04 18:54:56 +01:00
bool show_local = true ; // If this is false, the message is already displayed
// on the client who did sent it.
2004-12-19 16:14:55 +01:00
/* Find all clients that belong to this player */
2004-12-20 16:26:19 +01:00
ci_to = NULL ;
2004-12-04 18:54:56 +01:00
FOR_ALL_CLIENTS ( cs ) {
ci = DEREF_CLIENT_INFO ( cs ) ;
if ( ci - > client_playas = = dest ) {
2004-12-19 16:14:55 +01:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , from_index , false , msg ) ;
2006-10-18 01:34:12 +02:00
if ( cs - > index = = from_index ) show_local = false ;
2004-12-20 16:26:19 +01:00
ci_to = ci ; // Remember a client that is in the company for company-name
2004-12-04 18:54:56 +01:00
}
}
2004-12-20 16:26:19 +01:00
2004-12-04 18:54:56 +01: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 12:35:15 +02:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci - > client_playas ) , false , ci - > client_name , " %s " , msg ) ;
2006-10-18 01:34:12 +02:00
if ( from_index = = NETWORK_SERVER_INDEX ) show_local = false ;
2005-05-17 20:22:59 +02:00
ci_to = ci_own ;
2004-12-04 18:54:56 +01:00
}
2004-12-20 16:26:19 +01:00
/* There is no such player */
2005-05-17 20:22:59 +02:00
if ( ci_to = = NULL ) break ;
2004-12-20 16:26:19 +01:00
2004-12-04 18:54:56 +01: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 ] ;
2007-06-25 17:59:37 +02:00
StringID str = IsValidPlayer ( ci_to - > client_playas ) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS ;
SetDParam ( 0 , ci_to - > client_playas ) ;
2006-10-25 00:26:20 +02:00
GetString ( name , str , lastof ( name ) ) ;
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci_own - > client_playas ) , true , name , " %s " , msg ) ;
2004-12-04 18:54:56 +01:00
} else {
FOR_ALL_CLIENTS ( cs ) {
if ( cs - > index = = from_index ) {
2004-12-23 14:53:05 +01:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , ci_to - > client_index , true , msg ) ;
2004-12-04 18:54:56 +01:00
}
}
}
}
}
break ;
default :
2006-12-26 18:36:18 +01:00
DEBUG ( net , 0 , " [server] received unknown chat destination type %d. Doing broadcast instead " , desttype ) ;
2004-12-04 18:54:56 +01:00
/* fall-through to next case */
case DESTTYPE_BROADCAST :
FOR_ALL_CLIENTS ( cs ) {
2004-12-19 16:14:55 +01:00
SEND_COMMAND ( PACKET_SERVER_CHAT ) ( cs , action , from_index , false , msg ) ;
2004-12-04 18:54:56 +01:00
}
ci = NetworkFindClientInfoFromIndex ( from_index ) ;
if ( ci ! = NULL )
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( action , ( ConsoleColour ) GetDrawStringPlayerColor ( ci - > client_playas ) , false , ci - > client_name , " %s " , msg ) ;
2004-12-04 18:54:56 +01:00
break ;
}
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_CHAT )
{
2007-02-02 00:26:44 +01:00
NetworkAction action = ( NetworkAction ) p - > Recv_uint8 ( ) ;
DestType desttype = ( DestType ) p - > Recv_uint8 ( ) ;
2007-04-26 09:41:24 +02:00
int dest = p - > Recv_uint16 ( ) ;
2004-12-04 18:54:56 +01:00
char msg [ MAX_TEXT_MSG_LEN ] ;
2007-02-02 00:26:44 +01:00
p - > Recv_string ( msg , MAX_TEXT_MSG_LEN ) ;
2004-12-04 18:54:56 +01:00
NetworkServer_HandleChat ( action , desttype , dest , msg , cs - > index ) ;
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_SET_PASSWORD )
{
char password [ NETWORK_PASSWORD_LENGTH ] ;
2006-10-18 01:34:12 +02:00
const NetworkClientInfo * ci ;
2004-12-04 18:54:56 +01:00
2007-02-02 00:26:44 +01:00
p - > Recv_string ( password , sizeof ( password ) ) ;
2004-12-04 18:54:56 +01:00
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-10-18 00:16:46 +02:00
if ( IsValidPlayer ( ci - > client_playas ) ) {
ttd_strlcpy ( _network_player_info [ ci - > client_playas ] . password , password , sizeof ( _network_player_info [ 0 ] . password ) ) ;
2004-12-04 18:54:56 +01:00
}
}
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_SET_NAME )
{
2004-12-23 21:33:57 +01:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 18:54:56 +01:00
NetworkClientInfo * ci ;
2007-02-02 00:26:44 +01:00
p - > Recv_string ( client_name , sizeof ( client_name ) ) ;
2004-12-04 18:54:56 +01:00
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-10-18 01:34:12 +02:00
if ( cs - > has_quit ) return ;
2005-01-05 15:39:48 +01:00
2004-12-04 18:54:56 +01:00
if ( ci ! = NULL ) {
// Display change
2004-12-23 21:33:57 +01:00
if ( NetworkFindName ( client_name ) ) {
2008-05-24 12:35:15 +02:00
NetworkTextMessage ( NETWORK_ACTION_NAME_CHANGE , CC_DEFAULT , false , ci - > client_name , " %s " , client_name ) ;
2004-12-23 21:33:57 +01:00
ttd_strlcpy ( ci - > client_name , client_name , sizeof ( ci - > client_name ) ) ;
2004-12-04 18:54:56 +01:00
NetworkUpdateClientInfo ( ci - > client_index ) ;
}
}
}
2005-01-15 21:09:16 +01:00
DEF_SERVER_RECEIVE_COMMAND ( PACKET_CLIENT_RCON )
{
char pass [ NETWORK_PASSWORD_LENGTH ] ;
char command [ NETWORK_RCONCOMMAND_LENGTH ] ;
2006-06-27 23:25:53 +02:00
if ( _network_game_info . rcon_password [ 0 ] = = ' \0 ' ) return ;
2005-01-15 21:09:16 +01:00
2007-02-02 00:26:44 +01:00
p - > Recv_string ( pass , sizeof ( pass ) ) ;
p - > Recv_string ( command , sizeof ( command ) ) ;
2005-01-15 21:09:16 +01:00
2006-06-14 15:22:30 +02:00
if ( strcmp ( pass , _network_game_info . rcon_password ) ! = 0 ) {
2006-12-26 18:36:18 +01:00
DEBUG ( net , 0 , " [rcon] wrong password from client-id %d " , cs - > index ) ;
2005-01-15 21:09:16 +01:00
return ;
}
2006-12-26 18:36:18 +01:00
DEBUG ( net , 0 , " [rcon] client-id %d executed: '%s' " , cs - > index , command ) ;
2005-01-15 21:09:16 +01:00
_redirect_console_to_client = cs - > index ;
IConsoleCmdExec ( command ) ;
_redirect_console_to_client = 0 ;
return ;
}
2004-12-04 18:54:56 +01:00
// The layout for the receive-functions by the server
2007-01-12 21:19:49 +01:00
typedef void NetworkServerPacket ( NetworkTCPSocketHandler * cs , Packet * p ) ;
2004-12-04 18:54:56 +01: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 13:03:43 +01:00
NULL , /*PACKET_SERVER_BANNED,*/
2004-12-04 18:54:56 +01: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 21:09:16 +01:00
NULL , /*PACKET_SERVER_RCON,*/
RECEIVE_COMMAND ( PACKET_CLIENT_RCON ) ,
2007-01-30 18:22:56 +01:00
NULL , /*PACKET_CLIENT_CHECK_NEWGRFS,*/
RECEIVE_COMMAND ( PACKET_CLIENT_NEWGRFS_CHECKED ) ,
2004-12-04 18:54:56 +01: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 12:47:46 +01:00
void NetworkPopulateCompanyInfo ( )
2004-12-04 18:54:56 +01:00
{
char password [ NETWORK_PASSWORD_LENGTH ] ;
2006-10-18 01:34:12 +02:00
const Player * p ;
const Vehicle * v ;
const Station * s ;
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * cs ;
2006-10-18 01:34:12 +02:00
const NetworkClientInfo * ci ;
uint i ;
2004-12-16 14:59:23 +01:00
uint16 months_empty ;
2004-12-04 18:54:56 +01:00
FOR_ALL_PLAYERS ( p ) {
if ( ! p - > is_active ) {
memset ( & _network_player_info [ p - > index ] , 0 , sizeof ( NetworkPlayerInfo ) ) ;
continue ;
}
// Clean the info but not the password
ttd_strlcpy ( password , _network_player_info [ p - > index ] . password , sizeof ( password ) ) ;
2004-12-16 14:59:23 +01:00
months_empty = _network_player_info [ p - > index ] . months_empty ;
2004-12-04 18:54:56 +01:00
memset ( & _network_player_info [ p - > index ] , 0 , sizeof ( NetworkPlayerInfo ) ) ;
2004-12-16 14:59:23 +01:00
_network_player_info [ p - > index ] . months_empty = months_empty ;
2004-12-04 18:54:56 +01:00
ttd_strlcpy ( _network_player_info [ p - > index ] . password , password , sizeof ( _network_player_info [ p - > index ] . password ) ) ;
// Grap the company name
2007-06-25 17:59:37 +02: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 18:54:56 +01:00
// Check the income
2006-08-20 21:05:28 +02:00
if ( _cur_year - 1 = = p - > inaugurated_year ) {
2004-12-04 18:54:56 +01:00
// The player is here just 1 year, so display [2], else display[1]
2006-10-18 01:34:12 +02:00
for ( i = 0 ; i < lengthof ( p - > yearly_expenses [ 2 ] ) ; i + + ) {
2004-12-04 18:54:56 +01:00
_network_player_info [ p - > index ] . income - = p - > yearly_expenses [ 2 ] [ i ] ;
2006-06-27 23:25:53 +02:00
}
} else {
2006-10-18 01:34:12 +02:00
for ( i = 0 ; i < lengthof ( p - > yearly_expenses [ 1 ] ) ; i + + ) {
2004-12-04 18:54:56 +01:00
_network_player_info [ p - > index ] . income - = p - > yearly_expenses [ 1 ] [ i ] ;
2006-06-27 23:25:53 +02:00
}
}
2004-12-04 18:54:56 +01: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 23:00:14 +02:00
_network_player_info [ p - > index ] . money = p - > player_money ;
2004-12-04 18:54:56 +01: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-01-18 22:25:18 +01:00
if ( ! IsValidPlayer ( v - > owner ) | | ! v - > IsPrimaryVehicle ( ) ) continue ;
2008-01-13 23:27:06 +01:00
byte type = 0 ;
2006-06-27 23:25:53 +02:00
switch ( v - > type ) {
2008-01-13 23:27:06 +01: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 23:25:53 +02:00
}
2008-01-18 22:25:18 +01:00
_network_player_info [ v - > owner ] . num_vehicle [ type ] + + ;
2004-12-04 18:54:56 +01:00
}
// Go through all stations and count the types of stations
FOR_ALL_STATIONS ( s ) {
2006-10-15 00:31:18 +02:00
if ( IsValidPlayer ( s - > owner ) ) {
2006-10-18 01:34:12 +02:00
NetworkPlayerInfo * npi = & _network_player_info [ s - > owner ] ;
2006-06-27 23:25:53 +02: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 18:54:56 +01:00
}
}
ci = NetworkFindClientInfoFromIndex ( NETWORK_SERVER_INDEX ) ;
// Register local player (if not dedicated)
2006-10-18 00:16:46 +02:00
if ( ci ! = NULL & & IsValidPlayer ( ci - > client_playas ) )
ttd_strlcpy ( _network_player_info [ ci - > client_playas ] . players , ci - > client_name , sizeof ( _network_player_info [ 0 ] . players ) ) ;
2004-12-04 18:54:56 +01:00
FOR_ALL_CLIENTS ( cs ) {
2004-12-23 21:33:57 +01:00
char client_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 18:54:56 +01:00
NetworkGetClientName ( client_name , sizeof ( client_name ) , cs ) ;
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-10-18 00:16:46 +02:00
if ( ci ! = NULL & & IsValidPlayer ( ci - > client_playas ) ) {
2007-01-13 16:00:16 +01:00
if ( ! StrEmpty ( _network_player_info [ ci - > client_playas ] . players ) ) {
2006-10-18 00:16:46 +02:00
ttd_strlcat ( _network_player_info [ ci - > client_playas ] . players , " , " , lengthof ( _network_player_info [ 0 ] . players ) ) ;
2007-01-13 16:00:16 +01:00
}
2004-12-15 21:10:34 +01:00
2006-10-18 00:16:46 +02:00
ttd_strlcat ( _network_player_info [ ci - > client_playas ] . players , client_name , lengthof ( _network_player_info [ 0 ] . players ) ) ;
2004-12-04 18:54:56 +01:00
}
}
}
// Send a packet to all clients with updated info about this client_index
void NetworkUpdateClientInfo ( uint16 client_index )
{
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * cs ;
2006-10-18 01:34:12 +02:00
NetworkClientInfo * ci = NetworkFindClientInfoFromIndex ( client_index ) ;
2004-12-04 18:54:56 +01:00
2006-06-27 23:25:53 +02:00
if ( ci = = NULL ) return ;
2004-12-14 21:27:00 +01:00
2004-12-04 18:54:56 +01:00
FOR_ALL_CLIENTS ( cs ) {
SEND_COMMAND ( PACKET_SERVER_CLIENT_INFO ) ( cs , ci ) ;
}
}
2004-12-23 18:37:26 +01:00
/* Check if we want to restart the map */
2007-03-07 12:47:46 +01:00
static void NetworkCheckRestartMap ( )
2004-12-23 18:37:26 +01:00
{
2008-05-29 22:21:28 +02:00
if ( _settings_client . network . restart_game_year ! = 0 & & _cur_year > = _settings_client . network . restart_game_year ) {
2006-12-26 18:36:18 +01:00
DEBUG ( net , 0 , " Auto-restarting map. Year %d reached " , _cur_year ) ;
2004-12-23 18:37:26 +01: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 12:00:30 +02:00
StartNewGameWithoutGUI ( GENERATE_NEW_SEED ) ;
2004-12-23 18:37:26 +01:00
}
}
2004-12-16 14:59:23 +01: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 12:47:46 +01:00
static void NetworkAutoCleanCompanies ( )
2004-12-16 14:59:23 +01:00
{
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * cs ;
2006-10-18 01:34:12 +02:00
const NetworkClientInfo * ci ;
const Player * p ;
2004-12-16 14:59:23 +01:00
bool clients_in_company [ MAX_PLAYERS ] ;
2008-05-29 22:21:28 +02:00
if ( ! _settings_client . network . autoclean_companies ) return ;
2004-12-16 14:59:23 +01:00
memset ( clients_in_company , 0 , sizeof ( clients_in_company ) ) ;
/* Detect the active companies */
FOR_ALL_CLIENTS ( cs ) {
ci = DEREF_CLIENT_INFO ( cs ) ;
2006-10-18 00:16:46 +02:00
if ( IsValidPlayer ( ci - > client_playas ) ) clients_in_company [ ci - > client_playas ] = true ;
2004-12-16 14:59:23 +01:00
}
2006-10-18 01:34:12 +02:00
2004-12-16 14:59:23 +01:00
if ( ! _network_dedicated ) {
ci = NetworkFindClientInfoFromIndex ( NETWORK_SERVER_INDEX ) ;
2006-10-18 00:16:46 +02:00
if ( IsValidPlayer ( ci - > client_playas ) ) clients_in_company [ ci - > client_playas ] = true ;
2004-12-16 14:59:23 +01:00
}
/* Go through all the comapnies */
FOR_ALL_PLAYERS ( p ) {
/* Skip the non-active once */
2006-06-27 23:25:53 +02:00
if ( ! p - > is_active | | p - > is_ai ) continue ;
2004-12-16 14:59:23 +01: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-05-29 22:21:28 +02:00
if ( _network_player_info [ p - > index ] . months_empty > _settings_client . network . autoclean_unprotected & & _network_player_info [ p - > index ] . password [ 0 ] = = ' \0 ' ) {
2004-12-16 14:59:23 +01:00
/* Shut the company down */
DoCommandP ( 0 , 2 , p - > index , NULL , CMD_PLAYER_CTRL ) ;
2008-05-24 12:35:15 +02:00
IConsolePrintF ( CC_DEFAULT , " Auto-cleaned company #%d " , p - > index + 1 ) ;
2004-12-16 14:59:23 +01:00
}
/* Is the compnay empty for autoclean_protected-months, and there is a protection? */
2008-05-29 22:21:28 +02:00
if ( _network_player_info [ p - > index ] . months_empty > _settings_client . network . autoclean_protected & & _network_player_info [ p - > index ] . password [ 0 ] ! = ' \0 ' ) {
2004-12-16 14:59:23 +01:00
/* Unprotect the company */
_network_player_info [ p - > index ] . password [ 0 ] = ' \0 ' ;
2008-05-24 12:35:15 +02:00
IConsolePrintF ( CC_DEFAULT , " Auto-removed protection from company #%d " , p - > index + 1 ) ;
2004-12-16 14:59:23 +01: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 18:54:56 +01: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 21:33:57 +01:00
bool NetworkFindName ( char new_name [ NETWORK_CLIENT_NAME_LENGTH ] )
2004-12-04 18:54:56 +01:00
{
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * new_cs ;
2004-12-04 18:54:56 +01:00
bool found_name = false ;
byte number = 0 ;
2004-12-23 21:33:57 +01:00
char original_name [ NETWORK_CLIENT_NAME_LENGTH ] ;
2004-12-04 18:54:56 +01:00
2006-04-22 11:46:31 +02:00
// We use NETWORK_CLIENT_NAME_LENGTH in here, because new_name is really a pointer
2004-12-23 21:33:57 +01:00
ttd_strlcpy ( original_name , new_name , NETWORK_CLIENT_NAME_LENGTH ) ;
2004-12-04 18:54:56 +01:00
while ( ! found_name ) {
2006-10-18 01:34:12 +02:00
const NetworkClientInfo * ci ;
2004-12-04 18:54:56 +01:00
found_name = true ;
FOR_ALL_CLIENTS ( new_cs ) {
ci = DEREF_CLIENT_INFO ( new_cs ) ;
2006-06-14 15:22:30 +02:00
if ( strcmp ( ci - > client_name , new_name ) = = 0 ) {
2004-12-04 18:54:56 +01: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-18 01:34:12 +02:00
if ( strcmp ( ci - > client_name , new_name ) = = 0 ) found_name = false ; // name already in use
2004-12-04 18:54:56 +01:00
}
if ( ! found_name ) {
// Try a new name (<name> #1, <name> #2, and so on)
2004-12-29 14:13:29 +01:00
// Stop if we tried for more than 50 times..
2004-12-04 18:54:56 +01:00
if ( number + + > 50 ) break ;
2004-12-23 21:33:57 +01:00
snprintf ( new_name , NETWORK_CLIENT_NAME_LENGTH , " %s #%d " , original_name , number ) ;
2004-12-04 18:54:56 +01:00
}
}
return found_name ;
}
// Reads a packet from the stream
2007-01-12 21:19:49 +01:00
bool NetworkServer_ReadPackets ( NetworkTCPSocketHandler * cs )
2004-12-04 18:54:56 +01:00
{
Packet * p ;
NetworkRecvStatus res ;
2007-02-02 00:50:15 +01:00
while ( ( p = cs - > Recv_Packet ( & res ) ) ! = NULL ) {
2007-02-02 00:26:44 +01:00
byte type = p - > Recv_uint8 ( ) ;
2006-10-18 01:34:12 +02:00
if ( type < PACKET_END & & _network_server_packet [ type ] ! = NULL & & ! cs - > has_quit ) {
2004-12-04 18:54:56 +01:00
_network_server_packet [ type ] ( cs , p ) ;
2006-06-27 23:25:53 +02:00
} else {
2006-12-26 18:36:18 +01:00
DEBUG ( net , 0 , " [server] received invalid packet type %d " , type ) ;
2006-06-27 23:25:53 +02:00
}
2007-02-01 23:30:35 +01:00
delete p ;
2004-12-04 18:54:56 +01:00
}
return true ;
}
// Handle the local command-queue
2007-01-12 21:19:49 +01:00
static void NetworkHandleCommandQueue ( NetworkTCPSocketHandler * cs )
2006-01-05 13:40:50 +01:00
{
2005-07-16 17:05:52 +02:00
CommandPacket * cp ;
2004-12-04 18:54:56 +01:00
2005-07-16 17:05:52 +02:00
while ( ( cp = cs - > command_queue ) ! = NULL ) {
SEND_COMMAND ( PACKET_SERVER_COMMAND ) ( cs , cp ) ;
2004-12-04 18:54:56 +01:00
2005-07-16 17:05:52 +02:00
cs - > command_queue = cp - > next ;
free ( cp ) ;
2004-12-04 18:54:56 +01:00
}
}
// This is called every tick if this is a _network_server
2005-07-29 23:55:49 +02:00
void NetworkServer_Tick ( bool send_frame )
2004-12-04 18:54:56 +01:00
{
2007-01-12 21:19:49 +01:00
NetworkTCPSocketHandler * cs ;
2005-07-16 14:59:23 +02:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
bool send_sync = false ;
# endif
2004-12-04 18:54:56 +01:00
2005-07-16 14:59:23 +02:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
2008-05-29 22:21:28 +02:00
if ( _frame_counter > = _last_sync_frame + _settings_client . network . sync_freq ) {
2005-07-16 14:59:23 +02:00
_last_sync_frame = _frame_counter ;
send_sync = true ;
}
# endif
2004-12-04 18:54:56 +01: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 12:35:15 +02: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 11:17:26 +01:00
NetworkCloseClient ( cs ) ;
2004-12-04 18:54:56 +01:00
continue ;
}
// Report once per time we detect the lag
if ( cs - > lag_test = = 0 ) {
2008-05-24 12:35:15 +02: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 18:54:56 +01:00
cs - > lag_test = 1 ;
}
} else {
cs - > lag_test = 0 ;
}
2005-03-29 21:10:13 +02:00
} else if ( cs - > status = = STATUS_PRE_ACTIVE ) {
int lag = NetworkCalculateLag ( cs ) ;
2008-05-29 22:21:28 +02: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 21:10:13 +02:00
NetworkCloseClient ( cs ) ;
}
2007-03-06 23:00:42 +01:00
} else if ( cs - > status = = STATUS_INACTIVE ) {
int lag = NetworkCalculateLag ( cs ) ;
if ( lag > 4 * DAY_TICKS ) {
2008-05-24 12:35:15 +02: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 23:00:42 +01:00
NetworkCloseClient ( cs ) ;
}
2004-12-04 18:54:56 +01:00
}
2005-07-16 14:59:23 +02:00
if ( cs - > status > = STATUS_PRE_ACTIVE ) {
// Check if we can send command, and if we have anything in the queue
2004-12-04 18:54:56 +01:00
NetworkHandleCommandQueue ( cs ) ;
2005-07-16 14:59:23 +02:00
// Send an updated _frame_counter_max to the client
2006-10-18 01:34:12 +02:00
if ( send_frame ) SEND_COMMAND ( PACKET_SERVER_FRAME ) ( cs ) ;
2004-12-04 18:54:56 +01:00
# ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
2005-07-16 14:59:23 +02:00
// Send a sync-check packet
2006-10-18 01:34:12 +02:00
if ( send_sync ) SEND_COMMAND ( PACKET_SERVER_SYNC ) ( cs ) ;
2004-12-04 18:54:56 +01:00
# endif
2005-07-16 14:59:23 +02:00
}
}
2004-12-15 21:10:34 +01:00
/* See if we need to advertise */
NetworkUDPAdvertise ( ) ;
2004-12-04 18:54:56 +01:00
}
2007-03-07 12:47:46 +01:00
void NetworkServerYearlyLoop ( )
2004-12-23 18:37:26 +01:00
{
NetworkCheckRestartMap ( ) ;
}
2007-03-07 12:47:46 +01:00
void NetworkServerMonthlyLoop ( )
2004-12-16 14:59:23 +01:00
{
NetworkAutoCleanCompanies ( ) ;
}
2004-12-04 18:54:56 +01:00
# endif /* ENABLE_NETWORK */