(svn r106) New network core (by sign_de)
authordominik
Sun, 22 Aug 2004 10:23:37 +0000
changeset 105 44e894da0fef
parent 104 ba246e85459f
child 106 51354fbb3e8a
(svn r106) New network core (by sign_de)

Features:
* network core is dynamicly loaded when needed (-n isn't needed anymore)
for easy switching between single and multiplayer. But commandline
shortcuts are still enabled:
-n = autodetect network server
-n [ip] = connect to the server
* udp now uses 2 different ports
- you can run 1 server and serveral clients on one pc
- the clients udp-socket gets unloaded when the
network game starts
- the servers udp-sockets remains online to allow the
network gui to detect itself
* new gameinfo structure
this struct is available for every online/lan game
* dynamic NetworkGameList
functions.h
intro_gui.c
lang/english.txt
misc.c
network.c
network_gui.c
settings.c
ttd.c
variables.h
--- a/functions.h	Sun Aug 22 00:53:39 2004 +0000
+++ b/functions.h	Sun Aug 22 10:23:37 2004 +0000
@@ -121,19 +121,36 @@
 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();
--- a/intro_gui.c	Sun Aug 22 00:53:39 2004 +0000
+++ b/intro_gui.c	Sun Aug 22 10:23:37 2004 +0000
@@ -58,7 +58,9 @@
 				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 @@
 	_random_seed_1 = p1;
 	_random_seed_2 = p2;
 
-	if (_networking) { NetworkStartSync(); }
+	if (_networking) { NetworkStartSync(true); }
 
 	MakeNewGame();
 	return 0;
@@ -159,7 +161,7 @@
 	_random_seed_1 = p1;
 	_random_seed_2 = p2;
 
-	if (_networking) { NetworkStartSync(); }
+	if (_networking) { NetworkStartSync(true); }
 
 	StartScenario();
 	return 0;
--- a/lang/english.txt	Sun Aug 22 00:53:39 2004 +0000
+++ b/lang/english.txt	Sun Aug 22 10:23:37 2004 +0000
@@ -1213,6 +1213,9 @@
 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
 
--- a/misc.c	Sun Aug 22 00:53:39 2004 +0000
+++ b/misc.c	Sun Aug 22 10:23:37 2004 +0000
@@ -542,6 +542,8 @@
 	/* yeah, increse day counter and call various daily loops */
 	_date++;
 
+	NetworkGameChangeDate(_date);
+
 	_vehicle_id_ctr_day = 0;
 
 	DisasterDailyLoop();
--- a/network.c	Sun Aug 22 00:53:39 2004 +0000
+++ b/network.c	Sun Aug 22 10:23:37 2004 +0000
@@ -1,5 +1,6 @@
 #include "stdafx.h"
 #include "ttd.h"
+#include "gui.h"
 #include "command.h"
 #include "player.h"
 
@@ -180,9 +181,10 @@
 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 @@
 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 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 @@
 
 		// 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 @@
 {
 	Packet *p, *next;
 
-	printf("CloseClient\n");
+	DEBUG(misc,1) ("[NET][TCP] closed client connection");
 
 	assert(cs->socket != INVALID_SOCKET);
 
@@ -523,6 +567,8 @@
 	}
 	cs->socket = INVALID_SOCKET;
 
+	if (_networking_server) _network_game.players_on--;
+
 	_num_clients--;
 }
 
@@ -683,6 +729,8 @@
 	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 @@
 
 }
 
+// ************************** //
+// * 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 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 @@
 	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);
+ 		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_SERVERACTIVE:
-			if (!_networking_server) {
-				_network_detected_serverip=inet_ntoa(*(struct in_addr *) &client_addr.sin_addr);
-				_network_detected_serverport=ntohs(client_addr.sin_port);
-			}
-			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
--- a/network_gui.c	Sun Aug 22 00:53:39 2004 +0000
+++ b/network_gui.c	Sun Aug 22 10:23:37 2004 +0000
@@ -21,16 +21,6 @@
 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 @@
 		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 @@
 		byte *b = e->edittext.str;
 		if (*b == 0)
 			return;
-		ConnectToServer(b);
+		NetworkCoreConnectGame(b,_network_server_port);
 	} break;
 
 	}
@@ -159,6 +157,8 @@
 {
 	Window *w;
 	DeleteWindowById(WC_NETWORK_WINDOW, 0);
+
+	NetworkLobbyInit();
 	
 	w = AllocateWindowDesc(&_network_game_window_desc);
 	strcpy(_edit_str_buf, "Your name");
@@ -168,24 +168,9 @@
 	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);
+	// 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);
-}
-
-
-
 static const StringID _players_dropdown[] = {
 	STR_NETWORK_2_PLAYERS,
 	STR_NETWORK_3_PLAYERS,
@@ -232,8 +217,9 @@
 			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 @@
 	WP(w,querystr_d).buf = _edit_str_buf;
 }
 
-
-
-
-
 static void NetworkLobbyWindowWndProc(Window *w, WindowEvent *e)
 {
 	switch(e->event) {
--- a/settings.c	Sun Aug 22 00:53:39 2004 +0000
+++ b/settings.c	Sun Aug 22 10:23:37 2004 +0000
@@ -760,7 +760,8 @@
 };
 
 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}
--- a/ttd.c	Sun Aug 22 00:53:39 2004 +0000
+++ b/ttd.c	Sun Aug 22 10:23:37 2004 +0000
@@ -484,6 +484,7 @@
 	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 @@
 		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 @@
 	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 @@
 	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 @@
 
 	SaveToConfig();
 
-  // uninitialize airport state machines
-  UnInitializeAirports();
+	// uninitialize airport state machines
+	UnInitializeAirports();
 
 	return 0;
 }
@@ -774,14 +775,14 @@
 		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 @@
 
 
 	case SM_MENU: // Switch to game menu
+		
+		if ((_networking) && (!_networking_override)) NetworkCoreDisconnect();
+		_networking_override=false;
+
 		LoadIntroGame();
 		break;
 
@@ -951,10 +956,8 @@
 	_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 @@
 	MouseLoop();
 
 	// send outgoing packets.
-	if (_networking)
-		NetworkSend();
+	NetworkCoreLoop(false);
+
 
 	if (_game_mode != GM_MENU)
 		MusicLoop();
--- a/variables.h	Sun Aug 22 00:53:39 2004 +0000
+++ b/variables.h	Sun Aug 22 10:23:37 2004 +0000
@@ -218,14 +218,16 @@
 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 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?