1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

get basic network game working

This commit is contained in:
IntelOrca
2015-02-12 11:30:57 +00:00
committed by zsilencer
parent 7e23d2d013
commit 196e6eb675
6 changed files with 245 additions and 21 deletions

View File

@@ -1,21 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ShowAllFiles>false</ShowAllFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
<LocalDebuggerCommandArguments>"C:\Program Files (x86)\Infogrames\RollerCoaster Tycoon 2\Scenarios\Crazy Castle.SC6" --port 5552 --server 127.0.0.1</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release with Tests|Win32'">
<LocalDebuggerWorkingDirectory>$(TargetDir)</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>
<LocalDebuggerCommandArguments>
</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup>
<ShowAllFiles>false</ShowAllFiles>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommand>$(TargetDir)\openrct2.exe</LocalDebuggerCommand>

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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 */

View File

@@ -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();