Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
add_subdirectory(core)
|
||||
|
||||
add_files(
|
||||
network.cpp
|
||||
network.h
|
||||
network_admin.cpp
|
||||
network_admin.h
|
||||
network_base.h
|
||||
network_chat_gui.cpp
|
||||
network_client.cpp
|
||||
network_client.h
|
||||
network_command.cpp
|
||||
network_content.cpp
|
||||
network_content.h
|
||||
network_content_gui.cpp
|
||||
network_content_gui.h
|
||||
network_func.h
|
||||
network_gamelist.cpp
|
||||
network_gamelist.h
|
||||
network_gui.cpp
|
||||
network_gui.h
|
||||
network_internal.h
|
||||
network_server.cpp
|
||||
network_server.h
|
||||
network_type.h
|
||||
network_udp.cpp
|
||||
network_udp.h
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
add_files(
|
||||
address.cpp
|
||||
address.h
|
||||
config.h
|
||||
core.cpp
|
||||
core.h
|
||||
game.h
|
||||
host.cpp
|
||||
host.h
|
||||
os_abstraction.h
|
||||
packet.cpp
|
||||
packet.h
|
||||
tcp.cpp
|
||||
tcp.h
|
||||
tcp_admin.cpp
|
||||
tcp_admin.h
|
||||
tcp_connect.cpp
|
||||
tcp_content.cpp
|
||||
tcp_content.h
|
||||
tcp_game.cpp
|
||||
tcp_game.h
|
||||
tcp_http.cpp
|
||||
tcp_http.h
|
||||
tcp_listen.h
|
||||
udp.cpp
|
||||
udp.h
|
||||
)
|
||||
@@ -96,12 +96,11 @@ void NetworkAddress::GetAddressAsString(char *buffer, const char *last, bool wit
|
||||
* Get the address as a string, e.g. 127.0.0.1:12345.
|
||||
* @param with_family whether to add the family (e.g. IPvX).
|
||||
* @return the address
|
||||
* @note NOT thread safe
|
||||
*/
|
||||
const char *NetworkAddress::GetAddressAsString(bool with_family)
|
||||
std::string NetworkAddress::GetAddressAsString(bool with_family)
|
||||
{
|
||||
/* 6 = for the : and 5 for the decimal port number */
|
||||
static char buf[NETWORK_HOSTNAME_LENGTH + 6 + 7];
|
||||
char buf[NETWORK_HOSTNAME_LENGTH + 6 + 7];
|
||||
this->GetAddressAsString(buf, lastof(buf), with_family);
|
||||
return buf;
|
||||
}
|
||||
@@ -268,6 +267,18 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList *
|
||||
this->address_length = (int)runp->ai_addrlen;
|
||||
assert(sizeof(this->address) >= runp->ai_addrlen);
|
||||
memcpy(&this->address, runp->ai_addr, runp->ai_addrlen);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten doesn't zero sin_zero, but as we compare addresses
|
||||
* to see if they are the same address, we need them to be zero'd.
|
||||
* Emscripten is, as far as we know, the only OS not doing this.
|
||||
*
|
||||
* https://github.com/emscripten-core/emscripten/issues/12998
|
||||
*/
|
||||
if (this->address.ss_family == AF_INET) {
|
||||
sockaddr_in *address_ipv4 = (sockaddr_in *)&this->address;
|
||||
memset(address_ipv4->sin_zero, 0, sizeof(address_ipv4->sin_zero));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -289,7 +300,8 @@ static SOCKET ConnectLoopProc(addrinfo *runp)
|
||||
{
|
||||
const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype);
|
||||
const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family);
|
||||
const char *address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString();
|
||||
char address[NETWORK_HOSTNAME_LENGTH + 6 + 7];
|
||||
NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(address, lastof(address));
|
||||
|
||||
SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
@@ -299,7 +311,15 @@ static SOCKET ConnectLoopProc(addrinfo *runp)
|
||||
|
||||
if (!SetNoDelay(sock)) DEBUG(net, 1, "[%s] setting TCP_NODELAY failed", type);
|
||||
|
||||
if (connect(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) {
|
||||
int err = connect(sock, runp->ai_addr, (int)runp->ai_addrlen);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten is asynchronous, and as such a connect() is still in
|
||||
* progress by the time the call returns. */
|
||||
if (err != 0 && errno != EINPROGRESS)
|
||||
#else
|
||||
if (err != 0)
|
||||
#endif
|
||||
{
|
||||
DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, strerror(errno));
|
||||
closesocket(sock);
|
||||
return INVALID_SOCKET;
|
||||
@@ -319,7 +339,7 @@ static SOCKET ConnectLoopProc(addrinfo *runp)
|
||||
*/
|
||||
SOCKET NetworkAddress::Connect()
|
||||
{
|
||||
DEBUG(net, 1, "Connecting to %s", this->GetAddressAsString());
|
||||
DEBUG(net, 1, "Connecting to %s", this->GetAddressAsString().c_str());
|
||||
|
||||
return this->Resolve(AF_UNSPEC, SOCK_STREAM, AI_ADDRCONFIG, nullptr, ConnectLoopProc);
|
||||
}
|
||||
@@ -333,7 +353,8 @@ static SOCKET ListenLoopProc(addrinfo *runp)
|
||||
{
|
||||
const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype);
|
||||
const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family);
|
||||
const char *address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString();
|
||||
char address[NETWORK_HOSTNAME_LENGTH + 6 + 7];
|
||||
NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(address, lastof(address));
|
||||
|
||||
SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol);
|
||||
if (sock == INVALID_SOCKET) {
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "../../string_func.h"
|
||||
#include "../../core/smallmap_type.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
class NetworkAddress;
|
||||
typedef std::vector<NetworkAddress> NetworkAddressList; ///< Type for a list of addresses.
|
||||
typedef SmallMap<NetworkAddress, SOCKET> SocketList; ///< Type for a mapping between address and socket.
|
||||
@@ -91,7 +93,7 @@ public:
|
||||
|
||||
const char *GetHostname();
|
||||
void GetAddressAsString(char *buffer, const char *last, bool with_family = true);
|
||||
const char *GetAddressAsString(bool with_family = true);
|
||||
std::string GetAddressAsString(bool with_family = true);
|
||||
const sockaddr_storage *GetAddress();
|
||||
|
||||
/**
|
||||
|
||||
@@ -83,6 +83,16 @@ typedef unsigned long in_addr_t;
|
||||
# include <errno.h>
|
||||
# include <sys/time.h>
|
||||
# include <netdb.h>
|
||||
|
||||
# if defined(__EMSCRIPTEN__)
|
||||
/* Emscripten doesn't support AI_ADDRCONFIG and errors out on it. */
|
||||
# undef AI_ADDRCONFIG
|
||||
# define AI_ADDRCONFIG 0
|
||||
/* Emscripten says it supports FD_SETSIZE fds, but it really only supports 64.
|
||||
* https://github.com/emscripten-core/emscripten/issues/1711 */
|
||||
# undef FD_SETSIZE
|
||||
# define FD_SETSIZE 64
|
||||
# endif
|
||||
#endif /* UNIX */
|
||||
|
||||
/* OS/2 stuff */
|
||||
@@ -141,6 +151,28 @@ typedef unsigned long in_addr_t;
|
||||
|
||||
#endif /* OS/2 */
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/**
|
||||
* Emscripten doesn't set 'addrlen' for accept(), getsockname(), getpeername()
|
||||
* and recvfrom(), which confuses other functions and causes them to crash.
|
||||
* This function needs to be called after these four functions to make sure
|
||||
* 'addrlen' is patched up.
|
||||
*
|
||||
* https://github.com/emscripten-core/emscripten/issues/12996
|
||||
*
|
||||
* @param address The address returned by those four functions.
|
||||
* @return The correct value for addrlen.
|
||||
*/
|
||||
static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address)
|
||||
{
|
||||
switch (address.ss_family) {
|
||||
case AF_INET6: return sizeof(struct sockaddr_in6);
|
||||
case AF_INET: return sizeof(struct sockaddr_in);
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Try to set the socket into non-blocking mode.
|
||||
* @param d The socket to set the non-blocking more for.
|
||||
@@ -148,12 +180,16 @@ typedef unsigned long in_addr_t;
|
||||
*/
|
||||
static inline bool SetNonBlocking(SOCKET d)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
u_long nonblocking = 1;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return true;
|
||||
#else
|
||||
# ifdef _WIN32
|
||||
u_long nonblocking = 1;
|
||||
# else
|
||||
int nonblocking = 1;
|
||||
#endif
|
||||
# endif
|
||||
return ioctlsocket(d, FIONBIO, &nonblocking) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,14 +199,18 @@ static inline bool SetNonBlocking(SOCKET d)
|
||||
*/
|
||||
static inline bool SetNoDelay(SOCKET d)
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return true;
|
||||
#else
|
||||
/* XXX should this be done at all? */
|
||||
int b = 1;
|
||||
/* The (const char*) cast is needed for windows */
|
||||
return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Make sure these structures have the size we expect them to be */
|
||||
assert_compile(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes.
|
||||
assert_compile(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes.
|
||||
static_assert(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes.
|
||||
static_assert(sizeof(in6_addr) == 16); ///< IPv6 addresses should be 16 bytes.
|
||||
|
||||
#endif /* NETWORK_CORE_OS_ABSTRACTION_H */
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "address.h"
|
||||
#include "packet.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
/** The states of sending the packets. */
|
||||
enum SendPacketsState {
|
||||
SPS_CLOSED, ///< The connection got closed.
|
||||
@@ -61,8 +63,8 @@ public:
|
||||
*/
|
||||
class TCPConnecter {
|
||||
private:
|
||||
bool connected; ///< Whether we succeeded in making the connection
|
||||
bool aborted; ///< Whether we bailed out (i.e. connection making failed)
|
||||
std::atomic<bool> connected;///< Whether we succeeded in making the connection
|
||||
std::atomic<bool> aborted; ///< Whether we bailed out (i.e. connection making failed)
|
||||
bool killed; ///< Whether we got killed
|
||||
SOCKET sock; ///< The socket we're connecting with
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@
|
||||
#include "../../safeguards.h"
|
||||
|
||||
/* Make sure that these enums match. */
|
||||
assert_compile((int)CRR_MANUAL == (int)ADMIN_CRR_MANUAL);
|
||||
assert_compile((int)CRR_AUTOCLEAN == (int)ADMIN_CRR_AUTOCLEAN);
|
||||
assert_compile((int)CRR_BANKRUPT == (int)ADMIN_CRR_BANKRUPT);
|
||||
assert_compile((int)CRR_END == (int)ADMIN_CRR_END);
|
||||
static_assert((int)CRR_MANUAL == (int)ADMIN_CRR_MANUAL);
|
||||
static_assert((int)CRR_AUTOCLEAN == (int)ADMIN_CRR_AUTOCLEAN);
|
||||
static_assert((int)CRR_BANKRUPT == (int)ADMIN_CRR_BANKRUPT);
|
||||
static_assert((int)CRR_END == (int)ADMIN_CRR_END);
|
||||
|
||||
/**
|
||||
* Create the admin handler for the given socket.
|
||||
@@ -115,6 +115,7 @@ NetworkRecvStatus NetworkAdminSocketHandler::ReceivePackets()
|
||||
Packet *p;
|
||||
while ((p = this->ReceivePacket()) != nullptr) {
|
||||
NetworkRecvStatus res = this->HandlePacket(p);
|
||||
delete p;
|
||||
if (res != NETWORK_RECV_STATUS_OKAY) return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ protected:
|
||||
|
||||
/**
|
||||
* Register updates to be sent at certain frequencies (as announced in the PROTOCOL packet):
|
||||
* uint16 Update type (see #AdminUpdateType).
|
||||
* uint16 Update type (see #AdminUpdateType). Note integer type - see "Certain Packet Information" in docs/admin_network.md.
|
||||
* uint16 Update frequency (see #AdminUpdateFrequency), setting #ADMIN_FREQUENCY_POLL is always ignored.
|
||||
* @param p The packet that was just received.
|
||||
* @return The state the network should have.
|
||||
@@ -143,7 +143,7 @@ protected:
|
||||
|
||||
/**
|
||||
* Poll the server for certain updates, an invalid poll (e.g. not existent id) gets silently dropped:
|
||||
* uint8 #AdminUpdateType the server should answer for, only if #AdminUpdateFrequency #ADMIN_FREQUENCY_POLL is advertised in the PROTOCOL packet.
|
||||
* uint8 #AdminUpdateType the server should answer for, only if #AdminUpdateFrequency #ADMIN_FREQUENCY_POLL is advertised in the PROTOCOL packet. Note integer type - see "Certain Packet Information" in docs/admin_network.md.
|
||||
* 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.
|
||||
|
||||
@@ -66,19 +66,21 @@ void TCPConnecter::Connect()
|
||||
{
|
||||
for (auto iter = _tcp_connecters.begin(); iter < _tcp_connecters.end(); /* nothing */) {
|
||||
TCPConnecter *cur = *iter;
|
||||
if ((cur->connected || cur->aborted) && cur->killed) {
|
||||
const bool connected = cur->connected.load();
|
||||
const bool aborted = cur->aborted.load();
|
||||
if ((connected || aborted) && cur->killed) {
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
if (cur->sock != INVALID_SOCKET) closesocket(cur->sock);
|
||||
delete cur;
|
||||
continue;
|
||||
}
|
||||
if (cur->connected) {
|
||||
if (connected) {
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
cur->OnConnect(cur->sock);
|
||||
delete cur;
|
||||
continue;
|
||||
}
|
||||
if (cur->aborted) {
|
||||
if (aborted) {
|
||||
iter = _tcp_connecters.erase(iter);
|
||||
cur->OnFailure();
|
||||
delete cur;
|
||||
|
||||
@@ -171,9 +171,9 @@ bool NetworkContentSocketHandler::HandlePacket(Packet *p)
|
||||
|
||||
default:
|
||||
if (this->HasClientQuit()) {
|
||||
DEBUG(net, 0, "[tcp/content] received invalid packet type %d from %s", type, this->client_addr.GetAddressAsString());
|
||||
DEBUG(net, 0, "[tcp/content] received invalid packet type %d from %s", type, this->client_addr.GetAddressAsString().c_str());
|
||||
} else {
|
||||
DEBUG(net, 0, "[tcp/content] received illegal packet from %s", this->client_addr.GetAddressAsString());
|
||||
DEBUG(net, 0, "[tcp/content] received illegal packet from %s", this->client_addr.GetAddressAsString().c_str());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -224,7 +224,7 @@ bool NetworkContentSocketHandler::ReceivePackets()
|
||||
*/
|
||||
bool NetworkContentSocketHandler::ReceiveInvalidPacket(PacketContentType type)
|
||||
{
|
||||
DEBUG(net, 0, "[tcp/content] received illegal packet type %d from %s", type, this->client_addr.GetAddressAsString());
|
||||
DEBUG(net, 0, "[tcp/content] received illegal packet type %d from %s", type, this->client_addr.GetAddressAsString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -250,8 +250,8 @@ int NetworkHTTPSocketHandler::Receive()
|
||||
|
||||
/* Wait till we read the end-of-header identifier */
|
||||
if (this->recv_length == 0) {
|
||||
int read = this->recv_pos + res;
|
||||
int end = min(read, lengthof(this->recv_buffer) - 1);
|
||||
ssize_t read = this->recv_pos + res;
|
||||
ssize_t end = std::min<ssize_t>(read, lengthof(this->recv_buffer) - 1);
|
||||
|
||||
/* Do a 'safe' search for the end of the header. */
|
||||
char prev = this->recv_buffer[end];
|
||||
@@ -272,7 +272,7 @@ int NetworkHTTPSocketHandler::Receive()
|
||||
this->recv_length = ret;
|
||||
|
||||
end_of_header += strlen(END_OF_HEADER);
|
||||
int len = min(read - (end_of_header - this->recv_buffer), res);
|
||||
int len = std::min(read - (end_of_header - this->recv_buffer), res);
|
||||
if (len != 0) {
|
||||
this->callback->OnReceiveData(end_of_header, len);
|
||||
this->recv_length -= len;
|
||||
@@ -281,7 +281,7 @@ int NetworkHTTPSocketHandler::Receive()
|
||||
this->recv_pos = 0;
|
||||
}
|
||||
} else {
|
||||
res = min(this->recv_length, res);
|
||||
res = std::min<ssize_t>(this->recv_length, res);
|
||||
/* Receive whatever we're expecting. */
|
||||
this->callback->OnReceiveData(this->recv_buffer, res);
|
||||
this->recv_length -= res;
|
||||
|
||||
@@ -42,6 +42,9 @@ public:
|
||||
socklen_t sin_len = sizeof(sin);
|
||||
SOCKET s = accept(ls, (struct sockaddr*)&sin, &sin_len);
|
||||
if (s == INVALID_SOCKET) return;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
sin_len = FixAddrLenForEmscripten(sin);
|
||||
#endif
|
||||
|
||||
SetNonBlocking(s); // XXX error handling?
|
||||
|
||||
|
||||
@@ -100,10 +100,10 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a
|
||||
|
||||
/* Send the buffer */
|
||||
int res = sendto(s.second, (const char*)p->buffer, p->size, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength());
|
||||
DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString());
|
||||
DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString().c_str());
|
||||
|
||||
/* Check for any errors, but ignore it otherwise */
|
||||
if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString(), GET_LAST_ERROR());
|
||||
if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString().c_str(), GET_LAST_ERROR());
|
||||
|
||||
if (!all) break;
|
||||
}
|
||||
@@ -129,6 +129,9 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
||||
/* Did we get the bytes for the base header of the packet? */
|
||||
if (nbytes <= 0) break; // No data, i.e. no packet
|
||||
if (nbytes <= 2) continue; // Invalid data; try next packet
|
||||
#ifdef __EMSCRIPTEN__
|
||||
client_len = FixAddrLenForEmscripten(client_addr);
|
||||
#endif
|
||||
|
||||
NetworkAddress address(client_addr, client_len);
|
||||
p.PrepareToRead();
|
||||
@@ -136,7 +139,7 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
||||
/* If the size does not match the packet must be corrupted.
|
||||
* Otherwise it will be marked as corrupted later on. */
|
||||
if (nbytes != p.size) {
|
||||
DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString());
|
||||
DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -313,9 +316,9 @@ void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_
|
||||
|
||||
default:
|
||||
if (this->HasClientQuit()) {
|
||||
DEBUG(net, 0, "[udp] received invalid packet type %d from %s", type, client_addr->GetAddressAsString());
|
||||
DEBUG(net, 0, "[udp] received invalid packet type %d from %s", type, client_addr->GetAddressAsString().c_str());
|
||||
} else {
|
||||
DEBUG(net, 0, "[udp] received illegal packet from %s", client_addr->GetAddressAsString());
|
||||
DEBUG(net, 0, "[udp] received illegal packet from %s", client_addr->GetAddressAsString().c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -328,7 +331,7 @@ void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_
|
||||
*/
|
||||
void NetworkUDPSocketHandler::ReceiveInvalidPacket(PacketUDPType type, NetworkAddress *client_addr)
|
||||
{
|
||||
DEBUG(net, 0, "[udp] received packet type %d on wrong port from %s", type, client_addr->GetAddressAsString());
|
||||
DEBUG(net, 0, "[udp] received packet type %d on wrong port from %s", type, client_addr->GetAddressAsString().c_str());
|
||||
}
|
||||
|
||||
void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER, client_addr); }
|
||||
|
||||
+22
-7
@@ -43,7 +43,7 @@ bool _ddc_fastforward = true;
|
||||
#endif /* DEBUG_DUMP_COMMANDS */
|
||||
|
||||
/** Make sure both pools have the same size. */
|
||||
assert_compile(NetworkClientInfoPool::MAX_SIZE == NetworkClientSocketPool::MAX_SIZE);
|
||||
static_assert(NetworkClientInfoPool::MAX_SIZE == NetworkClientSocketPool::MAX_SIZE);
|
||||
|
||||
/** The pool with client information. */
|
||||
NetworkClientInfoPool _networkclientinfo_pool("NetworkClientInfo");
|
||||
@@ -80,8 +80,8 @@ uint8 _network_advertise_retries; ///< The number of advertisement retries w
|
||||
CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies.
|
||||
|
||||
/* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */
|
||||
assert_compile((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE);
|
||||
assert_compile((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH);
|
||||
static_assert((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE);
|
||||
static_assert((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH);
|
||||
|
||||
extern NetworkUDPSocketHandler *_udp_client_socket; ///< udp client socket
|
||||
extern NetworkUDPSocketHandler *_udp_server_socket; ///< udp server socket
|
||||
@@ -245,7 +245,7 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
|
||||
break;
|
||||
case NETWORK_ACTION_LEAVE: strid = STR_NETWORK_MESSAGE_CLIENT_LEFT; break;
|
||||
case NETWORK_ACTION_NAME_CHANGE: strid = STR_NETWORK_MESSAGE_NAME_CHANGE; break;
|
||||
case NETWORK_ACTION_GIVE_MONEY: strid = self_send ? STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY : STR_NETWORK_MESSAGE_GIVE_MONEY; break;
|
||||
case NETWORK_ACTION_GIVE_MONEY: strid = STR_NETWORK_MESSAGE_GIVE_MONEY; break;
|
||||
case NETWORK_ACTION_CHAT_COMPANY: strid = self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY; break;
|
||||
case NETWORK_ACTION_CHAT_CLIENT: strid = self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT; break;
|
||||
case NETWORK_ACTION_KICKED: strid = STR_NETWORK_MESSAGE_KICKED; break;
|
||||
@@ -322,7 +322,7 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err)
|
||||
STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP,
|
||||
STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN,
|
||||
};
|
||||
assert_compile(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||
|
||||
if (err >= (ptrdiff_t)lengthof(network_error_strings)) err = NETWORK_ERROR_GENERAL;
|
||||
|
||||
@@ -342,7 +342,8 @@ void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode)
|
||||
case PM_PAUSED_NORMAL:
|
||||
case PM_PAUSED_JOIN:
|
||||
case PM_PAUSED_GAME_SCRIPT:
|
||||
case PM_PAUSED_ACTIVE_CLIENTS: {
|
||||
case PM_PAUSED_ACTIVE_CLIENTS:
|
||||
case PM_PAUSED_LINK_GRAPH: {
|
||||
bool changed = ((_pause_mode == PM_UNPAUSED) != (prev_mode == PM_UNPAUSED));
|
||||
bool paused = (_pause_mode != PM_UNPAUSED);
|
||||
if (!paused && !changed) return;
|
||||
@@ -355,6 +356,7 @@ void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode)
|
||||
if ((_pause_mode & PM_PAUSED_JOIN) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS);
|
||||
if ((_pause_mode & PM_PAUSED_GAME_SCRIPT) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT);
|
||||
if ((_pause_mode & PM_PAUSED_ACTIVE_CLIENTS) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS);
|
||||
if ((_pause_mode & PM_PAUSED_LINK_GRAPH) != PM_UNPAUSED) SetDParam(++i, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH);
|
||||
str = STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 + i;
|
||||
} else {
|
||||
switch (changed_mode) {
|
||||
@@ -362,6 +364,7 @@ void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode)
|
||||
case PM_PAUSED_JOIN: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS); break;
|
||||
case PM_PAUSED_GAME_SCRIPT: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT); break;
|
||||
case PM_PAUSED_ACTIVE_CLIENTS: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS); break;
|
||||
case PM_PAUSED_LINK_GRAPH: SetDParam(0, STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH); break;
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
str = paused ? STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED : STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED;
|
||||
@@ -917,7 +920,8 @@ void NetworkGameLoop()
|
||||
if (*p == ' ') p++;
|
||||
cp = CallocT<CommandPacket>(1);
|
||||
int company;
|
||||
int ret = sscanf(p, "%x; %x; %x; %x; %x; %x; %x; \"%[^\"]\"", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text);
|
||||
static_assert(sizeof(cp->text) == 128);
|
||||
int ret = sscanf(p, "%x; %x; %x; %x; %x; %x; %x; \"%127[^\"]\"", &next_date, &next_date_fract, &company, &cp->tile, &cp->p1, &cp->p2, &cp->cmd, cp->text);
|
||||
/* There are 8 pieces of data to read, however the last is a
|
||||
* string that might or might not exist. Ignore it if that
|
||||
* string misses because in 99% of the time it's not used. */
|
||||
@@ -1153,3 +1157,14 @@ bool IsNetworkCompatibleVersion(const char *other)
|
||||
const char *hash2 = ExtractNetworkRevisionHash(other);
|
||||
return hash1 && hash2 && (strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0);
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
extern "C" {
|
||||
|
||||
void CDECL em_openttd_add_server(const char *host, int port)
|
||||
{
|
||||
NetworkUDPQueryServer(NetworkAddress(host, port), true);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -54,7 +54,7 @@ static const AdminUpdateFrequency _admin_update_type_frequencies[] = {
|
||||
ADMIN_FREQUENCY_AUTOMATIC, ///< ADMIN_UPDATE_GAMESCRIPT
|
||||
};
|
||||
/** Sanity check. */
|
||||
assert_compile(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END);
|
||||
static_assert(lengthof(_admin_update_type_frequencies) == ADMIN_UPDATE_END);
|
||||
|
||||
/**
|
||||
* Create a new socket for the server side of the admin network.
|
||||
@@ -86,7 +86,7 @@ ServerNetworkAdminSocketHandler::~ServerNetworkAdminSocketHandler()
|
||||
bool accept = !StrEmpty(_settings_client.network.admin_password) && _network_admins_connected < MAX_ADMINS;
|
||||
/* We can't go over the MAX_ADMINS limit here. However, if we accept
|
||||
* the connection, there has to be space in the pool. */
|
||||
assert_compile(NetworkAdminSocketPool::MAX_SIZE == MAX_ADMINS);
|
||||
static_assert(NetworkAdminSocketPool::MAX_SIZE == MAX_ADMINS);
|
||||
assert(!accept || ServerNetworkAdminSocketHandler::CanAllocateItem());
|
||||
return accept;
|
||||
}
|
||||
@@ -413,13 +413,13 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCompanyEconomy()
|
||||
p->Send_uint64(company->money);
|
||||
p->Send_uint64(company->current_loan);
|
||||
p->Send_uint64(income);
|
||||
p->Send_uint16(min(UINT16_MAX, company->cur_economy.delivered_cargo.GetSum<OverflowSafeInt64>()));
|
||||
p->Send_uint16(static_cast<uint16>(std::min<uint64>(UINT16_MAX, company->cur_economy.delivered_cargo.GetSum<OverflowSafeInt64>())));
|
||||
|
||||
/* Send stats for the last 2 quarters. */
|
||||
for (uint i = 0; i < 2; i++) {
|
||||
p->Send_uint64(company->old_economy[i].company_value);
|
||||
p->Send_uint16(company->old_economy[i].performance_history);
|
||||
p->Send_uint16(min(UINT16_MAX, company->old_economy[i].delivered_cargo.GetSum<OverflowSafeInt64>()));
|
||||
p->Send_uint16(static_cast<uint16>(std::min<uint64>(UINT16_MAX, company->old_economy[i].delivered_cargo.GetSum<OverflowSafeInt64>())));
|
||||
}
|
||||
|
||||
this->SendPacket(p);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
/** The draw buffer must be able to contain the chat message, client name and the "[All]" message,
|
||||
* some spaces and possible translations of [All] to other languages. */
|
||||
assert_compile((int)DRAW_STRING_BUFFER >= (int)NETWORK_CHAT_LENGTH + NETWORK_NAME_LENGTH + 40);
|
||||
static_assert((int)DRAW_STRING_BUFFER >= (int)NETWORK_CHAT_LENGTH + NETWORK_NAME_LENGTH + 40);
|
||||
|
||||
/** Spacing between chat lines. */
|
||||
static const uint NETWORK_CHAT_LINE_SPACING = 3;
|
||||
@@ -154,7 +154,7 @@ void NetworkUndrawChatMessage()
|
||||
int width = _chatmsg_box.width;
|
||||
int height = _chatmsg_box.height;
|
||||
if (y < 0) {
|
||||
height = max(height + y, min(_chatmsg_box.height, _screen.height));
|
||||
height = std::max(height + y, std::min(_chatmsg_box.height, _screen.height));
|
||||
y = 0;
|
||||
}
|
||||
if (x + width >= _screen.width) {
|
||||
@@ -214,7 +214,7 @@ void NetworkDrawChatMessage()
|
||||
int width = _chatmsg_box.width;
|
||||
int height = _chatmsg_box.height;
|
||||
if (y < 0) {
|
||||
height = max(height + y, min(_chatmsg_box.height, _screen.height));
|
||||
height = std::max(height + y, std::min(_chatmsg_box.height, _screen.height));
|
||||
y = 0;
|
||||
}
|
||||
if (x + width >= _screen.width) {
|
||||
@@ -235,7 +235,7 @@ void NetworkDrawChatMessage()
|
||||
string_height += GetStringLineCount(STR_JUST_RAW_STRING, width - 1) * FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING;
|
||||
}
|
||||
|
||||
string_height = min(string_height, MAX_CHAT_MESSAGES * (FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING));
|
||||
string_height = std::min<uint>(string_height, MAX_CHAT_MESSAGES * (FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING));
|
||||
|
||||
int top = _screen.height - _chatmsg_box.y - string_height - 2;
|
||||
int bottom = _screen.height - _chatmsg_box.y - 2;
|
||||
|
||||
@@ -68,7 +68,7 @@ struct PacketReader : LoadFilter {
|
||||
assert(this->read_bytes == 0);
|
||||
|
||||
size_t in_packet = p->size - p->pos;
|
||||
size_t to_write = min((size_t)(this->bufe - this->buf), in_packet);
|
||||
size_t to_write = std::min<size_t>(this->bufe - this->buf, in_packet);
|
||||
const byte *pbuf = p->buffer + p->pos;
|
||||
|
||||
this->written_bytes += in_packet;
|
||||
@@ -93,7 +93,7 @@ struct PacketReader : LoadFilter {
|
||||
size_t Read(byte *rbuf, size_t size) override
|
||||
{
|
||||
/* Limit the amount to read to whatever we still have. */
|
||||
size_t ret_size = size = min(this->written_bytes - this->read_bytes, size);
|
||||
size_t ret_size = size = std::min(this->written_bytes - this->read_bytes, size);
|
||||
this->read_bytes += ret_size;
|
||||
const byte *rbufe = rbuf + ret_size;
|
||||
|
||||
@@ -103,7 +103,7 @@ struct PacketReader : LoadFilter {
|
||||
this->bufe = this->buf + CHUNK;
|
||||
}
|
||||
|
||||
size_t to_write = min(this->bufe - this->buf, rbufe - rbuf);
|
||||
size_t to_write = std::min(this->bufe - this->buf, rbufe - rbuf);
|
||||
memcpy(rbuf, this->buf, to_write);
|
||||
rbuf += to_write;
|
||||
this->buf += to_write;
|
||||
@@ -211,16 +211,24 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res)
|
||||
default: errorno = NETWORK_ERROR_GENERAL; break;
|
||||
}
|
||||
|
||||
/* This means we fucked up and the server closed the connection */
|
||||
if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL &&
|
||||
res != NETWORK_RECV_STATUS_SERVER_BANNED) {
|
||||
if (res == NETWORK_RECV_STATUS_SERVER_ERROR || res == NETWORK_RECV_STATUS_SERVER_FULL ||
|
||||
res == NETWORK_RECV_STATUS_SERVER_BANNED) {
|
||||
/* This means the server closed the connection. Emergency save is
|
||||
* already created if this was appropriate during handling of the
|
||||
* disconnect. */
|
||||
this->CloseConnection(res);
|
||||
} else {
|
||||
/* This means we as client made a boo-boo. */
|
||||
SendError(errorno);
|
||||
|
||||
/* Close connection before we make an emergency save, as the save can
|
||||
* take a bit of time; better that the server doesn't stall while we
|
||||
* are doing the save, and already disconnects us. */
|
||||
this->CloseConnection(res);
|
||||
ClientNetworkEmergencySave();
|
||||
}
|
||||
|
||||
ClientNetworkEmergencySave();
|
||||
|
||||
_switch_mode = SM_MENU;
|
||||
this->CloseConnection(res);
|
||||
_networking = false;
|
||||
}
|
||||
|
||||
@@ -323,7 +331,7 @@ const char *_network_join_server_password = nullptr;
|
||||
const char *_network_join_company_password = nullptr;
|
||||
|
||||
/** Make sure the server ID length is the same as a md5 hash. */
|
||||
assert_compile(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1);
|
||||
static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1);
|
||||
|
||||
/***********
|
||||
* Sending functions
|
||||
@@ -540,7 +548,7 @@ bool ClientNetworkGameSocketHandler::IsConnected()
|
||||
* DEF_CLIENT_RECEIVE_COMMAND has parameter: Packet *p
|
||||
************/
|
||||
|
||||
extern bool SafeLoad(const char *filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr);
|
||||
extern bool SafeLoad(const std::string &filename, SaveLoadOperation fop, DetailedFileType dft, GameMode newgm, Subdirectory subdir, struct LoadFilter *lf = nullptr);
|
||||
|
||||
NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p)
|
||||
{
|
||||
@@ -681,7 +689,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p
|
||||
STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP
|
||||
STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN
|
||||
};
|
||||
assert_compile(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||
static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END);
|
||||
|
||||
NetworkErrorCode error = (NetworkErrorCode)p->Recv_uint8();
|
||||
|
||||
@@ -866,7 +874,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet
|
||||
|
||||
/* The map is done downloading, load it */
|
||||
ClearErrorMessages();
|
||||
bool load_success = SafeLoad(nullptr, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, lf);
|
||||
bool load_success = SafeLoad({}, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, lf);
|
||||
|
||||
/* Long savegame loads shouldn't affect the lag calculation! */
|
||||
this->last_packet = _realtime_tick;
|
||||
@@ -992,11 +1000,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHAT(Packet *p)
|
||||
ci = NetworkClientInfo::GetByClientID(_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;
|
||||
FALLTHROUGH;
|
||||
|
||||
/* For speaking to company, we need the company-name */
|
||||
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);
|
||||
|
||||
@@ -39,7 +39,7 @@ static CommandCallback * const _callback_table[] = {
|
||||
/* 0x11 */ CcTerraform,
|
||||
/* 0x12 */ CcAI,
|
||||
/* 0x13 */ CcCloneVehicle,
|
||||
/* 0x14 */ CcGiveMoney,
|
||||
/* 0x14 */ nullptr,
|
||||
/* 0x15 */ CcCreateGroup,
|
||||
/* 0x16 */ CcFoundRandomTown,
|
||||
/* 0x17 */ CcRoadStop,
|
||||
@@ -298,7 +298,7 @@ const char *NetworkGameSocketHandler::ReceiveCommand(Packet *p, CommandPacket *c
|
||||
cp->company = (CompanyID)p->Recv_uint8();
|
||||
cp->cmd = p->Recv_uint32();
|
||||
if (!IsValidCommand(cp->cmd)) return "invalid command";
|
||||
if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "offline only command";
|
||||
if (GetCommandFlags(cp->cmd) & CMD_OFFLINE) return "single-player only command";
|
||||
if ((cp->cmd & CMD_FLAGS_MASK) != 0) return "invalid command flag";
|
||||
|
||||
cp->p1 = p->Recv_uint32();
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
extern bool HasScenario(const ContentInfo *ci, bool md5sum);
|
||||
@@ -217,7 +221,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(uint count, const Con
|
||||
* A packet begins with the packet size and a byte for the type.
|
||||
* Then this packet adds a uint16 for the count in this packet.
|
||||
* The rest of the packet can be used for the IDs. */
|
||||
uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
|
||||
uint p_count = std::min<uint>(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
|
||||
|
||||
Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_ID);
|
||||
p->Send_uint16(p_count);
|
||||
@@ -289,6 +293,13 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin
|
||||
{
|
||||
bytes = 0;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
/* Emscripten is loaded via an HTTPS connection. As such, it is very
|
||||
* difficult to make HTTP connections. So always use the TCP method of
|
||||
* downloading content. */
|
||||
fallback = true;
|
||||
#endif
|
||||
|
||||
ContentIDList content;
|
||||
for (const ContentInfo *ci : this->infos) {
|
||||
if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue;
|
||||
@@ -352,7 +363,7 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const Co
|
||||
* A packet begins with the packet size and a byte for the type.
|
||||
* Then this packet adds a uint16 for the count in this packet.
|
||||
* The rest of the packet can be used for the IDs. */
|
||||
uint p_count = min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
|
||||
uint p_count = std::min<uint>(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32));
|
||||
|
||||
Packet *p = new Packet(PACKET_CONTENT_CLIENT_CONTENT);
|
||||
p->Send_uint16(p_count);
|
||||
@@ -374,14 +385,14 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const Co
|
||||
* @return a statically allocated buffer with the filename or
|
||||
* nullptr when no filename could be made.
|
||||
*/
|
||||
static char *GetFullFilename(const ContentInfo *ci, bool compressed)
|
||||
static std::string GetFullFilename(const ContentInfo *ci, bool compressed)
|
||||
{
|
||||
Subdirectory dir = GetContentInfoSubDir(ci->type);
|
||||
if (dir == NO_DIRECTORY) return nullptr;
|
||||
if (dir == NO_DIRECTORY) return {};
|
||||
|
||||
static char buf[MAX_PATH];
|
||||
FioGetFullPath(buf, lastof(buf), SP_AUTODOWNLOAD_DIR, dir, ci->filename);
|
||||
strecat(buf, compressed ? ".tar.gz" : ".tar", lastof(buf));
|
||||
std::string buf = FioGetDirectory(SP_AUTODOWNLOAD_DIR, dir);
|
||||
buf += ci->filename;
|
||||
buf += compressed ? ".tar.gz" : ".tar";
|
||||
|
||||
return buf;
|
||||
}
|
||||
@@ -397,13 +408,13 @@ static bool GunzipFile(const ContentInfo *ci)
|
||||
bool ret = true;
|
||||
|
||||
/* Need to open the file with fopen() to support non-ASCII on Windows. */
|
||||
FILE *ftmp = fopen(GetFullFilename(ci, true), "rb");
|
||||
FILE *ftmp = fopen(GetFullFilename(ci, true).c_str(), "rb");
|
||||
if (ftmp == nullptr) return false;
|
||||
/* Duplicate the handle, and close the FILE*, to avoid double-closing the handle later. */
|
||||
gzFile fin = gzdopen(dup(fileno(ftmp)), "rb");
|
||||
fclose(ftmp);
|
||||
|
||||
FILE *fout = fopen(GetFullFilename(ci, false), "wb");
|
||||
FILE *fout = fopen(GetFullFilename(ci, false).c_str(), "wb");
|
||||
|
||||
if (fin == nullptr || fout == nullptr) {
|
||||
ret = false;
|
||||
@@ -498,8 +509,8 @@ bool ClientNetworkContentSocketHandler::BeforeDownload()
|
||||
|
||||
if (this->curInfo->filesize != 0) {
|
||||
/* The filesize is > 0, so we are going to download it */
|
||||
const char *filename = GetFullFilename(this->curInfo, true);
|
||||
if (filename == nullptr || (this->curFile = fopen(filename, "wb")) == nullptr) {
|
||||
std::string filename = GetFullFilename(this->curInfo, true);
|
||||
if (filename.empty() || (this->curFile = fopen(filename.c_str(), "wb")) == nullptr) {
|
||||
/* Unless that fails of course... */
|
||||
DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
|
||||
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
|
||||
@@ -521,20 +532,25 @@ void ClientNetworkContentSocketHandler::AfterDownload()
|
||||
this->curFile = nullptr;
|
||||
|
||||
if (GunzipFile(this->curInfo)) {
|
||||
unlink(GetFullFilename(this->curInfo, true));
|
||||
unlink(GetFullFilename(this->curInfo, true).c_str());
|
||||
|
||||
Subdirectory sd = GetContentInfoSubDir(this->curInfo->type);
|
||||
if (sd == NO_DIRECTORY) NOT_REACHED();
|
||||
|
||||
TarScanner ts;
|
||||
ts.AddFile(sd, GetFullFilename(this->curInfo, false));
|
||||
std::string fname = GetFullFilename(this->curInfo, false);
|
||||
ts.AddFile(sd, fname);
|
||||
|
||||
if (this->curInfo->type == CONTENT_TYPE_BASE_MUSIC) {
|
||||
/* Music can't be in a tar. So extract the tar! */
|
||||
ExtractTar(GetFullFilename(this->curInfo, false), BASESET_DIR);
|
||||
unlink(GetFullFilename(this->curInfo, false));
|
||||
ExtractTar(fname, BASESET_DIR);
|
||||
unlink(fname.c_str());
|
||||
}
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
|
||||
#endif
|
||||
|
||||
this->OnDownloadComplete(this->curInfo->id);
|
||||
} else {
|
||||
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_EXTRACT, INVALID_STRING_ID, WL_ERROR);
|
||||
@@ -727,6 +743,7 @@ public:
|
||||
void OnConnect(SOCKET s) override
|
||||
{
|
||||
assert(_network_content_client.sock == INVALID_SOCKET);
|
||||
_network_content_client.lastActivity = _realtime_tick;
|
||||
_network_content_client.isConnecting = false;
|
||||
_network_content_client.sock = s;
|
||||
_network_content_client.Reopen();
|
||||
@@ -739,8 +756,6 @@ public:
|
||||
*/
|
||||
void ClientNetworkContentSocketHandler::Connect()
|
||||
{
|
||||
this->lastActivity = _realtime_tick;
|
||||
|
||||
if (this->sock != INVALID_SOCKET || this->isConnecting) return;
|
||||
this->isConnecting = true;
|
||||
new NetworkContentConnecter(NetworkAddress(NETWORK_CONTENT_SERVER_HOST, NETWORK_CONTENT_SERVER_PORT, AF_UNSPEC));
|
||||
@@ -888,7 +903,7 @@ void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *c
|
||||
*/
|
||||
void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const
|
||||
{
|
||||
for (const ContentInfo * const &ci : this->infos) {
|
||||
for (const ContentInfo *ci : this->infos) {
|
||||
if (ci == child) continue;
|
||||
|
||||
for (uint i = 0; i < ci->dependency_count; i++) {
|
||||
|
||||
@@ -577,8 +577,8 @@ public:
|
||||
}
|
||||
|
||||
case WID_NCL_MATRIX:
|
||||
resize->height = SETTING_BUTTON_HEIGHT;
|
||||
size->height = 6 * resize->height;
|
||||
resize->height = std::max(this->checkbox_size.height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
|
||||
size->height = 10 * resize->height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -628,7 +628,7 @@ public:
|
||||
const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(WID_NCL_NAME);
|
||||
const NWidgetBase *nwi_type = this->GetWidget<NWidgetBase>(WID_NCL_TYPE);
|
||||
|
||||
int line_height = max(this->checkbox_size.height, (uint)FONT_HEIGHT_NORMAL);
|
||||
int line_height = std::max(this->checkbox_size.height, (uint)FONT_HEIGHT_NORMAL);
|
||||
|
||||
/* Fill the matrix with the information */
|
||||
int sprite_y_offset = WD_MATRIX_TOP + (line_height - this->checkbox_size.height) / 2 - 1 + (this->resize.step_height - line_height) / 2;
|
||||
@@ -879,7 +879,7 @@ public:
|
||||
break;
|
||||
case WKC_PAGEDOWN:
|
||||
/* scroll down a page */
|
||||
this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.size() - 1);
|
||||
this->list_pos = std::min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.size() - 1);
|
||||
break;
|
||||
case WKC_HOME:
|
||||
/* jump to beginning */
|
||||
@@ -953,7 +953,7 @@ public:
|
||||
{
|
||||
if (this->auto_select && !rci->IsSelected()) _network_content_client.ToggleSelectedState(rci);
|
||||
this->content.ForceRebuild();
|
||||
this->InvalidateData();
|
||||
this->InvalidateData(0, false);
|
||||
}
|
||||
|
||||
void OnDownloadComplete(ContentID cid) override
|
||||
|
||||
@@ -175,21 +175,15 @@ void NetworkAfterNewGRFScan()
|
||||
/* 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. */
|
||||
c->name->Release();
|
||||
c->name = FindUnknownGRFName(c->ident.grfid, c->ident.md5sum, true);
|
||||
c->name->AddRef();
|
||||
c->status = GCS_NOT_FOUND;
|
||||
|
||||
/* If we miss a file, we're obviously incompatible. */
|
||||
item->info.compatible = false;
|
||||
} else {
|
||||
c->filename = f->filename;
|
||||
c->name->Release();
|
||||
c->name = f->name;
|
||||
c->name->AddRef();
|
||||
c->info->Release();
|
||||
c->info = f->info;
|
||||
c->info->AddRef();
|
||||
c->status = GCS_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
+44
-84
@@ -40,6 +40,9 @@
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
# include <emscripten.h>
|
||||
#endif
|
||||
|
||||
static void ShowNetworkStartServerWindow();
|
||||
static void ShowNetworkLobbyWindow(NetworkGameList *ngl);
|
||||
@@ -53,15 +56,6 @@ static const StringID _connection_types_dropdown[] = {
|
||||
INVALID_STRING_ID
|
||||
};
|
||||
|
||||
/**
|
||||
* Advertisement options in the server list
|
||||
*/
|
||||
static const StringID _lan_internet_types_dropdown[] = {
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED_NO,
|
||||
STR_NETWORK_SERVER_LIST_ADVERTISED_YES,
|
||||
INVALID_STRING_ID
|
||||
};
|
||||
|
||||
static std::vector<StringID> _language_dropdown;
|
||||
|
||||
void SortNetworkLanguages()
|
||||
@@ -130,7 +124,7 @@ public:
|
||||
/* First initialise some variables... */
|
||||
for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
|
||||
child_wid->SetupSmallestSize(w, init_array);
|
||||
this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
|
||||
this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
|
||||
}
|
||||
|
||||
/* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */
|
||||
@@ -476,6 +470,14 @@ public:
|
||||
this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
|
||||
this->SetFocusedWidget(WID_NG_FILTER);
|
||||
|
||||
/* As the master-server doesn't support "websocket" servers yet, we
|
||||
* let "os/emscripten/pre.js" hardcode a list of servers people can
|
||||
* join. This means the serverlist is curated for now, but it is the
|
||||
* best we can offer. */
|
||||
#ifdef __EMSCRIPTEN__
|
||||
EM_ASM(if (window["openttd_server_list"]) openttd_server_list());
|
||||
#endif
|
||||
|
||||
this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
|
||||
this->server = this->last_joined;
|
||||
if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address);
|
||||
@@ -493,24 +495,9 @@ public:
|
||||
this->last_sorting = this->servers.GetListing();
|
||||
}
|
||||
|
||||
void SetStringParameters(int widget) const override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_NG_CONN_BTN:
|
||||
SetDParam(0, _lan_internet_types_dropdown[_settings_client.network.lan_internet]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_NG_CONN_BTN:
|
||||
*size = maxdim(*size, maxdim(GetStringBoundingBox(_lan_internet_types_dropdown[0]), GetStringBoundingBox(_lan_internet_types_dropdown[1])));
|
||||
size->width += padding.width + GetMinSizing(NWST_STEP, 11U);;
|
||||
size->height += padding.height;
|
||||
break;
|
||||
|
||||
case WID_NG_MATRIX:
|
||||
resize->height = SETTING_BUTTON_HEIGHT;
|
||||
size->height = 5 * resize->height;
|
||||
@@ -550,10 +537,6 @@ public:
|
||||
SetDParamMaxValue(0, 5);
|
||||
*size = maxdim(*size, GetStringBoundingBox(STR_JUST_INT));
|
||||
break;
|
||||
|
||||
case WID_NG_DETAILS_SPACER:
|
||||
size->height = 20 + 10 * FONT_HEIGHT_NORMAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,7 +546,7 @@ public:
|
||||
case WID_NG_MATRIX: {
|
||||
uint16 y = r.top;
|
||||
|
||||
const int max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.size());
|
||||
const int max = std::min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), (int)this->servers.size());
|
||||
|
||||
for (int i = this->vscroll->GetPosition(); i < max; ++i) {
|
||||
const NetworkGameList *ngl = this->servers[i];
|
||||
@@ -616,6 +599,13 @@ public:
|
||||
this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr);
|
||||
this->GetWidget<NWidgetStacked>(WID_NG_NEWGRF_MISSING_SEL)->SetDisplayedPlane(sel == nullptr || !sel->online || sel->info.grfconfig == nullptr || !sel->info.version_compatible || sel->info.compatible);
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
this->SetWidgetDisabledState(WID_NG_SEARCH_INTERNET, true);
|
||||
this->SetWidgetDisabledState(WID_NG_SEARCH_LAN, true);
|
||||
this->SetWidgetDisabledState(WID_NG_ADD, true);
|
||||
this->SetWidgetDisabledState(WID_NG_START, true);
|
||||
#endif
|
||||
|
||||
this->DrawWidgets();
|
||||
}
|
||||
|
||||
@@ -665,7 +655,9 @@ public:
|
||||
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
|
||||
SetDParamStr(0, sel->address.GetAddressAsString());
|
||||
char network_addr_buffer[NETWORK_HOSTNAME_LENGTH + 6 + 7];
|
||||
sel->address.GetAddressAsString(network_addr_buffer, lastof(network_addr_buffer));
|
||||
SetDParamStr(0, network_addr_buffer);
|
||||
DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address
|
||||
y += FONT_HEIGHT_NORMAL;
|
||||
|
||||
@@ -697,10 +689,6 @@ public:
|
||||
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME);
|
||||
break;
|
||||
|
||||
case WID_NG_CONN_BTN: // 'Connection' droplist
|
||||
ShowDropDownMenu(this, _lan_internet_types_dropdown, _settings_client.network.lan_internet, WID_NG_CONN_BTN, 0, 0); // do it for widget WID_NSS_CONN_BTN
|
||||
break;
|
||||
|
||||
case WID_NG_NAME: // Sort by name
|
||||
case WID_NG_CLIENTS: // Sort by connected clients
|
||||
case WID_NG_MAPSIZE: // Sort by map size
|
||||
@@ -745,11 +733,12 @@ public:
|
||||
break;
|
||||
}
|
||||
|
||||
case WID_NG_FIND: // Find server automatically
|
||||
switch (_settings_client.network.lan_internet) {
|
||||
case 0: NetworkUDPSearchGame(); break;
|
||||
case 1: NetworkUDPQueryMasterServer(); break;
|
||||
}
|
||||
case WID_NG_SEARCH_INTERNET:
|
||||
NetworkUDPQueryMasterServer();
|
||||
break;
|
||||
|
||||
case WID_NG_SEARCH_LAN:
|
||||
NetworkUDPSearchGame();
|
||||
break;
|
||||
|
||||
case WID_NG_ADD: // Add a server
|
||||
@@ -787,20 +776,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void OnDropdownSelect(int widget, int index) override
|
||||
{
|
||||
switch (widget) {
|
||||
case WID_NG_CONN_BTN:
|
||||
_settings_client.network.lan_internet = index;
|
||||
break;
|
||||
|
||||
default:
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
this->SetDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Some data on this window has become invalid.
|
||||
* @param data Information about the changed data.
|
||||
@@ -838,7 +813,7 @@ public:
|
||||
case WKC_PAGEDOWN:
|
||||
/* scroll down a page */
|
||||
if (this->list_pos == SLP_INVALID) return ES_HANDLED;
|
||||
this->list_pos = min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.size() - 1);
|
||||
this->list_pos = std::min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.size() - 1);
|
||||
break;
|
||||
case WKC_HOME:
|
||||
/* jump to beginning */
|
||||
@@ -930,7 +905,7 @@ GUIGameServerList::FilterFunction * const NetworkGameWindow::filter_funcs[] = {
|
||||
|
||||
static NWidgetBase *MakeResizableHeader(int *biggest_index)
|
||||
{
|
||||
*biggest_index = max<int>(*biggest_index, WID_NG_INFO);
|
||||
*biggest_index = std::max<int>(*biggest_index, WID_NG_INFO);
|
||||
return new NWidgetServerListHeader();
|
||||
}
|
||||
|
||||
@@ -947,9 +922,6 @@ static const NWidgetPart _nested_network_game_widgets[] = {
|
||||
/* LEFT SIDE */
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, 7, 0),
|
||||
NWidget(NWID_HORIZONTAL), SetPIP(0, 7, 0),
|
||||
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_CONNECTION), SetSizingType(NWST_STEP), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NG_CONN_BTN),
|
||||
SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP),
|
||||
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NG_FILTER_LABEL), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL),
|
||||
NWidget(WWT_EDITBOX, COLOUR_LIGHT_BLUE, WID_NG_FILTER), SetMinimalSize(251, 12), SetFill(1, 0), SetResize(1, 0),
|
||||
SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
|
||||
@@ -1008,7 +980,8 @@ static const NWidgetPart _nested_network_game_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 7, 4),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_FIND), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_FIND_SERVER, STR_NETWORK_SERVER_LIST_FIND_SERVER_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_SEARCH_INTERNET), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET, STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_SEARCH_LAN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN, STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_ADD), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADD_SERVER, STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_START), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_START_SERVER, STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CANCEL), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_NULL),
|
||||
@@ -1276,8 +1249,8 @@ static const NWidgetPart _nested_network_start_server_window_widgets[] = {
|
||||
|
||||
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
|
||||
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_SERVER_LIST_ADVERTISED, STR_NULL),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetSizingType(NWST_BUTTON), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_SERVER_LIST_ADVERTISED_TOOLTIP),
|
||||
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_ADVERTISED_LABEL, STR_NULL),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetSizingType(NWST_BUTTON), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL), SetPIP(0, 1, 0),
|
||||
NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN, STR_NULL),
|
||||
@@ -1576,7 +1549,7 @@ struct NetworkLobbyWindow : public Window {
|
||||
NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info
|
||||
NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data
|
||||
/* Clear the information so removed companies don't remain */
|
||||
memset(this->company_info, 0, sizeof(this->company_info));
|
||||
for (auto &company : this->company_info) company = {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1660,8 +1633,7 @@ NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company)
|
||||
}
|
||||
|
||||
/* The window below gives information about the connected clients
|
||||
* and also makes able to give money to them, kick them (if server)
|
||||
* and stuff like that. */
|
||||
* and also makes able to kick them (if server) and stuff like that. */
|
||||
|
||||
extern void DrawCompanyIcon(CompanyID cid, int x, int y);
|
||||
|
||||
@@ -1693,11 +1665,6 @@ static void ClientList_Ban(const NetworkClientInfo *ci)
|
||||
NetworkServerKickOrBanIP(ci->client_id, true, nullptr);
|
||||
}
|
||||
|
||||
static void ClientList_GiveMoney(const NetworkClientInfo *ci)
|
||||
{
|
||||
ShowNetworkGiveMoneyWindow(ci->client_playas);
|
||||
}
|
||||
|
||||
static void ClientList_SpeakToClient(const NetworkClientInfo *ci)
|
||||
{
|
||||
ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, ci->client_id);
|
||||
@@ -1754,13 +1721,6 @@ struct NetworkClientListPopupWindow : Window {
|
||||
}
|
||||
this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, &ClientList_SpeakToAll);
|
||||
|
||||
if (_network_own_client_id != ci->client_id) {
|
||||
/* We are no spectator and the company we want to give money to is no spectator and money gifts are allowed. */
|
||||
if (Company::IsValidID(_local_company) && Company::IsValidID(ci->client_playas) && _settings_game.economy.give_money) {
|
||||
this->AddAction(STR_NETWORK_CLIENTLIST_GIVE_MONEY, &ClientList_GiveMoney);
|
||||
}
|
||||
}
|
||||
|
||||
/* A server can kick clients (but not himself). */
|
||||
if (_network_server && _network_own_client_id != ci->client_id) {
|
||||
this->AddAction(STR_NETWORK_CLIENTLIST_KICK, &ClientList_Kick);
|
||||
@@ -1919,14 +1879,14 @@ struct NetworkClientListWindow : Window {
|
||||
{
|
||||
if (widget != WID_CL_PANEL) return;
|
||||
|
||||
this->server_client_width = max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
|
||||
this->server_client_width = std::max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT;
|
||||
this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
|
||||
this->line_height = max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
|
||||
this->line_height = std::max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
|
||||
this->line_height = GetMinSizing(NWST_STEP, this->line_height);
|
||||
|
||||
uint width = 100; // Default width
|
||||
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
|
||||
width = max(width, GetStringBoundingBox(ci->client_name).width);
|
||||
width = std::max(width, GetStringBoundingBox(ci->client_name).width);
|
||||
}
|
||||
|
||||
this->line_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT;
|
||||
@@ -2097,18 +2057,18 @@ struct NetworkJoinStatusWindow : Window {
|
||||
/* Account for the statuses */
|
||||
uint width = 0;
|
||||
for (uint i = 0; i < NETWORK_JOIN_STATUS_END; i++) {
|
||||
width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i).width);
|
||||
width = std::max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_1 + i).width);
|
||||
}
|
||||
|
||||
/* For the number of waiting (other) players */
|
||||
SetDParamMaxValue(0, MAX_CLIENTS);
|
||||
width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_WAITING).width);
|
||||
width = std::max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_WAITING).width);
|
||||
|
||||
/* Account for downloading ~ 10 MiB */
|
||||
SetDParamMaxDigits(0, 8);
|
||||
SetDParamMaxDigits(1, 8);
|
||||
width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_1).width);
|
||||
width = max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_2).width);
|
||||
width = std::max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_1).width);
|
||||
width = std::max(width, GetStringBoundingBox(STR_NETWORK_CONNECTING_DOWNLOADING_2).width);
|
||||
|
||||
/* Give a bit more clearing for the widest strings than strictly needed */
|
||||
size->width = width + WD_FRAMERECT_LEFT + WD_FRAMERECT_BOTTOM + 10;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "network_type.h"
|
||||
|
||||
void ShowNetworkNeedPassword(NetworkPasswordType npt);
|
||||
void ShowNetworkGiveMoneyWindow(CompanyID company);
|
||||
void ShowNetworkChatQueryWindow(DestType type, int dest);
|
||||
void ShowJoinStatusWindow();
|
||||
void ShowNetworkGameWindow();
|
||||
|
||||
@@ -41,9 +41,9 @@ DECLARE_POSTFIX_INCREMENT(ClientID)
|
||||
static ClientID _network_client_id = CLIENT_ID_FIRST;
|
||||
|
||||
/** Make very sure the preconditions given in network_type.h are actually followed */
|
||||
assert_compile(MAX_CLIENT_SLOTS > MAX_CLIENTS);
|
||||
static_assert(MAX_CLIENT_SLOTS > MAX_CLIENTS);
|
||||
/** Yes... */
|
||||
assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS);
|
||||
static_assert(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENT_SLOTS);
|
||||
|
||||
/** The pool with clients. */
|
||||
NetworkClientSocketPool _networkclientsocket_pool("NetworkClientSocket");
|
||||
@@ -153,6 +153,16 @@ struct PacketWriter : SaveFilter {
|
||||
this->current = nullptr;
|
||||
}
|
||||
|
||||
/** Prepend the current packet to the queue. */
|
||||
void PrependQueue()
|
||||
{
|
||||
if (this->current == nullptr) return;
|
||||
|
||||
this->current->next = this->packets;
|
||||
this->packets = this->current;
|
||||
this->current = nullptr;
|
||||
}
|
||||
|
||||
void Write(byte *buf, size_t size) override
|
||||
{
|
||||
/* We want to abort the saving when the socket is closed. */
|
||||
@@ -164,7 +174,7 @@ struct PacketWriter : SaveFilter {
|
||||
|
||||
byte *bufe = buf + size;
|
||||
while (buf != bufe) {
|
||||
size_t to_write = min(SEND_MTU - this->current->size, bufe - buf);
|
||||
size_t to_write = std::min<size_t>(SEND_MTU - this->current->size, bufe - buf);
|
||||
memcpy(this->current->buffer + this->current->size, buf, to_write);
|
||||
this->current->size += (PacketSize)to_write;
|
||||
buf += to_write;
|
||||
@@ -193,9 +203,9 @@ struct PacketWriter : SaveFilter {
|
||||
this->AppendQueue();
|
||||
|
||||
/* Fast-track the size to the client. */
|
||||
Packet *p = new Packet(PACKET_SERVER_MAP_SIZE);
|
||||
p->Send_uint32((uint32)this->total_size);
|
||||
this->cs->NetworkTCPSocketHandler::SendPacket(p);
|
||||
this->current = new Packet(PACKET_SERVER_MAP_SIZE);
|
||||
this->current->Send_uint32((uint32)this->total_size);
|
||||
this->PrependQueue();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -213,7 +223,7 @@ ServerNetworkGameSocketHandler::ServerNetworkGameSocketHandler(SOCKET s) : Netwo
|
||||
/* The Socket and Info pools need to be the same in size. After all,
|
||||
* 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);
|
||||
static_assert(NetworkClientSocketPool::MAX_SIZE == NetworkClientInfoPool::MAX_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -301,7 +311,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
|
||||
/* We can't go over the MAX_CLIENTS limit here. However, the
|
||||
* pool must have place for all clients and ourself. */
|
||||
assert_compile(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1);
|
||||
static_assert(NetworkClientSocketPool::MAX_SIZE == MAX_CLIENTS + 1);
|
||||
assert(!accept || ServerNetworkGameSocketHandler::CanAllocateItem());
|
||||
return accept;
|
||||
}
|
||||
@@ -1372,9 +1382,6 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_CHAT(Packet *p)
|
||||
|
||||
NetworkClientInfo *ci = this->GetInfo();
|
||||
switch (action) {
|
||||
case NETWORK_ACTION_GIVE_MONEY:
|
||||
if (!Company::IsValidID(ci->client_playas)) break;
|
||||
FALLTHROUGH;
|
||||
case NETWORK_ACTION_CHAT:
|
||||
case NETWORK_ACTION_CHAT_CLIENT:
|
||||
case NETWORK_ACTION_CHAT_COMPANY:
|
||||
@@ -1800,7 +1807,7 @@ void NetworkServer_Tick(bool send_frame)
|
||||
for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
|
||||
/* We allow a number of bytes per frame, but only to the burst amount
|
||||
* to be available for packet receiving at any particular time. */
|
||||
cs->receive_limit = min(cs->receive_limit + _settings_client.network.bytes_per_frame,
|
||||
cs->receive_limit = std::min<int>(cs->receive_limit + _settings_client.network.bytes_per_frame,
|
||||
_settings_client.network.bytes_per_frame_burst);
|
||||
|
||||
/* Check if the speed of the client is what we can expect from a client */
|
||||
@@ -1952,7 +1959,7 @@ void NetworkServerShowStatusToConsole()
|
||||
"ready",
|
||||
"active"
|
||||
};
|
||||
assert_compile(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
|
||||
static_assert(lengthof(stat_str) == NetworkClientSocket::STATUS_END);
|
||||
|
||||
for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
|
||||
NetworkClientInfo *ci = cs->GetInfo();
|
||||
|
||||
@@ -74,18 +74,23 @@ enum NetworkPasswordType {
|
||||
NETWORK_COMPANY_PASSWORD, ///< The password of the company.
|
||||
};
|
||||
|
||||
/** Destination of our chat messages. */
|
||||
/**
|
||||
* Destination of our chat messages.
|
||||
* @warning The values of the enum items are part of the admin network API. Only append at the end.
|
||||
*/
|
||||
enum DestType {
|
||||
DESTTYPE_BROADCAST, ///< Send message/notice to all clients (All)
|
||||
DESTTYPE_TEAM, ///< Send message/notice to everyone playing the same company (Team)
|
||||
DESTTYPE_CLIENT, ///< Send message/notice to only a certain client (Private)
|
||||
};
|
||||
|
||||
/** Actions that can be used for NetworkTextMessage */
|
||||
/**
|
||||
* Actions that can be used for NetworkTextMessage.
|
||||
* @warning The values of the enum items are part of the admin network API. Only append at the end.
|
||||
*/
|
||||
enum NetworkAction {
|
||||
NETWORK_ACTION_JOIN,
|
||||
NETWORK_ACTION_LEAVE,
|
||||
NETWORK_ACTION_KICKED,
|
||||
NETWORK_ACTION_SERVER_MESSAGE,
|
||||
NETWORK_ACTION_CHAT,
|
||||
NETWORK_ACTION_CHAT_COMPANY,
|
||||
@@ -95,9 +100,13 @@ enum NetworkAction {
|
||||
NETWORK_ACTION_COMPANY_SPECTATOR,
|
||||
NETWORK_ACTION_COMPANY_JOIN,
|
||||
NETWORK_ACTION_COMPANY_NEW,
|
||||
NETWORK_ACTION_KICKED,
|
||||
};
|
||||
|
||||
/** The error codes we send around in the protocols. */
|
||||
/**
|
||||
* The error codes we send around in the protocols.
|
||||
* @warning The values of the enum items are part of the admin network API. Only append at the end.
|
||||
*/
|
||||
enum NetworkErrorCode {
|
||||
NETWORK_ERROR_GENERAL, // Try to use this one like never
|
||||
|
||||
|
||||
+10
-18
@@ -244,7 +244,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ
|
||||
uint8 in_reply_count = 0;
|
||||
size_t packet_len = 0;
|
||||
|
||||
DEBUG(net, 6, "[udp] newgrf data request from %s", client_addr->GetAddressAsString());
|
||||
DEBUG(net, 6, "[udp] newgrf data request from %s", client_addr->GetAddressAsString().c_str());
|
||||
|
||||
num_grfs = p->Recv_uint8 ();
|
||||
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
|
||||
@@ -263,7 +263,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ
|
||||
* the current list and do not send the other data.
|
||||
* The name could be an empty string, if so take the filename. */
|
||||
packet_len += sizeof(c.grfid) + sizeof(c.md5sum) +
|
||||
min(strlen(f->GetName()) + 1, (size_t)NETWORK_GRF_NAME_LENGTH);
|
||||
std::min(strlen(f->GetName()) + 1, (size_t)NETWORK_GRF_NAME_LENGTH);
|
||||
if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply
|
||||
break;
|
||||
}
|
||||
@@ -307,7 +307,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd
|
||||
/* Just a fail-safe.. should never happen */
|
||||
if (_network_udp_server) return;
|
||||
|
||||
DEBUG(net, 4, "[udp] server response from %s", client_addr->GetAddressAsString());
|
||||
DEBUG(net, 4, "[udp] server response from %s", client_addr->GetAddressAsString().c_str());
|
||||
|
||||
/* Find next item */
|
||||
item = NetworkGameListAddItem(*client_addr);
|
||||
@@ -407,7 +407,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd
|
||||
uint8 num_grfs;
|
||||
uint i;
|
||||
|
||||
DEBUG(net, 6, "[udp] newgrf data reply from %s", client_addr->GetAddressAsString());
|
||||
DEBUG(net, 6, "[udp] newgrf data reply from %s", client_addr->GetAddressAsString().c_str());
|
||||
|
||||
num_grfs = p->Recv_uint8 ();
|
||||
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
|
||||
@@ -426,9 +426,9 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd
|
||||
/* Try to find the GRFTextWrapper for the name of this 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. */
|
||||
GRFTextWrapper *unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false);
|
||||
if (unknown_name != nullptr && strcmp(GetGRFStringFromGRFText(unknown_name->text), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) {
|
||||
AddGRFTextToList(&unknown_name->text, name);
|
||||
GRFTextWrapper unknown_name = FindUnknownGRFName(c.grfid, c.md5sum, false);
|
||||
if (unknown_name && strcmp(GetGRFStringFromGRFText(unknown_name), UNKNOWN_GRF_NAME_PLACEHOLDER) == 0) {
|
||||
AddGRFTextToList(unknown_name, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,21 +441,13 @@ void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFCo
|
||||
/* 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 */
|
||||
config->name->Release();
|
||||
config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true);
|
||||
config->name->AddRef();
|
||||
config->status = GCS_NOT_FOUND;
|
||||
} else {
|
||||
config->filename = f->filename;
|
||||
config->name->Release();
|
||||
config->name = f->name;
|
||||
config->name->AddRef();
|
||||
config->info->Release();
|
||||
config->info = f->info;
|
||||
config->info->AddRef();
|
||||
config->url->Release();
|
||||
config->url = f->url;
|
||||
config->url->AddRef();
|
||||
}
|
||||
SetBit(config->flags, GCF_COPY);
|
||||
}
|
||||
@@ -485,7 +477,7 @@ void NetworkUDPQueryMasterServer()
|
||||
|
||||
_udp_client_socket->SendPacket(&p, &out_addr, true);
|
||||
|
||||
DEBUG(net, 2, "[udp] master server queried at %s", out_addr.GetAddressAsString());
|
||||
DEBUG(net, 2, "[udp] master server queried at %s", out_addr.GetAddressAsString().c_str());
|
||||
}
|
||||
|
||||
/** Find all servers */
|
||||
@@ -549,8 +541,8 @@ static void NetworkUDPAdvertiseThread()
|
||||
if (_session_key == 0 && session_key_retries++ == 2) {
|
||||
DEBUG(net, 0, "[udp] advertising to the master server is failing");
|
||||
DEBUG(net, 0, "[udp] we are not receiving the session key from the server");
|
||||
DEBUG(net, 0, "[udp] please allow udp packets from %s to you to be delivered", out_addr.GetAddressAsString(false));
|
||||
DEBUG(net, 0, "[udp] please allow udp packets from you to %s to be delivered", out_addr.GetAddressAsString(false));
|
||||
DEBUG(net, 0, "[udp] please allow udp packets from %s to you to be delivered", out_addr.GetAddressAsString(false).c_str());
|
||||
DEBUG(net, 0, "[udp] please allow udp packets from you to %s to be delivered", out_addr.GetAddressAsString(false).c_str());
|
||||
}
|
||||
if (_session_key != 0 && _network_advertise_retries == 0) {
|
||||
DEBUG(net, 0, "[udp] advertising to the master server is failing");
|
||||
|
||||
Reference in New Issue
Block a user