Changeset - r10454:ba5e39738ffa
[Not reviewed]
master
0 15 0
rubidium - 16 years ago 2008-12-22 12:59:31
rubidium@openttd.org
(svn r14709) -Codechange: make a clearer distinction between 'unique' client identification ids and the indices into the clients/client info arrays.
15 files changed with 191 insertions and 187 deletions:
0 comments (0 inline, 0 general)
src/company_cmd.cpp
Show inline comments
 
@@ -798,41 +798,41 @@ CommandCost CmdCompanyCtrl(TileIndex til
 
			/* This command is only executed in a multiplayer game */
 
			if (!_networking) return CMD_ERROR;
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
			/* Joining Client:
 
			* _local_company: COMPANY_SPECTATOR
 
			* _network_playas/cid = requested company/clientid
 
			*
 
			* Other client(s)/server:
 
			* _local_company/_network_playas: what they play as
 
			* cid = requested company/company of joining client */
 
			uint16 cid = p2; // ClientID
 
			ClientIndex cid = (ClientIndex)p2;
 

	
 
			/* Has the network client a correct ClientID? */
 
			/* Has the network client a correct ClientIndex? */
 
			if (!(flags & DC_EXEC)) return CommandCost();
 
			if (cid >= MAX_CLIENT_INFO) return CommandCost();
 

	
 
			/* Delete multiplayer progress bar */
 
			DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
			Company *c = DoStartupNewCompany(false);
 

	
 
			/* A new company could not be created, revert to being a spectator */
 
			if (c == NULL) {
 
				if (_network_server) {
 
					NetworkClientInfo *ci = &_network_client_info[cid];
 
					ci->client_playas = COMPANY_SPECTATOR;
 
					NetworkUpdateClientInfo(ci->client_index);
 
					NetworkUpdateClientInfo(ci->client_id);
 
				} else if (_local_company == COMPANY_SPECTATOR) {
 
					_network_playas = COMPANY_SPECTATOR;
 
				}
 
				break;
 
			}
 

	
 
			/* This is the joining client who wants a new company */
 
			if (_local_company != _network_playas && _network_playas == c->index) {
 
				assert(_local_company == COMPANY_SPECTATOR);
 
				SetLocalCompany(c->index);
 
				if (!StrEmpty(_settings_client.network.default_company_pass)) {
 
					char *password = _settings_client.network.default_company_pass;
 
@@ -850,25 +850,25 @@ CommandCost CmdCompanyCtrl(TileIndex til
 
					NULL
 
				);
 

	
 
				MarkWholeScreenDirty();
 
			}
 

	
 
			if (_network_server) {
 
				/* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at
 
				* server-side in network_server.c:838, function
 
				* DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
 
				NetworkClientInfo *ci = &_network_client_info[cid];
 
				ci->client_playas = c->index;
 
				NetworkUpdateClientInfo(ci->client_index);
 
				NetworkUpdateClientInfo(ci->client_id);
 

	
 
				if (IsValidCompanyID(ci->client_playas)) {
 
					CompanyID company_backup = _local_company;
 
					_network_company_info[c->index].months_empty = 0;
 

	
 
					/* XXX - When a client joins, we automatically set its name to the
 
					* client's name (for some reason). As it stands now only the server
 
					* knows the client's name, so it needs to send out a "broadcast" to
 
					* do this. To achieve this we send a network command. However, it
 
					* uses _local_company to execute the command as.  To prevent abuse
 
					* (eg. only yourself can change your name/company), we 'cheat' by
 
					* impersonation _local_company as the server. Not the best solution;
src/console.cpp
Show inline comments
 
@@ -29,25 +29,25 @@ IConsoleCmd   *_iconsole_cmds;    ///< l
 
IConsoleVar   *_iconsole_vars;    ///< list of registred vars
 
IConsoleAlias *_iconsole_aliases; ///< list of registred aliases
 

	
 
/* ** stdlib ** */
 
byte _stdlib_developer = 1;
 
bool _stdlib_con_developer = false;
 
FILE *_iconsole_output_file;
 

	
 
void IConsoleInit()
 
{
 
	_iconsole_output_file = NULL;
 
#ifdef ENABLE_NETWORK /* Initialize network only variables */
 
	_redirect_console_to_client = 0;
 
	_redirect_console_to_client = INVALID_CLIENT_ID;
 
#endif
 

	
 
	IConsoleGUIInit();
 

	
 
	IConsoleStdLibRegister();
 
}
 

	
 
static void IConsoleWriteToLogFile(const char *string)
 
{
 
	if (_iconsole_output_file != NULL) {
 
		/* if there is an console output file ... also print it there */
 
		if (fwrite(string, strlen(string), 1, _iconsole_output_file) != 1 ||
 
@@ -81,25 +81,25 @@ void IConsoleFree()
 
 * Handle the printing of text entered into the console or redirected there
 
 * by any other means. Text can be redirected to other clients in a network game
 
 * as well as to a logfile. If the network server is a dedicated server, all activities
 
 * are also logged. All lines to print are added to a temporary buffer which can be
 
 * used as a history to print them onscreen
 
 * @param color_code the colour of the command. Red in case of errors, etc.
 
 * @param string the message entered or output on the console (notice, error, etc.)
 
 */
 
void IConsolePrint(ConsoleColour color_code, const char *string)
 
{
 
	char *str;
 
#ifdef ENABLE_NETWORK
 
	if (_redirect_console_to_client != 0) {
 
	if (_redirect_console_to_client != INVALID_CLIENT_ID) {
 
		/* Redirect the string to the client */
 
		NetworkServerSendRcon(_redirect_console_to_client, color_code, string);
 
		return;
 
	}
 
#endif
 

	
 
	/* Create a copy of the string, strip if of colours and invalid
 
	 * characters and (when applicable) assign it to the console buffer */
 
	str = strdup(string);
 
	str_strip_colours(str);
 
	str_validate(str);
 

	
src/console_cmds.cpp
Show inline comments
 
@@ -363,68 +363,68 @@ DEF_CONSOLE_CMD(ConClearBuffer)
 
}
 

	
 

	
 
// ********************************* //
 
// * Network Core Console Commands * //
 
// ********************************* //
 
#ifdef ENABLE_NETWORK
 

	
 
DEF_CONSOLE_CMD(ConBan)
 
{
 
	NetworkClientInfo *ci;
 
	const char *banip = NULL;
 
	uint32 index;
 
	ClientID client_id;
 

	
 
	if (argc == 0) {
 
		IConsoleHelp("Ban a client from a network game. Usage: 'ban <ip | client-id>'");
 
		IConsoleHelp("For client-id's, see the command 'clients'");
 
		IConsoleHelp("If the client is no longer online, you can still ban his/her IP");
 
		return true;
 
	}
 

	
 
	if (argc != 2) return false;
 

	
 
	if (strchr(argv[1], '.') == NULL) { // banning with ID
 
		index = atoi(argv[1]);
 
		ci = NetworkFindClientInfoFromIndex(index);
 
		client_id = (ClientID)atoi(argv[1]);
 
		ci = NetworkFindClientInfoFromIndex(client_id);
 
	} else { // banning IP
 
		ci = NetworkFindClientInfoFromIP(argv[1]);
 
		if (ci == NULL) {
 
			banip = argv[1];
 
			index = (uint32)-1;
 
			client_id = (ClientID)-1;
 
		} else {
 
			index = ci->client_index;
 
			client_id = ci->client_id;
 
		}
 
	}
 

	
 
	if (index == NETWORK_SERVER_INDEX) {
 
	if (client_id == CLIENT_ID_SERVER) {
 
		IConsoleError("Silly boy, you can not ban yourself!");
 
		return true;
 
	}
 

	
 
	if (index == 0 || (ci == NULL && index != (uint32)-1)) {
 
	if (client_id == INVALID_CLIENT_ID || (ci == NULL && client_id != (ClientID)-1)) {
 
		IConsoleError("Invalid client");
 
		return true;
 
	}
 

	
 
	if (ci != NULL) {
 
		IConsolePrint(CC_DEFAULT, "Client banned");
 
		banip = GetClientIP(ci);
 
		NetworkServerSendError(index, NETWORK_ERROR_KICKED);
 
		NetworkServerSendError(client_id, NETWORK_ERROR_KICKED);
 
	} else {
 
		IConsolePrint(CC_DEFAULT, "Client not online, banned IP");
 
	}
 

	
 
	/* Add user to ban-list */
 
	for (index = 0; index < lengthof(_network_ban_list); index++) {
 
	for (uint index = 0; index < lengthof(_network_ban_list); index++) {
 
		if (_network_ban_list[index] == NULL) {
 
			_network_ban_list[index] = strdup(banip);
 
			break;
 
		}
 
	}
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConUnBan)
 
{
 
	uint i, index;
 
@@ -546,54 +546,54 @@ DEF_CONSOLE_CMD(ConServerInfo)
 
	}
 

	
 
	IConsolePrintF(CC_DEFAULT, "Current/maximum clients:    %2d/%2d", _network_game_info.clients_on, _settings_client.network.max_clients);
 
	IConsolePrintF(CC_DEFAULT, "Current/maximum companies:  %2d/%2d", ActiveCompanyCount(), _settings_client.network.max_companies);
 
	IConsolePrintF(CC_DEFAULT, "Current/maximum spectators: %2d/%2d", NetworkSpectatorCount(), _settings_client.network.max_spectators);
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConKick)
 
{
 
	NetworkClientInfo *ci;
 
	uint32 index;
 
	ClientID client_id;
 

	
 
	if (argc == 0) {
 
		IConsoleHelp("Kick a client from a network game. Usage: 'kick <ip | client-id>'");
 
		IConsoleHelp("For client-id's, see the command 'clients'");
 
		return true;
 
	}
 

	
 
	if (argc != 2) return false;
 

	
 
	if (strchr(argv[1], '.') == NULL) {
 
		index = atoi(argv[1]);
 
		ci = NetworkFindClientInfoFromIndex(index);
 
		client_id = (ClientID)atoi(argv[1]);
 
		ci = NetworkFindClientInfoFromIndex(client_id);
 
	} else {
 
		ci = NetworkFindClientInfoFromIP(argv[1]);
 
		index = (ci == NULL) ? 0 : ci->client_index;
 
		client_id = (ci == NULL) ? INVALID_CLIENT_ID : ci->client_id;
 
	}
 

	
 
	if (index == NETWORK_SERVER_INDEX) {
 
	if (client_id == CLIENT_ID_SERVER) {
 
		IConsoleError("Silly boy, you can not kick yourself!");
 
		return true;
 
	}
 

	
 
	if (index == 0) {
 
	if (client_id == INVALID_CLIENT_ID) {
 
		IConsoleError("Invalid client");
 
		return true;
 
	}
 

	
 
	if (ci != NULL) {
 
		NetworkServerSendError(index, NETWORK_ERROR_KICKED);
 
		NetworkServerSendError(client_id, NETWORK_ERROR_KICKED);
 
	} else {
 
		IConsoleError("Client not found");
 
	}
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConResetCompany)
 
{
 
	CompanyID index;
 

	
 
	if (argc == 0) {
 
@@ -614,49 +614,49 @@ DEF_CONSOLE_CMD(ConResetCompany)
 

	
 
	const Company *c = GetCompany(index);
 

	
 
	if (c->is_ai) {
 
		IConsoleError("Company is owned by an AI.");
 
		return true;
 
	}
 

	
 
	if (NetworkCompanyHasClients(index)) {
 
		IConsoleError("Cannot remove company: a client is connected to that company.");
 
		return false;
 
	}
 
	const NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
	const NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(CLIENT_ID_SERVER);
 
	if (ci->client_playas == index) {
 
		IConsoleError("Cannot remove company: the server is connected to that company.");
 
		return true;
 
	}
 

	
 
	/* It is safe to remove this company */
 
	DoCommandP(0, 2, index, NULL, CMD_COMPANY_CTRL);
 
	IConsolePrint(CC_DEFAULT, "Company deleted.");
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConNetworkClients)
 
{
 
	NetworkClientInfo *ci;
 

	
 
	if (argc == 0) {
 
		IConsoleHelp("Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'");
 
		return true;
 
	}
 

	
 
	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
 
		IConsolePrintF(CC_INFO, "Client #%1d  name: '%s'  company: %1d  IP: %s",
 
		               ci->client_index, ci->client_name,
 
		               ci->client_id, ci->client_name,
 
		               ci->client_playas + (IsValidCompanyID(ci->client_playas) ? 1 : 0),
 
		               GetClientIP(ci));
 
	}
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConNetworkConnect)
 
{
 
	char *ip;
 
	const char *port = NULL;
 
	const char *company = NULL;
 
@@ -1123,25 +1123,25 @@ DEF_CONSOLE_CMD(ConListAliases)
 
DEF_CONSOLE_CMD(ConSay)
 
{
 
	if (argc == 0) {
 
		IConsoleHelp("Chat to your fellow players in a multiplayer game. Usage: 'say \"<msg>\"'");
 
		return true;
 
	}
 

	
 
	if (argc != 2) return false;
 

	
 
	if (!_network_server) {
 
		NetworkClientSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0 /* param does not matter */, argv[1]);
 
	} else {
 
		NetworkServerSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], NETWORK_SERVER_INDEX);
 
		NetworkServerSendChat(NETWORK_ACTION_CHAT, DESTTYPE_BROADCAST, 0, argv[1], CLIENT_ID_SERVER);
 
	}
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConCompanies)
 
{
 
	Company *c;
 

	
 
	if (argc == 0) {
 
		IConsoleHelp("List the in-game details of all clients connected to the server. Usage 'companies'");
 
		return true;
 
@@ -1176,44 +1176,44 @@ DEF_CONSOLE_CMD(ConSayCompany)
 

	
 
	if (argc != 3) return false;
 

	
 
	CompanyID company_id = (CompanyID)(atoi(argv[1]) - 1);
 
	if (!IsValidCompanyID(company_id)) {
 
		IConsolePrintF(CC_DEFAULT, "Unknown company. Company range is between 1 and %d.", MAX_COMPANIES);
 
		return true;
 
	}
 

	
 
	if (!_network_server) {
 
		NetworkClientSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2]);
 
	} else {
 
		NetworkServerSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2], NETWORK_SERVER_INDEX);
 
		NetworkServerSendChat(NETWORK_ACTION_CHAT_COMPANY, DESTTYPE_TEAM, company_id, argv[2], CLIENT_ID_SERVER);
 
	}
 

	
 
	return true;
 
}
 

	
 
DEF_CONSOLE_CMD(ConSayClient)
 
{
 
	if (argc == 0) {
 
		IConsoleHelp("Chat to a certain client in a multiplayer game. Usage: 'say_client <client-no> \"<msg>\"'");
 
		IConsoleHelp("For client-id's, see the command 'clients'");
 
		return true;
 
	}
 

	
 
	if (argc != 3) return false;
 

	
 
	if (!_network_server) {
 
		NetworkClientSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2]);
 
	} else {
 
		NetworkServerSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], NETWORK_SERVER_INDEX);
 
		NetworkServerSendChat(NETWORK_ACTION_CHAT_CLIENT, DESTTYPE_CLIENT, atoi(argv[1]), argv[2], CLIENT_ID_SERVER);
 
	}
 

	
 
	return true;
 
}
 

	
 
extern void HashCurrentCompanyPassword();
 

	
 
/* Also use from within company_gui to change the password graphically */
 
bool NetworkChangeCompanyPassword(byte argc, char *argv[])
 
{
 
	if (argc == 0) {
 
		if (!IsValidCompanyID(_local_company)) return true; // dedicated server
src/main_gui.cpp
Show inline comments
 
@@ -46,25 +46,25 @@ static int _rename_what = -1;
 
void CcGiveMoney(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
#ifdef ENABLE_NETWORK
 
	if (!success || !_settings_game.economy.give_money) return;
 

	
 
	char msg[20];
 
	/* Inform the company of the action of one of it's clients (controllers). */
 
	snprintf(msg, sizeof(msg), "%d", p1);
 

	
 
	if (!_network_server) {
 
		NetworkClientSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg);
 
	} else {
 
		NetworkServerSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, NETWORK_SERVER_INDEX);
 
		NetworkServerSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, CLIENT_ID_SERVER);
 
	}
 
#endif /* ENABLE_NETWORK */
 
}
 

	
 
void HandleOnEditText(const char *str)
 
{
 
	_cmd_text = str;
 

	
 
	switch (_rename_what) {
 
#ifdef ENABLE_NETWORK
 
	case 3: { // Give money, you can only give money in excess of loan
 
		const Company *c = GetCompany(_current_company);
 
@@ -307,25 +307,25 @@ struct MainWindow : Window
 

	
 
			case 'X' | WKC_CTRL:
 
				ShowTransparencyToolbar();
 
				break;
 

	
 
			case 'X':
 
				ResetRestoreAllTransparency();
 
				break;
 

	
 
#ifdef ENABLE_NETWORK
 
			case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
 
				if (_networking) {
 
					const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
					const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_id);
 
					bool teamchat = false;
 

	
 
					if (cio == NULL) break;
 

	
 
					/* Only companies actually playing can speak to team. Eg spectators cannot */
 
					if (_settings_client.gui.prefer_teamchat && IsValidCompanyID(cio->client_playas)) {
 
						const NetworkClientInfo *ci;
 
						FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
 
							if (ci->client_playas == cio->client_playas && ci != cio) {
 
								teamchat = true;
 
								break;
 
							}
 
@@ -333,25 +333,25 @@ struct MainWindow : Window
 
					}
 

	
 
					ShowNetworkChatQueryWindow(teamchat ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
 
				}
 
				break;
 

	
 
			case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all clients
 
				if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
 
				break;
 

	
 
			case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
 
				if (_networking) {
 
					const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
					const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_id);
 
					if (cio == NULL) break;
 

	
 
					ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas);
 
				}
 
				break;
 
#endif
 

	
 
			default: return ES_NOT_HANDLED;
 
		}
 
		return ES_HANDLED;
 
	}
 

	
