1
0
Fork 0

(svn r22461) [1.1] -Backport from trunk:

- Fix: [NewGRF] Zero register 0x100 as specified before resolving custom station foundations (r22452)
- Fix: Do not 'log' the NewGRFs in the screenshot when in the menu [FS#4610] (r22450)
- Fix: Keep better accounting of the order in which clients joined; client can't be starved from joining and they get shown the amount of clients waiting in front of them. (r22372, r22370, r22369, r22368, r22367, r22366, r22365, r22364, r22363, r22362, r22361)
- Fix: Delete the client list popup when the client got removed (instead of previously selecting some other client) (r22360, r22359, r22358)
release/1.1
rubidium 2011-05-15 09:38:54 +00:00
parent 829a2c201d
commit 59a11e6626
20 changed files with 187 additions and 177 deletions

View File

@ -556,7 +556,7 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY)
GeneratePresidentName(c);
SetWindowDirty(WC_GRAPH_LEGEND, 0);
SetWindowDirty(WC_TOOLBAR_MENU, 0);
SetWindowClassesDirty(WC_CLIENT_LIST_POPUP);
SetWindowDirty(WC_CLIENT_LIST, 0);
BuildOwnerLegend();
InvalidateWindowData(WC_SMALLMAP, 0, 1);
@ -813,7 +813,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
#ifdef ENABLE_NETWORK
/* Has the network client a correct ClientIndex? */
if (!(flags & DC_EXEC)) return CommandCost();
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
if (ci == NULL) return CommandCost();
/* Delete multiplayer progress bar */

View File

