Changeset - r662:d42c2c6d320b
[Not reviewed]
master
0 5 0
truelight - 20 years ago 2004-12-15 15:19:51
truelight@openttd.org
(svn r1096) -Fix: [Network] PlayAs is now registered correctly
-Codewise: [Network] Cleaned some code, removed some comment, changed
some wrong comment
5 files changed with 20 insertions and 17 deletions:
0 comments (0 inline, 0 general)
network.c
Show inline comments
 
@@ -359,97 +359,97 @@ unsigned long NetworkResolveHost(const c
 
//  Format: IP#player:port
 
//
 
// connection_string will be re-terminated to seperate out the hostname, and player and port will
 
// be set to the player and port strings given by the user, inside the memory area originally
 
// occupied by connection_string.
 
void ParseConnectionString(const byte **player, const byte **port, byte *connection_string)
 
{
 
	byte *p;
 
	for (p = connection_string; *p != '\0'; p++) {
 
		if (*p == '#') {
 
			*player = p + 1;
 
			*p = '\0';
 
		} else if (*p == ':') {
 
			*port = p + 1;
 
			*p = '\0';
 
		}
 
	}
 
}
 

	
 
// Creates a new client from a socket
 
//   Used both by the server and the client
 
static ClientState *AllocClient(SOCKET s)
 
{
 
	ClientState *cs;
 
	NetworkClientInfo *ci;
 
	byte client_no;
 

	
 
	client_no = 0;
 

	
 
	if (_network_server) {
 
		// Can we handle a new client?
 
		if (_network_clients_connected >= MAX_CLIENTS)
 
			return NULL;
 

	
 
		if (_network_game_info.clients_on >= _network_game_info.clients_max)
 
			return NULL;
 

	
 
		// Register the login
 
		client_no = _network_clients_connected++;
 
	}
 

	
 
	cs = &_clients[client_no];
 
	memset(cs, 0, sizeof(*cs));
 
	cs->socket = s;
 
	cs->last_frame = 0;
 
	cs->quited = false;
 

	
 
	if (_network_server) {
 
		ci = &_network_client_info[client_no];
 
		ci = DEREF_CLIENT_INFO(cs);
 
		memset(ci, 0, sizeof(*ci));
 

	
 
		cs->index = _network_client_index++;
 
		ci->client_index = cs->index;
 
		ci->join_date = _date;
 

	
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 
	}
 

	
 
	return cs;
 
}
 

	
 
// Close a connection
 
void CloseClient(ClientState *cs)
 
{
 
	NetworkClientInfo *ci;
 
	// Socket is already dead
 
	if (cs->socket == INVALID_SOCKET) return;
 

	
 
	DEBUG(net, 1) ("[NET] Closed client connection");
 

	
 
	if (!cs->quited && _network_server && cs->status > STATUS_INACTIVE) {
 
		// We did not receive a leave message from this client...
 
		NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST;
 
		char str1[100], str2[100];
 
		char client_name[NETWORK_NAME_LENGTH];
 
		ClientState *new_cs;
 

	
 
		NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
		GetString(str1, STR_NETWORK_ERR_LEFT);
 
		GetString(str2, STR_NETWORK_ERR_CLIENT_GENERAL + errorno);
 

	
 
		NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, client_name, "%s (%s)", str1, str2);
 

	
 
		// Inform other clients of this... strange leaving ;)
 
		FOR_ALL_CLIENTS(new_cs) {
 
			if (new_cs->status > STATUS_AUTH && cs != new_cs) {
 
				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
 
			}
 
		}
 
	}
 

	
 
	closesocket(cs->socket);
 
	cs->writable = false;
 

	
 
	// Free all pending and partially received packets
 
	while (cs->packet_queue != NULL) {
 
@@ -655,96 +655,97 @@ bool NetworkListen(void)
 
	sin.sin_addr.s_addr = _network_server_bind_ip;
 
	sin.sin_port = htons(port);
 

	
 
	if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
 
		ServerStartError("bind() failed");
 
		return false;
 
	}
 

	
 
	if (listen(ls, 1) != 0) {
 
		ServerStartError("listen() failed");
 
		return false;
 
	}
 

	
 
	_listensocket = ls;
 

	
 
	return true;
 
}
 

	
 