src/network/core/tcp.cpp
Show inline comments
 
@@ -13,25 +13,25 @@
 

	
 
#include "../network_internal.h"
 
#include "packet.h"
 
#include "tcp.h"
 

	
 
#include "table/strings.h"
 

	
 
/** Very ugly temporary hack !!! */
 
void NetworkTCPSocketHandler::Initialize()
 
{
 
	this->sock              = INVALID_SOCKET;
 

	
 
	this->index             = 0;
 
	this->client_id         = INVALID_CLIENT_ID;
 
	this->last_frame        = 0;
 
	this->last_frame_server = 0;
 
	this->lag_test          = 0;
 

	
 
	this->status            = STATUS_INACTIVE;
 
	this->has_quit          = false;
 
	this->writable          = false;
 

	
 
	this->packet_queue      = NULL;
 
	this->packet_recv       = NULL;
 

	
 
	this->command_queue     = NULL;
src/network/core/tcp.h
Show inline comments
 
@@ -82,25 +82,25 @@ enum ClientStatus {
 
	STATUS_DONE_MAP,   ///< The client has downloaded the map
 
	STATUS_PRE_ACTIVE, ///< The client is catching up the delayed frames
 
	STATUS_ACTIVE,     ///< The client is active within in the game
 
};
 

	
 
/** Base socket handler for all TCP sockets */
 
class NetworkTCPSocketHandler : public NetworkSocketHandler {
 
/* TODO: rewrite into a proper class */
 
private:
 
	Packet *packet_queue;     ///< Packets that are awaiting delivery
 
	Packet *packet_recv;      ///< Partially received packet
 
public:
 
	uint16 index;             ///< Client index
 
	ClientID client_id;       ///< Client identifier
 
	uint32 last_frame;        ///< Last frame we have executed
 
	uint32 last_frame_server; ///< Last frame the server has executed
 
	byte lag_test;            ///< Byte used for lag-testing the client
 

	
 
	ClientStatus status;      ///< Status of this client
 
	bool writable;            ///< Can we write to this socket?
 

	
 
	CommandPacket *command_queue; ///< The command-queue awaiting delivery
 

	
 
	NetworkRecvStatus CloseConnection();
 
	void Initialize();
 
	void Destroy();
src/network/network.cpp
Show inline comments
 
@@ -34,33 +34,35 @@
 
#include "../string_func.h"
 
#include "../company_func.h"
 
#include "../settings_type.h"
 
#include "../landscape_type.h"
 
#include "../rev.h"
 
#ifdef DEBUG_DUMP_COMMANDS
 
	#include "../core/alloc_func.hpp"
 
	#include "../fileio_func.h"
 
#endif /* DEBUG_DUMP_COMMANDS */
 
#include "table/strings.h"
 
#include "../company_base.h"
 

	
 
DECLARE_POSTFIX_INCREMENT(ClientID);
 

	
 
bool _network_server;     ///< network-server is active
 
bool _network_available;  ///< is network mode available?
 
bool _network_dedicated;  ///< are we a dedicated server?
 
bool _is_network_server;  ///< Does this client wants to be a network-server?
 
NetworkServerGameInfo _network_game_info;
 
NetworkCompanyInfo _network_company_info[MAX_COMPANIES];
 
NetworkClientInfo _network_client_info[MAX_CLIENT_INFO];
 
uint16 _network_own_client_index;
 
uint16 _redirect_console_to_client;
 
ClientID _network_own_client_id;
 
ClientID _redirect_console_to_client;
 
bool _network_need_advertise;
 
uint32 _network_last_advertise_frame;
 
uint8 _network_reconnect;
 
char *_network_host_list[10];
 
char *_network_ban_list[25];
 
uint32 _frame_counter_server; // The frame_counter of the server, if in network-mode
 
uint32 _frame_counter_max; // To where we may go with our clients
 
uint32 _last_sync_frame; // Used in the server to store the last time a sync packet was sent to clients.
 
uint32 _broadcast_list[MAX_INTERFACES + 1];
 
uint32 _network_server_bind_ip;
 
uint32 _sync_seed_1, _sync_seed_2;
 
uint32 _sync_frame;
 
@@ -83,77 +85,77 @@ extern NetworkUDPSocketHandler *_udp_mas
 

	
 
// Here we keep track of the clients
 
//  (and the client uses [0] for his own communication)
 
NetworkTCPSocketHandler _clients[MAX_CLIENTS];
 

	
 

	
 

	
 
// The listen socket for the server
 
static SOCKET _listensocket;
 

	
 
// The amount of clients connected
 
static byte _network_clients_connected = 0;
 
// The index counter for new clients (is never decreased)
 
static uint16 _network_client_index = NETWORK_SERVER_INDEX + 1;
 
// The identifier counter for new clients (is never decreased)
 
static ClientID _network_client_id = CLIENT_ID_FIRST;
 

	
 
/* Some externs / forwards */
 
extern void StateGameLoop();
 

	
 
// Function that looks up the CI for a given client-index
 
NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index)
 
// Function that looks up the CI for a given client-identifier
 
NetworkClientInfo *NetworkFindClientInfoFromIndex(ClientID client_id)
 
{
 
	NetworkClientInfo *ci;
 

	
 
	for (ci = _network_client_info; ci != endof(_network_client_info); ci++) {
 
		if (ci->client_index == client_index) return ci;
 
		if (ci->client_id == client_id) return ci;
 
	}
 

	
 
	return NULL;
 
}
 

	
 
/** Return the CI for a given IP
 
 * @param ip IP of the client we are looking for. This must be in string-format
 
 * @return return a pointer to the corresponding NetworkClientInfo struct or NULL on failure */
 
NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip)
 
