mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-08-19 12:39:11 +00:00
(svn r15242) -Feature: allow moving clients between companies/spectators by the server and the clients themselves (dihedral)
This commit is contained in:
@@ -54,6 +54,10 @@ enum {
|
||||
PACKET_CLIENT_RCON,
|
||||
PACKET_SERVER_CHECK_NEWGRFS,
|
||||
PACKET_CLIENT_NEWGRFS_CHECKED,
|
||||
PACKET_SERVER_MOVE,
|
||||
PACKET_CLIENT_MOVE,
|
||||
PACKET_SERVER_COMPANY_UPDATE,
|
||||
PACKET_SERVER_CONFIG_UPDATE,
|
||||
PACKET_END ///< Must ALWAYS be on the end of this list!! (period)
|
||||
};
|
||||
|
||||
|
@@ -75,6 +75,7 @@ bool _network_first_time;
|
||||
bool _network_udp_server;
|
||||
uint16 _network_udp_broadcast;
|
||||
uint8 _network_advertise_retries;
|
||||
CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies.
|
||||
|
||||
/* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */
|
||||
assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE);
|
||||
@@ -182,6 +183,16 @@ byte NetworkSpectatorCount()
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the company we want to join requires a password.
|
||||
* @param company_id id of the company we want to check the 'passworded' flag for.
|
||||
* @return true if the company requires a password.
|
||||
*/
|
||||
bool NetworkCompanyIsPassworded(CompanyID company_id)
|
||||
{
|
||||
return HasBit(_network_company_passworded, company_id);
|
||||
}
|
||||
|
||||
// This puts a text-message to the console, or in the future, the chat-box,
|
||||
// (to keep it all a bit more general)
|
||||
// If 'self_send' is true, this is the client who is sending the message
|
||||
@@ -199,6 +210,18 @@ void NetworkTextMessage(NetworkAction action, ConsoleColour color, bool self_sen
|
||||
color = CC_DEFAULT;
|
||||
data = STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED_PLAYERS + data;
|
||||
break;
|
||||
case NETWORK_ACTION_COMPANY_SPECTATOR:
|
||||
color = CC_DEFAULT;
|
||||
strid = STR_NETWORK_CLIENT_COMPANY_SPECTATE;
|
||||
break;
|
||||
case NETWORK_ACTION_COMPANY_JOIN:
|
||||
color = CC_DEFAULT;
|
||||
strid = STR_NETWORK_CLIENT_COMPANY_JOIN;
|
||||
break;
|
||||
case NETWORK_ACTION_COMPANY_NEW:
|
||||
color = CC_DEFAULT;
|
||||
strid = STR_NETWORK_CLIENT_COMPANY_NEW;
|
||||
break;
|
||||
case NETWORK_ACTION_JOIN: strid = STR_NETWORK_CLIENT_JOINED; break;
|
||||
case NETWORK_ACTION_LEAVE: strid = STR_NETWORK_CLIENT_LEFT; break;
|
||||
case NETWORK_ACTION_NAME_CHANGE: strid = STR_NETWORK_NAME_CHANGE; break;
|
||||
|
@@ -7,6 +7,7 @@
|
||||
#include "../stdafx.h"
|
||||
#include "../debug.h"
|
||||
#include "../openttd.h"
|
||||
#include "../gfx_func.h"
|
||||
#include "network_internal.h"
|
||||
#include "core/tcp.h"
|
||||
#include "network_client.h"
|
||||
@@ -25,6 +26,7 @@
|
||||
#include "../company_func.h"
|
||||
#include "../company_base.h"
|
||||
#include "../company_gui.h"
|
||||
#include "../company_type.h"
|
||||
#include "../settings_type.h"
|
||||
#include "../rev.h"
|
||||
|
||||
@@ -43,6 +45,11 @@ static uint32 _password_game_seed;
|
||||
/** The other bit of 'entropy' used to generate a salt for the company passwords. */
|
||||
static char _password_server_unique_id[NETWORK_UNIQUE_ID_LENGTH];
|
||||
|
||||
/** Maximum number of companies of the currently joined server. */
|
||||
static uint8 _network_server_max_companies;
|
||||
/** Maximum number of spectators of the currently joined server. */
|
||||
static uint8 _network_server_max_spectators;
|
||||
|
||||
/** Make sure the unique ID length is the same as a md5 hash. */
|
||||
assert_compile(NETWORK_UNIQUE_ID_LENGTH == 16 * 2 + 1);
|
||||
|
||||
@@ -86,6 +93,10 @@ void HashCurrentCompanyPassword(const char *password)
|
||||
|
||||
const char *new_pw = GenerateCompanyPasswordHash(password);
|
||||
strecpy(_network_company_states[_local_company].password, new_pw, lastof(_network_company_states[_local_company].password));
|
||||
|
||||
if (_network_server) {
|
||||
NetworkServerUpdateCompanyPassworded(_local_company, !StrEmpty(_network_company_states[_local_company].password));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -315,6 +326,14 @@ DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_RCON)(const char *pass, const char *
|
||||
MY_CLIENT->Send_Packet(p);
|
||||
}
|
||||
|
||||
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_MOVE)(CompanyID company, const char *pass)
|
||||
{
|
||||
Packet *p = NetworkSend_Init(PACKET_CLIENT_MOVE);
|
||||
p->Send_uint8(company);
|
||||
p->Send_string(GenerateCompanyPasswordHash(pass));
|
||||
MY_CLIENT->Send_Packet(p);
|
||||
}
|
||||
|
||||
|
||||
// **********
|
||||
// Receiving functions
|
||||
@@ -811,6 +830,51 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_RCON)
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MOVE)
|
||||
{
|
||||
/* Nothing more in this packet... */
|
||||
ClientID client_id = (ClientID)p->Recv_uint32();
|
||||
CompanyID company_id = (CompanyID)p->Recv_uint8();
|
||||
|
||||
if (client_id == 0) {
|
||||
/* definitely an invalid client id, debug message and do nothing. */
|
||||
DEBUG(net, 0, "[move] received invalid client index = 0");
|
||||
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||
}
|
||||
|
||||
const NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
|
||||
/* Just make sure we do not try to use a client_index that does not exist */
|
||||
if (ci == NULL) return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
/* if not valid player, force spectator, else check player exists */
|
||||
if (!IsValidCompanyID(company_id)) company_id = COMPANY_SPECTATOR;
|
||||
|
||||
if (client_id == _network_own_client_id) {
|
||||
_network_playas = company_id;
|
||||
SetLocalCompany(company_id);
|
||||
|
||||
/* Disable any buttons in any windows the client is now not supposed to get to, and do it fast. */
|
||||
/* Do this ASAP else the client has a chance of sending DoCommands with an incorrect company_id (=kick)! */
|
||||
MarkWholeScreenDirty();
|
||||
}
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CONFIG_UPDATE)
|
||||
{
|
||||
_network_server_max_companies = p->Recv_uint8();
|
||||
_network_server_max_spectators = p->Recv_uint8();
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_COMPANY_UPDATE)
|
||||
{
|
||||
_network_company_passworded = p->Recv_uint16();
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
}
|
||||
|
||||
|
||||
// The layout for the receive-functions by the client
|
||||
@@ -855,6 +919,10 @@ static NetworkClientPacket * const _network_client_packet[] = {
|
||||
NULL, /*PACKET_CLIENT_RCON,*/
|
||||
RECEIVE_COMMAND(PACKET_SERVER_CHECK_NEWGRFS),
|
||||
NULL, /*PACKET_CLIENT_NEWGRFS_CHECKED,*/
|
||||
RECEIVE_COMMAND(PACKET_SERVER_MOVE),
|
||||
NULL, /* PACKET_CLIENT_MOVE */
|
||||
RECEIVE_COMMAND(PACKET_SERVER_COMPANY_UPDATE),
|
||||
RECEIVE_COMMAND(PACKET_SERVER_CONFIG_UPDATE),
|
||||
};
|
||||
|
||||
// If this fails, check the array above with network_data.h
|
||||
@@ -897,6 +965,17 @@ void NetworkClientSendRcon(const char *password, const char *command)
|
||||
SEND_COMMAND(PACKET_CLIENT_RCON)(password, command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the server of this client wanting to be moved to another company.
|
||||
* @param company_id id of the company the client wishes to be moved to.
|
||||
* @param pass the password, is only checked on the server end if a password is needed.
|
||||
* @return void
|
||||
*/
|
||||
void NetworkClientRequestMove(CompanyID company_id, const char *pass)
|
||||
{
|
||||
SEND_COMMAND(PACKET_CLIENT_MOVE)(company_id, pass);
|
||||
}
|
||||
|
||||
void NetworkUpdateClientName()
|
||||
{
|
||||
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(_network_own_client_id);
|
||||
@@ -945,6 +1024,24 @@ bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if max_companies has been reached on the server (local check only).
|
||||
* @return true if the max value has been reached or exceeded, false otherwise.
|
||||
*/
|
||||
bool NetworkMaxCompaniesReached()
|
||||
{
|
||||
return ActiveCompanyCount() >= (_network_server ? _settings_client.network.max_companies : _network_server_max_companies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if max_spectatos has been reached on the server (local check only).
|
||||
* @return true if the max value has been reached or exceeded, false otherwise.
|
||||
*/
|
||||
bool NetworkMaxSpectatorsReached()
|
||||
{
|
||||
return NetworkSpectatorCount() >= (_network_server ? _settings_client.network.max_spectators : _network_server_max_spectators);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print all the clients to the console
|
||||
*/
|
||||
|
@@ -18,6 +18,7 @@ DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password);
|
||||
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_NAME)(const char *name);
|
||||
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK);
|
||||
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_RCON)(const char *pass, const char *command);
|
||||
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_MOVE)(CompanyID company, const char *pass);
|
||||
|
||||
NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientSocket *cs);
|
||||
void NetworkClient_Connected();
|
||||
|
@@ -38,18 +38,24 @@ void NetworkPopulateCompanyStats(NetworkCompanyStats *stats);
|
||||
|
||||
void NetworkUpdateClientInfo(ClientID client_id);
|
||||
void NetworkClientConnectGame(NetworkAddress address);
|
||||
void NetworkClientRequestMove(CompanyID company, const char *pass = "");
|
||||
void NetworkClientSendRcon(const char *password, const char *command);
|
||||
void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data = 0);
|
||||
void NetworkClientSetPassword(const char *password);
|
||||
bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio);
|
||||
bool NetworkCompanyIsPassworded(CompanyID company_id);
|
||||
bool NetworkMaxCompaniesReached();
|
||||
bool NetworkMaxSpectatorsReached();
|
||||
void NetworkPrintClients();
|
||||
|
||||
/*** Commands ran by the server ***/
|
||||
void NetworkServerMonthlyLoop();
|
||||
void NetworkServerYearlyLoop();
|
||||
void NetworkServerChangeOwner(Owner current_owner, Owner new_owner);
|
||||
void NetworkServerSendConfigUpdate();
|
||||
void NetworkServerShowStatusToConsole();
|
||||
bool NetworkServerStart();
|
||||
void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded);
|
||||
bool NetworkServerChangeClientName(ClientID client_id, const char *new_name);
|
||||
|
||||
NetworkClientInfo *NetworkFindClientInfoFromIndex(ClientIndex index);
|
||||
@@ -57,6 +63,7 @@ NetworkClientInfo *NetworkFindClientInfoFromClientID(ClientID client_id);
|
||||
NetworkClientInfo *NetworkFindClientInfoFromIP(const char *ip);
|
||||
const char *GetClientIP(const NetworkClientInfo *ci);
|
||||
|
||||
void NetworkServerDoMove(ClientID client_id, CompanyID company_id);
|
||||
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, int64 data = 0);
|
||||
|
@@ -121,6 +121,8 @@ extern uint16 _network_udp_broadcast;
|
||||
|
||||
extern uint8 _network_advertise_retries;
|
||||
|
||||
extern CompanyMask _network_company_passworded;
|
||||
|
||||
void NetworkTCPQueryServer(NetworkAddress address);
|
||||
|
||||
void NetworkAddServer(const char *b);
|
||||
|
@@ -586,6 +586,32 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientSocket *cs, uint1
|
||||
cs->Send_Packet(p);
|
||||
}
|
||||
|
||||
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_MOVE)(NetworkClientSocket *cs, ClientID client_id, CompanyID company_id)
|
||||
{
|
||||
Packet *p = NetworkSend_Init(PACKET_SERVER_MOVE);
|
||||
|
||||
p->Send_uint32(client_id);
|
||||
p->Send_uint8(company_id);
|
||||
cs->Send_Packet(p);
|
||||
}
|
||||
|
||||
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMPANY_UPDATE)(NetworkClientSocket *cs)
|
||||
{
|
||||
Packet *p = NetworkSend_Init(PACKET_SERVER_COMPANY_UPDATE);
|
||||
|
||||
p->Send_uint16(_network_company_passworded);
|
||||
cs->Send_Packet(p);
|
||||
}
|
||||
|
||||
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_CONFIG_UPDATE)
|
||||
{
|
||||
Packet *p = NetworkSend_Init(PACKET_SERVER_CONFIG_UPDATE);
|
||||
|
||||
p->Send_uint8(_settings_client.network.max_companies);
|
||||
p->Send_uint8(_settings_client.network.max_spectators);
|
||||
cs->Send_Packet(p);
|
||||
}
|
||||
|
||||
// **********
|
||||
// Receiving functions
|
||||
// DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p
|
||||
@@ -803,6 +829,12 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK)
|
||||
|
||||
NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "", CLIENT_ID_SERVER, NETWORK_SERVER_MESSAGE_GAME_PAUSED_CONNECT);
|
||||
}
|
||||
|
||||
/* also update the new client with our max values */
|
||||
SEND_COMMAND(PACKET_SERVER_CONFIG_UPDATE)(cs);
|
||||
|
||||
/* quickly update the syncing client with company details */
|
||||
SEND_COMMAND(PACKET_SERVER_COMPANY_UPDATE)(cs);
|
||||
} else {
|
||||
// Wrong status for this packet, give a warning to client, and close connection
|
||||
SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
|
||||
@@ -872,6 +904,12 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if we are full - else it's possible for spectators to send a CMD_COMPANY_CTRL and the company is created regardless of max_companies! */
|
||||
if (ActiveCompanyCount() >= _settings_client.network.max_companies) {
|
||||
NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
|
||||
return;
|
||||
}
|
||||
|
||||
/* XXX - Execute the command as a valid company. Normally this would be done by a
|
||||
* spectator, but that is not allowed any commands. So do an impersonation. The drawback
|
||||
* of this is that the first company's last_built_tile is also updated... */
|
||||
@@ -1145,6 +1183,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD)
|
||||
|
||||
if (IsValidCompanyID(ci->client_playas)) {
|
||||
strecpy(_network_company_states[ci->client_playas].password, password, lastof(_network_company_states[ci->client_playas].password));
|
||||
NetworkServerUpdateCompanyPassworded(ci->client_playas, !StrEmpty(_network_company_states[ci->client_playas].password));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1197,6 +1236,30 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_RCON)
|
||||
return;
|
||||
}
|
||||
|
||||
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MOVE)
|
||||
{
|
||||
CompanyID company_id = (Owner)p->Recv_uint8();
|
||||
|
||||
/* Check if the company is valid */
|
||||
if (!IsValidCompanyID(company_id) && company_id != COMPANY_SPECTATOR) return;
|
||||
|
||||
/* Check if we require a password for this company */
|
||||
if (company_id != COMPANY_SPECTATOR && !StrEmpty(_network_company_states[company_id].password)) {
|
||||
/* we need a password from the client - should be in this packet */
|
||||
char password[NETWORK_PASSWORD_LENGTH];
|
||||
p->Recv_string(password, sizeof(password));
|
||||
|
||||
/* Incorrect password sent, return! */
|
||||
if (strcmp(password, _network_company_states[company_id].password) != 0) {
|
||||
DEBUG(net, 2, "[move] wrong password from client-id #%d for company #%d", cs->client_id, company_id + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* if we get here we can move the client */
|
||||
NetworkServerDoMove(cs->client_id, company_id);
|
||||
}
|
||||
|
||||
// The layout for the receive-functions by the server
|
||||
typedef void NetworkServerPacket(NetworkClientSocket *cs, Packet *p);
|
||||
|
||||
@@ -1240,6 +1303,10 @@ static NetworkServerPacket * const _network_server_packet[] = {
|
||||
RECEIVE_COMMAND(PACKET_CLIENT_RCON),
|
||||
NULL, /*PACKET_CLIENT_CHECK_NEWGRFS,*/
|
||||
RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED),
|
||||
NULL, /*PACKET_SERVER_MOVE,*/
|
||||
RECEIVE_COMMAND(PACKET_CLIENT_MOVE),
|
||||
NULL, /*PACKET_SERVER_COMPANY_UPDATE,*/
|
||||
NULL, /*PACKET_SERVER_CONFIG_UPDATE,*/
|
||||
};
|
||||
|
||||
// If this fails, check the array above with network_data.h
|
||||
@@ -1394,6 +1461,7 @@ static void NetworkAutoCleanCompanies()
|
||||
_network_company_states[c->index].password[0] = '\0';
|
||||
IConsolePrintF(CC_DEFAULT, "Auto-removed protection from company #%d", c->index + 1);
|
||||
_network_company_states[c->index].months_empty = 0;
|
||||
NetworkServerUpdateCompanyPassworded(c->index, false);
|
||||
}
|
||||
} else {
|
||||
/* It is not empty, reset the date */
|
||||
@@ -1635,6 +1703,63 @@ void NetworkServerShowStatusToConsole()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Config Update
|
||||
*/
|
||||
void NetworkServerSendConfigUpdate()
|
||||
{
|
||||
NetworkClientSocket *cs;
|
||||
|
||||
FOR_ALL_CLIENT_SOCKETS(cs) {
|
||||
SEND_COMMAND(PACKET_SERVER_CONFIG_UPDATE)(cs);
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded)
|
||||
{
|
||||
if (NetworkCompanyIsPassworded(company_id) == passworded) return;
|
||||
|
||||
SB(_network_company_passworded, company_id, 1, !!passworded);
|
||||
|
||||
NetworkClientSocket *cs;
|
||||
FOR_ALL_CLIENT_SOCKETS(cs) {
|
||||
SEND_COMMAND(PACKET_SERVER_COMPANY_UPDATE)(cs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the tid-bits of moving a client from one company to another.
|
||||
* @param client_id id of the client we want to move.
|
||||
* @param company_id id of the company we want to move the client to.
|
||||
* @return void
|
||||
**/
|
||||
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
|
||||
{
|
||||
/* Only allow non-dedicated servers and normal clients to be moved */
|
||||
if (client_id == CLIENT_ID_SERVER && _network_dedicated) return;
|
||||
|
||||
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
|
||||
|
||||
/* No need to waste network resources if the client is in the company already! */
|
||||
if (ci->client_playas == company_id) return;
|
||||
|
||||
ci->client_playas = company_id;
|
||||
|
||||
if (client_id == CLIENT_ID_SERVER) {
|
||||
SetLocalCompany(company_id);
|
||||
} else {
|
||||
SEND_COMMAND(PACKET_SERVER_MOVE)(NetworkFindClientStateFromClientID(client_id), client_id, company_id);
|
||||
}
|
||||
|
||||
/* announce the client's move */
|
||||
NetworkUpdateClientInfo(client_id);
|
||||
|
||||
NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN;
|
||||
NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1);
|
||||
|
||||
CheckMinActiveClients();
|
||||
}
|
||||
|
||||
void NetworkServerSendRcon(ClientID client_id, ConsoleColour colour_code, const char *string)
|
||||
{
|
||||
SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromClientID(client_id), colour_code, string);
|
||||
|
@@ -13,6 +13,7 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientSocket *cs, Netw
|
||||
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN);
|
||||
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME);
|
||||
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientSocket *cs, uint16 color, const char *command);
|
||||
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_MOVE)(NetworkClientSocket *cs, uint16 client_id, CompanyID company_id);
|
||||
|
||||
bool NetworkServer_ReadPackets(NetworkClientSocket *cs);
|
||||
void NetworkServer_Tick(bool send_frame);
|
||||
|
@@ -80,6 +80,9 @@ enum NetworkAction {
|
||||
NETWORK_ACTION_CHAT_CLIENT,
|
||||
NETWORK_ACTION_GIVE_MONEY,
|
||||
NETWORK_ACTION_NAME_CHANGE,
|
||||
NETWORK_ACTION_COMPANY_SPECTATOR,
|
||||
NETWORK_ACTION_COMPANY_JOIN,
|
||||
NETWORK_ACTION_COMPANY_NEW,
|
||||
};
|
||||
|
||||
/** Messages the server can give */
|
||||
|
Reference in New Issue
Block a user