// Close all current connections
 
void NetworkClose(void)
 
{
 
	ClientState *cs;
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		if (!_network_server) {
 
			SEND_COMMAND(PACKET_CLIENT_QUIT)("leaving");
 
			NetworkSend_Packets(cs);
 
		}
 
		CloseClient(cs);
 
	}
 

	
 
	if (_network_server) {
 
		// We are a server, also close the listensocket
 
		closesocket(_listensocket);
 
		_listensocket = INVALID_SOCKET;
 
		DEBUG(net, 1) ("[NET] Closed listener");
 
		NetworkUDPClose();
 
	}
 
}
 

	
 
// Inits the network (cleans sockets and stuff)
 
void NetworkInitialize(void)
 
{
 
	ClientState *cs;
 

	
 
	_local_command_queue = NULL;
 

	
 
	// Clean all client-sockets
 
	memset(_clients, 0, sizeof(_clients));
 
	for (cs = _clients; cs != &_clients[MAX_CLIENTS]; cs++) {
 
		cs->socket = INVALID_SOCKET;
 
		cs->status = STATUS_INACTIVE;
 
		cs->command_queue = NULL;
 
	}
 

	
 
	// Clean the client_info memory
 
	memset(_network_client_info, 0, sizeof(_network_client_info));
 
	memset(_network_player_info, 0, sizeof(_network_player_info));
 

	
 
	_sync_frame = 0;
 
	_network_first_time = true;
 

	
 
	_network_reconnect = 0;
 

	
 
	InitPlayerRandoms();
 

	
 
	NetworkUDPInitialize();
 
}
 

	
 
// Query a server to fetch his game-info
 
//  If game_info is true, only the gameinfo is fetched,
 
//   else only the client_info is fetched
 
void NetworkQueryServer(const byte* host, unsigned short port, bool game_info)
 