{
 
	NetworkClientInfo *ci;
 
	uint32 ip_number = inet_addr(ip);
 

	
 
	for (ci = _network_client_info; ci != endof(_network_client_info); ci++) {
 
		if (ci->client_ip == ip_number) return ci;
 
	}
 

	
 
	return NULL;
 
}
 

	
 
// Function that looks up the CS for a given client-index
 
NetworkTCPSocketHandler *NetworkFindClientStateFromIndex(uint16 client_index)
 
// Function that looks up the CS for a given client-identifier
 
NetworkTCPSocketHandler *NetworkFindClientStateFromClientID(ClientID client_id)
 
{
 
	NetworkTCPSocketHandler *cs;
 

	
 
	for (cs = _clients; cs != endof(_clients); cs++) {
 
		if (cs->index == client_index) return cs;
 
		if (cs->client_id == client_id) return cs;
 
	}
 

	
 
	return NULL;
 
}
 

	
 
// NetworkGetClientName is a server-safe function to get the name of the client
 
//  if the user did not send it yet, Client #<no> is used.
 
void NetworkGetClientName(char *client_name, size_t size, const NetworkTCPSocketHandler *cs)
 
{
 
	const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
 

	
 
	if (ci->client_name[0] == '\0') {
 
		snprintf(client_name, size, "Client #%4d", cs->index);
 
		snprintf(client_name, size, "Client #%4d", cs->client_id);
 
	} else {
 
		ttd_strlcpy(client_name, ci->client_name, size);
 
	}
 
}
 

	
 
byte NetworkSpectatorCount()
 
{
 
	NetworkTCPSocketHandler *cs;
 
	byte count = 0;
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		if (DEREF_CLIENT_INFO(cs)->client_playas == COMPANY_SPECTATOR) count++;
 
@@ -352,31 +354,31 @@ static uint NetworkCountActiveClients()
 
static bool _min_active_clients_paused = false;
 

	
 
/* Check if the minimum number of active clients has been reached and pause or unpause the game as appropriate */
 
void CheckMinActiveClients()
 
{
 
	if (!_network_dedicated) return;
 

	
 
	if (NetworkCountActiveClients() < _settings_client.network.min_active_clients) {
 
		if (_min_active_clients_paused) return;
 

	
 
		_min_active_clients_paused = true;
 
		DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
 
		NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (not enough players)", NETWORK_SERVER_INDEX);
 
		NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (not enough players)", CLIENT_ID_SERVER);
 
	} else {
 
		if (!_min_active_clients_paused) return;
 

	
 
		_min_active_clients_paused = false;
 
		DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
 
		NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (enough players)", NETWORK_SERVER_INDEX);
 
		NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (enough players)", CLIENT_ID_SERVER);
 
	}
 
}
 

	
 
/** Converts a string to ip/port/company
 
 *  Format: IP#company:port
 
 *
 
 * connection_string will be re-terminated to seperate out the hostname, and company and port will
 
 * be set to the company and port strings given by the user, inside the memory area originally
 
 * occupied by connection_string. */
 
void ParseConnectionString(const char **company, const char **port, char *connection_string)
 
{
 
	char *p;
 
@@ -411,72 +413,72 @@ static NetworkTCPSocketHandler *NetworkA
 
	}
 

	
 
	cs = DEREF_CLIENT(client_no);
 
	cs->Initialize();
 
	cs->sock = s;
 
	cs->last_frame = _frame_counter;
 
	cs->last_frame_server = _frame_counter;
 

	
 
	if (_network_server) {
 
		NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
 
		memset(ci, 0, sizeof(*ci));
 

	
 
		cs->index = _network_client_index++;
 
		ci->client_index = cs->index;
 
		cs->client_id = _network_client_id++;
 
		ci->client_id = cs->client_id;
 
		ci->client_playas = COMPANY_INACTIVE_CLIENT;
 
		ci->join_date = _date;
 

	
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 
	}
 

	
 
	return cs;
 
}
 

	
 
// Close a connection
 
void NetworkCloseClient(NetworkTCPSocketHandler *cs)
 
{
 
	NetworkClientInfo *ci;
 
	// Socket is already dead
 
	if (cs->sock == INVALID_SOCKET) {
 
		cs->has_quit = true;
 
		return;
 
	}
 

	
 
	DEBUG(net, 1, "Closed client connection %d", cs->index);
 
	DEBUG(net, 1, "Closed client connection %d", cs->client_id);
 

	
 
	if (!cs->has_quit && _network_server && cs->status > STATUS_INACTIVE) {
 
		// We did not receive a leave message from this client...
 
		NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST;
 
		char str[100];
 
		char client_name[NETWORK_CLIENT_NAME_LENGTH];
 
		NetworkTCPSocketHandler *new_cs;
 

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

	
 
		GetNetworkErrorMsg(str, errorno, lastof(str));
 

	
 
		NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "%s", str);
 

	
 
		// 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);
 
				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->client_id, errorno);
 
			}
 
		}
 
	}
 

	
 
	/* When the client was PRE_ACTIVE, the server was in pause mode, so unpause */
 
	if (cs->status == STATUS_PRE_ACTIVE && _settings_client.network.pause_on_join) {
 
		DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
 
		NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused", NETWORK_SERVER_INDEX);
 
		NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused", CLIENT_ID_SERVER);
 
	}
 

	
 
	cs->Destroy();
 

	
 
	// Close the gap in the client-list
 
	ci = DEREF_CLIENT_INFO(cs);
 

	
 
	if (_network_server) {
 
		// We just lost one client :(
 
		if (cs->status >= STATUS_AUTH) _network_game_info.clients_on--;
 
		_network_clients_connected--;
 

	
 
@@ -484,26 +486,26 @@ void NetworkCloseClient(NetworkTCPSocket
 
			*cs = *(cs + 1);
 
			*ci = *(ci + 1);
 
			cs++;
 
			ci++;
 
		}
 

	
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 
	}
 

	
 
	// Reset the status of the last socket
 
	cs->sock = INVALID_SOCKET;
 
	cs->status = STATUS_INACTIVE;
 
	cs->index = NETWORK_EMPTY_INDEX;
 
	ci->client_index = NETWORK_EMPTY_INDEX;
 
	cs->client_id = INVALID_CLIENT_ID;
 
	ci->client_id = INVALID_CLIENT_ID;
 

	
 
	CheckMinActiveClients();
 
}
 

	
 
// A client wants to connect to a server
 
static bool NetworkConnect(const char *hostname, int port)
 
{
 
	SOCKET s;
 
	struct sockaddr_in sin;
 

	
 
	DEBUG(net, 1, "Connecting to %s %d", hostname, port);
 

	
 
@@ -799,29 +801,29 @@ static void NetworkInitGameInfo()
 
{
 
	NetworkClientInfo *ci;
 

	
 
	if (StrEmpty(_settings_client.network.server_name)) {
 
		snprintf(_settings_client.network.server_name, sizeof(_settings_client.network.server_name), "Unnamed Server");
 
	}
 

	
 
	/* The server is a client too */
 
	_network_game_info.clients_on = _network_dedicated ? 0 : 1;
 
	_network_game_info.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
 

	
 
	// We use _network_client_info[MAX_CLIENT_INFO - 1] to store the server-data in it
 
	//  The index is NETWORK_SERVER_INDEX ( = 1)
 
	//  The client identifier is CLIENT_ID_SERVER ( = 1)
 
	ci = &_network_client_info[MAX_CLIENT_INFO - 1];
 
	memset(ci, 0, sizeof(*ci));
 

	
 
	ci->client_index = NETWORK_SERVER_INDEX;
 
	ci->client_id = CLIENT_ID_SERVER;
 
	ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : _local_company;
 

	
 
	strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name));
 
	strecpy(ci->unique_id, _settings_client.network.network_id, lastof(ci->unique_id));
 
}
 

	
 
bool NetworkServerStart()
 
{
 
	if (!_network_available) return false;
 

	
 
	/* Call the pre-scripts */
 
	IConsoleCmdExec("exec scripts/pre_server.scr 0");
 
@@ -831,25 +833,25 @@ bool NetworkServerStart()
 
	if (!NetworkListen()) return false;
 

	
 
	// Try to start UDP-server
 
	_network_udp_server = true;
 
	_network_udp_server = _udp_server_socket->Listen(_network_server_bind_ip, _settings_client.network.server_port, false);
 

	
 
	_network_server = true;
 
	_networking = true;
 
	_frame_counter = 0;
 
	_frame_counter_server = 0;
 
	_frame_counter_max = 0;
 
	_last_sync_frame = 0;
 
	_network_own_client_index = NETWORK_SERVER_INDEX;
 
	_network_own_client_id = CLIENT_ID_SERVER;
 

	
 
	/* Non-dedicated server will always be company #1 */
 
	if (!_network_dedicated) _network_playas = COMPANY_FIRST;
 

	
 
	_network_clients_connected = 0;
 

	
 
	NetworkInitGameInfo();
 

	
 
	// execute server initialization script
 
	IConsoleCmdExec("exec scripts/on_server.scr 0");
 
	// if the server is dedicated ... add some other script
 
	if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
src/network/network_chat_gui.cpp
Show inline comments
 
@@ -250,25 +250,25 @@ void NetworkDrawChatMessage()
 

	
 
	_chatmessage_visible = true;
 
	_chatmessage_dirty = false;
 
}
 

	
 

	
 
static void SendChat(const char *buf, DestType type, int dest)
 
