DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHAT) { if (this->status != STATUS_ACTIVE) return NETWORK_RECV_STATUS_MALFORMED_PACKET; char name[NETWORK_NAME_LENGTH], msg[NETWORK_CHAT_LENGTH]; const NetworkClientInfo *ci = NULL, *ci_to; NetworkAction action = (NetworkAction)p->Recv_uint8(); ClientID client_id = (ClientID)p->Recv_uint32(); bool self_send = p->Recv_bool(); p->Recv_string(msg, NETWORK_CHAT_LENGTH); int64 data = p->Recv_uint64(); ci_to = NetworkFindClientInfoFromClientID(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 = NetworkFindClientInfoFromClientID(_network_own_client_id); break; /* For speaking to company or giving money, we need the company-name */ case NETWORK_ACTION_GIVE_MONEY: if (!Company::IsValidID(ci_to->client_playas)) return NETWORK_RECV_STATUS_OKAY; /* FALL THROUGH */ case NETWORK_ACTION_CHAT_COMPANY: { StringID str = Company::IsValidID(ci_to->client_playas) ? STR_COMPANY_NAME : STR_NETWORK_SPECTATORS; SetDParam(0, ci_to->client_playas); GetString(name, str, lastof(name)); ci = NetworkFindClientInfoFromClientID(_network_own_client_id); break; } default: return NETWORK_RECV_STATUS_MALFORMED_PACKET; } } else { /* Display message from somebody else */ snprintf(name, sizeof(name), "%s", ci_to->client_name); ci = ci_to; } if (ci != NULL) { NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), self_send, name, msg, data); } return NETWORK_RECV_STATUS_OKAY; }
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MOVE) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; /* 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 (!Company::IsValidID(company_id)) company_id = COMPANY_SPECTATOR; if (client_id == _network_own_client_id) { SetLocalCompany(company_id); } return NETWORK_RECV_STATUS_OKAY; }
virtual void DrawWidget(const Rect &r, int widget) const { if (widget != NWCW_DESTINATION) return; if (this->dtype == DESTTYPE_CLIENT) { SetDParamStr(0, NetworkFindClientInfoFromClientID((ClientID)this->dest)->client_name); } DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, this->dest_string, TC_BLACK, SA_RIGHT); }
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { if (widget != NWCW_DESTINATION) return; if (this->dtype == DESTTYPE_CLIENT) { SetDParamStr(0, NetworkFindClientInfoFromClientID((ClientID)this->dest)->client_name); } Dimension d = GetStringBoundingBox(this->dest_string); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(*size, d); }
/* This packet contains info about the client (playas and name) * as client we save this in NetworkClientInfo, linked via 'client_id' * which is always an unique number on a server. */ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CLIENT_INFO) { NetworkClientInfo *ci; 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 (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; ci = NetworkFindClientInfoFromClientID(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, name); } else if (playas != ci->client_playas) { /* The client changed from client-player.. * Do not display that for now */ } /* Make sure we're in the company the server tells us to be in, * for the rare case that we get moved while joining. */ if (client_id == _network_own_client_id) SetLocalCompany(!Company::IsValidID(playas) ? COMPANY_SPECTATOR : playas); ci->client_playas = playas; strecpy(ci->client_name, name, lastof(ci->client_name)); SetWindowDirty(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } /* There are at most as many ClientInfo as ClientSocket objects in a * server. Having more Infos than a server can have means something * has gone wrong somewhere, i.e. the server has more Infos than it * has actual clients. That means the server is feeding us an invalid * state. So, bail out! This server is broken. */ if (!NetworkClientInfo::CanAllocateItem()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; /* We don't have this client_id yet, find an empty client_id, and put the data there */ ci = new NetworkClientInfo(client_id); ci->client_playas = playas; if (client_id == _network_own_client_id) this->SetInfo(ci); strecpy(ci->client_name, name, lastof(ci->client_name)); SetWindowDirty(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; }
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_JOIN) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id); if (ci != NULL) { NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name); } SetWindowDirty(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; }
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_ERROR_QUIT) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id); if (ci != NULL) { NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, GetNetworkErrorMsg((NetworkErrorCode)p->Recv_uint8())); delete ci; } SetWindowDirty(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; }
DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_QUIT) { if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; ClientID client_id = (ClientID)p->Recv_uint32(); NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id); if (ci != NULL) { NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING); delete ci; } else { DEBUG(net, 0, "Unknown client (%d) is leaving the game", client_id); } SetWindowDirty(WC_CLIENT_LIST, 0); /* If we come here it means we could not locate the client.. strange :s */ return NETWORK_RECV_STATUS_OKAY; }
void NetworkUpdateClientName() { NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(_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) { MyClient::SendSetName(_settings_client.network.client_name); } else { if (NetworkFindName(_settings_client.network.client_name)) { NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, _settings_client.network.client_name); strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name)); NetworkUpdateClientInfo(CLIENT_ID_SERVER); } } } }
/** Control the companies: add, delete, etc. * @param tile unused * @param flags operation to perform * @param p1 various functionality * - p1 = 0 - create a new company, Which company (network) it will be is in p2 * - p1 = 1 - create a new AI company * - p1 = 2 - delete a company. Company is identified by p2 * @param p2 various functionality, dictated by p1 * - p1 = 0 - ClientID of the newly created client * - p1 = 1 - CompanyID to start AI (INVALID_COMPANY for first available) * - p1 = 2 - CompanyID of the that is getting deleted * @param text unused * @return the cost of this operation or an error * * @todo In the case of p1=0, create new company, the clientID of the new client is in parameter * p2. This parameter is passed in at function DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) * on the server itself. First of all this is unbelievably ugly; second of all, well, * it IS ugly! <b>Someone fix this up :)</b> So where to fix?@n * @arg - network_server.c:838 DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)@n * @arg - network_client.c:536 DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_MAP) from where the map has been received */ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0); switch (p1) { case 0: { // Create a new company /* This command is only executed in a multiplayer game */ if (!_networking) return CMD_ERROR; #ifdef ENABLE_NETWORK /* Joining Client: * _local_company: COMPANY_SPECTATOR * cid = clientid * * Other client(s)/server: * _local_company: what they play as * cid = requested company/company of joining client */ ClientID cid = (ClientID)p2; /* Has the network client a correct ClientIndex? */ if (!(flags & DC_EXEC)) return CommandCost(); NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(cid); if (ci == NULL) 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) { ci->client_playas = COMPANY_SPECTATOR; NetworkUpdateClientInfo(ci->client_id); } break; } /* This is the client (or non-dedicated server) who wants a new company */ if (cid == _network_own_client_id) { assert(_local_company == COMPANY_SPECTATOR); SetLocalCompany(c->index); if (!StrEmpty(_settings_client.network.default_company_pass)) { NetworkChangeCompanyPassword(_settings_client.network.default_company_pass); } /* Now that we have a new company, broadcast our company settings to * all clients so everything is in sync */ SyncCompanySettings(); 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) */ CompanyID old_playas = ci->client_playas; ci->client_playas = c->index; NetworkUpdateClientInfo(ci->client_id); if (Company::IsValidID(ci->client_playas)) { _network_company_states[c->index].months_empty = 0; _network_company_states[c->index].password[0] = '\0'; NetworkServerUpdateCompanyPassworded(ci->client_playas, false); /* 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; * but it works. * TODO: Perhaps this could be improved by when the client is ready * with joining to let it send itself the command, and not the server? * For example in network_client.c:534? */ NetworkSend_Command(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name, ci->client_playas); } /* Announce new company on network, if the client was a SPECTATOR before */ if (old_playas == COMPANY_SPECTATOR) { NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, ci->client_playas + 1); } } #endif /* ENABLE_NETWORK */ } break; case 1: // Make a new AI company if (!(flags & DC_EXEC)) return CommandCost(); if (p2 != INVALID_COMPANY && (p2 >= MAX_COMPANIES || Company::IsValidID(p2))) return CMD_ERROR; DoStartupNewCompany(true, (CompanyID)p2); break; case 2: { // Delete a company Company *c = Company::GetIfValid(p2); if (c == NULL) return CMD_ERROR; if (!(flags & DC_EXEC)) return CommandCost(); /* Delete any open window of the company */ DeleteCompanyWindows(c->index); CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1); cni->FillData(c); /* Show the bankrupt news */ SetDParam(0, STR_NEWS_COMPANY_BANKRUPT_TITLE); SetDParam(1, STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION); SetDParamStr(2, cni->company_name); AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_BANKRUPT, cni); /* Remove the company */ ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER); if (c->is_ai) AI::Stop(c->index); CompanyID c_index = c->index; delete c; AI::BroadcastNewEvent(new AIEventCompanyBankrupt(c_index)); } break; default: return CMD_ERROR; } return CommandCost(); }