MCPcopy Create free account
hub / github.com/OpenTTD/OpenTTD / Receive_CLIENT_COMMAND

Method Receive_CLIENT_COMMAND

src/network/network_server.cpp:1054–1136  ·  view source on GitHub ↗

* The client has done a command and wants us to handle it * @param p the packet in which the command was sent */

Source from the content-addressed store, hash-verified

1052 * @param p the packet in which the command was sent
1053 */
1054NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMMAND(Packet &p)
1055{
1056 /* The client was never joined.. so this is impossible, right?
1057 * Ignore the packet, give the client a warning, and close the connection */
1058 if (this->status < STATUS_DONE_MAP || this->HasClientQuit()) {
1059 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1060 }
1061
1062 if (this->incoming_queue.size() >= _settings_client.network.max_commands_in_queue) {
1063 return this->SendError(NETWORK_ERROR_TOO_MANY_COMMANDS);
1064 }
1065
1066 Debug(net, 9, "client[{}] Receive_CLIENT_COMMAND()", this->client_id);
1067
1068 CommandPacket cp;
1069 auto err = this->ReceiveCommand(p, cp);
1070
1071 if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CLIENT_QUIT;
1072
1073 NetworkClientInfo *ci = this->GetInfo();
1074
1075 if (err.has_value()) {
1076 IConsolePrint(CC_WARNING, "Dropping client #{} (IP: {}) due to {}.", ci->client_id, this->GetClientIP(), *err);
1077 return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
1078 }
1079
1080 if (GetCommandFlags(cp.cmd).Test(CommandFlag::Server) && ci->client_id != CLIENT_ID_SERVER) {
1081 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a server only command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1082 return this->SendError(NETWORK_ERROR_KICKED);
1083 }
1084
1085 if (!GetCommandFlags(cp.cmd).Test(CommandFlag::Spectator) && !Company::IsValidID(cp.company) && ci->client_id != CLIENT_ID_SERVER) {
1086 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a non-spectator command {}.", ci->client_id, this->GetClientIP(), cp.cmd);
1087 return this->SendError(NETWORK_ERROR_KICKED);
1088 }
1089
1090 /**
1091 * Only CMD_COMPANY_CTRL is always allowed, for the rest, playas needs
1092 * to match the company in the packet. If it doesn't, the client has done
1093 * something pretty naughty (or a bug), and will be kicked
1094 */
1095 CompanyCtrlAction cca = cp.cmd == CMD_COMPANY_CTRL ? std::get<0>(EndianBufferReader::ToValue<CommandTraits<CMD_COMPANY_CTRL>::Args>(cp.data)) : CCA_NEW;
1096 if (!(cp.cmd == CMD_COMPANY_CTRL && cca == CCA_NEW && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
1097 IConsolePrint(CC_WARNING, "Kicking client #{} (IP: {}) due to calling a command as another company {}.",
1098 ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
1099 return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
1100 }
1101
1102 if (cp.cmd == CMD_COMPANY_CTRL) {
1103 if (cca != CCA_NEW || cp.company != COMPANY_SPECTATOR) {
1104 return this->SendError(NETWORK_ERROR_CHEATER);
1105 }
1106
1107 /* 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! */
1108 if (Company::GetNumItems() >= _settings_client.network.max_companies) {
1109 NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER);
1110 return NETWORK_RECV_STATUS_OKAY;
1111 }

Callers

nothing calls this directly

Calls 12

SendErrorMethod · 0.95
GetClientIPMethod · 0.95
NetworkServerSendChatFunction · 0.85
HasClientQuitMethod · 0.80
ReceiveCommandMethod · 0.80
TestMethod · 0.80
push_backMethod · 0.80
IConsolePrintFunction · 0.50
GetCommandFlagsFunction · 0.50
sizeMethod · 0.45
GetInfoMethod · 0.45

Tested by

no test coverage detected