@ -490,7 +490,7 @@ DEF_CONSOLE_CMD(ConClearBuffer)
static bool ConKickOrBan(const char *argv, bool ban)
{
const char *ip = argv;
uint n;
if (strchr(argv, '.') == NULL && strchr(argv, ':') == NULL) { // banning with ID
ClientID client_id = (ClientID)atoi(argv);
@ -504,7 +504,7 @@ static bool ConKickOrBan(const char *argv, bool ban)
return true;
}
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
if (ci == NULL) {
IConsoleError("Invalid client");
return true;
@ -517,10 +517,11 @@ static bool ConKickOrBan(const char *argv, bool ban)
}
/* When banning, kick+ban all clients with that IP */
ip = GetClientIP(ci);
n = NetworkServerKickOrBanIP(client_id, ban);
} else {
n = NetworkServerKickOrBanIP(argv, ban);
}
uint n = NetworkServerKickOrBanIP(ip, ban);
if (n == 0) {
IConsolePrint(CC_DEFAULT, ban ? "Client not online, address added to banlist" : "Client not found");
} else {
@ -699,7 +700,7 @@ DEF_CONSOLE_CMD(ConClientNickChange)
return true;
}
if (NetworkFindClientInfoFromClientID(client_id) == NULL) {
if (NetworkClientInfo::GetByClientID(client_id) == NULL) {
IConsoleError("Invalid client");
return true;
}
@ -727,7 +728,7 @@ DEF_CONSOLE_CMD(ConJoinCompany)
return true;
}
if (NetworkFindClientInfoFromClientID(_network_own_client_id)->client_playas == company_id) {
if (NetworkClientInfo::GetByClientID(_network_own_client_id)->client_playas == company_id) {
IConsoleError("You are already there!");
return true;
}
@ -766,7 +767,7 @@ DEF_CONSOLE_CMD(ConMoveClient)
return true;
}
const NetworkClientInfo *ci = NetworkFindClientInfoFromClientID((ClientID)atoi(argv[1]));
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID((ClientID)atoi(argv[1]));
CompanyID company_id = (CompanyID)(atoi(argv[2]) <= MAX_COMPANIES ? atoi(argv[2]) - 1 : atoi(argv[2]));
/* check the client exists */
@ -828,7 +829,7 @@ DEF_CONSOLE_CMD(ConResetCompany)
IConsoleError("Cannot remove company: a client is connected to that company.");
return false;
}
const NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
if (ci->client_playas == index) {
IConsoleError("Cannot remove company: the server is connected to that company.");
return true;

View File

@ -377,7 +377,7 @@ struct MainWindow : Window
#ifdef ENABLE_NETWORK
case GHK_CHAT: // smart chat; send to team if any, otherwise to all
if (_networking) {
const NetworkClientInfo *cio = NetworkFindClientInfoFromClientID(_network_own_client_id);
const NetworkClientInfo *cio = NetworkClientInfo::GetByClientID(_network_own_client_id);
if (cio == NULL) break;
ShowNetworkChatQueryWindow(NetworkClientPreferTeamChat(cio) ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
@ -390,7 +390,7 @@ struct MainWindow : Window
case GHK_CHAT_COMPANY: // send text to all team mates
if (_networking) {
const NetworkClientInfo *cio = NetworkFindClientInfoFromClientID(_network_own_client_id);
const NetworkClientInfo *cio = NetworkClientInfo::GetByClientID(_network_own_client_id);
if (cio == NULL) break;
ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas);

View File

@ -266,7 +266,7 @@ protected:
/**
* Notification that another client is currently receiving the map:
* uint8 Number of clients awaiting the map.
* uint8 Number of clients waiting in front of you.
*/
DECLARE_GAME_RECEIVE_COMMAND(PACKET_SERVER_WAIT);

View File

@ -108,7 +108,7 @@ NetworkClientInfo::~NetworkClientInfo()
* @param client_id the ClientID to search for
* @return return a pointer to the corresponding NetworkClientInfo struct or NULL when not found
*/
NetworkClientInfo *NetworkFindClientInfoFromClientID(ClientID client_id)
/* static */ NetworkClientInfo *NetworkClientInfo::GetByClientID(ClientID client_id)
{
NetworkClientInfo *ci;
@ -124,7 +124,7 @@ NetworkClientInfo *NetworkFindClientInfoFromClientID(ClientID client_id)
* @param client_id the ClientID to search for
* @return return a pointer to the corresponding NetworkClientSocket struct or NULL when not found
*/
NetworkClientSocket *NetworkFindClientStateFromClientID(ClientID client_id)
/* static */ NetworkClientSocket *NetworkClientSocket::GetByClientID(ClientID client_id)
{
NetworkClientSocket *cs;
@ -484,7 +484,7 @@ void ParseConnectionString(const char **company, const char **port, char *connec
SetWindowDirty(WC_CLIENT_LIST, 0);
ServerNetworkGameSocketHandler *cs = new ServerNetworkGameSocketHandler(s);
cs->GetInfo()->client_address = address; // Save the IP of the client
cs->client_address = address; // Save the IP of the client
}
/**
@ -686,11 +686,6 @@ static void NetworkInitGameInfo()
assert(NetworkClientInfo::CanAllocateItem());
NetworkClientInfo *ci = new NetworkClientInfo(CLIENT_ID_SERVER);
ci->client_playas = _network_dedicated ? COMPANY_SPECTATOR : _local_company;
/* Give the server a valid IP; banning it is pointless anyways */
sockaddr_in sock;
memset(&sock, 0, sizeof(sock));
sock.sin_family = AF_INET;
ci->client_address = NetworkAddress((sockaddr*)&sock, sizeof(sock));
strecpy(ci->client_name, _settings_client.network.client_name, lastof(ci->client_name));
}

View File

@ -201,12 +201,16 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientJoin(ClientID clien
return NETWORK_RECV_STATUS_OKAY;
}
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkClientInfo *ci)
NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkClientSocket *cs)
{
/* Only send data when we're a proper client, not just someone trying to query the server. */
const NetworkClientInfo *ci = cs->GetInfo();
if (ci == NULL) return NETWORK_RECV_STATUS_OKAY;
Packet *p = new Packet(ADMIN_PACKET_SERVER_CLIENT_INFO);
p->Send_uint32(ci->client_id);
p->Send_string(const_cast<NetworkAddress &>(ci->client_address).GetHostname());
p->Send_string(const_cast<NetworkAddress &>(cs->client_address).GetHostname());
p->Send_string(ci->client_name);
p->Send_uint8 (ci->client_lang);
p->Send_uint32(ci->join_date);
@ -565,14 +569,14 @@ DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_POLL)
case ADMIN_UPDATE_CLIENT_INFO:
/* The admin is requesting client info. */
const NetworkClientInfo *ci;
const NetworkClientSocket *cs;
if (d1 == UINT32_MAX) {
FOR_ALL_CLIENT_INFOS(ci) {
this->SendClientInfo(ci);
FOR_ALL_CLIENT_SOCKETS(cs) {
this->SendClientInfo(cs);
}
} else {
ci = NetworkFindClientInfoFromClientID((ClientID)d1);
if (ci != NULL) this->SendClientInfo(ci);
cs = NetworkClientSocket::GetByClientID((ClientID)d1);
if (cs != NULL) this->SendClientInfo(cs);
}
break;
@ -649,14 +653,14 @@ DEF_ADMIN_RECEIVE_COMMAND(Server, ADMIN_PACKET_ADMIN_CHAT)
* @param ci the client info.
* @param new_client if this is a new client, send the respective packet too.
*/
void NetworkAdminClientInfo(const NetworkClientInfo *ci, bool new_client)
void NetworkAdminClientInfo(const NetworkClientSocket *cs, bool new_client)
{
ServerNetworkAdminSocketHandler *as;
FOR_ALL_ADMIN_SOCKETS(as) {
if (as->update_frequency[ADMIN_UPDATE_CLIENT_INFO] & ADMIN_FREQUENCY_AUTOMATIC) {
as->SendClientInfo(ci);
as->SendClientInfo(cs);
if (new_client) {
as->SendClientJoin(ci->client_id);
as->SendClientJoin(cs->client_id);
}
}
}

View File

@ -50,7 +50,7 @@ public:
NetworkRecvStatus SendDate();
NetworkRecvStatus SendClientJoin(ClientID client_id);
NetworkRecvStatus SendClientInfo(const NetworkClientInfo *ci);
NetworkRecvStatus SendClientInfo(const NetworkClientSocket *cs);
NetworkRecvStatus SendClientUpdate(const NetworkClientInfo *ci);
NetworkRecvStatus SendClientQuit(ClientID client_id);
NetworkRecvStatus SendClientError(ClientID client_id, NetworkErrorCode error);
@ -85,7 +85,7 @@ public:
#define FOR_ALL_ADMIN_SOCKETS_FROM(var, start) FOR_ALL_ITEMS_FROM(ServerNetworkAdminSocketHandler, adminsocket_index, var, start)
#define FOR_ALL_ADMIN_SOCKETS(var) FOR_ALL_ADMIN_SOCKETS_FROM(var, 0)
void NetworkAdminClientInfo(const NetworkClientInfo *ci, bool new_client = false);
void NetworkAdminClientInfo(const NetworkClientSocket *cs, bool new_client = false);
void NetworkAdminClientUpdate(const NetworkClientInfo *ci);
void NetworkAdminClientQuit(ClientID client_id);
void NetworkAdminClientError(ClientID client_id, NetworkErrorCode error_code);

View File

@ -27,11 +27,12 @@ struct NetworkClientInfo : NetworkClientInfoPool::PoolItem<&_networkclientinfo_p
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)
NetworkAddress client_address; ///< IP-address of the client (so he can be banned)
Date join_date; ///< Gamedate the client has joined
NetworkClientInfo(ClientID client_id = INVALID_CLIENT_ID) : client_id(client_id) {}
~NetworkClientInfo();
static NetworkClientInfo *GetByClientID(ClientID client_id);
};
#define FOR_ALL_CLIENT_INFOS_FROM(var, start) FOR_ALL_ITEMS_FROM(NetworkClientInfo, clientinfo_index, var, start)

View File

@ -468,7 +468,7 @@ struct NetworkChatWindow : public QueryStringBaseWindow {
if (widget != NWCW_DESTINATION) return;
if (this->dtype == DESTTYPE_CLIENT) {
SetDParamStr(0, NetworkFindClientInfoFromClientID((ClientID)this->dest)->client_name);
SetDParamStr(0, NetworkClientInfo::GetByClientID((ClientID)this->dest)->client_name);
}
Dimension d = GetStringBoundingBox(this->dest_string);
d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
@ -481,7 +481,7 @@ struct NetworkChatWindow : public QueryStringBaseWindow {
if (widget != NWCW_DESTINATION) return;
if (this->dtype == DESTTYPE_CLIENT) {
SetDParamStr(0, NetworkFindClientInfoFromClientID((ClientID)this->dest)->client_name);
SetDParamStr(0, NetworkClientInfo::GetByClientID((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);
}

View File

@ -563,7 +563,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CLIENT_INFO)
if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST;
ci = NetworkFindClientInfoFromClientID(client_id);
ci = NetworkClientInfo::GetByClientID(client_id);
if (ci != NULL) {
if (playas == ci->client_playas && strcmp(name, ci->client_name) != 0) {
/* Client name changed, display the change */
@ -916,7 +916,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHAT)
p->Recv_string(msg, NETWORK_CHAT_LENGTH);
int64 data = p->Recv_uint64();
ci_to = NetworkFindClientInfoFromClientID(client_id);
ci_to = NetworkClientInfo::GetByClientID(client_id);
if (ci_to == NULL) return NETWORK_RECV_STATUS_OKAY;
/* Did we initiate the action locally? */
@ -925,7 +925,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHAT)
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);
ci = NetworkClientInfo::GetByClientID(_network_own_client_id);
break;
/* For speaking to company or giving money, we need the company-name */
@ -937,7 +937,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_CHAT)
SetDParam(0, ci_to->client_playas);
GetString(name, str, lastof(name));
ci = NetworkFindClientInfoFromClientID(_network_own_client_id);
ci = NetworkClientInfo::GetByClientID(_network_own_client_id);
break;
}
@ -961,7 +961,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_ERROR_QUIT)
ClientID client_id = (ClientID)p->Recv_uint32();
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
if (ci != NULL) {
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, GetNetworkErrorMsg((NetworkErrorCode)p->Recv_uint8()));
delete ci;
@ -978,7 +978,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_QUIT)
ClientID client_id = (ClientID)p->Recv_uint32();
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
if (ci != NULL) {
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, ci->client_name, NULL, STR_NETWORK_MESSAGE_CLIENT_LEAVING);
delete ci;
@ -998,7 +998,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_JOIN)
ClientID client_id = (ClientID)p->Recv_uint32();
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
if (ci != NULL) {
NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name);
}
@ -1063,7 +1063,7 @@ DEF_GAME_RECEIVE_COMMAND(Client, PACKET_SERVER_MOVE)
return NETWORK_RECV_STATUS_MALFORMED_PACKET;
}
const NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(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;
@ -1176,7 +1176,7 @@ void NetworkClientsToSpectators(CompanyID cid)
void NetworkUpdateClientName()
{
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(_network_own_client_id);
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(_network_own_client_id);
if (ci == NULL) return;
@ -1244,19 +1244,4 @@ bool NetworkMaxSpectatorsReached()
return NetworkSpectatorCount() >= (_network_server ? _settings_client.network.max_spectators : _network_server_max_spectators);
}
/**
* Print all the clients to the console
*/
void NetworkPrintClients()
{
NetworkClientInfo *ci;
FOR_ALL_CLIENT_INFOS(ci) {
IConsolePrintF(CC_INFO, "Client #%1d name: '%s' company: %1d IP: %s",
ci->client_id,
ci->client_name,
ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
GetClientIP(ci));
}
}
#endif /* ENABLE_NETWORK */

View File

@ -68,14 +68,13 @@ bool NetworkServerStart();
void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded);
bool NetworkServerChangeClientName(ClientID client_id, const char *new_name);
NetworkClientInfo *NetworkFindClientInfoFromClientID(ClientID client_id);
const char *GetClientIP(NetworkClientInfo *ci);
void NetworkServerDoMove(ClientID client_id, CompanyID company_id);
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string);
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const char *msg, ClientID from_id, int64 data = 0, bool from_admin = false);
void NetworkServerKickClient(ClientID client_id);
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban);
uint NetworkServerKickOrBanIP(const char *ip, bool ban);
void NetworkInitChatMessage();

