summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--functions.h31
-rw-r--r--intro_gui.c8
-rw-r--r--lang/english.txt3
-rw-r--r--misc.c2
-rw-r--r--network.c805
-rw-r--r--network_gui.c46
-rw-r--r--settings.c3
-rw-r--r--ttd.c57
-rw-r--r--variables.h14
9 files changed, 691 insertions, 278 deletions
diff --git a/functions.h b/functions.h
index f684fa055..64be83efb 100644
--- a/functions.h
+++ b/functions.h
@@ -121,19 +121,36 @@ int CalcBridgeLenCostFactor(int x);
typedef void CommandCallback(bool success, uint tile, uint32 p1, uint32 p2);
bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback, uint32 cmd);
-void NetworkConnect(const char *hostname, int port);
void NetworkReceive();
void NetworkSend();
void NetworkProcessCommands();
-void NetworkListen(int port);
-void NetworkInitialize(const char *hostname);
+void NetworkListen();
+void NetworkInitialize();
void NetworkShutdown();
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback);
-void NetworkStartSync();
-void NetworkUDPListen(int port);
-void NetworkUDPReceive();
+void NetworkStartSync(bool fcreset);
+void NetworkClose(bool client);
+
void NetworkIPListInit();
-bool NetworkUDPSearchServer();
+
+void NetworkCoreInit();
+void NetworkCoreShutdown();
+void NetworkCoreDisconnect();
+void NetworkCoreLoop(bool incomming);
+bool NetworkCoreConnectGame(byte* b, unsigned short port);
+bool NetworkCoreStartGame();
+
+void NetworkLobbyShutdown();
+void NetworkLobbyInit();
+
+void NetworkGameListClear();
+char * NetworkGameListAdd();
+void NetworkGameListFromLAN();
+void NetworkGameListFromInternet();
+char * NetworkGameListItem(uint16 index);
+
+void NetworkGameFillDefaults();
+void NetworkGameChangeDate(uint16 newdate);
/* misc_cmd.c */
void PlaceTreesRandomly();
diff --git a/intro_gui.c b/intro_gui.c
index b1095691e..83cb5a043 100644
--- a/intro_gui.c
+++ b/intro_gui.c
@@ -58,7 +58,9 @@ static void SelectGameWndProc(Window *w, WindowEvent *e) {
DoCommandP(0, 0, 0, NULL, CMD_SET_SINGLE_PLAYER);
break;
case 7:
- ShowNetworkGameWindow();
+ if (!_network_available) {
+ ShowErrorMessage(-1,STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
+ } else ShowNetworkGameWindow();
break;
case 8: ShowGameOptions(); break;
case 9: ShowGameDifficulty(); break;
@@ -118,7 +120,7 @@ int32 CmdGenRandomNewGame(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_random_seed_1 = p1;
_random_seed_2 = p2;
- if (_networking) { NetworkStartSync(); }
+ if (_networking) { NetworkStartSync(true); }
MakeNewGame();
return 0;
@@ -159,7 +161,7 @@ int32 CmdStartScenario(int x, int y, uint32 flags, uint32 p1, uint32 p2)
_random_seed_1 = p1;
_random_seed_2 = p2;
- if (_networking) { NetworkStartSync(); }
+ if (_networking) { NetworkStartSync(true); }
StartScenario();
return 0;
diff --git a/lang/english.txt b/lang/english.txt
index a79d6b8fd..bd3c5c018 100644
--- a/lang/english.txt
+++ b/lang/english.txt
@@ -1213,6 +1213,9 @@ STR_NETWORK_NEW_COMPANY :{BLACK}New company
STR_NETWORK_NEW_COMPANY_TIP :{BLACK}Open a new company
STR_NETWORK_READY :{BLACK}Ready
+STR_NETWORK_ERR_NOTAVAILABLE :{WHITE} No network devices found or compiled without ENABLE_NETWORK
+STR_NETWORK_ERR_NOSERVER :{WHITE} Could not find any network game
+STR_NETWORK_ERR_NOCONNECTION :{WHITE} The server didn't answer the request
############ end network gui strings
diff --git a/misc.c b/misc.c
index 2a57f73ba..06e790019 100644
--- a/misc.c
+++ b/misc.c
@@ -542,6 +542,8 @@ void IncreaseDate()
/* yeah, increse day counter and call various daily loops */
_date++;
+ NetworkGameChangeDate(_date);
+
_vehicle_id_ctr_day = 0;
DisasterDailyLoop();
diff --git a/network.c b/network.c
index e7a9b69cf..028099782 100644
--- a/network.c
+++ b/network.c
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "ttd.h"
+#include "gui.h"
#include "command.h"
#include "player.h"
@@ -180,9 +181,10 @@ typedef struct FutureSeeds {
static FutureSeeds _future_seed[8];
static int _num_future_seed;
-static SOCKET _listensocket;
-static SOCKET _udpsocket;
+static SOCKET _listensocket; // tcp socket
+static SOCKET _udp_client_socket; // udp server socket
+static SOCKET _udp_server_socket; // udp client socket
typedef struct UDPPacket {
byte command_code;
@@ -194,15 +196,13 @@ typedef struct UDPPacket {
enum {
NET_UDPCMD_SERVERSEARCH = 1,
NET_UDPCMD_SERVERACTIVE,
+ NET_UDPCMD_GETSERVERINFO,
+ NET_UDPCMD_SERVERINFO,
};
-uint32 _network_ip_list[10]; // Network ips
-char * _network_detected_serverip = "255.255.255.255"; // UDP Broadcast detected server-ip
-uint32 _network_detected_serverport = 0; // UDP Broadcast detected server-port
+void NetworkUDPSend(bool client, struct sockaddr_in recv,struct UDPPacket packet);
-void NetworkUDPSend(struct sockaddr_in recv,struct UDPPacket packet);
-
-static bool _network_synced;
+uint32 _network_ip_list[10]; // network ip list
// this is set to point to the savegame
static byte *_transmit_file;
@@ -210,8 +210,51 @@ static size_t _transmit_file_size;
static FILE *_recv_file;
+typedef struct NetworkGameInfo {
+ char server_name[40]; // name of the game
+ char server_revision[8]; // server game version
+ byte server_lang; // langid
+ byte players_max; // max players allowed on server
+ byte players_on; // current count of players on server
+ uint16 game_date; // current date
+ char game_password[10]; // should fit ... 14 chars
+ char map_name[40]; // map which is played ["random" for a randomized map]
+ uint map_width; // map width / 8
+ uint map_height; // map height / 8
+ byte map_set; // graphical set
+} NetworkGameInfo;
+
+typedef struct NetworkGameList {
+ NetworkGameInfo item;
+ uint32 ip;
+ uint16 port;
+ char * _next;
+} NetworkGameList;
+
+static NetworkGameInfo _network_game;
+static NetworkGameList * _network_game_list = NULL;
+
+/* multi os compatible sleep function */
+void CSleep(int milliseconds) {
+#if defined(WIN32)
+Sleep(milliseconds);
+#endif
+#if defined(UNIX)
+#ifndef __BEOS__
+usleep(milliseconds*1000);
+#endif
+#ifdef __BEOS__
+snooze(milliseconds*1000);
+#endif
+#endif
+}
+
//////////////////////////////////////////////////////////////////////
+// ****************************** //
+// * TCP Packets and Handlers * //
+// ****************************** //
+
static QueuedCommand *AllocQueuedCommand(CommandQueue *nq)
{
QueuedCommand *qp = (QueuedCommand*)calloc(sizeof(QueuedCommand), 1);
@@ -471,12 +514,13 @@ static void HandleFilePacket(FilePacketHdr *fp)
// sync to server.
_networking_queuing = false;
-
+ NetworkStartSync(false);
+/*
_networking_sync = true;
_frame_counter = 0; // start executing at frame 0.
_sync_seed_1 = _sync_seed_2 = 0;
_num_future_seed = 0;
- memset(_my_seed_list, 0, sizeof(_my_seed_list));
+ memset(_my_seed_list, 0, sizeof(_my_seed_list)); */
if (_network_playas == 0) {
// send a command to make a new player
@@ -504,7 +548,7 @@ static void CloseClient(ClientState *cs)
{
Packet *p, *next;
- printf("CloseClient\n");
+ DEBUG(misc,1) ("[NET][TCP] closed client connection");
assert(cs->socket != INVALID_SOCKET);
@@ -523,6 +567,8 @@ static void CloseClient(ClientState *cs)
}
cs->socket = INVALID_SOCKET;
+ if (_networking_server) _network_game.players_on--;
+
_num_clients--;
}
@@ -683,6 +729,8 @@ static ClientState *AllocClient(SOCKET s)
if (_num_clients == MAX_CLIENTS)
return NULL;
+ if (_networking_server) _network_game.players_on++;
+
cs = &_clients[_num_clients++];
memset(cs, 0, sizeof(*cs));
cs->last = &cs->head;
@@ -779,14 +827,89 @@ static void SendQueuedCommandsToNewClient(ClientState *cs)
}
+// ************************** //
+// * TCP Networking * //
+// ************************** //
+
+bool NetworkConnect(const char *hostname, int port)
+{
+ SOCKET s;
+ struct sockaddr_in sin;
+ int b;
+
+ DEBUG(misc, 1) ("[NET][TCP] Connecting to %s %d", hostname, port);
+
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s == INVALID_SOCKET) error("socket() failed");
+
+ b = 1;
+ setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b));
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = inet_addr(hostname);
+ sin.sin_port = htons(port);
+
+ if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) {
+ NetworkClose(true);
+ return false;
+ }
+
+ // set nonblocking mode for socket..
+ { unsigned long blocking = 1; ioctlsocket(s, FIONBIO, &blocking); }
+
+ // in client mode, only the first client field is used. it's pointing to the server.
+ AllocClient(s);
+
+ // queue packets.. because we're waiting for the savegame.
+ _networking_queuing = true;
+ _frame_counter_max = 0;
+
+ return true;
+}
+
+void NetworkListen()
+{
+
+ SOCKET ls;
+ struct sockaddr_in sin;
+ int port;
+
+ port = _network_server_port;
+
+ DEBUG(misc, 1) ("[NET][TCP] listening on port %d", port);
+
+ ls = socket(AF_INET, SOCK_STREAM, 0);
+ if (ls == INVALID_SOCKET)
+ error("socket() on listen socket failed");
+
+ // reuse the socket
+ {
+ int reuse = 1; if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1)
+ error("setsockopt() on listen socket failed");
+ }
+
+ // set nonblocking mode for socket
+ { unsigned long blocking = 1; ioctlsocket(ls, FIONBIO, &blocking); }
+
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = 0;
+ sin.sin_port = htons(port);
+
+ if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0)
+ error("bind() failed");
+
+ if (listen(ls, 1) != 0)
+ error("listen() failed");
+
+ _listensocket = ls;
+}
+
void NetworkReceive()
{
ClientState *cs;
int n;
fd_set read_fd, write_fd;
struct timeval tv;
-
- NetworkUDPReceive(); // udp handling
FD_ZERO(&read_fd);
FD_ZERO(&write_fd);
@@ -897,165 +1020,76 @@ void NetworkSend()
}
}
-void NetworkConnect(const char *hostname, int port)
-{
- SOCKET s;
- struct sockaddr_in sin;
- int b;
-
-
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s == INVALID_SOCKET) error("socket() failed");
-
- b = 1;
- setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b));
- if (strcmp(hostname,"auto")==0) {
- // autodetect server over udp broadcast [works 4 lan]
- if (NetworkUDPSearchServer()) {
- hostname=_network_detected_serverip;
- port=_network_detected_serverport;
- } else {
- error("udp: server not found");
- }
- }
-
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = inet_addr(hostname);
- sin.sin_port = htons(port);
-
- if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0)
- error("connect() failed");
-
- // set nonblocking mode for socket..
- { unsigned long blocking = 1; ioctlsocket(s, FIONBIO, &blocking); }
-
- // in client mode, only the first client field is used. it's pointing to the server.
- AllocClient(s);
-
- // queue packets.. because we're waiting for the savegame.
- _networking_queuing = true;
- _frame_counter_max = 0;
-
-}
-
-void NetworkListen(int port)
-{
-
- SOCKET ls;
- struct sockaddr_in sin;
-
- ls = socket(AF_INET, SOCK_STREAM, 0);
- if (ls == INVALID_SOCKET)
- error("socket() on listen socket failed");
-
- // reuse the socket
- {
- int reuse = 1; if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1)
- error("setsockopt() on listen socket failed");
- }
-
- // set nonblocking mode for socket
- { unsigned long blocking = 1; ioctlsocket(ls, FIONBIO, &blocking); }
-
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = 0;
- sin.sin_port = htons(port);
-
- if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0)
- error("bind() failed");
-
- if (listen(ls, 1) != 0)
- error("listen() failed");
-
- _listensocket = ls;
-}
-
-void NetworkInitialize(const char *hostname)
+void NetworkInitialize()
{
ClientState *cs;
-#if defined(WIN32)
- WSADATA wsa;
- if (WSAStartup(MAKEWORD(2,0), &wsa) != 0)
- error("WSAStartup failed");
-#endif
-
-#if defined(__MORPHOS__) || defined(__AMIGA__)
- if (!(SocketBase = OpenLibrary("bsdsocket.library", 4))) {
- error("Couldn't open bsdsocket.library version 4.");
- }
-#endif
-
_command_queue.last = &_command_queue.head;
_ack_queue.last = &_ack_queue.head;
// invalidate all clients
for(cs=_clients; cs != &_clients[MAX_CLIENTS]; cs++)
cs->socket = INVALID_SOCKET;
-
- /* startup udp listener
- * - only if this instance is a server, so clients can find it
- * OR
- * - a client, wanting to find a server to connect to
- */
- if (hostname == NULL || strcmp(hostname,"auto") == 0) {
- printf("Trying to open UDP port...\n");
- NetworkUDPListen(_network_port);
- }
+
+}
+
+void NetworkClose(bool client) {
+
+ ClientState *cs;
+ // invalidate all clients
+
+ for(cs=_clients; cs != &_clients[MAX_CLIENTS]; cs++) if (cs->socket != INVALID_SOCKET) {
+ CloseClient(cs);
+ }
+
+ if (!client) {
+ // if in servermode --> close listener
+ closesocket(_listensocket);
+ _listensocket= INVALID_SOCKET;
+ DEBUG(misc,1) ("[NET][TCP] closed listener on port %i", _network_server_port);
+ }
}
void NetworkShutdown()
{
-#if defined(__MORPHOS__) || defined(__AMIGA__)
- if (SocketBase) {
- CloseLibrary(SocketBase);
- }
-#endif
+
}
// switch to synced mode.
-void NetworkStartSync()
+void NetworkStartSync(bool fcreset)
{
+ DEBUG(misc,3) ("[NET][SYNC] switching to synced game mode");
_networking_sync = true;
_frame_counter = 0;
- _frame_counter_max = 0;
- _frame_counter_srv = 0;
+ if (fcreset) {
+ _frame_counter_max = 0;
+ _frame_counter_srv = 0;
+ }
_num_future_seed = 0;
_sync_seed_1 = _sync_seed_2 = 0;
memset(_my_seed_list, 0, sizeof(_my_seed_list));
+
}
// ************************** //
// * UDP Network Extensions * //
// ************************** //
-/* multi os compatible sleep function */
-void CSleep(int milliseconds) {
-#if defined(WIN32)
-Sleep(milliseconds);
-#endif
-#if defined(UNIX)
-#ifndef __BEOS__
-usleep(milliseconds*1000);
-#endif
-#ifdef __BEOS__
-snooze(milliseconds*1000);
-#endif
-#endif
-}
-
-void NetworkUDPListen(int port)
+void NetworkUDPListen(bool client)
{
SOCKET udp;
struct sockaddr_in sin;
+ int port;
- DEBUG(misc,0) ("udp: listener initiated on port %i", port);
- NetworkIPListInit();
+ if (client) { port = _network_client_port; } else { port = _network_server_port; };
+
+ DEBUG(misc,1) ("[NET][UDP] listening on port %i", port);
udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (udp == INVALID_SOCKET)
- error("udp: socket() on listen socket failed");
+
+ // this disables network
+ _network_available = !(udp == INVALID_SOCKET);
// set nonblocking mode for socket
{ unsigned long blocking = 1; ioctlsocket(udp, FIONBIO, &blocking); }
@@ -1065,137 +1099,502 @@ void NetworkUDPListen(int port)
sin.sin_port = htons(port);
if (bind(udp, (struct sockaddr*)&sin, sizeof(sin)) != 0)
- error("udp: bind() failed");
+ DEBUG(misc,1) ("[NET][UDP] error: bind failed on port %i", port);
+
// enable broadcasting
{ unsigned long val=1; setsockopt(udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val)); }
-
- _udpsocket = udp;
+ // allow reusing
+ { unsigned long val=1; setsockopt(udp, SOL_SOCKET, SO_REUSEADDR, (char *) &val , sizeof(val)); }
+
+ if (client) { _udp_client_socket = udp; } else { _udp_server_socket = udp; } ;
}
-void NetworkUDPReceive() {
+void NetworkUDPClose(bool client) {
+ if (client) {
+ DEBUG(misc,1) ("[NET][UDP] closed listener on port %i", _network_client_port);
+ closesocket(_udp_client_socket);
+ _udp_client_socket = INVALID_SOCKET;
+ } else {
+ DEBUG(misc,1) ("[NET][UDP] closed listener on port %i", _network_server_port);
+ closesocket(_udp_server_socket);
+ _udp_server_socket = INVALID_SOCKET;
+ };
+ }
+
+void NetworkUDPReceive(bool client) {
struct sockaddr_in client_addr;
int client_len;
int nbytes;
struct UDPPacket packet;
int packet_len;
+ SOCKET udp;
+ if (client) udp=_udp_client_socket; else udp=_udp_server_socket;
+
packet_len = sizeof(packet);
client_len = sizeof(client_addr);
- nbytes = recvfrom(_udpsocket, (char *) &packet, packet_len , 0, (struct sockaddr *) &client_addr, &client_len);
+ nbytes = recvfrom(udp, (char *) &packet, packet_len , 0, (struct sockaddr *) &client_addr, &client_len);
if (nbytes>0) {
if (packet.command_code==packet.command_check) switch (packet.command_code) {
- case NET_UDPCMD_SERVERSEARCH:
- if (_networking_server) {
- packet.command_check=packet.command_code=NET_UDPCMD_SERVERACTIVE;
- NetworkUDPSend(client_addr, packet);
- }
- break;
- case NET_UDPCMD_SERVERACTIVE:
- if (!_networking_server) {
- _network_detected_serverip=inet_ntoa(*(struct in_addr *) &client_addr.sin_addr);
- _network_detected_serverport=ntohs(client_addr.sin_port);
+ case NET_UDPCMD_SERVERSEARCH:
+ if (!client) {
+ packet.command_check=packet.command_code=NET_UDPCMD_SERVERINFO;
+ memcpy(&packet.data,&_network_game,sizeof(_network_game));
+ packet.data_len=sizeof(_network_game);
+ NetworkUDPSend(client,client_addr, packet);
+ }
+ break;
+ case NET_UDPCMD_GETSERVERINFO:
+ if (!client) {
+ packet.command_check=packet.command_code=NET_UDPCMD_SERVERINFO;
+ memcpy(&packet.data,&_network_game,sizeof(_network_game));
+ packet.data_len=sizeof(_network_game);
+ NetworkUDPSend(client,client_addr, packet);
}
break;
+ case NET_UDPCMD_SERVERINFO:
+ if (client) {
+ NetworkGameList * item;
+
+ item = (NetworkGameList *) NetworkGameListAdd();
+ item -> ip = inet_addr(inet_ntoa(client_addr.sin_addr));
+ item -> port = ntohs(client_addr.sin_port);
+
+ memcpy(item,&packet.data,packet.data_len);
+ }
+ break;
}
}
}
-void NetworkIPListInit() {
- struct hostent* he;
- char hostname[250];
- uint32 bcaddr;
- int i=0;
-
- _network_detected_serverip="";
-
- gethostname(hostname,250);
- DEBUG(misc,0) ("iplist: init for host %s", hostname);
- he=gethostbyname((char *) hostname);
-
- if (he == NULL) {
- DEBUG(misc, 0) ("iplist: gethostbyname failed for host %s...trying with IP address", hostname);
- bcaddr = inet_addr(hostname);
- he = gethostbyaddr(inet_ntoa(*(struct in_addr *)bcaddr), sizeof(bcaddr), AF_INET);
- }
- if (he == NULL) {
- DEBUG(misc, 0) ("iplist: cannot resolve %s", hostname);
- } else {
- while(he->h_addr_list[i]) {
- bcaddr = inet_addr(inet_ntoa(*(struct in_addr *) he->h_addr_list[i]));
- _network_ip_list[i]=bcaddr;
- DEBUG(misc,0) ("iplist: add %s",inet_ntoa(*(struct in_addr *) he->h_addr_list[i]));
- i++;
- }
- }
- _network_ip_list[i]=0;
-
-}
-void NetworkUDPBroadCast(struct UDPPacket packet) {
+void NetworkUDPBroadCast(bool client, struct UDPPacket packet) {
int i=0, res;
struct sockaddr_in out_addr;
uint32 bcaddr;
byte * bcptr;
+
+ SOCKET udp;
+ if (client) udp=_udp_client_socket; else udp=_udp_server_socket;
+
while (_network_ip_list[i]!=0) {
bcaddr=_network_ip_list[i];
out_addr.sin_family = AF_INET;
- out_addr.sin_port = htons(_network_port);
+ if (client) { out_addr.sin_port = htons(_network_server_port); } else { out_addr.sin_port = htons(_network_client_port); };
bcptr = (byte *) &bcaddr;
bcptr[3]=255;
out_addr.sin_addr.s_addr = bcaddr;
- res=sendto(_udpsocket,(char *) &packet,sizeof(packet),0,(struct sockaddr *) &out_addr,sizeof(out_addr));
+ res=sendto(udp,(char *) &packet,sizeof(packet),0,(struct sockaddr *) &out_addr,sizeof(out_addr));
if (res==-1) error("udp: broadcast error: %i",GET_LAST_ERROR());
i++;
}
}
-void NetworkUDPSend(struct sockaddr_in recv,struct UDPPacket packet) {
- sendto(_udpsocket,(char *) &packet,sizeof(packet),0,(struct sockaddr *) &recv,sizeof(recv));
+void NetworkUDPSend(bool client, struct sockaddr_in recv,struct UDPPacket packet) {
+
+ SOCKET udp;
+ if (client) udp=_udp_client_socket; else udp=_udp_server_socket;
+
+ sendto(udp,(char *) &packet,sizeof(packet),0,(struct sockaddr *) &recv,sizeof(recv));
}
-bool NetworkUDPSearchServer() {
+
+bool NetworkUDPSearchGame(byte ** _network_detected_serverip, unsigned short * _network_detected_serverport) {
struct UDPPacket packet;
int timeout=3000;
- DEBUG(misc,0) ("udp: searching server");
- _network_detected_serverip = "255.255.255.255";
- _network_detected_serverport = 0;
+
+ NetworkGameListClear();
+
+ DEBUG(misc,0) ("[NET][UDP] searching server");
+ *_network_detected_serverip = "255.255.255.255";
+ *_network_detected_serverport = 0;
packet.command_check=packet.command_code=NET_UDPCMD_SERVERSEARCH;
packet.data_len=0;
- NetworkUDPBroadCast(packet);
+ NetworkUDPBroadCast(true, packet);
while (timeout>=0) {
CSleep(100);
timeout-=100;
- NetworkUDPReceive();
- if (_network_detected_serverport>0) {
- timeout=-1;
- DEBUG(misc,0) ("udp: server found on %s", _network_detected_serverip);
- }
+ NetworkUDPReceive(true);
+
+ if (_network_game_count>0) {
+ NetworkGameList * item;
+ item = (NetworkGameList *) NetworkGameListItem(0);
+ *_network_detected_serverip=inet_ntoa(*(struct in_addr *) &item->ip);
+ *_network_detected_serverport=item->port;
+ timeout=-1;
+ DEBUG(misc,0) ("[NET][UDP] server found on %s", *_network_detected_serverip);
+ }
+
}
+
return (_network_detected_serverport>0);
}
+// *************************** //
+// * New Network Core System * //
+// *************************** //
+
+void NetworkIPListInit() {
+ struct hostent* he = NULL;
+ char hostname[250];
+ uint32 bcaddr;
+ int i=0;
+
+ gethostname(hostname,250);
+ DEBUG(misc,2) ("[NET][IP] init for host %s", hostname);
+ he=gethostbyname((char *) hostname);
+
+ if (he == NULL) {
+ he = gethostbyname("localhost");
+ }
+
+ if (he == NULL) {
+ bcaddr = inet_addr("127.0.0.1");
+ he = gethostbyaddr(inet_ntoa(*(struct in_addr *) &bcaddr), sizeof(bcaddr), AF_INET);
+ }
+
+ if (he == NULL) {
+ DEBUG(misc, 2) ("[NET][IP] cannot resolve %s", hostname);
+ } else {
+ while(he->h_addr_list[i]) {
+ bcaddr = inet_addr(inet_ntoa(*(struct in_addr *) he->h_addr_list[i]));
+ _network_ip_list[i]=bcaddr;
+ DEBUG(misc,2) ("[NET][IP] add %s",inet_ntoa(*(struct in_addr *) he->h_addr_list[i]));
+ i++;
+ }
+
+ }
+ _network_ip_list[i]=0;
+
+}
+
+/* *************************************************** */
+
+void NetworkCoreInit() {
+
+DEBUG(misc,3) ("[NET][Core] init()");
+_network_available=true;
+
+// [win32] winsock startup
+
+#if defined(WIN32)
+{
+ WSADATA wsa;
+ DEBUG(misc,3) ("[NET][Core] using windows socket library");
+ if (WSAStartup(MAKEWORD(2,0), &wsa) != 0) {
+ DEBUG(misc,3) ("[NET][Core] error: WSAStartup failed");
+ _network_available=false;
+ }
+}
+#else
+
+// [morphos/amigaos] bsd-socket startup
+
+#if defined(__MORPHOS__) || defined(__AMIGA__)
+{
+ DEBUG(misc,3) ("[NET][Core] using bsd socket library");
+ if (!(SocketBase = OpenLibrary("bsdsocket.library", 4))) {
+ DEBUG(misc,3) ("[NET][Core] Couldn't open bsdsocket.library version 4.");
+ _network_available=false;
+ }
+}
+#else
+
+// [linux/macos] unix-socket startup
+
+ DEBUG(misc,3) ("[NET][Core] using unix socket library");
+
+#endif
+
+#endif
+
+
+if (_network_available) {
+ DEBUG(misc,3) ("[NET][Core] OK: multiplayer available");
+ // initiate network ip list
+ NetworkIPListInit();
+ } else {
+ DEBUG(misc,3) ("[NET][Core] FAILED: multiplayer not available");
+ }
+}
+
+/* *************************************************** */
+
+void NetworkCoreShutdown() {
+
+DEBUG(misc,3) ("[NET][Core] shutdown()");
+
+#if defined(__MORPHOS__) || defined(__AMIGA__)
+{
+ if (SocketBase) {
+ CloseLibrary(SocketBase);
+ }
+}
+#endif
+
+
+#if defined(WIN32)
+{
+ WSACleanup();
+}
+#endif
+
+}
+
+/* *************************************************** */
+
+bool NetworkCoreConnectGame(byte* b, unsigned short port)
+{
+ if (!_network_available) return false;
+
+ if (strcmp((char *) b,"auto")==0) {
+ // do autodetect
+ NetworkUDPSearchGame(&b, &port);
+ }
+
+ if (port==0) {
+ // autodetection failed
+ if (_networking_override) NetworkLobbyShutdown();
+ ShowErrorMessage(-1, STR_NETWORK_ERR_NOSERVER, 0, 0);
+ return false;
+ }
+ NetworkInitialize();
+ _networking = NetworkConnect(b, port);
+ if (_networking) {
+ NetworkLobbyShutdown();
+ } else {
+ if (_networking_override) NetworkLobbyShutdown();
+ ShowErrorMessage(-1, STR_NETWORK_ERR_NOCONNECTION,0,0);
+ }
+ return _networking;
+}
+
+/* *************************************************** */
+
+bool NetworkCoreStartGame()
+{
+ if (!_network_available) return false;
+ NetworkLobbyShutdown();
+ NetworkInitialize();
+ NetworkListen();
+ NetworkUDPListen(false);
+ _networking_server = true;
+ _networking = true;
+ NetworkGameFillDefaults(); // clears the network game info
+ _network_game.players_on++; // the serverplayer is online
+ return true;
+}
+
+/* *************************************************** */
+
+void NetworkCoreDisconnect()
+{
+ /* terminate server */
+ if (_networking_server) {
+ NetworkUDPClose(false);
+ NetworkClose(false);
+ }
+
+ /* terminate client connection */
+ else if (_networking) {
+ NetworkClose(true);
+ }
+
+ _networking_server = false;
+ _networking = false;
+ NetworkShutdown();
+}
+
+/* *************************************************** */
+
+void NetworkCoreLoop(bool incomming) {
+
+
+if (incomming) {
+
+ // incomming
+
+ if ( _udp_client_socket != INVALID_SOCKET ) NetworkUDPReceive(true);
+ if ( _udp_server_socket != INVALID_SOCKET ) NetworkUDPReceive(false);
+
+ if (_networking) {
+ NetworkReceive();
+ NetworkProcessCommands(); // to check if we got any new commands belonging to the current frame before we increase it.
+ }
+
+ } else {
+
+ // outgoing
+
+ if (_networking) {
+ NetworkSend();
+ }
+
+ }
+
+}
+
+void NetworkLobbyInit() {
+ DEBUG(misc,3) ("[NET][Lobby] init()");
+ NetworkUDPListen(true);
+}
+
+void NetworkLobbyShutdown() {
+ DEBUG(misc,3) ("[NET][Lobby] shutdown()");
+ NetworkUDPClose(true);
+}
+
+
+// ******************************** //
+// * Network Game List Extensions * //
+// ******************************** //
+
+void NetworkGameListClear() {
+NetworkGameList * item;
+NetworkGameList * next;
+
+DEBUG(misc,4) ("[NET][G-List] cleared server list");
+
+item = _network_game_list;
+while (item != NULL) {
+ next = (NetworkGameList *) item -> _next;
+ free (item);
+ item = next;
+ }
+_network_game_list=NULL;
+_network_game_count=0;
+}
+
+char * NetworkGameListAdd() {
+NetworkGameList * item;
+NetworkGameList * before;
+
+DEBUG(misc,4) ("[NET][G-List] added server to list");
+
+item = _network_game_list;
+before = item;
+while (item != NULL) {
+ before = item;
+ item = (NetworkGameList *) item -> _next;
+ }
+item = malloc(sizeof(NetworkGameList));
+item -> _next = NULL;
+if (before == NULL) {
+ _network_game_list = item;
+ } else {
+ before -> _next = (char *) item;
+ }
+_network_game_count++;
+return (char *) item;
+}
+
+void NetworkGameListFromLAN() {
+ struct UDPPacket packet;
+ DEBUG(misc,2) ("[NET][G-List] searching server over lan");
+ NetworkGameListClear();
+ packet.command_check=packet.command_code=NET_UDPCMD_SERVERSEARCH;
+ packet.data_len=0;
+ NetworkUDPBroadCast(true,packet);
+}
+
+void NetworkGameListFromInternet() {
+ DEBUG(misc,2) ("[NET][G-List] searching servers over internet");
+ NetworkGameListClear();
+
+ // **TODO** masterserver communication [internet protocol list]
+
+}
+
+char * NetworkGameListItem(uint16 index) {
+NetworkGameList * item;
+NetworkGameList * next;
+uint16 cnt = 0;
+
+item = _network_game_list;
+
+while ((item != NULL) && (cnt != index)) {
+ next = (NetworkGameList *) item -> _next;
+ item = next;
+ cnt++;
+ }
+
+return (char *) item;
+}
+
+// *************************** //
+// * Network Game Extensions * //
+// *************************** //
+
+void NetworkGameFillDefaults() {
+ NetworkGameInfo * game = &_network_game;
+#if defined(WITH_REV)
+ extern char _openttd_revision[];
+#endif
+
+ DEBUG(misc,4) ("[NET][G-Info] setting defaults");
+
+ ttd_strlcpy(game->server_name,"OpenTTD Game",13);
+ game->game_password[0]='\0';
+ game->map_name[0]='\0';
+#if defined(WITH_REV)
+ ttd_strlcpy(game->server_revision,_openttd_revision,strlen(_openttd_revision));
+#else
+ ttd_strlcpy(game->server_revision,"norev000",strlen("norev000"));
+#endif
+ game->game_date=0;
+
+ game->map_height=0;
+ game->map_width=0;
+ game->map_set=0;
+
+ game->players_max=8;
+ game->players_on=0;
+
+ game->server_lang=_dynlang.curr;
+}
+
+void NetworkGameChangeDate(uint16 newdate) {
+ if (_networking_server) {
+ _network_game.game_date = newdate;
+ }
+}
+
#else // not ENABLE_NETWORK
// stubs
-void NetworkInitialize(const char *hostname) {}
+void NetworkInitialize() {}
void NetworkShutdown() {}
-void NetworkListen(int port) {}
+void NetworkListen() {}
void NetworkConnect(const char *hostname, int port) {}
void NetworkReceive() {}
void NetworkSend() {}
void NetworkSendCommand(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) {}
void NetworkProcessCommands() {}
void NetworkStartSync() {}
-void NetworkUDPListen(int port) {}
-void NetworkUDPReceive() {}
-bool NetworkUDPSearchServer() { return false; }
-#endif // ENABLE_NETWORK
+void NetworkCoreInit() { _network_available=false; };
+void NetworkCoreShutdown() {};
+void NetworkCoreDisconnect() {};
+void NetworkCoreLoop(bool incomming) {};
+bool NetworkCoreConnectGame(byte* b, unsigned short port) {};
+bool NetworkCoreStartGame() {};
+void NetworkLobbyShutdown() {};
+void NetworkLobbyInit() {};
+void NetworkGameListClear() {};
+char * NetworkGameListAdd() {return NULL;};
+void NetworkGameListFromLAN() {};
+void NetworkGameListFromInternet() {};
+void NetworkGameFillDefaults() {};
+char * NetworkGameListItem(uint16 index) {return NULL;};
+void NetworkGameChangeDate(uint16 newdate) {};
+}
+
+#endif
diff --git a/network_gui.c b/network_gui.c
index 008067e4d..75f65d89b 100644
--- a/network_gui.c
+++ b/network_gui.c
@@ -21,16 +21,6 @@ void ShowQueryString(StringID str, StringID caption, int maxlen, int maxwidth, b
static byte _selected_field;
char *direct_ip = NULL;
-
-void ConnectToServer(byte* b)
-{
- _networking = true;
-
- NetworkInitialize(b);
- DEBUG(misc, 1) ("Connecting to %s %d\n", b, _network_port);
- NetworkConnect(b, _network_port);
-}
-
static const StringID _connection_types_dropdown[] = {
STR_NETWORK_LAN,
STR_NETWORK_INTERNET,
@@ -65,7 +55,15 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
case 0: // close X
case 15: // cancel button
DeleteWindowById(WC_NETWORK_WINDOW, 0);
+ NetworkLobbyShutdown();
break;
+ case 3: // find server automaticaly
+ {
+ byte *b = "auto";
+ NetworkCoreConnectGame(b,_network_server_port);
+ }
+ break;
+
case 4: // connect via direct ip
{
StringID str;
@@ -111,7 +109,7 @@ static void NetworkGameWindowWndProc(Window *w, WindowEvent *e)
byte *b = e->edittext.str;
if (*b == 0)
return;
- ConnectToServer(b);
+ NetworkCoreConnectGame(b,_network_server_port);
} break;
}
@@ -159,6 +157,8 @@ void ShowNetworkGameWindow()
{
Window *w;
DeleteWindowById(WC_NETWORK_WINDOW, 0);
+
+ NetworkLobbyInit();
w = AllocateWindowDesc(&_network_game_window_desc);
strcpy(_edit_str_buf, "Your name");
@@ -168,24 +168,9 @@ void ShowNetworkGameWindow()
WP(w,querystr_d).maxlen = MAX_QUERYSTR_LEN;
WP(w,querystr_d).maxwidth = 240;
WP(w,querystr_d).buf = _edit_str_buf;
-
-
- ShowErrorMessage(-1, TEMP_STRING_NO_NETWORK, 0, 0);
-}
-
-
-void StartServer()
-{
- _networking = true;
- NetworkInitialize(NULL);
- DEBUG(misc, 1) ("Listening on port %d\n", _network_port);
- NetworkListen(_network_port);
- _networking_server = true;
- DoCommandP(0, 0, 0, NULL, CMD_START_NEW_GAME);
+ // ShowErrorMessage(-1, TEMP_STRING_NO_NETWORK, 0, 0);
}
-
-
static const StringID _players_dropdown[] = {
STR_NETWORK_2_PLAYERS,
STR_NETWORK_3_PLAYERS,
@@ -232,8 +217,9 @@ static void NetworkStartServerWindowWndProc(Window *w, WindowEvent *e)
ShowDropDownMenu(w, _players_dropdown, _opt_mod_ptr->currency, e->click.widget, 0);
return;
case 9: // start game
- StartServer();
+ NetworkCoreStartGame();
ShowNetworkLobbyWindow();
+ DoCommandP(0, 0, 0, NULL, CMD_START_NEW_GAME);
break;
}
@@ -308,10 +294,6 @@ static void ShowNetworkStartServerWindow()
WP(w,querystr_d).buf = _edit_str_buf;
}
-
-
-
-
static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
{
switch(e->event) {
diff --git a/settings.c b/settings.c
index 134153672..56fee932c 100644
--- a/settings.c
+++ b/settings.c
@@ -760,7 +760,8 @@ static const SettingDesc misc_settings[] = {
};
static const SettingDesc network_settings[] = {
- {"port", SDT_UINT | SDT_NOSAVE, (void*)3979, &_network_port},
+ {"port", SDT_UINT | SDT_NOSAVE, (void*)3978, &_network_client_port},
+ {"server_port", SDT_UINT | SDT_NOSAVE, (void*)3979, &_network_server_port},
{"sync_freq", SDT_UINT | SDT_NOSAVE, (void*)4, &_network_sync_freq},
{"ahead_frames", SDT_UINT | SDT_NOSAVE, (void*)5, &_network_ahead_frames},
{NULL}
diff --git a/ttd.c b/ttd.c
index 1ea0ef015..531fe40bf 100644
--- a/ttd.c
+++ b/ttd.c
@@ -484,6 +484,7 @@ int ttd_main(int argc, char* argv[])
uint startdate = -1;
_ignore_wrong_grf = false;
musicdriver[0] = sounddriver[0] = videodriver[0] = 0;
+ _networking_override=false;
_game_mode = GM_MENU;
_switch_mode = SM_MENU;
@@ -496,6 +497,7 @@ int ttd_main(int argc, char* argv[])
case 'v': ttd_strlcpy(videodriver, mgo.opt, sizeof(videodriver)); break;
case 'n': {
network = 1;
+ _networking_override=true;
if (mgo.opt) {
network_conn = mgo.opt;
network++;
@@ -551,14 +553,17 @@ int ttd_main(int argc, char* argv[])
if (resolution[0]) { _cur_resolution[0] = resolution[0]; _cur_resolution[1] = resolution[1]; }
if (startdate != -1) _patches.starting_date = startdate;
+ // initialize network-core
+ NetworkCoreInit();
+
// enumerate language files
InitializeLanguagePacks();
// initialize screenshot formats
InitializeScreenshotFormats();
- // initialize airport state machines
- InitializeAirports();
+ // initialize airport state machines
+ InitializeAirports();
// Sample catalogue
DEBUG(misc, 1) ("Loading sound effects...");
@@ -583,25 +588,21 @@ int ttd_main(int argc, char* argv[])
if (_opt_mod_ptr->diff_level == 9)
SetDifficultyLevel(0, _opt_mod_ptr);
- if (network) {
- _networking = true;
-
- NetworkInitialize(network_conn);
- if (network==1) {
- DEBUG(misc, 1) ("Listening on port %d\n", _network_port);
- NetworkListen(_network_port);
- _networking_server = true;
- } else {
- DEBUG(misc, 1) ("Connecting to %s %d\n", network_conn, _network_port);
- NetworkConnect(network_conn, _network_port);
+ if ((network) && (_network_available)) {
+ NetworkLobbyInit();
+ if (network_conn!=NULL) {
+ NetworkCoreConnectGame(network_conn,_network_server_port);
+ } else {
+ NetworkCoreConnectGame("auto",_network_server_port);
+ }
}
- }
while (_video_driver->main_loop() == ML_SWITCHDRIVER) {}
- if (network) {
- NetworkShutdown();
- }
+ if (_network_available) {
+ // shutdown network-core
+ NetworkCoreShutdown();
+ }
_video_driver->stop();
_music_driver->stop();
@@ -609,8 +610,8 @@ int ttd_main(int argc, char* argv[])
SaveToConfig();
- // uninitialize airport state machines
- UnInitializeAirports();
+ // uninitialize airport state machines
+ UnInitializeAirports();
return 0;
}
@@ -774,14 +775,14 @@ static void SwitchMode(int new_mode)
break;
case SM_NEWGAME:
- if (_networking) { NetworkStartSync(); } // UGLY HACK HACK HACK
+ if (_networking) { NetworkStartSync(true); } // UGLY HACK HACK HACK
MakeNewGame();
break;
normal_load:
case SM_LOAD: { // Load game
- if (_networking) { NetworkStartSync(); } // UGLY HACK HACK HACK
+ if (_networking) { NetworkStartSync(true); } // UGLY HACK HACK HACK
_error_message = INVALID_STRING_ID;
if (!SafeSaveOrLoad(_file_to_saveload.name, _file_to_saveload.mode, GM_NORMAL)) {
@@ -820,6 +821,10 @@ normal_load:
case SM_MENU: // Switch to game menu
+
+ if ((_networking) && (!_networking_override)) NetworkCoreDisconnect();
+ _networking_override=false;
+
LoadIntroGame();
break;
@@ -951,10 +956,8 @@ void GameLoop()
_timer_counter+=8;
CursorTick();
- if (_networking) {
- NetworkReceive();
- NetworkProcessCommands(); // to check if we got any new commands belonging to the current frame before we increase it.
- }
+ // incomming packets
+ NetworkCoreLoop(true);
if (_networking_sync) {
// make sure client's time is synched to the server by running frames quickly up to where the server is.
@@ -983,8 +986,8 @@ void GameLoop()
MouseLoop();
// send outgoing packets.
- if (_networking)
- NetworkSend();
+ NetworkCoreLoop(false);
+
if (_game_mode != GM_MENU)
MusicLoop();
diff --git a/variables.h b/variables.h
index e2a353ac4..21e60e71d 100644
--- a/variables.h
+++ b/variables.h
@@ -218,14 +218,16 @@ VARDEF int32 _frame_counter_max; // for networking, this is the frame that we ar
VARDEF int32 _frame_counter_srv; // for networking, this is the last known framecounter of the server. it is always less than frame_counter_max.
// networking settings
-VARDEF uint _network_port;
+VARDEF bool _network_available; // is network mode available?
+VARDEF uint32 _network_ip_list[10]; // Network IPs
+VARDEF uint16 _network_game_count;
+
+VARDEF uint _network_client_port;
+VARDEF uint _network_server_port;
+
VARDEF uint _network_sync_freq;
VARDEF uint _network_ahead_frames;
-VARDEF uint32 _network_ip_list[10]; // Network IPs
-VARDEF char * _network_detected_serverip; // UDP Broadcast detected Server
-VARDEF uint32 _network_detected_serverport; // UDP Broadcast detected server-port
-
VARDEF uint32 _sync_seed_1, _sync_seed_2;
VARDEF bool _is_ai_player; // current player is an AI player? - Can be removed if new AI is done
@@ -283,6 +285,8 @@ VARDEF SmallFiosItem _file_to_saveload;
VARDEF byte _make_screenshot;
VARDEF bool _networking;
+VARDEF bool _networking_override; // dont shutdown network core when the GameMenu appears.
+
VARDEF bool _networking_sync; // if we use network mode and the games must stay in sync.
VARDEF bool _networking_server;
VARDEF bool _networking_queuing; // queueing only?