{
 
	if (!_network_available) return;
 

	
 
	NetworkDisconnect();
 

	
 
	if (game_info) {
 
		NetworkUDPQueryServer(host, port);
 
		return;
 
	}
 

	
 
	NetworkInitialize();
 

	
 
	_network_server = false;
 

	
 
	// Try to connect
 
	_networking = NetworkConnect(host, port);
 

	
 
//	ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host));
 
//	_network_last_port = port;
 

	
 
	// We are connected
 
	if (_networking) {
 
		SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
 
		return;
network.h
Show inline comments
 
#ifndef NETWORK_H
 
#define NETWORK_H
 

	
 
#include "network_core.h"
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
// If this line is enable, every frame will have a sync test
 
//  this is not needed in normal games. Normal is like 1 sync in 100
 
//  frames. You can enable this if you have a lot of desyncs on a certain
 
//  game.
 
// Remember: both client and server have to be compiled with this
 
//  option enabled to make it to work. If one of the two has it disabled
 
//  nothing will happen.
 
//#define ENABLE_NETWORK_SYNC_EVERY_FRAME
 

	
 
// In theory sending 1 of the 2 seeds is enough to check for desyncs
 
//   so in theory, this next define can be left off.
 
//#define NETWORK_SEND_DOUBLE_SEED
 

	
 
// How many clients can we have? Like.. MAX_PLAYERS - 1 is the amount of
 
//  players that can really play.. so.. a max of 4 spectators.. gives us..
 
//  MAX_PLAYERS + 3
 
#define MAX_CLIENTS (MAX_PLAYERS + 3)
 

	
 

	
 
// Do not change this next line. It should _ALWAYS_ be MAX_CLIENTS + 1
 
#define MAX_CLIENT_INFO (MAX_CLIENTS + 1)
 

	
 
#define NETWORK_DISCOVER_PORT 3978
 
#define NETWORK_DEFAULT_PORT 3979
 

	
 
#define MAX_INTERFACES 9
 

	
 

	
 
// How many vehicle/station types we put over the network
 
#define NETWORK_VEHICLE_TYPES 5
 
#define NETWORK_STATION_TYPES 5
 

	
 
#define NETWORK_NAME_LENGTH 80
 
#define NETWORK_HOSTNAME_LENGTH 80
 
#define NETWORK_REVISION_LENGTH 10
 
#define NETWORK_PASSWORD_LENGTH 20
 
#define NETWORK_PLAYERS_LENGTH 200
 

	
 
// This is the struct used by both client and server
 
//  some fields will be empty on the client (like game_password) by default
 
//  and only filled with data a player enters.
 
typedef struct NetworkGameInfo {
 
	char server_name[NETWORK_NAME_LENGTH];					// Server name
 
	char hostname[NETWORK_HOSTNAME_LENGTH];					// Hostname of the server (if any)
 
	char server_revision[NETWORK_REVISION_LENGTH];	// The SVN version number the server is using (e.g.: 'r304')
 
																									//  It even shows a SVN version in release-version, so
 
																									//  it is easy to compare if a server is of the correct version
 
	byte server_lang;																// Language of the server (we should make a nice table for this)
 
	byte use_password;															// Is set to != 0 if it uses a password
 
	char server_password[NETWORK_PASSWORD_LENGTH];	// On the server: the game password, on the client: != "" if server has password
 
	byte clients_max;																// Max clients allowed on server
 
	byte clients_on;																// Current count of clients on server
 
	byte spectators_on;															// How many spectators do we have?
 
	uint16 game_date;																// Current date
 
	uint16 start_date;															// When the game started
 
	char map_name[NETWORK_NAME_LENGTH];							// Map which is played ["random" for a randomized map]
 
	uint16 map_width;																// Map width
 
	uint16 map_height;															// Map height
 
	byte map_set;																		// Graphical set
 
	bool dedicated;																	// Is this a dedicated server?
 
} NetworkGameInfo;
 

	
 
typedef struct NetworkPlayerInfo {
 
	char company_name[NETWORK_NAME_LENGTH];					// Company name
 
	char password[NETWORK_PASSWORD_LENGTH];					// The password for the player
 
	byte inaugurated_year;													// What year the company started in
 
	int64 company_value;														// The company value
 
	int64 money;																		// The amount of money the company has
 
	int64 income;																		// How much did the company earned last year
 
	uint16 performance;															// What was his performance last month?
 
	uint16 num_vehicle[NETWORK_VEHICLE_TYPES];			// How many vehicles are there of this type?
network_client.c
Show inline comments
 
@@ -20,97 +20,97 @@
 

	
 
static uint32 last_ack_frame;
 

	
 
void NetworkRecvPatchSettings(Packet *p);
 

	
 
// **********
 
// Sending functions
 
//   DEF_CLIENT_SEND_COMMAND has no parameters
 
// **********
 

	
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)
 
{
 
	//
 
	// Packet: CLIENT_COMPANY_INFO
 
	// Function: Request company-info (in detail)
 
	// Data:
 
	//    <none>
 
	//
 
	Packet *p;
 
	_network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO;
 
	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
	p = NetworkSend_Init(PACKET_CLIENT_COMPANY_INFO);
 
	NetworkSend_Packet(p, MY_CLIENT);
 
}
 

	
 
extern const char _openttd_revision[];
 

	
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_JOIN)
 
{
 
	//
 
	// Packet: CLIENT_JOIN
 
	// Function: Try to join the server
 
	// Data:
 
	//    String: OpenTTD Revision (norev000 if no revision)
 
	//    String: Player Name (max NETWORK_NAME_LENGTH)
 
	//    uint8:  Play as Player id (1..MAX_PLAYERS)
 
	//    uint8:  Language ID
 
	//    String: Unique id to find the player back in server-listing
 
	//
 

	
 
	Packet *p;
 
	_network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
 
	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
	p = NetworkSend_Init(PACKET_CLIENT_JOIN);
 
	NetworkSend_string(p, _openttd_revision);
 
	NetworkSend_string(p, _network_player_name); // Player name
 
	NetworkSend_uint8(p, _network_playas); // Password
 
	NetworkSend_uint8(p, _network_playas); // PlayAs
 
	NetworkSend_uint8(p, NETLANG_ANY); // Language
 
	NetworkSend_string(p, _network_unique_id);
 
	NetworkSend_Packet(p, MY_CLIENT);
 
}
 

	
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password)
 