View File

@ -1693,8 +1693,11 @@ NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
extern void DrawCompanyIcon(CompanyID cid, int x, int y);
/* Every action must be of this form */
typedef void ClientList_Action_Proc(byte client_no);
/**
* Prototype for ClientList actions.
* @param ci The information about the current client.
*/
typedef void ClientList_Action_Proc(const NetworkClientInfo *ci);
static const NWidgetPart _nested_client_list_popup_widgets[] = {
NWidget(WWT_PANEL, COLOUR_GREY, 0), EndContainer(),
@ -1702,65 +1705,38 @@ static const NWidgetPart _nested_client_list_popup_widgets[] = {
static const WindowDesc _client_list_popup_desc(
WDP_AUTO, 0, 0,
WC_TOOLBAR_MENU, WC_CLIENT_LIST,
WC_CLIENT_LIST_POPUP, WC_CLIENT_LIST,
0,
_nested_client_list_popup_widgets, lengthof(_nested_client_list_popup_widgets)
);
/* Finds the Xth client-info that is active */
static NetworkClientInfo *NetworkFindClientInfo(byte client_no)
{
NetworkClientInfo *ci;
FOR_ALL_CLIENT_INFOS(ci) {
if (client_no == 0) return ci;
client_no--;
}
return NULL;
}
/* Here we start to define the options out of the menu */
static void ClientList_Kick(byte client_no)
static void ClientList_Kick(const NetworkClientInfo *ci)
{
const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
if (ci == NULL) return;
NetworkServerKickClient(ci->client_id);
}
static void ClientList_Ban(byte client_no)
static void ClientList_Ban(const NetworkClientInfo *ci)
{
NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
if (ci == NULL) return;
NetworkServerKickOrBanIP(GetClientIP(ci), true);
NetworkServerKickOrBanIP(ci->client_id, true);
}
static void ClientList_GiveMoney(byte client_no)
static void ClientList_GiveMoney(const NetworkClientInfo *ci)
{
if (NetworkFindClientInfo(client_no) != NULL) {
ShowNetworkGiveMoneyWindow(NetworkFindClientInfo(client_no)->client_playas);
}
ShowNetworkGiveMoneyWindow(ci->client_playas);
}
static void ClientList_SpeakToClient(byte client_no)
static void ClientList_SpeakToClient(const NetworkClientInfo *ci)
{
if (NetworkFindClientInfo(client_no) != NULL) {
ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, NetworkFindClientInfo(client_no)->client_id);
}
ShowNetworkChatQueryWindow(DESTTYPE_CLIENT,ci->client_id);
}
static void ClientList_SpeakToCompany(byte client_no)
static void ClientList_SpeakToCompany(const NetworkClientInfo *ci)
{
if (NetworkFindClientInfo(client_no) != NULL) {
ShowNetworkChatQueryWindow(DESTTYPE_TEAM, NetworkFindClientInfo(client_no)->client_playas);
}
ShowNetworkChatQueryWindow(DESTTYPE_TEAM, ci->client_playas);
}
static void ClientList_SpeakToAll(byte client_no)
static void ClientList_SpeakToAll(const NetworkClientInfo *ci)
{
ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
}
@ -1774,7 +1750,7 @@ struct NetworkClientListPopupWindow : Window {
};
uint sel_index;
int client_no;
ClientID client_id;
Point desired_location;
SmallVector<ClientListAction, 2> actions; ///< Actions to execute
@ -1790,14 +1766,14 @@ struct NetworkClientListPopupWindow : Window {
action->proc = proc;
}
NetworkClientListPopupWindow(const WindowDesc *desc, int x, int y, int client_no) :
NetworkClientListPopupWindow(const WindowDesc *desc, int x, int y, ClientID client_id) :
Window(),
sel_index(0), client_no(client_no)
sel_index(0), client_id(client_id)
{
this->desired_location.x = x;
this->desired_location.y = y;
const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
if (_network_own_client_id != ci->client_id) {
this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, &ClientList_SpeakToClient);
@ -1822,7 +1798,7 @@ struct NetworkClientListPopupWindow : Window {
}
this->flags4 &= ~WF_WHITE_BORDER_MASK;
this->InitNested(desc, 0);
this->InitNested(desc, client_id);
}
virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
@ -1873,10 +1849,11 @@ struct NetworkClientListPopupWindow : Window {
this->SetDirty();
} else {
if (index < this->actions.Length() && _cursor.pos.y >= this->top) {
this->actions[index].proc(this->client_no);
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(this->client_id);
if (ci != NULL) this->actions[index].proc(ci);
}
DeleteWindowById(WC_TOOLBAR_MENU, 0);
DeleteWindowByClass(WC_CLIENT_LIST_POPUP);
}
}
};
@ -1884,13 +1861,13 @@ struct NetworkClientListPopupWindow : Window {
/**
* Show the popup (action list)
*/
static void PopupClientList(int client_no, int x, int y)
static void PopupClientList(ClientID client_id, int x, int y)
{
DeleteWindowById(WC_TOOLBAR_MENU, 0);
DeleteWindowByClass(WC_CLIENT_LIST_POPUP);
if (NetworkFindClientInfo(client_no) == NULL) return;
if (NetworkClientInfo::GetByClientID(client_id) == NULL) return;
new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_no);
new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_id);
}
@ -2027,7 +2004,15 @@ struct NetworkClientListWindow : Window {
{
/* Show the popup with option */
if (this->selected_item != -1) {
PopupClientList(this->selected_item, pt.x + this->left, pt.y + this->top);
NetworkClientInfo *ci;
int client_no = this->selected_item;
FOR_ALL_CLIENT_INFOS(ci) {
if (client_no == 0) break;
client_no--;
}
if (ci != NULL) PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top);
}
}