{
 
	if (StrEmpty(buf)) return;
 
	if (!_network_server) {
 
		SEND_COMMAND(PACKET_CLIENT_CHAT)((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf);
 
	} else {
 
		NetworkServerSendChat((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf, NETWORK_SERVER_INDEX);
 
		NetworkServerSendChat((NetworkAction)(NETWORK_ACTION_CHAT + type), type, dest, buf, CLIENT_ID_SERVER);
 
	}
 
}
 

	
 

	
 
struct NetworkChatWindow : public QueryStringBaseWindow {
 
	DestType dtype;
 
	int dest;
 

	
 
	NetworkChatWindow (const WindowDesc *desc, DestType type, int dest) : QueryStringBaseWindow(NETWORK_CHAT_LENGTH, desc)
 
	{
 
		this->LowerWidget(2);
 
		this->dtype   = type;
 
@@ -292,25 +292,25 @@ struct NetworkChatWindow : public QueryS
 
	 * Find the next item of the list of things that can be auto-completed.
 
	 * @param item The current indexed item to return. This function can, and most
 
	 *     likely will, alter item, to skip empty items in the arrays.
 
	 * @return Returns the char that matched to the index.
 
	 */
 
	const char *ChatTabCompletionNextItem(uint *item)
 
	{
 
		static char chat_tab_temp_buffer[64];
 

	
 
		/* First, try clients */
 
		if (*item < MAX_CLIENT_INFO) {
 
			/* Skip inactive clients */
 
			while (_network_client_info[*item].client_index == NETWORK_EMPTY_INDEX && *item < MAX_CLIENT_INFO) (*item)++;
 
			while (_network_client_info[*item].client_id == INVALID_CLIENT_ID && *item < MAX_CLIENT_INFO) (*item)++;
 
			if (*item < MAX_CLIENT_INFO) return _network_client_info[*item].client_name;
 
		}
 

	
 
		/* Then, try townnames */
 
		/* Not that the following assumes all town indices are adjacent, ie no
 
		* towns have been deleted. */
 
		if (*item <= (uint)MAX_CLIENT_INFO + GetMaxTownIndex()) {
 
			const Town *t;
 

	
 
			FOR_ALL_TOWNS_FROM(t, *item - MAX_CLIENT_INFO) {
 
				/* Get the town-name via the string-system */
 
				SetDParam(0, t->index);
src/network/network_client.cpp
Show inline comments
 
@@ -235,33 +235,33 @@ DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLI
 
	MY_CLIENT->Send_Packet(p);
 
}
 

	
 
// Send a chat-packet over the network
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_CHAT)(NetworkAction action, DestType type, int dest, const char *msg)
 
{
 
	//
 
	// Packet: CLIENT_CHAT
 
	// Function: Send a chat-packet to the serve
 
	// Data:
 
	//    uint8:  ActionID (see network_data.h, NetworkAction)
 
	//    uint8:  Destination Type (see network_data.h, DestType);
 
	//    uint16: Destination Company/Client
 
	//    uint32: Destination CompanyID/Client-identifier
 
	//    String: Message (max NETWORK_CHAT_LENGTH)
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_CLIENT_CHAT);
 

	
 
	p->Send_uint8 (action);
 
	p->Send_uint8 (type);
 
	p->Send_uint16(dest);
 
	p->Send_uint32(dest);
 
	p->Send_string(msg);
 
	MY_CLIENT->Send_Packet(p);
 
}
 

	
 
// Send an error-packet over the network
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_ERROR)(NetworkErrorCode errorno)
 
{
 
	//
 
	// Packet: CLIENT_ERROR
 
	// Function: The client made an error and is quiting the game
 
	// Data:
 
	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
 
@@ -383,62 +383,62 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER
 

	
 
		p->Recv_string(_network_company_info[current].clients, sizeof(_network_company_info[current].clients));
 

	
 
		InvalidateWindow(WC_NETWORK_WINDOW, 0);
 

	
 
		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'
 
//  as client we save this in NetworkClientInfo, linked via 'client_id'
 
//  which is always an unique number on a server.
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO)
 
{
 
	NetworkClientInfo *ci;
 
	uint16 index = p->Recv_uint16();
 
	ClientID client_id = (ClientID)p->Recv_uint32();
 
	CompanyID playas = (CompanyID)p->Recv_uint8();
 
	char name[NETWORK_NAME_LENGTH];
 

	
 
	p->Recv_string(name, sizeof(name));
 

	
 
	if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_CONN_LOST;
 

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

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	ci = NetworkFindClientInfoFromIndex(client_id);
 
	if (ci != NULL) {
 
		if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) {
 
			// Client name changed, display the change
 
			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, "%s", name);
 
		} else if (playas != ci->client_playas) {
 
			// The client changed from client-player..
 
			// Do not display that for now
 
		}
 

	
 
		ci->client_playas = playas;
 
		strecpy(ci->client_name, name, lastof(ci->client_name));
 

	
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 

	
 
		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);
 
	// We don't have this client_id yet, find an empty client_id, and put the data there
 
	ci = NetworkFindClientInfoFromIndex(INVALID_CLIENT_ID);
 
	if (ci != NULL) {
 
		ci->client_index = index;
 
		ci->client_id = client_id;
 
		ci->client_playas = playas;
 

	
 
		strecpy(ci->client_name, name, lastof(ci->client_name));
 

	
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 

	
 
		return NETWORK_RECV_STATUS_OKAY;
 
	}
 

	
 
	// Here the program should never ever come.....
 
	return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 
}
 
@@ -521,25 +521,25 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER
 
			if (MY_CLIENT->has_quit) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 

	
 
		case NETWORK_GAME_PASSWORD:
 
			ShowNetworkNeedPassword(type);
 
			return NETWORK_RECV_STATUS_OKAY;
 

	
 
		default: return NETWORK_RECV_STATUS_MALFORMED_PACKET;
 
	}
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WELCOME)
 
{
 
	_network_own_client_index = p->Recv_uint16();
 
	_network_own_client_id = (ClientID)p->Recv_uint32();
 

	
 
	/* Initialize the password hash salting variables, even if they were previously. */
 
	_password_game_seed = p->Recv_uint32();
 
	p->Recv_string(_password_server_unique_id, sizeof(_password_server_unique_id));
 

	
 
	// Start receiving the map
 
	SEND_COMMAND(PACKET_CLIENT_GETMAP)();
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_WAIT)
 
{
 
@@ -708,120 +708,115 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER
 
		c->next = cp;
 
	}
 

	
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHAT)
 
{
 
	char name[NETWORK_NAME_LENGTH], msg[NETWORK_CHAT_LENGTH];
 
	const NetworkClientInfo *ci = NULL, *ci_to;
 

	
 
	NetworkAction action = (NetworkAction)p->Recv_uint8();
 
	uint16 index = p->Recv_uint16();
 
	ClientID client_id = (ClientID)p->Recv_uint32();
 
	bool self_send = p->Recv_bool();
 
	p->Recv_string(msg, NETWORK_CHAT_LENGTH);
 

	
 
	ci_to = NetworkFindClientInfoFromIndex(index);
 
	ci_to = NetworkFindClientInfoFromIndex(client_id);
 
	if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY;
 

	
 
	/* Did we initiate the action locally? */
 
	if (self_send) {
 
		switch (action) {
 
			case NETWORK_ACTION_CHAT_CLIENT:
 
				/* For speaking to client we need the client-name */
 
				snprintf(name, sizeof(name), "%s", ci_to->client_name);
 
				ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
				ci = NetworkFindClientInfoFromIndex(_network_own_client_id);
 
				break;
 

	
 
			/* For speaking to company or giving money, we need the company-name */
 
			case NETWORK_ACTION_GIVE_MONEY:
 
				if (!IsValidCompanyID(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY;
 
				/* fallthrough */
 
			case NETWORK_ACTION_CHAT_COMPANY: {
 
				StringID str = IsValidCompanyID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
 
				SetDParam(0, ci_to->client_playas);
 

	
 
				GetString(name, str, lastof(name));
 
				ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
				ci = NetworkFindClientInfoFromIndex(_network_own_client_id);
 
			} break;
 

	
 
			default: NOT_REACHED(); break;
 
		}
 
	} else {
 
		/* Display message from somebody else */
 
		snprintf(name, sizeof(name), "%s", ci_to->client_name);
 
		ci = ci_to;
 
	}
 

	
 
	if (ci != NULL)
 
		NetworkTextMessage(action, (ConsoleColour)GetDrawStringCompanyColor(ci->client_playas), self_send, name, "%s", msg);
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR_QUIT)
 
{
 
	char str[100];
 
	uint16 index;
 
	NetworkClientInfo *ci;
 

	
 
	index = p->Recv_uint16();
 
	ClientID client_id = (ClientID)p->Recv_uint32();
 
	GetNetworkErrorMsg(str, (NetworkErrorCode)p->Recv_uint8(), lastof(str));
 

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	ci = NetworkFindClientInfoFromIndex(client_id);
 
	if (ci != NULL) {
 
		NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, "%s", str);
 

	
 
		// The client is gone, give the NetworkClientInfo free
 
		ci->client_index = NETWORK_EMPTY_INDEX;
 
		ci->client_id = INVALID_CLIENT_ID;
 
	}
 

	
 
	InvalidateWindow(WC_CLIENT_LIST, 0);
 

	
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_QUIT)
 
{
 
	char str[100];
 
	uint16 index;
 
	NetworkClientInfo *ci;
 

	
 
	index = p->Recv_uint16();
 
	ClientID client_id = (ClientID)p->Recv_uint32();
 
	p->Recv_string(str, lengthof(str));
 

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	ci = NetworkFindClientInfoFromIndex(client_id);
 
	if (ci != NULL) {
 
		NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, "%s", str);
 

	
 
		// The client is gone, give the NetworkClientInfo free
 
		ci->client_index = NETWORK_EMPTY_INDEX;
 
		ci->client_id = INVALID_CLIENT_ID;
 
	} else {
 
		DEBUG(net, 0, "Unknown client (%d) is leaving the game", index);
 
		DEBUG(net, 0, "Unknown client (%d) is leaving the game", client_id);
 
	}
 

	
 
	InvalidateWindow(WC_CLIENT_LIST, 0);
 

	
 
	// If we come here it means we could not locate the client.. strange :s
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_JOIN)
 
{
 
	uint16 index;
 
	NetworkClientInfo *ci;
 
	ClientID client_id = (ClientID)p->Recv_uint32();
 

	
 
	index = p->Recv_uint16();
 

	
 
	ci = NetworkFindClientInfoFromIndex(index);
 
	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_id);
 
	if (ci != NULL)
 
		NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name, "");
 

	
 
	InvalidateWindow(WC_CLIENT_LIST, 0);
 

	
 
	return NETWORK_RECV_STATUS_OKAY;
 
}
 

	
 
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_SHUTDOWN)
 
{
 
	_switch_mode_errorstr = STR_NETWORK_SERVER_SHUTDOWN;
 

	
 
@@ -931,37 +926,37 @@ NetworkRecvStatus NetworkClient_ReadPack
 
	}
 

	
 
	return res;
 
}
 

	
 
void NetworkClientSendRcon(const char *password, const char *command)
 
{
 
	SEND_COMMAND(PACKET_CLIENT_RCON)(password, command);
 
}
 

	
 
void NetworkUpdateClientName()
 