{
 
	//
 
	// Packet: CLIENT_PASSWORD
 
	// Function: Send a password to the server to authorize
 
	// Data:
 
	//    uint8:  NetworkPasswordType
 
	//    String: Password
 
	//
 
	Packet *p = NetworkSend_Init(PACKET_CLIENT_PASSWORD);
 
	NetworkSend_uint8(p, type);
 
	NetworkSend_string(p, password);
 
	NetworkSend_Packet(p, MY_CLIENT);
 
}
 

	
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_GETMAP)
 
{
 
	//
 
	// Packet: CLIENT_GETMAP
 
	// Function: Request the map from the server
 
	// Data:
 
	//    <none>
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_CLIENT_GETMAP);
 
	NetworkSend_Packet(p, MY_CLIENT);
 
}
 

	
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_MAP_OK)
 
{
 
	//
 
	// Packet: CLIENT_MAP_OK
 
	// Function: Tell the server that we are done receiving/loading the map
 
	// Data:
 
	//    <none>
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_CLIENT_MAP_OK);
 
	NetworkSend_Packet(p, MY_CLIENT);
 
}
 

	
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK)
 
{
 
@@ -272,125 +272,132 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER
 

	
 
	if (company_info_version == 1) {
 
		byte total;
 
		byte current;
 

	
 
		total = NetworkRecv_uint8(p);
 
		_network_lobby_company_count = total;
 

	
 
		// There is no data at all..
 
		if (total == 0)
 
			return NETWORK_RECV_STATUS_CLOSE_QUERY;
 

	
 
		current = NetworkRecv_uint8(p) - 1;
 
		if (current >= MAX_PLAYERS)
 
			return NETWORK_RECV_STATUS_CLOSE_QUERY;
 

	
 
		NetworkRecv_string(p, _network_player_info[current].company_name, sizeof(_network_player_info[current].company_name));
 
		_network_player_info[current].inaugurated_year = NetworkRecv_uint8(p);
 
		_network_player_info[current].company_value = NetworkRecv_uint64(p);
 
		_network_player_info[current].money = NetworkRecv_uint64(p);
 
		_network_player_info[current].income = NetworkRecv_uint64(p);
 
		_network_player_info[current].performance = NetworkRecv_uint16(p);
 
		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++)
 
			_network_player_info[current].num_vehicle[i] = NetworkRecv_uint16(p);
 
		for (i = 0; i < NETWORK_STATION_TYPES; i++)
 
			_network_player_info[current].num_station[i] = NetworkRecv_uint16(p);
 

	
 
		NetworkRecv_string(p, _network_player_info[current].players, sizeof(_network_player_info[current].players));
 

	
 
		InvalidateWindow(WC_NETWORK_WINDOW, 0);
 

	
 
		if (total == current + 1)
 
			// This was the last one
 
			return NETWORK_RECV_STATUS_CLOSE_QUERY;
 
		else
 
			return NETWORK_RECV_STATUS_OKAY;
 
	}
 

	
 
	return NETWORK_RECV_STATUS_CLOSE_QUERY;
 
}
 

	
 
