mirror of https://github.com/OpenTTD/OpenTTD
(svn r7505) -Feature: show NewGRFs used on a game server, show which NewGRFs you do and do not have.
-Feature: show NewGRF compatability of network games in the Game List window; a green square if you got the same OpenTTD version and have the needed NewGRF, a red square if the version does not match and a yellow square if the version matches, but the client is missing at least one of the NewGRFs.release/0.5
parent
f010066c1b
commit
32db875d97
|
@ -1308,6 +1308,7 @@ STR_NETWORK_PASSWORD :{SILVER}Passwor
|
||||||
STR_NETWORK_SERVER_OFFLINE :{SILVER}SERVER OFFLINE
|
STR_NETWORK_SERVER_OFFLINE :{SILVER}SERVER OFFLINE
|
||||||
STR_NETWORK_SERVER_FULL :{SILVER}SERVER FULL
|
STR_NETWORK_SERVER_FULL :{SILVER}SERVER FULL
|
||||||
STR_NETWORK_VERSION_MISMATCH :{SILVER}VERSION MISMATCH
|
STR_NETWORK_VERSION_MISMATCH :{SILVER}VERSION MISMATCH
|
||||||
|
STR_NETWORK_GRF_MISMATCH :{SILVER}NEWGRF MISMATCH
|
||||||
|
|
||||||
STR_NETWORK_JOIN_GAME :{BLACK}Join game
|
STR_NETWORK_JOIN_GAME :{BLACK}Join game
|
||||||
|
|
||||||
|
|
15
network.h
15
network.h
|
@ -54,6 +54,17 @@ enum {
|
||||||
NETWORK_CLIENT_NAME_LENGTH = 25,
|
NETWORK_CLIENT_NAME_LENGTH = 25,
|
||||||
NETWORK_RCONCOMMAND_LENGTH = 500,
|
NETWORK_RCONCOMMAND_LENGTH = 500,
|
||||||
|
|
||||||
|
NETWORK_GRF_NAME_LENGTH = 80, ///< Maximum length of the name of a GRF
|
||||||
|
/* Maximum number of GRFs that can be sent.
|
||||||
|
* This value is related to number of handles (files) OpenTTD can open.
|
||||||
|
* This is currently 64 and about 10 are currently used when OpenTTD loads
|
||||||
|
* without any NewGRFs. Therefore one can only load about 55 NewGRFs, so
|
||||||
|
* this is not a limit, but rather a way to easily check whether the limit
|
||||||
|
* imposed by the handle count is reached. Secondly it isn't possible to
|
||||||
|
* send much more GRF IDs + MD5sums in the PACKET_UDP_SERVER_RESPONSE, due
|
||||||
|
* to the limited size of UDP packets. */
|
||||||
|
NETWORK_MAX_GRF_COUNT = 55,
|
||||||
|
|
||||||
NETWORK_NUM_LANGUAGES = 4,
|
NETWORK_NUM_LANGUAGES = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,7 +77,8 @@ typedef struct NetworkGameInfo {
|
||||||
char server_revision[NETWORK_REVISION_LENGTH]; // The SVN version number the server is using (e.g.: 'r304')
|
char server_revision[NETWORK_REVISION_LENGTH]; // The SVN version number the server is using (e.g.: 'r304')
|
||||||
// It even shows a SVN version in release-version, so
|
// It even shows a SVN version in release-version, so
|
||||||
// it is easy to compare if a server is of the correct version
|
// it is easy to compare if a server is of the correct version
|
||||||
bool compatible; // Can we connect to this server or not? (based on server_revision)
|
bool version_compatible; // Can we connect to this server or not? (based on server_revision)
|
||||||
|
bool compatible; // Can we connect to this server or not? (based on server_revision _and_ grf_match
|
||||||
byte server_lang; // Language of the server (we should make a nice table for this)
|
byte server_lang; // Language of the server (we should make a nice table for this)
|
||||||
byte use_password; // Is set to != 0 if it uses a password
|
byte use_password; // Is set to != 0 if it uses a password
|
||||||
char server_password[NETWORK_PASSWORD_LENGTH]; // On the server: the game password, on the client: != "" if server has password
|
char server_password[NETWORK_PASSWORD_LENGTH]; // On the server: the game password, on the client: != "" if server has password
|
||||||
|
@ -84,6 +96,7 @@ typedef struct NetworkGameInfo {
|
||||||
byte map_set; // Graphical set
|
byte map_set; // Graphical set
|
||||||
bool dedicated; // Is this a dedicated server?
|
bool dedicated; // Is this a dedicated server?
|
||||||
char rcon_password[NETWORK_PASSWORD_LENGTH]; // RCon password for the server. "" if rcon is disabled
|
char rcon_password[NETWORK_PASSWORD_LENGTH]; // RCon password for the server. "" if rcon is disabled
|
||||||
|
struct GRFConfig *grfconfig; // List of NewGRF files required
|
||||||
} NetworkGameInfo;
|
} NetworkGameInfo;
|
||||||
|
|
||||||
typedef struct NetworkPlayerInfo {
|
typedef struct NetworkPlayerInfo {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#define NETWORK_EMPTY_INDEX 0
|
#define NETWORK_EMPTY_INDEX 0
|
||||||
|
|
||||||
// What version of game-info do we use?
|
// What version of game-info do we use?
|
||||||
#define NETWORK_GAME_INFO_VERSION 3
|
#define NETWORK_GAME_INFO_VERSION 4
|
||||||
// What version of company info is this?
|
// What version of company info is this?
|
||||||
#define NETWORK_COMPANY_INFO_VERSION 4
|
#define NETWORK_COMPANY_INFO_VERSION 4
|
||||||
// What version of master-server-protocol do we use?
|
// What version of master-server-protocol do we use?
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "network_data.h"
|
#include "network_data.h"
|
||||||
|
#include "newgrf_config.h"
|
||||||
|
|
||||||
// This file handles the GameList
|
// This file handles the GameList
|
||||||
// Also, it handles the request to a server for data about the server
|
// Also, it handles the request to a server for data about the server
|
||||||
|
@ -57,6 +58,9 @@ void NetworkGameListRemoveItem(NetworkGameList *remove)
|
||||||
prev_item->next = remove->next;
|
prev_item->next = remove->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove GRFConfig information */
|
||||||
|
ClearGRFConfigList(remove->info.grfconfig);
|
||||||
|
|
||||||
free(remove);
|
free(remove);
|
||||||
DEBUG(net, 4) ("[NET][GameList] Removed server from list");
|
DEBUG(net, 4) ("[NET][GameList] Removed server from list");
|
||||||
UpdateNetworkGameWindow(false);
|
UpdateNetworkGameWindow(false);
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "town.h"
|
#include "town.h"
|
||||||
|
#include "newgrf.h"
|
||||||
|
|
||||||
#define BGC 5
|
#define BGC 5
|
||||||
#define BTC 15
|
#define BTC 15
|
||||||
|
@ -241,6 +242,10 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
|
||||||
sel->info.clients_on >= sel->info.clients_max || // Server full
|
sel->info.clients_on >= sel->info.clients_max || // Server full
|
||||||
!sel->info.compatible); // Revision mismatch
|
!sel->info.compatible); // Revision mismatch
|
||||||
|
|
||||||
|
SetWindowWidgetHiddenState(w, 18, sel == NULL ||
|
||||||
|
!sel->online ||
|
||||||
|
sel->info.grfconfig == NULL);
|
||||||
|
|
||||||
SetDParam(0, 0x00);
|
SetDParam(0, 0x00);
|
||||||
SetDParam(7, _lan_internet_types_dropdown[_network_lan_internet]);
|
SetDParam(7, _lan_internet_types_dropdown[_network_lan_internet]);
|
||||||
DrawWindowWidgets(w);
|
DrawWindowWidgets(w);
|
||||||
|
@ -288,7 +293,7 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
|
||||||
if (cur_item->info.use_password) DrawSprite(SPR_LOCK, w->widget[8].left + 5, y - 1);
|
if (cur_item->info.use_password) DrawSprite(SPR_LOCK, w->widget[8].left + 5, y - 1);
|
||||||
|
|
||||||
// draw red or green icon, depending on compatibility with server.
|
// draw red or green icon, depending on compatibility with server.
|
||||||
DrawSprite(SPR_BLOT | (cur_item->info.compatible ? PALETTE_TO_GREEN : PALETTE_TO_RED), w->widget[8].left + 15, y);
|
DrawSprite(SPR_BLOT | (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), w->widget[8].left + 15, y);
|
||||||
|
|
||||||
// draw flag according to server language
|
// draw flag according to server language
|
||||||
DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, w->widget[8].left + 25, y);
|
DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, w->widget[8].left + 25, y);
|
||||||
|
@ -362,7 +367,7 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
|
||||||
y += 2;
|
y += 2;
|
||||||
|
|
||||||
if (!sel->info.compatible) {
|
if (!sel->info.compatible) {
|
||||||
DrawStringCentered(425, y, STR_NETWORK_VERSION_MISMATCH, 0); // server mismatch
|
DrawStringCentered(425, y, sel->info.version_compatible ? STR_NETWORK_GRF_MISMATCH : STR_NETWORK_VERSION_MISMATCH, 0); // server mismatch
|
||||||
} else if (sel->info.clients_on == sel->info.clients_max) {
|
} else if (sel->info.clients_on == sel->info.clients_max) {
|
||||||
// Show: server full, when clients_on == clients_max
|
// Show: server full, when clients_on == clients_max
|
||||||
DrawStringCentered(425, y, STR_NETWORK_SERVER_FULL, 0); // server full
|
DrawStringCentered(425, y, STR_NETWORK_SERVER_FULL, 0); // server full
|
||||||
|
@ -436,6 +441,9 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
|
||||||
if (nd->server != NULL)
|
if (nd->server != NULL)
|
||||||
NetworkQueryServer(nd->server->info.hostname, nd->server->port, true);
|
NetworkQueryServer(nd->server->info.hostname, nd->server->port, true);
|
||||||
break;
|
break;
|
||||||
|
case 18: // NewGRF Settings
|
||||||
|
if (nd->server != NULL) ShowNewGRFSettings(false, false, &nd->server->info.grfconfig);
|
||||||
|
break;
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -496,7 +504,7 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
|
||||||
static const Widget _network_game_window_widgets[] = {
|
static const Widget _network_game_window_widgets[] = {
|
||||||
{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
{ WWT_CLOSEBOX, RESIZE_NONE, BGC, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
|
||||||
{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 549, 0, 13, STR_NETWORK_MULTIPLAYER, STR_NULL},
|
{ WWT_CAPTION, RESIZE_NONE, BGC, 11, 549, 0, 13, STR_NETWORK_MULTIPLAYER, STR_NULL},
|
||||||
{ WWT_PANEL, RESIZE_NONE, BGC, 0, 549, 14, 249, 0x0, STR_NULL},
|
{ WWT_PANEL, RESIZE_NONE, BGC, 0, 549, 14, 261, 0x0, STR_NULL},
|
||||||
|
|
||||||
/* LEFT SIDE */
|
/* LEFT SIDE */
|
||||||
{ WWT_PANEL, RESIZE_NONE, BGC, 310, 461, 22, 33, 0x0, STR_NETWORK_ENTER_NAME_TIP},
|
{ WWT_PANEL, RESIZE_NONE, BGC, 310, 461, 22, 33, 0x0, STR_NETWORK_ENTER_NAME_TIP},
|
||||||
|
@ -508,26 +516,28 @@ static const Widget _network_game_window_widgets[] = {
|
||||||
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 171, 250, 42, 53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP},
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 171, 250, 42, 53, STR_NETWORK_CLIENTS_CAPTION, STR_NETWORK_CLIENTS_CAPTION_TIP},
|
||||||
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 251, 290, 42, 53, STR_EMPTY, STR_NETWORK_INFO_ICONS_TIP},
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 251, 290, 42, 53, STR_EMPTY, STR_NETWORK_INFO_ICONS_TIP},
|
||||||
|
|
||||||
{ WWT_MATRIX, RESIZE_NONE, BGC, 10, 290, 54, 222, (12 << 8) + 1, STR_NETWORK_CLICK_GAME_TO_SELECT},
|
{ WWT_MATRIX, RESIZE_NONE, BGC, 10, 290, 54, 234, (12 << 8) + 1, STR_NETWORK_CLICK_GAME_TO_SELECT},
|
||||||
{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 291, 302, 42, 222, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
{ WWT_SCROLLBAR, RESIZE_NONE, BGC, 291, 302, 42, 234, STR_NULL, STR_0190_SCROLL_BAR_SCROLLS_LIST},
|
||||||
|
|
||||||
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 30, 130, 232, 243, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP},
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 30, 130, 244, 255, STR_NETWORK_FIND_SERVER, STR_NETWORK_FIND_SERVER_TIP},
|
||||||
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 180, 280, 232, 243, STR_NETWORK_ADD_SERVER, STR_NETWORK_ADD_SERVER_TIP},
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 180, 280, 244, 255, STR_NETWORK_ADD_SERVER, STR_NETWORK_ADD_SERVER_TIP},
|
||||||
|
|
||||||
/* RIGHT SIDE */
|
/* RIGHT SIDE */
|
||||||
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 315, 415, 232, 243, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP},
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 315, 415, 244, 255, STR_NETWORK_START_SERVER, STR_NETWORK_START_SERVER_TIP},
|
||||||
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 232, 243, STR_012E_CANCEL, STR_NULL},
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 244, 255, STR_012E_CANCEL, STR_NULL},
|
||||||
|
|
||||||
{ WWT_PANEL, RESIZE_NONE, BGC, 310, 540, 42, 222, 0x0, STR_NULL},
|
{ WWT_PANEL, RESIZE_NONE, BGC, 310, 540, 42, 234, 0x0, STR_NULL},
|
||||||
|
|
||||||
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 315, 415, 201, 212, STR_NETWORK_JOIN_GAME, STR_NULL},
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 315, 415, 213, 224, STR_NETWORK_JOIN_GAME, STR_NULL},
|
||||||
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 201, 212, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP},
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 213, 224, STR_NETWORK_REFRESH, STR_NETWORK_REFRESH_TIP},
|
||||||
|
|
||||||
|
{ WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 430, 535, 195, 206, STR_NEWGRF_SETTINGS_BUTTON, STR_NULL},
|
||||||
|
|
||||||
{ WIDGETS_END},
|
{ WIDGETS_END},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const WindowDesc _network_game_window_desc = {
|
static const WindowDesc _network_game_window_desc = {
|
||||||
WDP_CENTER, WDP_CENTER, 550, 250,
|
WDP_CENTER, WDP_CENTER, 550, 262,
|
||||||
WC_NETWORK_WINDOW,0,
|
WC_NETWORK_WINDOW,0,
|
||||||
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
|
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
|
||||||
_network_game_window_widgets,
|
_network_game_window_widgets,
|
||||||
|
|
226
network_udp.c
226
network_udp.c
|
@ -11,6 +11,7 @@
|
||||||
#include "network_gamelist.h"
|
#include "network_gamelist.h"
|
||||||
#include "network_udp.h"
|
#include "network_udp.h"
|
||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
|
#include "newgrf_config.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// This file handles all the LAN-stuff
|
// This file handles all the LAN-stuff
|
||||||
|
@ -28,6 +29,8 @@ typedef enum {
|
||||||
PACKET_UDP_CLIENT_GET_LIST, // Request for serverlist from master server
|
PACKET_UDP_CLIENT_GET_LIST, // Request for serverlist from master server
|
||||||
PACKET_UDP_MASTER_RESPONSE_LIST, // Response from master server with server ip's + port's
|
PACKET_UDP_MASTER_RESPONSE_LIST, // Response from master server with server ip's + port's
|
||||||
PACKET_UDP_SERVER_UNREGISTER, // Request to be removed from the server-list
|
PACKET_UDP_SERVER_UNREGISTER, // Request to be removed from the server-list
|
||||||
|
PACKET_UDP_CLIENT_GET_NEWGRFS, // Requests the name for a list of GRFs (GRF_ID and MD5)
|
||||||
|
PACKET_UDP_SERVER_NEWGRFS, // Sends the list of NewGRF's requested.
|
||||||
PACKET_UDP_END
|
PACKET_UDP_END
|
||||||
} PacketUDPType;
|
} PacketUDPType;
|
||||||
|
|
||||||
|
@ -42,6 +45,34 @@ static void NetworkSendUDP_Packet(SOCKET udp, Packet* p, struct sockaddr_in* rec
|
||||||
|
|
||||||
static NetworkClientState _udp_cs;
|
static NetworkClientState _udp_cs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet
|
||||||
|
* @param p the packet to write the data to
|
||||||
|
* @param c the configuration to write the GRF ID and MD5 checksum from
|
||||||
|
*/
|
||||||
|
static void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c)
|
||||||
|
{
|
||||||
|
uint j;
|
||||||
|
NetworkSend_uint32(p, c->grfid);
|
||||||
|
for (j = 0; j < sizeof(c->md5sum); j++) {
|
||||||
|
NetworkSend_uint8 (p, c->md5sum[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet
|
||||||
|
* @param p the packet to read the data from
|
||||||
|
* @param c the configuration to write the GRF ID and MD5 checksum to
|
||||||
|
*/
|
||||||
|
static void NetworkRecv_GRFIdentifier(Packet *p, GRFConfig *c)
|
||||||
|
{
|
||||||
|
uint j;
|
||||||
|
c->grfid = NetworkRecv_uint32(&_udp_cs, p);
|
||||||
|
for (j = 0; j < sizeof(c->md5sum); j++) {
|
||||||
|
c->md5sum[j] = NetworkRecv_uint8(&_udp_cs, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
|
DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
|
||||||
{
|
{
|
||||||
Packet *packet;
|
Packet *packet;
|
||||||
|
@ -59,6 +90,27 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
|
||||||
|
|
||||||
NetworkSend_uint8 (packet, NETWORK_GAME_INFO_VERSION);
|
NetworkSend_uint8 (packet, NETWORK_GAME_INFO_VERSION);
|
||||||
|
|
||||||
|
/* NETWORK_GAME_INFO_VERSION = 4 */
|
||||||
|
{
|
||||||
|
/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
|
||||||
|
* the GRFs that are needed, i.e. the ones that the server has
|
||||||
|
* selected in the NewGRF GUI and not the ones that are used due
|
||||||
|
* to the fact that they are in [newgrf-static] in openttd.cfg */
|
||||||
|
const GRFConfig *c;
|
||||||
|
uint i = 0;
|
||||||
|
|
||||||
|
/* Count number of GRFs to send information about */
|
||||||
|
for (c = _grfconfig; c != NULL; c = c->next) {
|
||||||
|
if (!HASBIT(c->flags, GCF_STATIC)) i++;
|
||||||
|
}
|
||||||
|
NetworkSend_uint8 (packet, i); // Send number of GRFs
|
||||||
|
|
||||||
|
/* Send actual GRF Identifications */
|
||||||
|
for (c = _grfconfig; c != NULL; c = c->next) {
|
||||||
|
if (!HASBIT(c->flags, GCF_STATIC)) NetworkSend_GRFIdentifier(packet, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* NETWORK_GAME_INFO_VERSION = 3 */
|
/* NETWORK_GAME_INFO_VERSION = 3 */
|
||||||
NetworkSend_uint32(packet, _network_game_info.game_date);
|
NetworkSend_uint32(packet, _network_game_info.game_date);
|
||||||
NetworkSend_uint32(packet, _network_game_info.start_date);
|
NetworkSend_uint32(packet, _network_game_info.start_date);
|
||||||
|
@ -109,9 +161,41 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
|
||||||
// Find next item
|
// Find next item
|
||||||
item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port));
|
item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port));
|
||||||
|
|
||||||
|
item->info.compatible = true;
|
||||||
/* Please observer the order. In the order in which packets are sent
|
/* Please observer the order. In the order in which packets are sent
|
||||||
* they are to be received */
|
* they are to be received */
|
||||||
switch (game_info_version) {
|
switch (game_info_version) {
|
||||||
|
case 4: {
|
||||||
|
GRFConfig *c, **dst = &item->info.grfconfig;
|
||||||
|
const GRFConfig *f;
|
||||||
|
uint i;
|
||||||
|
uint num_grfs = NetworkRecv_uint8(&_udp_cs, p);
|
||||||
|
|
||||||
|
for (i = 0; i < num_grfs; i++) {
|
||||||
|
c = calloc(1, sizeof(*c));
|
||||||
|
NetworkRecv_GRFIdentifier(p, c);
|
||||||
|
|
||||||
|
/* Find the matching GRF file */
|
||||||
|
f = FindGRFConfig(c->grfid, c->md5sum);
|
||||||
|
if (f == NULL) {
|
||||||
|
/* Don't know the GRF, so mark game incompatible and the (possibly)
|
||||||
|
* already resolved name for this GRF (another server has sent the
|
||||||
|
* name of the GRF already */
|
||||||
|
item->info.compatible = false;
|
||||||
|
c->name = FindUnknownGRFName(c->grfid, c->md5sum, true);
|
||||||
|
SETBIT(c->flags, GCF_NOT_FOUND);
|
||||||
|
} else {
|
||||||
|
c->filename = f->filename;
|
||||||
|
c->name = f->name;
|
||||||
|
c->info = f->info;
|
||||||
|
}
|
||||||
|
SETBIT(c->flags, GCF_COPY);
|
||||||
|
|
||||||
|
/* Append GRFConfig to the list */
|
||||||
|
*dst = c;
|
||||||
|
dst = &c->next;
|
||||||
|
}
|
||||||
|
} /* Fallthrough */
|
||||||
case 3:
|
case 3:
|
||||||
item->info.game_date = NetworkRecv_uint32(&_udp_cs, p);
|
item->info.game_date = NetworkRecv_uint32(&_udp_cs, p);
|
||||||
item->info.start_date = NetworkRecv_uint32(&_udp_cs, p);
|
item->info.start_date = NetworkRecv_uint32(&_udp_cs, p);
|
||||||
|
@ -146,12 +230,50 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
|
||||||
snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
|
snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
|
||||||
|
|
||||||
/* Check if we are allowed on this server based on the revision-match */
|
/* Check if we are allowed on this server based on the revision-match */
|
||||||
item->info.compatible =
|
item->info.version_compatible =
|
||||||
strcmp(item->info.server_revision, _openttd_revision) == 0 ||
|
strcmp(item->info.server_revision, _openttd_revision) == 0 ||
|
||||||
strcmp(item->info.server_revision, NOREV_STRING) == 0;
|
strcmp(item->info.server_revision, NOREV_STRING) == 0;
|
||||||
|
item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Checks whether there needs to be a request for names of GRFs and makes
|
||||||
|
* the request if necessary. GRFs that need to be requested are the GRFs
|
||||||
|
* that do not exist on the clients system and we do not have the name
|
||||||
|
* resolved of, i.e. the name is still UNKNOWN_GRF_NAME_PLACEHOLDER.
|
||||||
|
* The in_request array and in_request_count are used so there is no need
|
||||||
|
* to do a second loop over the GRF list, which can be relatively expensive
|
||||||
|
* due to the string comparisons. */
|
||||||
|
const GRFConfig *in_request[NETWORK_MAX_GRF_COUNT];
|
||||||
|
const GRFConfig *c;
|
||||||
|
uint in_request_count = 0;
|
||||||
|
struct sockaddr_in out_addr;
|
||||||
|
|
||||||
|
for (c = item->info.grfconfig; c != NULL; c = c->next) {
|
||||||
|
if (!HASBIT(c->flags, GCF_NOT_FOUND) || strcmp(c->name, UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue;
|
||||||
|
in_request[in_request_count] = c;
|
||||||
|
in_request_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_request_count > 0) {
|
||||||
|
/* There are 'unknown' GRFs, now send a request for them */
|
||||||
|
uint i;
|
||||||
|
Packet *packet = NetworkSend_Init(PACKET_UDP_CLIENT_GET_NEWGRFS);
|
||||||
|
|
||||||
|
NetworkSend_uint8 (packet, in_request_count);
|
||||||
|
for (i = 0; i < in_request_count; i++) {
|
||||||
|
NetworkSend_GRFIdentifier(packet, in_request[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
out_addr.sin_family = AF_INET;
|
||||||
|
out_addr.sin_port = htons(item->port);
|
||||||
|
out_addr.sin_addr.s_addr = item->ip;
|
||||||
|
NetworkSendUDP_Packet(_udp_client_socket, packet, &out_addr);
|
||||||
|
free(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item->online = true;
|
item->online = true;
|
||||||
|
|
||||||
UpdateNetworkGameWindow(false);
|
UpdateNetworkGameWindow(false);
|
||||||
|
@ -300,6 +422,104 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A client has requested the names of some NewGRFs.
|
||||||
|
*
|
||||||
|
* Replying this can be tricky as we have a limit of SEND_MTU bytes
|
||||||
|
* in the reply packet and we can send up to 100 bytes per NewGRF
|
||||||
|
* (GRF ID, MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name).
|
||||||
|
* As SEND_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it
|
||||||
|
* could be that a packet overflows. To stop this we only reply
|
||||||
|
* with the first N NewGRFs so that if the first N + 1 NewGRFs
|
||||||
|
* would be sent, the packet overflows.
|
||||||
|
* in_reply and in_reply_count are used to keep a list of GRFs to
|
||||||
|
* send in the reply.
|
||||||
|
*/
|
||||||
|
DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS)
|
||||||
|
{
|
||||||
|
uint8 num_grfs;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT];
|
||||||
|
Packet *packet;
|
||||||
|
uint8 in_reply_count = 0;
|
||||||
|
uint packet_len = 0;
|
||||||
|
|
||||||
|
/* Just a fail-safe.. should never happen */
|
||||||
|
if (_udp_cs.has_quit) return;
|
||||||
|
|
||||||
|
DEBUG(net, 6)("[NET][UDP] NewGRF data request from %s:%d", inet_ntoa(client_addr->sin_addr), ntohs(client_addr->sin_port));
|
||||||
|
|
||||||
|
num_grfs = NetworkRecv_uint8 (&_udp_cs, p);
|
||||||
|
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
|
||||||
|
|
||||||
|
for (i = 0; i < num_grfs; i++) {
|
||||||
|
GRFConfig c;
|
||||||
|
const GRFConfig *f;
|
||||||
|
|
||||||
|
NetworkRecv_GRFIdentifier(p, &c);
|
||||||
|
|
||||||
|
/* Find the matching GRF file */
|
||||||
|
f = FindGRFConfig(c.grfid, c.md5sum);
|
||||||
|
if (f == NULL) continue; // The GRF is unknown to this server
|
||||||
|
|
||||||
|
/* If the reply might exceed the size of the packet, only reply
|
||||||
|
* the current list and do not send the other data */
|
||||||
|
packet_len += sizeof(c.grfid) + sizeof(c.md5sum) + min(strlen(f->name) + 1, NETWORK_GRF_NAME_LENGTH);
|
||||||
|
if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
in_reply[in_reply_count] = f;
|
||||||
|
in_reply_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_reply_count == 0) return;
|
||||||
|
|
||||||
|
packet = NetworkSend_Init(PACKET_UDP_SERVER_NEWGRFS);
|
||||||
|
NetworkSend_uint8 (packet, in_reply_count);
|
||||||
|
for (i = 0; i < in_reply_count; i++) {
|
||||||
|
char name[NETWORK_GRF_NAME_LENGTH];
|
||||||
|
ttd_strlcpy(name, in_reply[i]->name, sizeof(name));
|
||||||
|
NetworkSend_GRFIdentifier(packet, in_reply[i]);
|
||||||
|
NetworkSend_string(packet, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr);
|
||||||
|
free(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The return of the client's request of the names of some NewGRFs */
|
||||||
|
DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS)
|
||||||
|
{
|
||||||
|
uint8 num_grfs;
|
||||||
|
uint i;
|
||||||
|
|
||||||
|
/* Just a fail-safe.. should never happen */
|
||||||
|
if (_udp_cs.has_quit) return;
|
||||||
|
|
||||||
|
DEBUG(net, 6)("[NET][UDP] NewGRF data reply from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port));
|
||||||
|
|
||||||
|
num_grfs = NetworkRecv_uint8 (&_udp_cs, p);
|
||||||
|
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
|
||||||
|
|
||||||
|
for (i = 0; i < num_grfs; i++) {
|
||||||
|
char *unknown_name;
|
||||||
|
char name[NETWORK_GRF_NAME_LENGTH];
|
||||||
|
GRFConfig c;
|
||||||
|
|
||||||
|
NetworkRecv_GRFIdentifier(p, &c);
|
||||||
|
NetworkRecv_string(&_udp_cs, p, name, sizeof(name));
|
||||||
|
|
||||||
|
/* Finds the fake GRFConfig for the just read GRF ID and MD5sum tuple.
|
||||||
|
* If it exists and not resolved yet, then name of the fake GRF is
|
||||||
|
* overwritten with the name from the reply. */
|
||||||
|
unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false);
|
||||||
|
if (unknown_name != NULL && strcmp(unknown_name, UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) {
|
||||||
|
ttd_strlcpy(unknown_name, name, NETWORK_GRF_NAME_LENGTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// The layout for the receive-functions by UDP
|
// The layout for the receive-functions by UDP
|
||||||
typedef void NetworkUDPPacket(Packet *p, struct sockaddr_in *client_addr);
|
typedef void NetworkUDPPacket(Packet *p, struct sockaddr_in *client_addr);
|
||||||
|
@ -313,7 +533,9 @@ static NetworkUDPPacket* const _network_udp_packet[] = {
|
||||||
RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER),
|
RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER),
|
||||||
NULL,
|
NULL,
|
||||||
RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST),
|
RECEIVE_COMMAND(PACKET_UDP_MASTER_RESPONSE_LIST),
|
||||||
NULL
|
NULL,
|
||||||
|
RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS),
|
||||||
|
RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "saveload.h"
|
#include "saveload.h"
|
||||||
#include "md5.h"
|
#include "md5.h"
|
||||||
|
#include "network_data.h"
|
||||||
#include "newgrf.h"
|
#include "newgrf.h"
|
||||||
#include "newgrf_config.h"
|
#include "newgrf_config.h"
|
||||||
|
|
||||||
|
@ -83,9 +84,12 @@ bool FillGRFDetails(GRFConfig *config, bool is_static)
|
||||||
|
|
||||||
void ClearGRFConfig(GRFConfig *config)
|
void ClearGRFConfig(GRFConfig *config)
|
||||||
{
|
{
|
||||||
|
/* GCF_COPY as in NOT strdupped/alloced the filename, name and info */
|
||||||
|
if (!HASBIT(config->flags, GCF_COPY)) {
|
||||||
free(config->filename);
|
free(config->filename);
|
||||||
free(config->name);
|
free(config->name);
|
||||||
free(config->info);
|
free(config->info);
|
||||||
|
}
|
||||||
free(config);
|
free(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,6 +268,55 @@ const GRFConfig *FindGRFConfig(uint32 grfid, uint8 *md5sum)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Structure for UnknownGRFs; this is a lightweight variant of GRFConfig */
|
||||||
|
typedef struct UnknownGRF UnknownGRF;
|
||||||
|
struct UnknownGRF {
|
||||||
|
UnknownGRF *next;
|
||||||
|
uint32 grfid;
|
||||||
|
uint8 md5sum[16];
|
||||||
|
char name[NETWORK_GRF_NAME_LENGTH];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the name of a NewGRF in the list of names for unknown GRFs. An
|
||||||
|
* unknown GRF is a GRF where the .grf is not found during scanning.
|
||||||
|
*
|
||||||
|
* The names are resolved via UDP calls to servers that should know the name,
|
||||||
|
* though the replies may not come. This leaves "<Unknown>" as name, though
|
||||||
|
* that shouldn't matter _very_ much as they need GRF crawler or so to look
|
||||||
|
* up the GRF anyway and that works better with the GRF ID.
|
||||||
|
*
|
||||||
|
* @param grfid the GRF ID part of the 'unique' GRF identifier
|
||||||
|
* @param md5sum the MD5 checksum part of the 'unique' GRF identifier
|
||||||
|
* @param create whether to create a new GRFConfig if the GRFConfig did not
|
||||||
|
* exist in the fake list of GRFConfigs.
|
||||||
|
* @return the GRFConfig with the given GRF ID and MD5 checksum or NULL when
|
||||||
|
* it does not exist and create is false. This value must NEVER be
|
||||||
|
* freed by the caller.
|
||||||
|
*/
|
||||||
|
char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create)
|
||||||
|
{
|
||||||
|
UnknownGRF *grf;
|
||||||
|
static UnknownGRF *unknown_grfs = NULL;
|
||||||
|
|
||||||
|
for (grf = unknown_grfs; grf != NULL; grf = grf->next) {
|
||||||
|
if (grf->grfid == grfid) {
|
||||||
|
if (memcmp(md5sum, grf->md5sum, sizeof(grf->md5sum)) == 0) return grf->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!create) return NULL;
|
||||||
|
|
||||||
|
grf = calloc(1, sizeof(*grf));
|
||||||
|
grf->grfid = grfid;
|
||||||
|
grf->next = unknown_grfs;
|
||||||
|
ttd_strlcpy(grf->name, UNKNOWN_GRF_NAME_PLACEHOLDER, sizeof(grf->name));
|
||||||
|
memcpy(grf->md5sum, md5sum, sizeof(grf->md5sum));
|
||||||
|
|
||||||
|
unknown_grfs = grf;
|
||||||
|
return grf->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Retrieve a NewGRF from the current config by its grfid */
|
/* Retrieve a NewGRF from the current config by its grfid */
|
||||||
GRFConfig *GetGRFConfig(uint32 grfid)
|
GRFConfig *GetGRFConfig(uint32 grfid)
|
||||||
|
|
|
@ -11,6 +11,7 @@ enum {
|
||||||
GCF_SYSTEM,
|
GCF_SYSTEM,
|
||||||
GCF_UNSAFE,
|
GCF_UNSAFE,
|
||||||
GCF_STATIC,
|
GCF_STATIC,
|
||||||
|
GCF_COPY, ///< The data is copied from a grf in _all_grfs
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct GRFConfig {
|
typedef struct GRFConfig {
|
||||||
|
@ -52,4 +53,8 @@ char *GRFBuildParamList(char *dst, const GRFConfig *c, const char *last);
|
||||||
/* In newgrf_gui.c */
|
/* In newgrf_gui.c */
|
||||||
void ShowNewGRFSettings(bool editable, bool show_params, GRFConfig **config);
|
void ShowNewGRFSettings(bool editable, bool show_params, GRFConfig **config);
|
||||||
|
|
||||||
|
/* For communication about GRFs over the network */
|
||||||
|
#define UNKNOWN_GRF_NAME_PLACEHOLDER "<Unknown>"
|
||||||
|
char *FindUnknownGRFName(uint32 grfid, uint8 *md5sum, bool create);
|
||||||
|
|
||||||
#endif /* NEWGRF_CONFIG_H */
|
#endif /* NEWGRF_CONFIG_H */
|
||||||
|
|
|
@ -43,9 +43,11 @@ static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint w, bool show
|
||||||
char *s;
|
char *s;
|
||||||
uint i;
|
uint i;
|
||||||
|
|
||||||
/* Draw filename */
|
/* Draw filename or not if it is not known (GRF sent over internet) */
|
||||||
|
if (c->filename != NULL) {
|
||||||
SetDParamStr(0, c->filename);
|
SetDParamStr(0, c->filename);
|
||||||
y += DrawStringMultiLine(x, y, STR_NEWGRF_FILENAME, w);
|
y += DrawStringMultiLine(x, y, STR_NEWGRF_FILENAME, w);
|
||||||
|
}
|
||||||
|
|
||||||
/* Prepare and draw GRF ID */
|
/* Prepare and draw GRF ID */
|
||||||
snprintf(buff, lengthof(buff), "%08X", (uint32)BSWAP32(c->grfid));
|
snprintf(buff, lengthof(buff), "%08X", (uint32)BSWAP32(c->grfid));
|
||||||
|
|
Loading…
Reference in New Issue