{
 
	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_index);
 
	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(_network_own_client_id);
 

	
 
	if (ci == NULL) return;
 

	
 
	/* Don't change the name if it is the same as the old name */
 
	if (strcmp(ci->client_name, _settings_client.network.client_name) != 0) {
 
		if (!_network_server) {
 
			SEND_COMMAND(PACKET_CLIENT_SET_NAME)(_settings_client.network.client_name);
 
		} else {
 
			if (NetworkFindName(_settings_client.network.client_name)) {
 
				NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, "%s", _settings_client.network.client_name);
 
				strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name));
 
				NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
 
				NetworkUpdateClientInfo(CLIENT_ID_SERVER);
 
			}
 
		}
 
	}
 
}
 

	
 
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg)
 
{
 
	SEND_COMMAND(PACKET_CLIENT_CHAT)(action, type, dest, msg);
 
}
 

	
 
void NetworkClientSetPassword()
 
{
src/network/network_func.h
Show inline comments
 
@@ -5,64 +5,64 @@
 
#ifndef NETWORK_FUNC_H
 
#define NETWORK_FUNC_H
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "network_type.h"
 
#include "../console_type.h"
 

	
 
extern NetworkServerGameInfo _network_game_info;
 
extern NetworkCompanyInfo _network_company_info[MAX_COMPANIES];
 
extern NetworkClientInfo _network_client_info[MAX_CLIENT_INFO];
 

	
 
extern uint16 _network_own_client_index;
 
extern uint16 _redirect_console_to_client;
 
extern ClientID _network_own_client_id;
 
extern ClientID _redirect_console_to_client;
 
extern bool _network_need_advertise;
 
extern uint32 _network_last_advertise_frame;
 
extern uint8 _network_reconnect;
 
extern char *_network_host_list[10];
 
extern char *_network_ban_list[25];
 

	
 
byte NetworkSpectatorCount();
 
void CheckMinActiveClients();
 
void NetworkUpdateClientName();
 
bool NetworkCompanyHasClients(CompanyID company);
 
bool NetworkChangeCompanyPassword(byte argc, char *argv[]);
 
void NetworkReboot();
 
void NetworkDisconnect();
 
void NetworkGameLoop();
 
void NetworkUDPGameLoop();
 
void NetworkUDPCloseAll();
 
void ParseConnectionString(const char **company, const char **port, char *connection_string);
 
void NetworkStartDebugLog(const char *hostname, uint16 port);
 
void NetworkPopulateCompanyInfo();
 

	
 
void NetworkUpdateClientInfo(uint16 client_index);
 
void NetworkUpdateClientInfo(ClientID client_id);
 
bool NetworkClientConnectGame(const char *host, uint16 port);
 
void NetworkClientSendRcon(const char *password, const char *command);
 
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg);
 
void NetworkClientSetPassword();
 

	
 
/*** Commands ran by the server ***/
 
void NetworkServerMonthlyLoop();
 
void NetworkServerYearlyLoop();
 
void NetworkServerChangeOwner(Owner current_owner, Owner new_owner);
 
void NetworkServerShowStatusToConsole();
 
bool NetworkServerStart();
 

	
 
NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index);
 
NetworkClientInfo *NetworkFindClientInfoFromIndex(ClientID client_id);
 
NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip);
 
const char* GetClientIP(const NetworkClientInfo *ci);
 

	
 
void NetworkServerSendRcon(uint16 client_index, ConsoleColour colour_code, const char *string);
 
void NetworkServerSendError(uint16 client_index, NetworkErrorCode error);
 
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const char *msg, uint16 from_index);
 
void NetworkServerSendRcon(ClientID client_id, ConsoleColour colour_code, const char *string);
 
void NetworkServerSendError(ClientID client_id, NetworkErrorCode error);
 
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const char *msg, ClientID from_id);
 

	
 
void NetworkInitChatMessage();
 
void CDECL NetworkAddChatMessage(uint16 color, uint8 duration, const char *message, ...);
 
void NetworkUndrawChatMessage();
 
void NetworkChatMessageDailyLoop();
 

	
 
#define FOR_ALL_ACTIVE_CLIENT_INFOS(ci) for (ci = _network_client_info; ci != endof(_network_client_info); ci++) if (ci->client_index != NETWORK_EMPTY_INDEX)
 
#define FOR_ALL_ACTIVE_CLIENT_INFOS(ci) for (ci = _network_client_info; ci != endof(_network_client_info); ci++) if (ci->client_id != INVALID_CLIENT_ID)
 

	
 
#endif /* ENABLE_NETWORK */
 
#endif /* NETWORK_FUNC_H */
src/network/network_gui.cpp
Show inline comments
 
@@ -1438,25 +1438,25 @@ static void ClientList_Ban(byte client_n
 
}
 

	
 
static void ClientList_GiveMoney(byte client_no)
 
{
 
	if (NetworkFindClientInfo(client_no) != NULL) {
 
		ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
 
	}
 
}
 

	
 
static void ClientList_SpeakToClient(byte client_no)
 
{
 
	if (NetworkFindClientInfo(client_no) != NULL) {
 
		ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_index);
 
		ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_id);
 
	}
 
}
 

	
 
static void ClientList_SpeakToCompany(byte client_no)
 
{
 
	if (NetworkFindClientInfo(client_no) != NULL) {
 
		ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
 
	}
 
}
 

	
 
static void ClientList_SpeakToAll(byte client_no)
 
{
 
@@ -1479,46 +1479,46 @@ struct NetworkClientListPopupWindow : Wi
 
	NetworkClientListPopupWindow(int x, int y, const Widget *widgets, int client_no) :
 
			Window(x, y, 150, 100, WC_TOOLBAR_MENU, widgets),
 
			sel_index(0), client_no(client_no)
 
	{
 
		/*
 
		 * Fill the actions this client has.
 
		 * Watch is, max 50 chars long!
 
		 */
 

	
 
		const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
 

	
 
		int i = 0;
 
		if (_network_own_client_index != ci->client_index) {
 
		if (_network_own_client_id != ci->client_id) {
 
			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(this->action[i]));
 
			this->proc[i++] = &ClientList_SpeakToClient;
 
		}
 

	
 
		if (IsValidCompanyID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) {
 
			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(this->action[i]));
 
			this->proc[i++] = &ClientList_SpeakToCompany;
 
		}
 
		GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
 
		this->proc[i++] = &ClientList_SpeakToAll;
 

	
 
		if (_network_own_client_index != ci->client_index) {
 
		if (_network_own_client_id != ci->client_id) {
 
			/* We are no spectator and the company we want to give money to is no spectator and money gifts are allowed */
 
			if (IsValidCompanyID(_network_playas) && IsValidCompanyID(ci->client_playas) && _settings_game.economy.give_money) {
 
				GetString(this->action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(this->action[i]));
 
				this->proc[i++] = &ClientList_GiveMoney;
 
			}
 
		}
 

	
 
		/* A server can kick clients (but not himself) */
 
		if (_network_server && _network_own_client_index != ci->client_index) {
 
		if (_network_server && _network_own_client_id != ci->client_id) {
 
			GetString(this->action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(this->action[i]));
 
			this->proc[i++] = &ClientList_Kick;
 

	
 
			seprintf(this->action[i], lastof(this->action[i]), "Ban"); // XXX GetString?
 
			this->proc[i++] = &ClientList_Ban;
 
		}
 

	
 
		if (i == 0) {
 
			GetString(this->action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(this->action[i]));
 
			this->proc[i++] = &ClientList_None;
 
		}
 

	
 
@@ -1675,25 +1675,25 @@ struct NetworkClientListWindow : Window
 

	
 
		int y = CLNWND_OFFSET;
 

	
 
		FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
 
			TextColour colour;
 
			if (this->selected_item == i++) { // Selected item, highlight it
 
				GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
 
				colour = TC_WHITE;
 
			} else {
 
				colour = TC_BLACK;
 
			}
 

	
 
			if (ci->client_index == NETWORK_SERVER_INDEX) {
 
			if (ci->client_id == CLIENT_ID_SERVER) {
 
				DrawString(4, y, STR_NETWORK_SERVER, colour);
 
			} else {
 
				DrawString(4, y, STR_NETWORK_CLIENT, colour);
 
			}
 

	
 
			/* Filter out spectators */
 
			if (IsValidCompanyID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, 64, y + 1);
 

	
 
			DoDrawString(ci->client_name, 81, y, colour);
 

	
 
			y += CLNWND_ROWSIZE;
 
		}
src/network/network_internal.h
Show inline comments
 
@@ -135,25 +135,25 @@ void UpdateNetworkGameWindow(bool unsele
 

	
 
bool IsNetworkCompatibleVersion(const char *version);
 

	
 
void NetworkExecuteCommand(CommandPacket *cp);
 
void NetworkAddCommandQueue(NetworkTCPSocketHandler *cs, CommandPacket *cp);
 

	
 
// from network.c
 
void NetworkCloseClient(NetworkTCPSocketHandler *cs);
 
void CDECL NetworkTextMessage(NetworkAction action, ConsoleColour color, bool self_send, const char *name, const char *str, ...);
 
void NetworkGetClientName(char *clientname, size_t size, const NetworkTCPSocketHandler *cs);
 
uint NetworkCalculateLag(const NetworkTCPSocketHandler *cs);
 
byte NetworkGetCurrentLanguageIndex();
 
NetworkTCPSocketHandler *NetworkFindClientStateFromIndex(uint16 client_index);
 
NetworkTCPSocketHandler *NetworkFindClientStateFromClientID(ClientID client_id);
 
char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last);
 
bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH]);
 

	
 
#define DEREF_CLIENT(i) (&_clients[i])
 
// This returns the NetworkClientInfo from a NetworkClientState
 
#define DEREF_CLIENT_INFO(cs) (&_network_client_info[cs - _clients])
 

	
 
// Macros to make life a bit more easier
 
#define DEF_CLIENT_RECEIVE_COMMAND(type) NetworkRecvStatus NetworkPacketReceive_ ## type ## _command(Packet *p)
 
#define DEF_CLIENT_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command()
 
#define DEF_CLIENT_SEND_COMMAND_PARAM(type) void NetworkPacketSend_ ## type ## _command
 
#define DEF_SERVER_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(NetworkTCPSocketHandler *cs, Packet *p)
src/network/network_server.cpp
Show inline comments
 
@@ -37,32 +37,32 @@ static void NetworkHandleCommandQueue(Ne
 

	
 
// **********
 
// Sending functions
 
//   DEF_SERVER_SEND_COMMAND has parameter: NetworkTCPSocketHandler *cs
 
// **********
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(NetworkTCPSocketHandler *cs, NetworkClientInfo *ci)
 
{
 
	//
 
	// Packet: SERVER_CLIENT_INFO
 
	// Function: Sends info about a client
 
	// Data:
 
	//    uint16:  The index of the client (always unique on a server. 1 = server)
 
	//    uint32:  The identifier of the client (always unique on a server. 1 = server, 0 is invalid)
 
	//    uint8:  As which company the client is playing
 
	//    String: The name of the client
 
	//
 

	
 
	if (ci->client_index != NETWORK_EMPTY_INDEX) {
 
	if (ci->client_id != INVALID_CLIENT_ID) {
 
		Packet *p = NetworkSend_Init(PACKET_SERVER_CLIENT_INFO);
 
		p->Send_uint16(ci->client_index);
 
		p->Send_uint32(ci->client_id);
 
		p->Send_uint8 (ci->client_playas);
 
		p->Send_string(ci->client_name);
 

	
 
		cs->Send_Packet(p);
 
	}
 
}
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)
 
{
 
//
 
	// Packet: SERVER_COMPANY_INFO
 
	// Function: Sends info about the companies
 
@@ -156,29 +156,29 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SER
 

	
 
		DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
 

	
 
		NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "%s", str);
 

	
 
		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);
 
				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->client_id, error);
 
			}
 
		}
 
	} else {
 
		DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", cs->index, str);
 
		DEBUG(net, 1, "Client %d made an error and has been disconnected. Reason: '%s'", cs->client_id, str);
 
	}
 

	
 
	cs->has_quit = true;
 

	
 
	// Make sure the data get's there before we close the connection
 
	cs->Send_Packets();
 

	
 
	// The client made a mistake, so drop his connection now!
 
	NetworkCloseClient(cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHECK_NEWGRFS)(NetworkTCPSocketHandler *cs)
 