View File

@ -164,7 +164,6 @@ void NetworkSyncCommandQueue(NetworkClientSocket *cs);
void NetworkError(StringID error_string);
void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const char *name, const char *str = "", int64 data = 0);
uint NetworkCalculateLag(const NetworkClientSocket *cs);
NetworkClientSocket *NetworkFindClientStateFromClientID(ClientID client_id);
StringID GetNetworkErrorMsg(NetworkErrorCode err);
bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH]);
const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed);

View File

@ -161,12 +161,6 @@ ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : Netwo
* each Socket will be associated with at most one Info object. As
* such if the Socket was allocated the Info object can as well. */
assert_compile(NetworkClientSocketPool::MAX_SIZE == NetworkClientInfoPool::MAX_SIZE);
assert(NetworkClientInfo::CanAllocateItem());
NetworkClientInfo *ci = new NetworkClientInfo(this->client_id);
this->SetInfo(ci);
ci->client_playas = COMPANY_INACTIVE_CLIENT;
ci->join_date = _date;
}
/**
@ -253,6 +247,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
extern byte _network_clients_connected;
_network_clients_connected--;
DeleteWindowById(WC_CLIENT_LIST_POPUP, this->client_id);
SetWindowDirty(WC_CLIENT_LIST, 0);
this->SendPackets(true);
@ -325,7 +320,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo()
memset(clients, 0, sizeof(clients));
/* Add the local player (if not dedicated) */
const NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
if (ci != NULL && Company::IsValidID(ci->client_playas)) {
strecpy(clients[ci->client_playas], ci->client_name, lastof(clients[ci->client_playas]));
}
@ -486,7 +481,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome()
}
}
/* Also send the info of the server */
return this->SendClientInfo(NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER));
return this->SendClientInfo(NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER));
}
NetworkRecvStatus ServerNetworkGameSocketHandler::SendWait()
@ -495,9 +490,10 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWait()
NetworkClientSocket *new_cs;
Packet *p;
/* Count how many clients are waiting in the queue */
/* Count how many clients are waiting in the queue, in front of you! */
FOR_ALL_CLIENT_SOCKETS(new_cs) {
if (new_cs->status == STATUS_MAP_WAIT) waiting++;
if (new_cs->status != STATUS_MAP_WAIT) continue;
if (new_cs->GetInfo()->join_date < this->GetInfo()->join_date || (new_cs->GetInfo()->join_date == this->GetInfo()->join_date && new_cs->client_id < this->client_id)) waiting++;
}
p = new Packet(PACKET_SERVER_WAIT);
@ -566,24 +562,28 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
* to send it is ready (maybe that happens like never ;)) */
this->status = STATUS_DONE_MAP;
/* Find the best candidate for joining, i.e. the first joiner. */
NetworkClientSocket *new_cs;
bool new_map_client = false;
/* Check if there is a client waiting for receiving the map
* and start sending him the map */
NetworkClientSocket *best = NULL;
FOR_ALL_CLIENT_SOCKETS(new_cs) {
if (new_cs->status == STATUS_MAP_WAIT) {
/* Check if we already have a new client to send the map to */
if (!new_map_client) {
/* If not, this client will get the map */
new_cs->status = STATUS_AUTHORIZED;
new_map_client = true;
new_cs->SendMap();
} else {
/* Else, send the other clients how many clients are in front of them */
new_cs->SendWait();
if (best == NULL || best->GetInfo()->join_date > new_cs->GetInfo()->join_date || (best->GetInfo()->join_date == new_cs->GetInfo()->join_date && best->client_id > new_cs->client_id)) {
best = new_cs;
}
}
}
/* Is there someone else to join? */
if (best != NULL) {
/* Let the first start joining. */
best->status = STATUS_AUTHORIZED;
best->SendMap();
/* And update the rest. */
FOR_ALL_CLIENT_SOCKETS(new_cs) {
if (new_cs->status == STATUS_MAP_WAIT) new_cs->SendWait();
}
}
}
switch (this->SendPackets()) {
@ -793,7 +793,6 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_JOIN)
}
char name[NETWORK_CLIENT_NAME_LENGTH];
NetworkClientInfo *ci;
CompanyID playas;
NetworkLanguage client_lang;
char client_revision[NETWORK_REVISION_LENGTH];
@ -839,8 +838,10 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_JOIN)
return this->SendError(NETWORK_ERROR_NAME_IN_USE);
}
ci = this->GetInfo();
assert(NetworkClientInfo::CanAllocateItem());
NetworkClientInfo *ci = new NetworkClientInfo(this->client_id);
this->SetInfo(ci);
ci->join_date = _date;
strecpy(ci->client_name, name, lastof(ci->client_name));
ci->client_playas = playas;
ci->client_lang = client_lang;
@ -978,7 +979,7 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_MAP_OK)
}
}
NetworkAdminClientInfo(this->GetInfo(), true);
NetworkAdminClientInfo(this, true);
/* also update the new client with our max values */
this->SendConfigUpdate();
@ -1015,18 +1016,18 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_COMMAND)
NetworkClientInfo *ci = this->GetInfo();
if (err != NULL) {
IConsolePrintF(CC_ERROR, "WARNING: %s from client %d (IP: %s).", err, ci->client_id, GetClientIP(ci));
IConsolePrintF(CC_ERROR, "WARNING: %s from client %d (IP: %s).", err, ci->client_id, this->GetClientIP());
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
}
if ((GetCommandFlags(cp.cmd) & 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));
IConsolePrintF(CC_ERROR, "WARNING: server only command from: client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
return this->SendError(NETWORK_ERROR_KICKED);
}
if ((GetCommandFlags(cp.cmd) & CMD_SPECTATOR) == 0 && !Company::IsValidID(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));
IConsolePrintF(CC_ERROR, "WARNING: spectator issueing command from client %d (IP: %s), kicking...", ci->client_id, this->GetClientIP());
return this->SendError(NETWORK_ERROR_KICKED);
}
@ -1037,7 +1038,7 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_COMMAND)
*/
if (!(cp.cmd == CMD_COMPANY_CTRL && cp.p1 == 0 && ci->client_playas == COMPANY_NEW_COMPANY) && ci->client_playas != cp.company) {
IConsolePrintF(CC_ERROR, "WARNING: client %d (IP: %s) tried to execute a command as company %d, kicking...",
ci->client_playas + 1, GetClientIP(ci), cp.company + 1);
ci->client_playas + 1, this->GetClientIP(), cp.company + 1);
return this->SendError(NETWORK_ERROR_COMPANY_MISMATCH);
}
@ -1176,7 +1177,7 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co
case DESTTYPE_CLIENT:
/* Are we sending to the server? */
if ((ClientID)dest == CLIENT_ID_SERVER) {
ci = NetworkFindClientInfoFromClientID(from_id);
ci = NetworkClientInfo::GetByClientID(from_id);
/* Display the text locally, and that is it */
if (ci != NULL) {
NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
@ -1198,8 +1199,8 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co
/* Display the message locally (so you know you have sent it) */
if (from_id != (ClientID)dest) {
if (from_id == CLIENT_ID_SERVER) {
ci = NetworkFindClientInfoFromClientID(from_id);
ci_to = NetworkFindClientInfoFromClientID((ClientID)dest);
ci = NetworkClientInfo::GetByClientID(from_id);
ci_to = NetworkClientInfo::GetByClientID((ClientID)dest);
if (ci != NULL && ci_to != NULL) {
NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), true, ci_to->client_name, msg, data);
}
@ -1220,7 +1221,7 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co
ci_to = NULL;
FOR_ALL_CLIENT_SOCKETS(cs) {
ci = cs->GetInfo();
if (ci->client_playas == (CompanyID)dest) {
if (ci != NULL && ci->client_playas == (CompanyID)dest) {
cs->SendChat(action, from_id, false, msg, data);
if (cs->client_id == from_id) show_local = false;
ci_to = ci; // Remember a client that is in the company for company-name
@ -1232,8 +1233,8 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co
NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
}
ci = NetworkFindClientInfoFromClientID(from_id);
ci_own = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
ci = NetworkClientInfo::GetByClientID(from_id);
ci_own = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
if (ci != NULL && ci_own != NULL && ci_own->client_playas == dest) {
NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
if (from_id == CLIENT_ID_SERVER) show_local = false;
@ -1271,7 +1272,7 @@ void NetworkServerSendChat(NetworkAction action, DestType desttype, int dest, co
NetworkAdminChat(action, desttype, from_id, msg, data, from_admin);
ci = NetworkFindClientInfoFromClientID(from_id);
ci = NetworkClientInfo::GetByClientID(from_id);
if (ci != NULL) {
NetworkTextMessage(action, GetDrawStringCompanyColour(ci->client_playas), false, ci->client_name, msg, data);
}
@ -1305,7 +1306,7 @@ DEF_GAME_RECEIVE_COMMAND(Server, PACKET_CLIENT_CHAT)
NetworkServerSendChat(action, desttype, dest, msg, this->client_id, data);
break;
default:
IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_id, GetClientIP(ci));
IConsolePrintF(CC_ERROR, "WARNING: invalid chat action from client %d (IP: %s).", ci->client_id, this->GetClientIP());
return this->SendError(NETWORK_ERROR_NOT_EXPECTED);
}
return NETWORK_RECV_STATUS_OKAY;
@ -1501,7 +1502,7 @@ void NetworkPopulateCompanyStats(NetworkCompanyStats *stats)
void NetworkUpdateClientInfo(ClientID client_id)
{
NetworkClientSocket *cs;
NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id);
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
if (ci == NULL) return;
@ -1546,7 +1547,7 @@ static void NetworkAutoCleanCompanies()
}
if (!_network_dedicated) {
ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
if (Company::IsValidID(ci->client_playas)) clients_in_company[ci->client_playas] = true;
}
@ -1621,7 +1622,7 @@ bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH])
}
}
/* Check if it is the same as the server-name */
ci = NetworkFindClientInfoFromClientID(CLIENT_ID_SERVER);
ci = NetworkClientInfo::GetByClientID(CLIENT_ID_SERVER);
if (ci != NULL) {
if (strcmp(ci->client_name, new_name) == 0) found_name = false; // name already in use
}
@ -1652,7 +1653,7 @@ bool NetworkServerChangeClientName(ClientID client_id, const char *new_name)
if (strcmp(ci->client_name, new_name) == 0) return false;
}
ci = NetworkFindClientInfoFromClientID(client_id);
ci = NetworkClientInfo::GetByClientID(client_id);
if (ci == NULL) return false;
NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, true, ci->client_name, new_name);
@ -1806,9 +1807,13 @@ void NetworkServerDailyLoop()
if ((_date % 7) == 3) NetworkAdminUpdate(ADMIN_FREQUENCY_WEEKLY);
}
const char *GetClientIP(NetworkClientInfo *ci)
/**
* Get the IP address/hostname of the connected client.
* @return The IP address.
*/
const char *ServerNetworkGameSocketHandler::GetClientIP()
{
return ci->client_address.GetHostname();
return this->client_address.GetHostname();
}
void NetworkServerShowStatusToConsole()
@ -1829,15 +1834,16 @@ void NetworkServerShowStatusToConsole()
NetworkClientSocket *cs;
FOR_ALL_CLIENT_SOCKETS(cs) {
uint lag = NetworkCalculateLag(cs);
NetworkClientInfo *ci = cs->GetInfo();
if (ci == NULL) continue;
uint lag = NetworkCalculateLag(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",
cs->client_id, ci->client_name, status, lag,
ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
GetClientIP(ci));
cs->GetClientIP());
}
}
@ -1879,7 +1885,7 @@ 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);
NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id);
/* No need to waste network resources if the client is in the company already! */
if (ci->client_playas == company_id) return;
@ -1889,7 +1895,7 @@ void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
if (client_id == CLIENT_ID_SERVER) {
SetLocalCompany(company_id);
} else {
NetworkClientSocket *cs = NetworkFindClientStateFromClientID(client_id);
NetworkClientSocket *cs = NetworkClientSocket::GetByClientID(client_id);
/* When the company isn't authorized we can't move them yet. */
if (cs->status < NetworkClientSocket::STATUS_AUTHORIZED) return;
cs->SendMove(client_id, company_id);
@ -1904,12 +1910,12 @@ void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string)
{
NetworkFindClientStateFromClientID(client_id)->SendRConResult(colour_code, string);
NetworkClientSocket::GetByClientID(client_id)->SendRConResult(colour_code, string);
}
static void NetworkServerSendError(ClientID client_id, NetworkErrorCode error)
{
NetworkFindClientStateFromClientID(client_id)->SendError(error);
NetworkClientSocket::GetByClientID(client_id)->SendError(error);
}
void NetworkServerKickClient(ClientID client_id)
@ -1918,6 +1924,11 @@ void NetworkServerKickClient(ClientID client_id)
NetworkServerSendError(client_id, NETWORK_ERROR_KICKED);
}
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban)
{
return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban);
}
uint NetworkServerKickOrBanIP(const char *ip, bool ban)
{
/* Add address to ban-list */
@ -1926,11 +1937,11 @@ uint NetworkServerKickOrBanIP(const char *ip, bool ban)
uint n = 0;
/* There can be multiple clients with the same IP, kick them all */
NetworkClientInfo *ci;
FOR_ALL_CLIENT_INFOS(ci) {
if (ci->client_id == CLIENT_ID_SERVER) continue;
if (ci->client_address.IsInNetmask(const_cast<char *>(ip))) {
NetworkServerKickClient(ci->client_id);
NetworkClientSocket *cs;
FOR_ALL_CLIENT_SOCKETS(cs) {
if (cs->client_id == CLIENT_ID_SERVER) continue;
if (cs->client_address.IsInNetmask(const_cast<char *>(ip))) {
NetworkServerKickClient(cs->client_id);
n++;
}
}
@ -1957,11 +1968,26 @@ void ServerNetworkGameSocketHandler::GetClientName(char *client_name, size_t siz
{
const NetworkClientInfo *ci = this->GetInfo();
if (StrEmpty(ci->client_name)) {
if (ci == NULL || StrEmpty(ci->client_name)) {
snprintf(client_name, size, "Client #%4d", this->client_id);
} else {
ttd_strlcpy(client_name, ci->client_name, size);
}
}
/**
* Print all the clients to the console
*/
void NetworkPrintClients()
{
NetworkClientInfo *ci;
FOR_ALL_CLIENT_INFOS(ci) {
IConsolePrintF(CC_INFO, _network_server ? "Client #%1d name: '%s' company: %1d IP: %s" : "Client #%1d name: '%s' company: %1d",
ci->client_id,
ci->client_name,
ci->client_playas + (Company::IsValidID(ci->client_playas) ? 1 : 0),
_network_server ? (ci->client_id == CLIENT_ID_SERVER ? "server" : NetworkClientSocket::GetByClientID(ci->client_id)->GetClientIP()) : "");
}
}
#endif /* ENABLE_NETWORK */

View File

@ -76,6 +76,7 @@ public:
Packet *savegame_packets; ///< Packet queue of the savegame; send these "slowly" to the client.
struct PacketWriter *savegame; ///< Writer used to write the savegame.
ThreadMutex *savegame_mutex; ///< Mutex for making threaded saving safe.
NetworkAddress client_address; ///< IP-address of the client (so he can be banned)
ServerNetworkGameSocketHandler(SOCKET s);
~ServerNetworkGameSocketHandler();
@ -115,6 +116,10 @@ public:
{
return "server";
}
const char *GetClientIP();
static ServerNetworkGameSocketHandler *GetByClientID(ClientID client_id);
};
void NetworkServer_Tick(bool send_frame);

View File

@ -35,6 +35,17 @@ static inline uint32 GetRegister(uint i)
return _temp_store.Get(i);
}
/**
* Clears the value of a so-called newgrf "register".
* @param i index of the register
* @pre i < 0x110
*/
static inline void ClearRegister(uint i)
{
extern TemporaryStorageArray<int32, 0x110> _temp_store;
_temp_store.Store(i, 0);
}
/* List of different sprite group types */
enum SpriteGroupType {
SGT_REAL,

View File

@ -114,7 +114,7 @@ uint32 GetPlatformInfo(Axis axis, byte tile, int platforms, int length, int x, i
x -= platforms / 2;
y -= length / 2;
x = Clamp(x, -8, 7);
y = Clamp(x, -8, 7);
y = Clamp(y, -8, 7);
SB(retval, 0, 4, y & 0xF);
SB(retval, 4, 4, x & 0xF);
} else {
@ -613,6 +613,7 @@ SpriteID GetCustomStationFoundationRelocation(const StationSpec *statspec, const
NewStationResolver(&object, statspec, st, tile);
object.callback_param1 = 2; // Indicate we are resolving the foundation sprites
ClearRegister(0x100);
group = ResolveStation(&object);
if (group == NULL || group->type != SGT_RESULT) return 0;
return group->GetResult() + GetRegister(0x100);

View File

@ -281,7 +281,7 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
char *p = buf;
p += seprintf(p, lastof(buf), "Graphics set: %s (%u)\n", BaseGraphics::GetUsedSet()->name, BaseGraphics::GetUsedSet()->version);
p = strecpy(p, "NewGRFs:\n", lastof(buf));
for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
for (const GRFConfig *c = _game_mode == GM_MENU ? NULL : _grfconfig; c != NULL; c = c->next) {
p += seprintf(p, lastof(buf), "%08X ", BSWAP32(c->ident.grfid));
p = md5sumToString(p, lastof(buf), c->ident.md5sum);
p += seprintf(p, lastof(buf), " %s\n", c->filename);

View File

@ -2565,7 +2565,6 @@ restart_search:
w->window_class != WC_SELECT_GAME &&
w->window_class != WC_MAIN_TOOLBAR &&
w->window_class != WC_STATUS_BAR &&
w->window_class != WC_TOOLBAR_MENU &&
w->window_class != WC_TOOLTIPS &&
(w->flags4 & WF_STICKY) == 0) { // do not delete windows which are 'pinned'
@ -2626,7 +2625,6 @@ restart_search:
/** Delete all always on-top windows to get an empty screen */
void HideVitalWindows()
{
DeleteWindowById(WC_TOOLBAR_MENU, 0);
DeleteWindowById(WC_MAIN_TOOLBAR, 0);
DeleteWindowById(WC_STATUS_BAR, 0);
}

View File

@ -51,7 +51,7 @@ enum WindowClass {
WC_QUERY_STRING,
WC_SAVELOAD,
WC_SELECT_GAME,
WC_TOOLBAR_MENU,
WC_CLIENT_LIST_POPUP,
WC_INCOME_GRAPH,
WC_OPERATING_PROFIT,
WC_TOOLTIPS,