// This packet contains info about the client (playas and name)
 
//  as client we save this in NetworkClientInfo, linked via 'index'
 
//  which is always an unique number on a server.
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
 
{
 
	NetworkClientInfo *ci;
 
	uint16 index = NetworkRecv_uint16(p);
 
	byte playas = NetworkRecv_uint8(p);
 
	char name[NETWORK_NAME_LENGTH];
 
	char unique_id[NETWORK_NAME_LENGTH];
 

	
 
	NetworkRecv_string(p, name, sizeof(name));
 
	NetworkRecv_string(p, unique_id, sizeof(unique_id));
 

	
 
	/* Do we receive a change of data? Most likely we changed playas */
 
	if (index == _network_own_client_index)
 
		_network_playas = playas;
 

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	if (ci != NULL) {
 
		byte playas;
 
		char name[NETWORK_NAME_LENGTH];
 

	
 
		playas = NetworkRecv_uint8(p);
 
		NetworkRecv_string(p, name, sizeof(name));
 

	
 
		if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) {
 
			// Client name changed, display the change
 
			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, ci->client_name, name);
 
		} else if (playas != ci->client_playas) {
 
			// The player changed from client-player..
 
			// Do not display that for now
 
		}
 

	
 
		ci->client_playas = playas;
 
		ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
 

	
 
		return NETWORK_RECV_STATUS_OKAY;
 
	}
 

	
 
	// We don't have this index yet, find an empty index, and put the data there
 
	ci = NetworkFindClientInfoFromIndex(NETWORK_EMPTY_INDEX);
 
	if (ci != NULL) {
 
		ci->client_index = index;
 
		ci->client_playas = NetworkRecv_uint8(p);
 
		NetworkRecv_string(p, ci->client_name, sizeof(ci->client_name));
 
		NetworkRecv_string(p, ci->unique_id, sizeof(ci->unique_id));
 
		ci->client_playas = playas;
 

	
 
		ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
 
		ttd_strlcpy(ci->unique_id, unique_id, sizeof(ci->unique_id));
 

	
 
		return NETWORK_RECV_STATUS_OKAY;
 
	}
 

	
 
	// Here the program should never ever come.....
 
	return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR)
 
{
 
	NetworkErrorCode error = NetworkRecv_uint8(p);
 

	
 
	if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED ||
 
			error == NETWORK_ERROR_PLAYER_MISMATCH) {
 
		// We made an error in the protocol, and our connection is closed.... :(
 
		_switch_mode_errorstr = STR_NETWORK_ERR_SERVER_ERROR;
 
	} else if (error == NETWORK_ERROR_WRONG_REVISION) {
 
		// Wrong revision :(
 
		_switch_mode_errorstr = STR_NETWORK_ERR_WRONG_REVISION;
 
	} else if (error == NETWORK_ERROR_WRONG_PASSWORD) {
 
		// Wrong password
 
		_switch_mode_errorstr = STR_NETWORK_ERR_WRONG_PASSWORD;
 
	} else if (error == NETWORK_ERROR_KICKED) {
 
		_switch_mode_errorstr = STR_NETWORK_ERR_KICKED;
 
	}
 

	
 
	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
	return NETWORK_RECV_STATUS_SERVER_ERROR;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD)
 
{
 
	NetworkPasswordType type;
 
	type = NetworkRecv_uint8(p);
 

	
 
	if (type == NETWORK_GAME_PASSWORD) {
 
		ShowNetworkNeedGamePassword();
 
		return NETWORK_RECV_STATUS_OKAY;
 
	} else if (type == NETWORK_COMPANY_PASSWORD) {
 
		ShowNetworkNeedCompanyPassword();
 
		return NETWORK_RECV_STATUS_OKAY;
 
	}
 

	
 
	return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME)
 
{
network_server.c
Show inline comments
 
@@ -733,97 +733,97 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 
		// Wrong status for this packet, give a warning to client, and close connection
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
	}
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
 
