From 196e6eb675db59f6806673b9785f989d61ad4e30 Mon Sep 17 00:00:00 2001 From: IntelOrca Date: Thu, 12 Feb 2015 11:30:57 +0000 Subject: [PATCH] get basic network game working --- projects/openrct2.vcxproj.user | 16 ++-- src/cmdline.c | 16 +++- src/game.c | 30 +++++++ src/network/network.c | 153 +++++++++++++++++++++++++++++++-- src/network/network.h | 30 ++++++- src/openrct2.c | 21 +++-- 6 files changed, 245 insertions(+), 21 deletions(-) diff --git a/projects/openrct2.vcxproj.user b/projects/openrct2.vcxproj.user index 093ce205e6..6e0ad43592 100644 --- a/projects/openrct2.vcxproj.user +++ b/projects/openrct2.vcxproj.user @@ -1,21 +1,23 @@  + + false + + + $(TargetDir)\openrct2.exe + WindowsLocalDebugger + $(TargetDir) + $(TargetDir) WindowsLocalDebugger $(TargetDir)\openrct2.exe - - + "C:\Program Files (x86)\Infogrames\RollerCoaster Tycoon 2\Scenarios\Crazy Castle.SC6" --port 5552 --server 127.0.0.1 $(TargetDir) WindowsLocalDebugger $(TargetDir)\openrct2.exe - - - - - false $(TargetDir)\openrct2.exe diff --git a/src/cmdline.c b/src/cmdline.c index c964e26e20..b15160ffb4 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -23,6 +23,7 @@ #include "addresses.h" #include "cmdline.h" #include "interface/screenshot.h" +#include "network/network.h" #include "openrct2.h" #include "platform/platform.h" #include "util/util.h" @@ -64,13 +65,16 @@ static const char *const usage[] = { int cmdline_run(const char **argv, int argc) { // - int version = 0, verbose = 0, width = 0, height = 0; + int version = 0, verbose = 0, width = 0, height = 0, port = 0; + char *server = NULL; argparse_option_t options[] = { OPT_HELP(), OPT_BOOLEAN('v', "version", &version, "show version information and exit"), OPT_BOOLEAN(0, "verbose", &verbose, "log verbose messages"), OPT_INTEGER('m', "mode", &sprite_mode, "the type of sprite conversion. 0 = default, 1 = simple closest pixel match, 2 = dithering"), + OPT_STRING(0, "server", &server, "server to connect to"), + OPT_INTEGER(0, "port", &port, "port"), OPT_END() }; @@ -88,6 +92,16 @@ int cmdline_run(const char **argv, int argc) if (verbose) _log_levels[DIAGNOSTIC_LEVEL_VERBOSE] = 1; + if (port != 0) { + gNetworkStart = NETWORK_SERVER; + gNetworkStartPort = port; + } + + if (server != NULL) { + gNetworkStart = NETWORK_CLIENT; + strncpy(gNetworkStartHost, server, sizeof(gNetworkStartHost)); + } + if (argc != 0) { gExitCode = cmdline_call_action(argv, argc); if (gExitCode != 0) diff --git a/src/game.c b/src/game.c index a5eab478be..ec55efbb4d 100644 --- a/src/game.c +++ b/src/game.c @@ -34,6 +34,7 @@ #include "management/marketing.h" #include "management/news_item.h" #include "management/research.h" +#include "network/network.h" #include "object.h" #include "openrct2.h" #include "peep/peep.h" @@ -389,6 +390,35 @@ int game_do_command_p(int command, int *eax, int *ebx, int *ecx, int *edx, int * int cost, flags, insufficientFunds; int original_ebx, original_edx, original_esi, original_edi, original_ebp; + int sendPacket = 0; + if (gNetworkStatus == NETWORK_CLIENT) { + if (command & (1 << 31)) { + command &= ~(1 << 31); + } else { + sendPacket = 1; + } + } else if (gNetworkStatus == NETWORK_SERVER) { + sendPacket = 1; + } + + if (sendPacket) { + network_packet packet; + packet.size = 8 * 4; + uint32 *args = (uint32*)&packet.data; + args[0] = command; + args[1] = *eax; + args[2] = *ebx; + args[3] = *ecx; + args[4] = *edx; + args[5] = *esi; + args[6] = *edi; + args[7] = *ebp; + network_send_packet(&packet); + + if (gNetworkStatus == NETWORK_CLIENT) + return MONEY32_UNDEFINED; + } + *esi = command; original_ebx = *ebx; original_edx = *edx; diff --git a/src/network/network.c b/src/network/network.c index 8ecbc3310b..683d5ba03b 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -20,14 +20,24 @@ #ifndef DISABLE_NETWORK +#include "../game.h" #include "network.h" #pragma comment(lib, "Ws2_32.lib") +int gNetworkStart = NETWORK_NONE; +char gNetworkStartHost[128]; +int gNetworkStartPort = NETWORK_DEFAULT_PORT; +int gNetworkStatus = NETWORK_NONE; + static int _wsaInitialised = 0; static WSADATA _wsaData; +static SOCKET _serverSocket; static SOCKET _clientSocket; +static int network_get_next_packet(network_packet *outPacket); +static void network_process_packet(network_packet *packet); + int network_init() { if (!_wsaInitialised) { @@ -44,15 +54,63 @@ int network_init() void network_close() { + if (!_wsaInitialised) + return; + + if (gNetworkStatus == NETWORK_CLIENT) + network_end_client(); + else if (gNetworkStatus == NETWORK_SERVER) + network_end_server(); + log_verbose("Closing WSA"); WSACleanup(); _wsaInitialised = 0; } +int network_begin_client(const char *host, int port) +{ + SOCKADDR_IN serverAddress; + u_long iMode; + + if (!network_init()) + return 0; + + _serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (_serverSocket == INVALID_SOCKET) { + log_error("Unable to create socket."); + return 0; + } + + serverAddress.sin_family = AF_INET; + serverAddress.sin_addr.S_un.S_addr = inet_addr(host); + serverAddress.sin_port = htons(port); + + if (connect(_serverSocket, (SOCKADDR*)&serverAddress, sizeof(SOCKADDR_IN)) != 0) { + log_error("Unable to connect to host."); + return 0; + } + + iMode = 1; + if (ioctlsocket(_serverSocket, FIONBIO, &iMode) != NO_ERROR) { + closesocket(_serverSocket); + log_error("Failed to set non-blocking mode."); + } + + gNetworkStatus = NETWORK_CLIENT; + return 1; +} + +void network_end_client() +{ + gNetworkStatus = NETWORK_NONE; + closesocket(_serverSocket); +} + int network_begin_server(int port) { SOCKET listeningSocket; SOCKADDR_IN localAddress; + u_long iMode; if (!network_init()) return 0; @@ -65,7 +123,7 @@ int network_begin_server(int port) } localAddress.sin_family = AF_INET; - localAddress.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); + localAddress.sin_addr.S_un.S_addr = INADDR_ANY; localAddress.sin_port = htons(port); if (bind(listeningSocket, (SOCKADDR*)&localAddress, sizeof(SOCKADDR_IN)) != 0) { @@ -89,23 +147,106 @@ int network_begin_server(int port) } closesocket(listeningSocket); - printf("Connected to client!"); + + iMode = 1; + if (ioctlsocket(_clientSocket, FIONBIO, &iMode) != NO_ERROR) { + closesocket(_clientSocket); + log_error("Failed to set non-blocking mode."); + } + + printf("Connected to client!\n"); + gNetworkStatus = NETWORK_SERVER; return 1; } void network_end_server() { + gNetworkStatus = NETWORK_NONE; closesocket(_clientSocket); } -int network_send_data(uint8 *data, int length) +void network_update() { - return send(_clientSocket, data, length, 0); + SOCKET socket; + int packetStatus; + network_packet packet; + + if (gNetworkStatus == NETWORK_NONE) + return; + + socket = gNetworkStatus == NETWORK_CLIENT ? _serverSocket : _clientSocket; + + do { + packetStatus = network_get_next_packet(&packet); + if (packetStatus == NETWORK_DISCONNECTED) { + network_print_error(); + if (gNetworkStatus == NETWORK_CLIENT) { + network_end_client(); + printf("Server disconnected...\n"); + return; + } else if (gNetworkStatus == NETWORK_SERVER) { + network_end_server(); + printf("client disconnected...\n"); + return; + } + } else if (packetStatus == NETWORK_SUCCESS) { + network_process_packet(&packet); + } + } while (packetStatus == NETWORK_SUCCESS); } -int network_receive_data(uint8 *data, int maxLength) +static int network_get_next_packet(network_packet *outPacket) { - return recv(_clientSocket, data, maxLength, 0); + SOCKET socket; + int readBytes; + + socket = gNetworkStatus == NETWORK_CLIENT ? _serverSocket : _clientSocket; + + readBytes = recv(socket, (char*)&outPacket->size, sizeof(outPacket->size), 0); + if (readBytes == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) + return NETWORK_DISCONNECTED; + + if (readBytes != sizeof(outPacket->size)) + return NETWORK_NO_DATA; + + readBytes = recv(socket, (char*)&outPacket->data, outPacket->size, 0); + if (readBytes != outPacket->size) + return NETWORK_NO_DATA; + + return NETWORK_SUCCESS; +} + +static void network_process_packet(network_packet *packet) +{ + uint32 *args; + int command; + + args = (uint32*)&packet->data; + command = args[0]; + + if (gNetworkStatus == NETWORK_CLIENT) + command |= (1 << 31); + + game_do_command_p(command, &args[1], &args[2], &args[3], &args[4], &args[5], &args[6], &args[7]); +} + +void network_send_packet(network_packet *packet) +{ + SOCKET socket; + + if (gNetworkStatus == NETWORK_NONE) + return; + + socket = gNetworkStatus == NETWORK_CLIENT ? _serverSocket : _clientSocket; + send(socket, (char*)packet, 2 + packet->size, 0); +} + +void network_print_error() +{ + wchar_t *s = NULL; + FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, WSAGetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&s, 0, NULL); + fprintf(stderr, "%S\n", s); + LocalFree(s); } #endif /* DISABLE_NETWORK */ \ No newline at end of file diff --git a/src/network/network.h b/src/network/network.h index e0d6d25583..e9e1b5c6ff 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -27,15 +27,41 @@ #include "../common.h" +typedef struct { + uint16 size; + uint8 data[128]; +} network_packet; + #define NETWORK_DEFAULT_PORT 11753 +enum { + NETWORK_NONE, + NETWORK_CLIENT, + NETWORK_SERVER +}; + +enum { + NETWORK_SUCCESS, + NETWORK_NO_DATA, + NETWORK_DISCONNECTED +}; + +extern int gNetworkStart; +extern char gNetworkStartHost[128]; +extern int gNetworkStartPort; +extern int gNetworkStatus; + int network_init(); void network_close(); +int network_begin_client(const char *host, int port); +void network_end_client(); int network_begin_server(int port); void network_end_server(); -int network_send_data(uint8 *data, int length); -int network_receive_data(uint8 *data, int maxLength); +void network_update(); +void network_send_packet(network_packet *packet); + +void network_print_error(); #endif /* DISABLE_NETWORK */ diff --git a/src/openrct2.c b/src/openrct2.c index 1a83f95a91..29bcbb28e8 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -30,6 +30,7 @@ #include "interface/viewport.h" #include "localisation/localisation.h" #include "network/http.h" +#include "network/network.h" #include "openrct2.h" #include "platform/platform.h" #include "ride/ride.h" @@ -168,10 +169,10 @@ bool openrct2_initialise() config_save_default(); // TODO add configuration option to allow multiple instances - if (!gOpenRCT2Headless && !platform_lock_single_instance()) { - log_fatal("OpenRCT2 is already running."); - return false; - } + // if (!gOpenRCT2Headless && !platform_lock_single_instance()) { + // log_fatal("OpenRCT2 is already running."); + // return false; + // } get_system_info(); if (!gOpenRCT2Headless) { @@ -248,7 +249,14 @@ void openrct2_launch() editor_load_landscape(gOpenRCT2StartupActionPath); } break; - } + } + + if (gNetworkStart == NETWORK_CLIENT) { + network_begin_client(gNetworkStartHost, gNetworkStartPort); + } else if (gNetworkStart == NETWORK_SERVER) { + network_begin_server(gNetworkStartPort); + } + openrct2_loop(); } openrct2_dispose(); @@ -259,6 +267,7 @@ void openrct2_launch() void openrct2_dispose() { + network_close(); http_dispose(); language_close_all(); platform_free(); @@ -344,6 +353,7 @@ static void openrct2_loop() } platform_process_messages(); + network_update(); rct2_draw(); platform_draw(); fps++; @@ -373,6 +383,7 @@ static void openrct2_loop() lastTick = currentTick; platform_process_messages(); + network_update(); rct2_update();