@@ -227,49 +227,49 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SER
 
	p->Send_uint8(type);
 
	p->Send_uint32(_settings_game.game_creation.generation_seed);
 
	p->Send_string(_settings_client.network.network_id);
 
	cs->Send_Packet(p);
 
}
 

	
 
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
 
	//    uint32:  Own Client identifier
 
	//
 

	
 
	Packet *p;
 
	NetworkTCPSocketHandler *new_cs;
 

	
 
	// Invalid packet when status is AUTH or higher
 
	if (cs->status >= STATUS_AUTH) return;
 

	
 
	cs->status = STATUS_AUTH;
 
	_network_game_info.clients_on++;
 

	
 
	p = NetworkSend_Init(PACKET_SERVER_WELCOME);
 
	p->Send_uint16(cs->index);
 
	p->Send_uint32(cs->client_id);
 
	p->Send_uint32(_settings_game.game_creation.generation_seed);
 
	p->Send_string(_settings_client.network.network_id);
 
	cs->Send_Packet(p);
 

	
 
		// 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));
 
	SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, NetworkFindClientInfoFromIndex(CLIENT_ID_SERVER));
 
}
 

	
 
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;
 
@@ -393,38 +393,38 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MA
 
		// Send all packets (forced) and check if we have send it all
 
		cs->Send_Packets();
 
		if (cs->IsPacketQueueEmpty()) {
 
			// 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;
 
		}
 
	}
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(NetworkTCPSocketHandler *cs, uint16 client_index)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(NetworkTCPSocketHandler *cs, ClientID client_id)
 
{
 
	//
 
	// 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
 
	//    uint32:  Client-identifier
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_JOIN);
 

	
 
	p->Send_uint16(client_index);
 
	p->Send_uint32(client_id);
 

	
 
	cs->Send_Packet(p);
 
}
 

	
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_FRAME)
 
{
 
	//
 
	// Packet: SERVER_FRAME
 
	// Function: Sends the current frame-counter to the client
 
	// Data:
 
	//    uint32: Frame Counter
 
@@ -490,78 +490,78 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SER
 
	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);
 
	p->Send_bool  (cp->my_cmd);
 

	
 
	cs->Send_Packet(p);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(NetworkTCPSocketHandler *cs, NetworkAction action, uint16 client_index, bool self_send, const char *msg)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(NetworkTCPSocketHandler *cs, NetworkAction action, ClientID client_id, bool self_send, const char *msg)
 
{
 
	//
 
	// Packet: SERVER_CHAT
 
	// Function: Sends a chat-packet to the client
 
	// Data:
 
	//    uint8:  ActionID (see network_data.h, NetworkAction)
 
	//    uint16:  Client-index
 
	//    uint32:  Client-identifier
 
	//    String: Message (max NETWORK_CHAT_LENGTH)
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_CHAT);
 

	
 
	p->Send_uint8 (action);
 
	p->Send_uint16(client_index);
 
	p->Send_uint32(client_id);
 
	p->Send_bool  (self_send);
 
	p->Send_string(msg);
 

	
 
	cs->Send_Packet(p);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkTCPSocketHandler *cs, uint16 client_index, NetworkErrorCode errorno)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkTCPSocketHandler *cs, ClientID client_id, NetworkErrorCode errorno)
 
{
 
	//
 
	// 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
 
	//    uint32:  Client-identifier
 
	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR_QUIT);
 

	
 
	p->Send_uint16(client_index);
 
	p->Send_uint32(client_id);
 
	p->Send_uint8 (errorno);
 

	
 
	cs->Send_Packet(p);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(NetworkTCPSocketHandler *cs, uint16 client_index, const char *leavemsg)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(NetworkTCPSocketHandler *cs, ClientID client_id, const char *leavemsg)
 
{
 
	//
 
	// Packet: SERVER_ERROR_QUIT
 
	// Function: A client left the game, and this packets informs the other clients
 
	//      of that.
 
	// Data:
 
	//    uint16:  Client-index
 
	//    uint32:  Client-identifier
 
	//    String: leave-message
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_QUIT);
 

	
 
	p->Send_uint16(client_index);
 
	p->Send_uint32(client_id);
 
	p->Send_string(leavemsg);
 

	
 
	cs->Send_Packet(p);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN)
 
{
 
	//
 
	// Packet: SERVER_SHUTDOWN
 
	// Function: Let the clients know that the server is closing
 
	// Data:
 
	//     <none>
 
@@ -791,61 +791,61 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 
		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);
 
				SEND_COMMAND(PACKET_SERVER_JOIN)(new_cs, cs->client_id);
 
			}
 
		}
 

	
 
		if (_settings_client.network.pause_on_join) {
 
			/* Now pause the game till the client is in sync */
 
			DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
 

	
 
			NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (incoming client)", NETWORK_SERVER_INDEX);
 
			NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game paused (incoming client)", CLIENT_ID_SERVER);
 
		}
 
	} else {
 
		// Wrong status for this packet, give a warning to client, and close connection
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
	}
 
}
 

	
 
/** 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) {
 
		IConsolePrintF(CC_ERROR, "WARNING: server only command from client %d (IP: %s), kicking...", ci->client_index, GetClientIP(ci));
 
	if (flags & CMD_SERVER && ci->client_id != CLIENT_ID_SERVER) {
 
		IConsolePrintF(CC_ERROR, "WARNING: server only command from client %d (IP: %s), kicking...", ci->client_id, GetClientIP(ci));
 
		return false;
 
	}
 

	
 
	if (flags & CMD_OFFLINE) {
 
		IConsolePrintF(CC_ERROR, "WARNING: offline only command from client %d (IP: %s), kicking...", ci->client_index, GetClientIP(ci));
 
		IConsolePrintF(CC_ERROR, "WARNING: offline only command from client %d (IP: %s), kicking...", ci->client_id, GetClientIP(ci));
 
		return false;
 
	}
 

	
 
	if (cp->cmd != CMD_COMPANY_CTRL && !IsValidCompanyID(cp->company) && ci->client_index != NETWORK_SERVER_INDEX) {
 
		IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_index, GetClientIP(ci));
 
	if (cp->cmd != CMD_COMPANY_CTRL && !IsValidCompanyID(cp->company) && ci->client_id != CLIENT_ID_SERVER) {
 
		IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_id, GetClientIP(ci));
 
		return false;
 
	}
 

	
 
	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
 
 */
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
 
{
 
@@ -870,25 +870,25 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 

	
 
	callback = p->Recv_uint8();
 

	
 
	if (cs->has_quit) {
 
		free(cp);
 
		return;
 
	}
 

	
 
	ci = DEREF_CLIENT_INFO(cs);
 

	
 
	/* Check if cp->cmd is valid */
 
	if (!IsValidCommand(cp->cmd)) {
 
		IConsolePrintF(CC_ERROR, "WARNING: invalid command from client %d (IP: %s).", ci->client_index, GetClientIP(ci));
 
		IConsolePrintF(CC_ERROR, "WARNING: invalid command from client %d (IP: %s).", ci->client_id, GetClientIP(ci));
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
		free(cp);
 
		return;
 
	}
 

	
 
	if (!CheckCommandFlags(cp, ci)) {
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_KICKED);
 
		free(cp);
 
		return;
 
	}
 

	
 
	/** Only CMD_COMPANY_CTRL is always allowed, for the rest, playas needs
 
@@ -968,25 +968,25 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 
	}
 

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

	
 
	GetNetworkErrorMsg(str, errorno, lastof(str));
 

	
 
	DEBUG(net, 2, "'%s' reported an error and is closing its connection (%s)", client_name, str);
 

	
 
	NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "%s", str);
 

	
 
	FOR_ALL_CLIENTS(new_cs) {
 
		if (new_cs->status > STATUS_AUTH) {
 
			SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
 
			SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->client_id, errorno);
 
		}
 
	}
 

	
 
	cs->has_quit = true;
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT)
 
{
 
	// The client wants to leave. Display this and report it to the other
 
	//  clients.
 
	NetworkTCPSocketHandler *new_cs;
 
	char str[100];
 
@@ -997,25 +997,25 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 
		cs->has_quit = true;
 
		return;
 
	}
 

	
 
	p->Recv_string(str, lengthof(str));
 

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

	
 
	NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, "%s", str);
 

	
 
	FOR_ALL_CLIENTS(new_cs) {
 
		if (new_cs->status > STATUS_AUTH) {
 
			SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->index, str);
 
			SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->client_id, str);
 
		}
 
	}
 

	
 
	cs->has_quit = true;
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK)
 
{
 
	if (cs->status < STATUS_AUTH) {
 
		/* Illegal call, return error and ignore the packet */
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED);
 
		return;
 
@@ -1024,165 +1024,165 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 
	uint32 frame = p->Recv_uint32();
 

	
 
	/* The client is trying to catch up with the server */
 
	if (cs->status == STATUS_PRE_ACTIVE) {
 
		/* The client is not yet catched up? */
 
		if (frame + DAY_TICKS < _frame_counter) return;
 

	
 
		/* Now he is! Unpause the game */
 
		cs->status = STATUS_ACTIVE;
 

	
 
		if (_settings_client.network.pause_on_join) {
 
			DoCommandP(0, 0, 0, NULL, CMD_PAUSE);
 
			NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (client connected)", NETWORK_SERVER_INDEX);
 
			NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "Game unpaused (client connected)", CLIENT_ID_SERVER);
 
		}
 

	
 
		CheckMinActiveClients();
 

	
 
		/* Execute script for, e.g. MOTD */
 
		IConsoleCmdExec("exec scripts/on_server_connect.scr 0");
 
	}
 

	
 
	// The client received the frame, make note of it
 
	cs->last_frame = frame;
 
	// With those 2 values we can calculate the lag realtime
 
	cs->last_frame_server = _frame_counter;
 
}
 

	
 

	
 

	
 
void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const char *msg, uint16 from_index)
 
void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, const char *msg, ClientID from_id)
 