{
 
	// The client has done a command and wants us to handle it
 
	int i;
 
	byte callback;
 
	ClientState *new_cs;
 
	NetworkClientInfo *ci;
 
	char *dparam_char;
 

	
 
	CommandPacket *cp = malloc(sizeof(CommandPacket));
 

	
 
	// The client was never joined.. so this is impossible, right?
 
	//  Ignore the packet, give the client a warning, and close his connection
 
	if (cs->status < STATUS_DONE_MAP || cs->quited) {
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
		return;
 
	}
 

	
 
	cp->player = NetworkRecv_uint8(p);
 
	cp->cmd = NetworkRecv_uint32(p);
 
	cp->p1 = NetworkRecv_uint32(p);
 
	cp->p2 = NetworkRecv_uint32(p);
 
	cp->tile = NetworkRecv_uint32(p);
 
	/* We are going to send them byte by byte, because dparam is misused
 
	    for chars (if it is used), and else we have a BigEndian / LittleEndian
 
	    problem.. we should fix the misuse of dparam... -- TrueLight */
 
	dparam_char = (char *)&cp->dp[0];
 
	for (i = 0; i < lengthof(cp->dp) * 4; i++) {
 
		*dparam_char = NetworkRecv_uint8(p);
 
		dparam_char++;
 
	}
 

	
 
	callback = NetworkRecv_uint8(p);
 

	
 
	ci = DEREF_CLIENT_INFO(cs);
 
	// Only CMD_PLAYER_CTRL is always allowed, for the rest, playas needs
 
	//  to match the player in the packet
 
	if (cp->cmd != CMD_PLAYER_CTRL && ci->client_playas-1 != cp->player) {
 
		// The player did a command with the wrong player_id.. bad!!
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_PLAYER_MISMATCH);
 
		return;
 
	}
 
	if (cp->cmd == CMD_PLAYER_CTRL) {
 
		// UGLY! p1 is mis-used to get the client-id in CmdPlayerCtrl
 
		// UGLY! p2 is mis-used to get the client-id in CmdPlayerCtrl
 
		cp->p2 = cs - _clients;
 
	}
 

	
 

	
 
	// 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;
 
	cp->next = NULL;
 

	
 
	// Queue the command for the clients (are send at the end of the frame
 
	//   if they can handle it ;))
 
	FOR_ALL_CLIENTS(new_cs) {
 
		if (new_cs->status > STATUS_AUTH) {
 
			// Callbacks are only send back to the client who sent them in the
 
			//  first place. This filters that out.
 
			if (new_cs != cs)
 
				cp->callback = 0;
 
			else
 
				cp->callback = callback;
 
			NetworkAddCommandQueue(new_cs, cp);
 
		}
 
	}
 

	
 
	cp->callback = 0;
 
	// 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
 
	ClientState *new_cs;
 
	byte errorno = NetworkRecv_uint8(p);
 
	char str1[100], str2[100];
 
	char client_name[NETWORK_NAME_LENGTH];
 

	
 
	// The client was never joined.. thank the client for the packet, but ignore it
 
	if (cs->status < STATUS_DONE_MAP || cs->quited) {
 
		cs->quited = true;
 
		return;
players.c
Show inline comments
 
@@ -617,108 +617,104 @@ static void DeletePlayerStuff(int pi)
 
{
 
	Player *p;
 

	
 
	DeletePlayerWindows(pi);
 
	p = DEREF_PLAYER(pi);
 
	DeleteName(p->name_1);
 
	DeleteName(p->president_name_1);
 
	p->name_1 = 0;
 
	p->president_name_1 = 0;
 
}
 

	
 
// functionality.
 
// 0 - make new player
 
// 1 - make new AI player
 
// 2 - delete player (p1 >> 8) & 0xFF
 
// 3 - join player (p1 >> 8) & 0xFF with (p1 >> 16) & 0xFF
 
int32 CmdPlayerCtrl(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	int pi;
 
	Player *p;
 

	
 
	if (!(flags & DC_EXEC))
 
		return 0;
 

	
 
	_current_player = OWNER_NONE;
 

	
 
	switch(p1 & 0xff) {
 
	case 0: // make new player
 
		p = DoStartupNewPlayer(false);
 
		if (p != NULL) {
 
			if (_local_player == OWNER_SPECTATOR) {
 
				_local_player = p->index;
 
				MarkWholeScreenDirty();
 
			}
 
#ifdef ENABLE_NETWORK
 
			if (_network_server) {
 
				NetworkClientInfo *ci;
 
				// UGLY! p2 is mis-used to fetch the client-id
 
				ci = &_network_client_info[p2];
 
				ci->client_playas = p->index + 1;
 
				NetworkUpdateClientInfo(ci->client_index);
 

	
 
				if (ci->client_playas != 0 && ci->client_playas <= MAX_PLAYERS) {
 
					memcpy(_decode_parameters, ci->client_name, 32);
 
					/* XXX - What are the consequents of this? It is needed, but is it bad? */
 
					_docommand_recursive = 0;
 
					DoCommandP(0, ci->client_playas-1, 0, NULL, CMD_CHANGE_PRESIDENT_NAME | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
 
				}
 
			} else {
 
				_network_playas = p->index + 1;
 
			}
 
		} else {
 
			if (_network_server) {
 
				NetworkClientInfo *ci;
 
				// UGLY! p2 is mis-used to fetch the client-id
 
				ci = &_network_client_info[p2];
 
				ci->client_playas = OWNER_SPECTATOR;
 
				NetworkUpdateClientInfo(ci->client_index);
 
			} else {
 
				_network_playas = OWNER_SPECTATOR;
 
			}
 
#endif /* ENABLE_NETWORK */
 
		}
 
		break;
 
	case 1: // make new ai player
 
		DoStartupNewPlayer(true);
 
		break;
 
	case 2: // delete player
 
		pi = (byte)(p1 >> 8);
 
		ChangeOwnershipOfPlayerItems(pi, 255);
 
		DeletePlayerStuff(pi);
 
		break;
 

	
 
	case 3: // join player
 
		pi = (byte)(p1 >> 8);
 
		ChangeOwnershipOfPlayerItems(pi, (byte)(p1 >> 16));
 
		DeletePlayerStuff(pi);
 
		break;
 
	}
 

	
 

	
 
	return 0;
 
}
 

	
 
// Save/load of players
 
static const byte _player_desc[] = {
 
	SLE_VAR(Player,name_2,					SLE_UINT32),
 
	SLE_VAR(Player,name_1,					SLE_STRINGID),
 

	
 
	SLE_VAR(Player,president_name_1,SLE_UINT16),
 
	SLE_VAR(Player,president_name_2,SLE_UINT32),
 

	
 
	SLE_VAR(Player,face,						SLE_UINT32),
 

	
 
	// money was changed to a 64 bit field in savegame version 1.
 
	SLE_CONDVAR(Player,money64,			SLE_VAR_I64 | SLE_FILE_I32, 0, 0),
 
	SLE_CONDVAR(Player,money64,			SLE_INT64, 1, 255),
 

	
 
	SLE_VAR(Player,current_loan,		SLE_INT32),
 

	
 
	SLE_VAR(Player,player_color,		SLE_UINT8),
 
	SLE_VAR(Player,player_money_fraction,SLE_UINT8),
 
	SLE_VAR(Player,max_railtype,		SLE_UINT8),
 
	SLE_VAR(Player,block_preview,		SLE_UINT8),
 

	
 
	SLE_VAR(Player,cargo_types,			SLE_UINT16),
 
	SLE_VAR(Player,location_of_house,SLE_UINT16),
 
	SLE_VAR(Player,last_build_coordinate,SLE_UINT16),
0 comments (0 inline, 0 general)