# HG changeset patch # User rubidium # Date 2010-10-17 17:37:45 # Node ID 4ee91980c70f6e398771d319f5ad048e701896f1 # Parent 7148460f4b1ce1c07e03489935ce72bd2b23d016 (svn r20970) -Add: company change notification to remote admins (dihedral) diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -21,6 +21,7 @@ #include "network/network.h" #include "network/network_func.h" #include "network/network_base.h" +#include "network/network_admin.h" #include "ai/ai.hpp" #include "company_manager_face.h" #include "window_func.h" @@ -740,6 +741,28 @@ void CompanyNewsInformation::FillData(co } /** + * Called whenever company related information changes in order to notify admins. + * @param company The company data changed of. + */ +void CompanyAdminUpdate(const Company *company) +{ +#ifdef ENABLE_NETWORK + if (_network_server) NetworkAdminCompanyUpdate(company); +#endif /* ENABLE_NETWORK */ +} + +/** + * Called whenever a company goes bankrupt in order to notify admins. + * @param company_id The company that went bankrupt. + */ +void CompanyAdminBankrupt(CompanyID company_id) +{ +#ifdef ENABLE_NETWORK + if (_network_server) NetworkAdminCompanyRemove(company_id, ADMIN_CRR_BANKRUPT); +#endif /* ENABLE_NETWORK */ +} + +/** * Control the companies: add, delete, etc. * @param tile unused * @param flags operation to perform @@ -827,6 +850,7 @@ CommandCost CmdCompanyCtrl(TileIndex til /* Announce new company on network, if the client was a SPECTATOR before */ if (old_playas == COMPANY_SPECTATOR) { + NetworkAdminCompanyInfo(c, true); NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, ci->client_playas + 1); } } @@ -865,6 +889,7 @@ CommandCost CmdCompanyCtrl(TileIndex til CompanyID c_index = c->index; delete c; AI::BroadcastNewEvent(new AIEventCompanyBankrupt(c_index)); + CompanyAdminBankrupt(c_index); break; } @@ -935,6 +960,7 @@ CommandCost CmdSetCompanyColour(TileInde if (scheme == LS_DEFAULT) { _company_colours[_current_company] = colour; c->colour = colour; + CompanyAdminUpdate(c); } break; @@ -1032,6 +1058,7 @@ CommandCost CmdRenameCompany(TileIndex t free(c->name); c->name = reset ? NULL : strdup(text); MarkWholeScreenDirty(); + CompanyAdminUpdate(c); } return CommandCost(); @@ -1089,6 +1116,7 @@ CommandCost CmdRenamePresident(TileIndex } MarkWholeScreenDirty(); + CompanyAdminUpdate(c); } return CommandCost(); diff --git a/src/company_func.h b/src/company_func.h --- a/src/company_func.h +++ b/src/company_func.h @@ -21,6 +21,8 @@ void ChangeOwnershipOfCompanyItems(Owner void GetNameOfOwner(Owner owner, TileIndex tile); void SetLocalCompany(CompanyID new_company); void ShowBuyCompanyDialog(CompanyID company); +void CompanyAdminUpdate(const Company *company); +void CompanyAdminBankrupt(CompanyID company_id); extern CompanyByte _local_company; extern CompanyByte _current_company; diff --git a/src/economy.cpp b/src/economy.cpp --- a/src/economy.cpp +++ b/src/economy.cpp @@ -534,6 +534,7 @@ static void CompanyCheckBankrupt(Company CompanyID c_index = c->index; delete c; AI::BroadcastNewEvent(new AIEventCompanyBankrupt(c_index)); + CompanyAdminBankrupt(c_index); } } @@ -1534,6 +1535,7 @@ CommandCost CmdBuyShareInCompany(TileInd } } SetWindowDirty(WC_COMPANY, target_company); + CompanyAdminUpdate(c); } return cost; } @@ -1568,6 +1570,7 @@ CommandCost CmdSellShareInCompany(TileIn while (*b != _current_company) b++; // share owners is guaranteed to contain company *b = COMPANY_SPECTATOR; SetWindowDirty(WC_COMPANY, target_company); + CompanyAdminUpdate(c); } return CommandCost(EXPENSES_OTHER, cost); } diff --git a/src/network/core/tcp_admin.cpp b/src/network/core/tcp_admin.cpp --- a/src/network/core/tcp_admin.cpp +++ b/src/network/core/tcp_admin.cpp @@ -69,6 +69,10 @@ NetworkRecvStatus NetworkAdminSocketHand ADMIN_COMMAND(ADMIN_PACKET_SERVER_CLIENT_UPDATE) ADMIN_COMMAND(ADMIN_PACKET_SERVER_CLIENT_QUIT) ADMIN_COMMAND(ADMIN_PACKET_SERVER_CLIENT_ERROR) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_COMPANY_NEW) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_COMPANY_INFO) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_COMPANY_UPDATE) + ADMIN_COMMAND(ADMIN_PACKET_SERVER_COMPANY_REMOVE) default: if (this->HasClientQuit()) { @@ -133,5 +137,9 @@ DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_UPDATE) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_QUIT) DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_ERROR) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_NEW) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_INFO) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_UPDATE) +DEFINE_UNAVAILABLE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_REMOVE) #endif /* ENABLE_NETWORK */ diff --git a/src/network/core/tcp_admin.h b/src/network/core/tcp_admin.h --- a/src/network/core/tcp_admin.h +++ b/src/network/core/tcp_admin.h @@ -45,6 +45,10 @@ enum PacketAdminType { ADMIN_PACKET_SERVER_CLIENT_UPDATE, ///< The server gives the admin an information update on a client. ADMIN_PACKET_SERVER_CLIENT_QUIT, ///< The server tells the admin that a client quit. ADMIN_PACKET_SERVER_CLIENT_ERROR, ///< The server tells the admin that a client caused an error. + ADMIN_PACKET_SERVER_COMPANY_NEW, ///< The server tells the admin that a new company has started. + ADMIN_PACKET_SERVER_COMPANY_INFO, ///< The server gives the admin information about a company. + ADMIN_PACKET_SERVER_COMPANY_UPDATE, ///< The server gives the admin an information update on a company. + ADMIN_PACKET_SERVER_COMPANY_REMOVE, ///< The server tells the admin that a company was removed. INVALID_ADMIN_PACKET = 0xFF, ///< An invalid marker for admin packets. }; @@ -60,6 +64,7 @@ enum AdminStatus { enum AdminUpdateType { ADMIN_UPDATE_DATE, ///< Updates about the date of the game. ADMIN_UPDATE_CLIENT_INFO, ///< Updates about the information of clients. + ADMIN_UPDATE_COMPANY_INFO, ///< Updates about the generic information of companies. ADMIN_UPDATE_END ///< Must ALWAYS be on the end of this list!! (period) }; @@ -75,6 +80,13 @@ enum AdminUpdateFrequency { }; DECLARE_ENUM_AS_BIT_SET(AdminUpdateFrequency); +/** Reasons for removing a company - communicated to admins. */ +enum AdminCompanyRemoveReason { + ADMIN_CRR_MANUAL, ///< The company is manually removed. + ADMIN_CRR_AUTOCLEAN, ///< The company is removed due to autoclean. + ADMIN_CRR_BANKRUPT ///< The company went belly-up. +}; + #define DECLARE_ADMIN_RECEIVE_COMMAND(type) virtual NetworkRecvStatus NetworkPacketReceive_## type ##_command(Packet *p) #define DEF_ADMIN_RECEIVE_COMMAND(cls, type) NetworkRecvStatus cls ##NetworkAdminSocketHandler::NetworkPacketReceive_ ## type ## _command(Packet *p) @@ -110,6 +122,7 @@ protected: * uint8 #AdminUpdateType the server should answer for, only if #AdminUpdateFrequency #ADMIN_FREQUENCY_POLL is advertised in the PROTOCOL packet. * uint32 ID relevant to the packet type, e.g. * - the client ID for #ADMIN_UPDATE_CLIENT_INFO. Use UINT32_MAX to show all clients. + * - the company ID for #ADMIN_UPDATE_COMPANY_INFO. Use UINT32_MAX to show all companies. */ DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_ADMIN_POLL); @@ -206,6 +219,46 @@ protected: */ DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_CLIENT_ERROR); + /** + * Notification of a new company: + * uint8 ID of the new company. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_NEW); + + /** + * Company information on a specific company: + * uint8 ID of the company. + * string Name of the company. + * string Name of the companies manager. + * uint8 Main company colour. + * bool Company is password protected. + * uint32 Year the company was inaugurated. + * bool Company is an AI. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_INFO); + + /** + * Company information of a specific company: + * uint8 ID of the company. + * string Name of the company. + * string Name of the companies manager. + * uint8 Main company colour. + * bool Company is password protected. + * uint8 Quarters of bankruptcy. + * uint8 Owner of share 1. + * uint8 Owner of share 2. + * uint8 Owner of share 3. + * uint8 Owner of share 4. + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_UPDATE); + + /** + * Notification about a removed company (e.g. due to banrkuptcy). + * uint8 ID of the company. + * uint8 Reason for being removed (see #AdminCompanyRemoveReason). + */ + DECLARE_ADMIN_RECEIVE_COMMAND(ADMIN_PACKET_SERVER_COMPANY_REMOVE); + NetworkRecvStatus HandlePacket(Packet *p); public: NetworkRecvStatus CloseConnection(bool error = true); diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -42,6 +42,7 @@ static const int ADMIN_AUTHORISATION_TIM static const AdminUpdateFrequency _admin_update_type_frequencies[] = { ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_DAILY | ADMIN_FREQUENCY_WEEKLY | ADMIN_FREQUENCY_MONTHLY | ADMIN_FREQUENCY_QUARTERLY | ADMIN_FREQUENCY_ANUALLY, ///< ADMIN_UPDATE_DATE ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_CLIENT_INFO + ADMIN_FREQUENCY_POLL | ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_COMPANY_INFO }; assert_compile(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END); @@ -241,6 +242,83 @@ NetworkRecvStatus ServerNetworkAdminSock return NETWORK_RECV_STATUS_OKAY; } +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyNew(CompanyID company_id) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_NEW); + p->Send_uint8(company_id); + + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyInfo(const Company *c) +{ + char company_name[NETWORK_COMPANY_NAME_LENGTH]; + char manager_name[NETWORK_COMPANY_NAME_LENGTH]; + + SetDParam(0, c->index); + GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); + + SetDParam(0, c->index); + GetString(manager_name, STR_PRESIDENT_NAME, lastof(manager_name)); + + Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_INFO); + + p->Send_uint8 (c->index); + p->Send_string(company_name); + p->Send_string(manager_name); + p->Send_uint8 (c->colour); + p->Send_bool (NetworkCompanyIsPassworded(c->index)); + p->Send_uint32(c->inaugurated_year); + p->Send_bool (c->is_ai); + + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyUpdate(const Company *c) +{ + char company_name[NETWORK_COMPANY_NAME_LENGTH]; + char manager_name[NETWORK_COMPANY_NAME_LENGTH]; + + SetDParam(0, c->index); + GetString(company_name, STR_COMPANY_NAME, lastof(company_name)); + + SetDParam(0, c->index); + GetString(manager_name, STR_PRESIDENT_NAME, lastof(manager_name)); + + Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_UPDATE); + + p->Send_uint8 (c->index); + p->Send_string(company_name); + p->Send_string(manager_name); + p->Send_uint8 (c->colour); + p->Send_bool (NetworkCompanyIsPassworded(c->index)); + p->Send_uint8 (c->quarters_of_bankruptcy); + + for (size_t i = 0; i < lengthof(c->share_owners); i++) { + p->Send_uint8(c->share_owners[i]); + } + + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + +NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason acrr) +{ + Packet *p = new Packet(ADMIN_PACKET_SERVER_COMPANY_REMOVE); + + p->Send_uint8(company_id); + p->Send_uint8(acrr); + + this->Send_Packet(p); + + return NETWORK_RECV_STATUS_OKAY; +} + /*********** * Receiving functions ************/ @@ -321,6 +399,19 @@ DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_ } break; + case ADMIN_UPDATE_COMPANY_INFO: + /* The admin is asking for company info. */ + const Company *company; + if (d1 == UINT32_MAX) { + FOR_ALL_COMPANIES(company) { + this->SendCompanyInfo(company); + } + } else { + company = Company::GetIfValid(d1); + if (company != NULL) this->SendCompanyInfo(company); + } + break; + default: /* An unsupported "poll" update type. */ DEBUG(net, 3, "[admin] Not supported poll %d (%d) from '%s' (%s).", type, d1, this->admin_name, this->admin_version); @@ -396,6 +487,58 @@ void NetworkAdminClientError(ClientID cl } /** + * Notify the admin network of company details. + * @param company the company of which details will be sent into the admin network. + * @param new_company whether this is a new company or not. + */ +void NetworkAdminCompanyInfo(const Company *company, bool new_company) +{ + if (company == NULL) { + DEBUG(net, 1, "[admin] Empty company given for update"); + return; + } + + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + if (as->update_frequency[ADMIN_UPDATE_COMPANY_INFO] != ADMIN_FREQUENCY_AUTOMATIC) continue; + + as->SendCompanyInfo(company); + if (new_company) { + as->SendCompanyNew(company->index); + } + } +} + +/** + * Notify the admin network of company updates. + * @param company company of which updates are going to be sent into the admin network. + */ +void NetworkAdminCompanyUpdate(const Company *company) +{ + if (company == NULL) return; + + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + if (as->update_frequency[ADMIN_UPDATE_COMPANY_INFO] != ADMIN_FREQUENCY_AUTOMATIC) continue; + + as->SendCompanyUpdate(company); + } +} + +/** + * Notify the admin network of a company to be removed (including the reason why). + * @param company_id ID of the company that got removed. + * @param bcrr the reason why the company got removed (e.g. bankruptcy). + */ +void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr) +{ + ServerNetworkAdminSocketHandler *as; + FOR_ALL_ADMIN_SOCKETS(as) { + as->SendCompanyRemove(company_id, bcrr); + } +} + +/** * Send a Welcome packet to all connected admins */ void ServerNetworkAdminSocketHandler::WelcomeAll() diff --git a/src/network/network_admin.h b/src/network/network_admin.h --- a/src/network/network_admin.h +++ b/src/network/network_admin.h @@ -49,6 +49,10 @@ public: NetworkRecvStatus SendClientUpdate(const NetworkClientInfo *ci); NetworkRecvStatus SendClientQuit(ClientID client_id); NetworkRecvStatus SendClientError(ClientID client_id, NetworkErrorCode error); + NetworkRecvStatus SendCompanyNew(CompanyID company_id); + NetworkRecvStatus SendCompanyInfo(const Company *c); + NetworkRecvStatus SendCompanyUpdate(const Company *c); + NetworkRecvStatus SendCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr); static void Send(); static void AcceptConnection(SOCKET s, const NetworkAddress &address); @@ -72,6 +76,9 @@ void NetworkAdminClientInfo(const Networ void NetworkAdminClientUpdate(const NetworkClientInfo *ci); void NetworkAdminClientQuit(ClientID client_id); void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code); +void NetworkAdminCompanyInfo(const Company *company, bool new_company); +void NetworkAdminCompanyUpdate(const Company *company); +void NetworkAdminCompanyRemove(CompanyID company_id, AdminCompanyRemoveReason bcrr); void NetworkAdminUpdate(AdminUpdateFrequency freq); #endif /* ENABLE_NETWORK */ diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1544,6 +1544,7 @@ static void NetworkAutoCleanCompanies() if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && StrEmpty(_network_company_states[c->index].password)) { /* Shut the company down */ DoCommandP(0, 2 | c->index << 16, 0, CMD_COMPANY_CTRL); + NetworkAdminCompanyRemove(c->index, ADMIN_CRR_AUTOCLEAN); IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no password", c->index + 1); } /* Is the company empty for autoclean_protected-months, and there is a protection? */ @@ -1558,6 +1559,7 @@ static void NetworkAutoCleanCompanies() if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) { /* Shut the company down */ DoCommandP(0, 2 | c->index << 16, 0, CMD_COMPANY_CTRL); + NetworkAdminCompanyRemove(c->index, ADMIN_CRR_AUTOCLEAN); IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1); } } else {