{
 
	NetworkTCPSocketHandler *cs;
 
	const NetworkClientInfo *ci, *ci_own, *ci_to;
 

	
 
	switch (desttype) {
 
	case DESTTYPE_CLIENT:
 
		/* Are we sending to the server? */
 
		if (dest == NETWORK_SERVER_INDEX) {
 
			ci = NetworkFindClientInfoFromIndex(from_index);
 
		if ((ClientID)dest == CLIENT_ID_SERVER) {
 
			ci = NetworkFindClientInfoFromIndex(from_id);
 
			/* Display the text locally, and that is it */
 
			if (ci != NULL)
 
				NetworkTextMessage(action, (ConsoleColour)GetDrawStringCompanyColor(ci->client_playas), false, ci->client_name, "%s", msg);
 
		} else {
 
			/* Else find the client to send the message to */
 
			FOR_ALL_CLIENTS(cs) {
 
				if (cs->index == dest) {
 
					SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
 
				if (cs->client_id == (ClientID)dest) {
 
					SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_id, false, msg);
 
					break;
 
				}
 
			}
 
		}
 

	
 
		// Display the message locally (so you know you have sent it)
 
		if (from_index != dest) {
 
			if (from_index == NETWORK_SERVER_INDEX) {
 
				ci = NetworkFindClientInfoFromIndex(from_index);
 
				ci_to = NetworkFindClientInfoFromIndex(dest);
 
		if (from_id != (ClientID)dest) {
 
			if (from_id == CLIENT_ID_SERVER) {
 
				ci = NetworkFindClientInfoFromIndex(from_id);
 
				ci_to = NetworkFindClientInfoFromIndex((ClientID)dest);
 
				if (ci != NULL && ci_to != NULL)
 
					NetworkTextMessage(action, (ConsoleColour)GetDrawStringCompanyColor(ci->client_playas), true, ci_to->client_name, "%s", msg);
 
			} else {
 
				FOR_ALL_CLIENTS(cs) {
 
					if (cs->index == from_index) {
 
						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, dest, true, msg);
 
					if (cs->client_id == from_id) {
 
						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, (ClientID)dest, true, msg);
 
						break;
 
					}
 
				}
 
			}
 
		}
 
		break;
 
	case DESTTYPE_TEAM: {
 
		bool show_local = true; // If this is false, the message is already displayed
 
														// on the client who did sent it.
 
		/* Find all clients that belong to this company */
 
		ci_to = NULL;
 
		FOR_ALL_CLIENTS(cs) {
 
			ci = DEREF_CLIENT_INFO(cs);
 
			if (ci->client_playas == dest) {
 
				SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
 
				if (cs->index == from_index) show_local = false;
 
			if (ci->client_playas == (CompanyID)dest) {
 
				SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_id, false, msg);
 
				if (cs->client_id == from_id) show_local = false;
 
				ci_to = ci; // Remember a client that is in the company for company-name
 
			}
 
		}
 

	
 
		ci = NetworkFindClientInfoFromIndex(from_index);
 
		ci_own = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
		ci = NetworkFindClientInfoFromIndex(from_id);
 
		ci_own = NetworkFindClientInfoFromIndex(CLIENT_ID_SERVER);
 
		if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
 
			NetworkTextMessage(action, (ConsoleColour)GetDrawStringCompanyColor(ci->client_playas), false, ci->client_name, "%s", msg);
 
			if (from_index == NETWORK_SERVER_INDEX) show_local = false;
 
			if (from_id == CLIENT_ID_SERVER) show_local = false;
 
			ci_to = ci_own;
 
		}
 

	
 
		/* There is no such client */
 
		if (ci_to == NULL) break;
 

	
 
		// Display the message locally (so you know you have sent it)
 
		if (ci != NULL && show_local) {
 
			if (from_index == NETWORK_SERVER_INDEX) {
 
			if (from_id == CLIENT_ID_SERVER) {
 
				char name[NETWORK_NAME_LENGTH];
 
				StringID str = IsValidCompanyID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS;
 
				SetDParam(0, ci_to->client_playas);
 
				GetString(name, str, lastof(name));
 
				NetworkTextMessage(action, (ConsoleColour)GetDrawStringCompanyColor(ci_own->client_playas), true, name, "%s", msg);
 
			} else {
 
				FOR_ALL_CLIENTS(cs) {
 
					if (cs->index == from_index) {
 
						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, ci_to->client_index, true, msg);
 
					if (cs->client_id == from_id) {
 
						SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, ci_to->client_id, true, msg);
 
					}
 
				}
 
			}
 
		}
 
		}
 
		break;
 
	default:
 
		DEBUG(net, 0, "[server] received unknown chat destination type %d. Doing broadcast instead", desttype);
 
		/* fall-through to next case */
 
	case DESTTYPE_BROADCAST:
 
		FOR_ALL_CLIENTS(cs) {
 
			SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, false, msg);
 
			SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_id, false, msg);
 
		}
 
		ci = NetworkFindClientInfoFromIndex(from_index);
 
		ci = NetworkFindClientInfoFromIndex(from_id);
 
		if (ci != NULL)
 
			NetworkTextMessage(action, (ConsoleColour)GetDrawStringCompanyColor(ci->client_playas), false, ci->client_name, "%s", msg);
 
		break;
 
	}
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_CHAT)
 
{
 
	if (cs->status < STATUS_AUTH) {
 
		/* Illegal call, return error and ignore the packet */
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED);
 
		return;
 
	}
 

	
 
	NetworkAction action = (NetworkAction)p->Recv_uint8();
 
	DestType desttype = (DestType)p->Recv_uint8();
 
	int dest = p->Recv_uint16();
 
	int dest = p->Recv_uint32();
 
	char msg[NETWORK_CHAT_LENGTH];
 

	
 
	p->Recv_string(msg, NETWORK_CHAT_LENGTH);
 

	
 
	const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
 
	switch (action) {
 
		case NETWORK_ACTION_GIVE_MONEY:
 
			if (!IsValidCompanyID(ci->client_playas)) break;
 
			/* Fall-through */
 
		case NETWORK_ACTION_CHAT:
 
		case NETWORK_ACTION_CHAT_CLIENT:
 
		case NETWORK_ACTION_CHAT_COMPANY:
 
			NetworkServerSendChat(action, desttype, dest, msg, cs->index);
 
			NetworkServerSendChat(action, desttype, dest, msg, cs->client_id);
 
			break;
 
		default:
 
			IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_index, GetClientIP(ci));
 
			IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_id, GetClientIP(ci));
 
			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
			break;
 
	}
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD)
 
{
 
	if (cs->status != STATUS_ACTIVE) {
 
		/* Illegal call, return error and ignore the packet */
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
		return;
 
	}
 
@@ -1210,49 +1210,49 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 
	NetworkClientInfo *ci;
 

	
 
	p->Recv_string(client_name, sizeof(client_name));
 
	ci = DEREF_CLIENT_INFO(cs);
 

	
 
	if (cs->has_quit) return;
 

	
 
	if (ci != NULL) {
 
		// Display change
 
		if (NetworkFindName(client_name)) {
 
			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, "%s", client_name);
 
			strecpy(ci->client_name, client_name, lastof(ci->client_name));
 
			NetworkUpdateClientInfo(ci->client_index);
 
			NetworkUpdateClientInfo(ci->client_id);
 
		}
 
	}
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_RCON)
 
{
 
	char pass[NETWORK_PASSWORD_LENGTH];
 
	char command[NETWORK_RCONCOMMAND_LENGTH];
 

	
 
	if (StrEmpty(_settings_client.network.rcon_password)) return;
 

	
 
	p->Recv_string(pass, sizeof(pass));
 
	p->Recv_string(command, sizeof(command));
 

	
 
	if (strcmp(pass, _settings_client.network.rcon_password) != 0) {
 
		DEBUG(net, 0, "[rcon] wrong password from client-id %d", cs->index);
 
		DEBUG(net, 0, "[rcon] wrong password from client-id %d", cs->client_id);
 
		return;
 
	}
 

	
 
	DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", cs->index, command);
 
	DEBUG(net, 0, "[rcon] client-id %d executed: '%s'", cs->client_id, command);
 

	
 
	_redirect_console_to_client = cs->index;
 
	_redirect_console_to_client = cs->client_id;
 
	IConsoleCmdExec(command);
 
	_redirect_console_to_client = 0;
 
	_redirect_console_to_client = INVALID_CLIENT_ID;
 
	return;
 
}
 

	
 
// The layout for the receive-functions by the server
 
typedef void NetworkServerPacket(NetworkTCPSocketHandler *cs, Packet *p);
 

	
 

	
 
// 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[] = {
 
@@ -1360,50 +1360,50 @@ void NetworkPopulateCompanyInfo()
 
	FOR_ALL_STATIONS(s) {
 
		if (IsValidCompanyID(s->owner)) {
 
			NetworkCompanyInfo *npi = &_network_company_info[s->owner];
 

	
 
			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]++;
 
		}
 
	}
 

	
 
	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
	ci = NetworkFindClientInfoFromIndex(CLIENT_ID_SERVER);
 
	// Register local company (if not dedicated)
 
	if (ci != NULL && IsValidCompanyID(ci->client_playas))
 
		strecpy(_network_company_info[ci->client_playas].clients, ci->client_name, lastof(_network_company_info[ci->client_playas].clients));
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		char client_name[NETWORK_CLIENT_NAME_LENGTH];
 

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

	
 
		ci = DEREF_CLIENT_INFO(cs);
 
		if (ci != NULL && IsValidCompanyID(ci->client_playas)) {
 
			if (!StrEmpty(_network_company_info[ci->client_playas].clients)) {
 
				strecat(_network_company_info[ci->client_playas].clients, ", ", lastof(_network_company_info[ci->client_playas].clients));
 
			}
 

	
 
			strecat(_network_company_info[ci->client_playas].clients, client_name, lastof(_network_company_info[ci->client_playas].clients));
 
		}
 
	}
 
}
 

	
 
// Send a packet to all clients with updated info about this client_index
 
void NetworkUpdateClientInfo(uint16 client_index)
 
// Send a packet to all clients with updated info about this client_id
 
void NetworkUpdateClientInfo(ClientID client_id)
 
{
 
	NetworkTCPSocketHandler *cs;
 
	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_index);
 
	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_id);
 

	
 
	if (ci == NULL) return;
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, ci);
 
	}
 
}
 

	
 
/* Check if we want to restart the map */
 
static void NetworkCheckRestartMap()
 
{
 
	if (_settings_client.network.restart_game_year != 0 && _cur_year >= _settings_client.network.restart_game_year) {
 
@@ -1427,25 +1427,25 @@ static void NetworkAutoCleanCompanies()
 

	
 
	if (!_settings_client.network.autoclean_companies) return;
 

	
 
	memset(clients_in_company, 0, sizeof(clients_in_company));
 

	
 
	/* Detect the active companies */
 
	FOR_ALL_CLIENTS(cs) {
 
		ci = DEREF_CLIENT_INFO(cs);
 
		if (IsValidCompanyID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
 
	}
 

	
 
	if (!_network_dedicated) {
 
		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
		ci = NetworkFindClientInfoFromIndex(CLIENT_ID_SERVER);
 
		if (IsValidCompanyID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
 
	}
 

	
 
	/* Go through all the comapnies */
 
	FOR_ALL_COMPANIES(c) {
 
		/* Skip the non-active once */
 
		if (c->is_ai) continue;
 

	
 
		if (!clients_in_company[c->index]) {
 
			/* The company is empty for one month more */
 
			_network_company_info[c->index].months_empty++;
 

	
 
@@ -1485,25 +1485,25 @@ bool NetworkFindName(char new_name[NETWO
 
		const NetworkClientInfo *ci;
 

	
 
		found_name = true;
 
		FOR_ALL_CLIENTS(new_cs) {
 
			ci = DEREF_CLIENT_INFO(new_cs);
 
			if (strcmp(ci->client_name, new_name) == 0) {
 
				// Name already in use
 
				found_name = false;
 
				break;
 
			}
 
		}
 
		// Check if it is the same as the server-name
 
		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
		ci = NetworkFindClientInfoFromIndex(CLIENT_ID_SERVER);
 
		if (ci != NULL) {
 
			if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use
 
		}
 

	
 
		if (!found_name) {
 
			// Try a new name (<name> #1, <name> #2, and so on)
 

	
 
			// Stop if we tried for more than 50 times..
 
			if (number++ > 50) break;
 
			snprintf(new_name, NETWORK_CLIENT_NAME_LENGTH, "%s #%d", original_name, number);
 
		}
 
	}
 
@@ -1559,47 +1559,47 @@ void NetworkServer_Tick(bool send_frame)
 

	
 
	// 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)
 
					IConsolePrintF(CC_ERROR,"Client #%d is dropped because the client did not respond for more than 4 game-days", cs->index);
 
					IConsolePrintF(CC_ERROR,"Client #%d is dropped because the client did not respond for more than 4 game-days", cs->client_id);
 
					NetworkCloseClient(cs);
 
					continue;
 
				}
 

	
 
				// Report once per time we detect the lag
 
				if (cs->lag_test == 0) {
 
					IConsolePrintF(CC_WARNING,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index);
 
					IConsolePrintF(CC_WARNING,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->client_id);
 
					cs->lag_test = 1;
 
				}
 
			} else {
 
				cs->lag_test = 0;
 
			}
 
		} else if (cs->status == STATUS_PRE_ACTIVE) {
 
			int lag = NetworkCalculateLag(cs);
 
			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);
 
				IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks for him to join", cs->client_id, _settings_client.network.max_join_time);
 
				NetworkCloseClient(cs);
 
			}
 
		} else if (cs->status == STATUS_INACTIVE) {
 
			int lag = NetworkCalculateLag(cs);
 
			if (lag > 4 * DAY_TICKS) {
 
				IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->index, 4 * DAY_TICKS);
 
				IConsolePrintF(CC_ERROR,"Client #%d is dropped because it took longer than %d ticks to start the joining process", cs->client_id, 4 * DAY_TICKS);
 
				NetworkCloseClient(cs);
 
			}
 
		}
 

	
 
		if (cs->status >= STATUS_PRE_ACTIVE) {
 
			// Check if we can send command, and if we have anything in the queue
 
			NetworkHandleCommandQueue(cs);
 

	
 
			// Send an updated _frame_counter_max to the client
 
			if (send_frame) SEND_COMMAND(PACKET_SERVER_FRAME)(cs);
 

	
 
#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
 
@@ -1619,38 +1619,38 @@ void NetworkServerYearlyLoop()
 
}
 

	
 
void NetworkServerMonthlyLoop()
 
{
 
	NetworkAutoCleanCompanies();
 
}
 

	
 
void NetworkServerChangeOwner(Owner current_owner, Owner new_owner)
 
{
 
	/* The server has to handle all administrative issues, for example
 
	 * updating and notifying all clients of what has happened */
 
	NetworkTCPSocketHandler *cs;
 
	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
	NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(CLIENT_ID_SERVER);
 

	
 
	/* The server has just changed from owner */
 
	if (current_owner == ci->client_playas) {
 
		ci->client_playas = new_owner;
 
		NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
 
		NetworkUpdateClientInfo(CLIENT_ID_SERVER);
 
	}
 

	
 
	/* Find all clients that were in control of this company, and mark them as new_owner */
 
	FOR_ALL_CLIENTS(cs) {
 
		ci = DEREF_CLIENT_INFO(cs);
 
		if (current_owner == ci->client_playas) {
 
			ci->client_playas = new_owner;
 
			NetworkUpdateClientInfo(ci->client_index);
 
			NetworkUpdateClientInfo(ci->client_id);
 
		}
 
	}
 
}
 

	
 
const char* GetClientIP(const NetworkClientInfo* ci)
 
{
 
	struct in_addr addr;
 

	
 
	addr.s_addr = ci->client_ip;
 
	return inet_ntoa(addr);
 
}
 

	
 
@@ -1666,38 +1666,38 @@ void NetworkServerShowStatusToConsole()
 
		"ready",
 
		"active"
 
	};
 

	
 
	NetworkTCPSocketHandler *cs;
 
	FOR_ALL_CLIENTS(cs) {
 
		int lag = NetworkCalculateLag(cs);
 
		const NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
 
		const char* status;
 

	
 
		status = (cs->status < (ptrdiff_t)lengthof(stat_str) ? stat_str[cs->status] : "unknown");
 
		IConsolePrintF(CC_INFO, "Client #%1d  name: '%s'  status: '%s'  frame-lag: %3d  company: %1d  IP: %s  unique-id: '%s'",
 
			cs->index, ci->client_name, status, lag,
 
			cs->client_id, ci->client_name, status, lag,
 
			ci->client_playas + (IsValidCompanyID(ci->client_playas) ? 1 : 0),
 
			GetClientIP(ci), ci->unique_id);
 
	}
 
}
 

	
 
void NetworkServerSendRcon(uint16 client_index, ConsoleColour colour_code, const char *string)
 
void NetworkServerSendRcon(ClientID client_id, ConsoleColour colour_code, const char *string)
 
{
 
	SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromIndex(client_index), colour_code, string);
 
	SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromClientID(client_id), colour_code, string);
 
}
 

	
 
void NetworkServerSendError(uint16 client_index, NetworkErrorCode error)
 
void NetworkServerSendError(ClientID client_id, NetworkErrorCode error)
 
{
 
	SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(client_index), error);
 
	SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromClientID(client_id), error);
 
}
 

	
 
bool NetworkCompanyHasClients(CompanyID company)
 
{
 
	const NetworkTCPSocketHandler *cs;
 
	const NetworkClientInfo *ci;
 
	FOR_ALL_CLIENTS(cs) {
 
		ci = DEREF_CLIENT_INFO(cs);
 
		if (ci->client_playas == company) return true;
 
	}
 
	return false;
 
}
src/network/network_server.h
Show inline comments
 
/* $Id$ */
 

	
 
/** @file network_server.h Server part of the network protocol. */
 

	
 
#ifndef NETWORK_SERVER_H
 
#define NETWORK_SERVER_H
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP);
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkTCPSocketHandler *cs, uint16 client_index, NetworkErrorCode errorno);
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkTCPSocketHandler *cs, ClientID client_id, NetworkErrorCode errorno);
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkTCPSocketHandler *cs, NetworkErrorCode error);
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN);
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME);
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkTCPSocketHandler *cs, uint16 color, const char *command);
 

	
 
bool NetworkServer_ReadPackets(NetworkTCPSocketHandler *cs);
 
void NetworkServer_Tick(bool send_frame);
 

	
 
#else /* ENABLE_NETWORK */
 
/* Network function stubs when networking is disabled */
 

	
 
static inline void NetworkServerMonthlyLoop() {}
src/network/network_type.h
Show inline comments
 
@@ -11,55 +11,62 @@
 
#include "../economy_type.h"
 
#include "core/config.h"
 
#include "core/game.h"
 

	
 
enum {
 
	/**
 
	 * How many clients can we have? Like.. MAX_COMPANIES is the amount of
 
	 *  companies that can really play.. so.. a max of 3 spectators.. gives us..
 
	 *  MAX_COMPANIES + 3
 
	 */
 
	MAX_CLIENTS = MAX_COMPANIES + 3,
 

	
 
	/** Do not change this next line. It should _ALWAYS_ be MAX_CLIENTS + 1 */
 
	MAX_CLIENT_INFO = MAX_CLIENTS + 1,
 

	
 
	/** Maximum number of internet interfaces supported. */
 
	MAX_INTERFACES = 9,
 

	
 
	/** How many vehicle/station types we put over the network */
 
	NETWORK_VEHICLE_TYPES = 5,
 
	NETWORK_STATION_TYPES = 5,
 
};
 

	
 
	NETWORK_SERVER_INDEX = 1,
 
	NETWORK_EMPTY_INDEX  = 0,
 
/** 'Unique' identifier to be given to clients */
 
enum ClientID {
 
	INVALID_CLIENT_ID = 0, ///< Client is not part of anything
 
	CLIENT_ID_SERVER  = 1, ///< Servers always have this ID
 
	CLIENT_ID_FIRST   = 2, ///< The first client ID
 
};
 

	
 
/** Indices into the client tables */
 
enum ClientIndex {
 
	/** Do not change this next line. It should _ALWAYS_ be MAX_CLIENTS + 1 */
 
	MAX_CLIENT_INFO = MAX_CLIENTS + 1,
 
};
 

	
 
struct NetworkCompanyInfo {
 
	char company_name[NETWORK_COMPANY_NAME_LENGTH]; ///< Company name
 
	char password[NETWORK_PASSWORD_LENGTH];         ///< The password for the company
 
	Year inaugurated_year;                          ///< What year the company started in
 
	Money company_value;                            ///< The company value
 
	Money money;                                    ///< The amount of money the company has
 
	Money income;                                   ///< How much did the company earned last year
 
	uint16 performance;                             ///< What was his performance last month?
 
	bool use_password;                              ///< Is there a password
 
	uint16 num_vehicle[NETWORK_VEHICLE_TYPES];      ///< How many vehicles are there of this type?
 
	uint16 num_station[NETWORK_STATION_TYPES];      ///< How many stations are there of this type?
 
	char clients[NETWORK_CLIENTS_LENGTH];           ///< The clients that control this company (Name1, name2, ..)
 
	uint16 months_empty;                            ///< How many months the company is empty
 
};
 

	
 
struct NetworkClientInfo {
 
	uint16 client_index;                            ///< Index of the client (same as ClientState->index)
 
	ClientID client_id;                             ///< Client identifier (same as ClientState->client_id)
 
	char client_name[NETWORK_CLIENT_NAME_LENGTH];   ///< Name of the client
 
	byte client_lang;                               ///< The language of the client
 
	CompanyID client_playas;                        ///< As which company is this client playing (CompanyID)
 
	uint32 client_ip;                               ///< IP-address of the client (so he can be banned)
 
	Date join_date;                                 ///< Gamedate the client has joined
 
	char unique_id[NETWORK_UNIQUE_ID_LENGTH];       ///< Every play sends an unique id so we can indentify him
 
};
 

	
 
enum NetworkPasswordType {
 
	NETWORK_GAME_PASSWORD,
 
	NETWORK_COMPANY_PASSWORD,
 
};
0 comments (0 inline, 0 general)