mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-20 22:33:02 +01:00
allow joining of servers in server list window
This commit is contained in:
@@ -3843,3 +3843,4 @@ STR_5501 :Start Server
|
||||
STR_5502 :Multiplayer
|
||||
STR_5503 :Enter hostname or IP address:
|
||||
STR_5504 :{SMALLFONT}{BLACK}Show multiplayer status
|
||||
STR_5505 :Unable to connect to server.
|
||||
|
||||
@@ -20,12 +20,13 @@
|
||||
|
||||
#include "addresses.h"
|
||||
#include "config.h"
|
||||
#include "interface/themes.h"
|
||||
#include "interface/title_sequences.h"
|
||||
#include "localisation/language.h"
|
||||
#include "localisation/localisation.h"
|
||||
#include "util/util.h"
|
||||
#include "interface/themes.h"
|
||||
#include "network/network.h"
|
||||
#include "openrct2.h"
|
||||
#include "interface/title_sequences.h"
|
||||
#include "util/util.h"
|
||||
|
||||
// Magic number for original game cfg file
|
||||
static const int MagicNumber = 0x0003113A;
|
||||
@@ -232,7 +233,7 @@ config_property_definition _twitchDefinitions[] = {
|
||||
|
||||
config_property_definition _networkDefinitions[] = {
|
||||
{ offsetof(network_configuration, player_name), "player_name", CONFIG_VALUE_TYPE_STRING, {.value_string = "Player" }, NULL },
|
||||
{ offsetof(network_configuration, default_port), "default_port", CONFIG_VALUE_TYPE_UINT32, true, NULL },
|
||||
{ offsetof(network_configuration, default_port), "default_port", CONFIG_VALUE_TYPE_UINT32, NETWORK_DEFAULT_PORT, NULL },
|
||||
};
|
||||
|
||||
config_section_definition _sectionDefinitions[] = {
|
||||
|
||||
@@ -1268,6 +1268,8 @@ static void ttf_process_initial_colour(int colour, text_draw_info *info)
|
||||
|
||||
static void ttf_draw_string(rct_drawpixelinfo *dpi, char *text, int colour, int x, int y)
|
||||
{
|
||||
if (text == NULL) return;
|
||||
|
||||
text_draw_info info;
|
||||
info.font_sprite_base = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_SPRITE_BASE, uint16);
|
||||
info.flags = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_FONT_FLAGS, uint16);
|
||||
|
||||
@@ -472,6 +472,7 @@ typedef enum {
|
||||
BTM_TB_DIRTY_FLAG_PARK_RATING = (1 << 4)
|
||||
} BTM_TOOLBAR_DIRTY_FLAGS;
|
||||
|
||||
// 000N_TTTL
|
||||
enum {
|
||||
LOADSAVETYPE_LOAD = 0 << 0,
|
||||
LOADSAVETYPE_SAVE = 1 << 0,
|
||||
@@ -479,7 +480,9 @@ enum {
|
||||
LOADSAVETYPE_GAME = 0 << 1,
|
||||
LOADSAVETYPE_LANDSCAPE = 1 << 1,
|
||||
LOADSAVETYPE_SCENARIO = 2 << 1,
|
||||
LOADSAVETYPE_TRACK = 3 << 1
|
||||
LOADSAVETYPE_TRACK = 3 << 1,
|
||||
|
||||
LOADSAVETYPE_NETWORK = 1 << 4,
|
||||
};
|
||||
|
||||
extern bool gLoadSaveTitleSequenceSave;
|
||||
|
||||
@@ -2044,6 +2044,7 @@ enum {
|
||||
STR_ENTER_HOSTNAME_OR_IP_ADDRESS = 5503,
|
||||
|
||||
STR_SHOW_MULTIPLAYER_STATUS_TIP = 5504,
|
||||
STR_UNABLE_TO_CONNECT_TO_SERVER = 5505,
|
||||
|
||||
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
|
||||
STR_COUNT = 32768
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "network.h"
|
||||
extern "C" {
|
||||
#include "../addresses.h"
|
||||
#include "../config.h"
|
||||
#include "../game.h"
|
||||
#include "../interface/chat.h"
|
||||
#include "../interface/window.h"
|
||||
@@ -301,7 +302,7 @@ bool Network::BeginClient(const char* host, unsigned short port)
|
||||
server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (server_socket == INVALID_SOCKET) {
|
||||
log_error("Unable to create socket.");
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
SOCKADDR_IN server_address;
|
||||
@@ -326,7 +327,7 @@ bool Network::BeginClient(const char* host, unsigned short port)
|
||||
|
||||
mode = NETWORK_MODE_CLIENT;
|
||||
|
||||
Client_Send_AUTH(OPENRCT2_VERSION, "Player", "");
|
||||
Client_Send_AUTH(OPENRCT2_VERSION, gConfigNetwork.player_name, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ rct_window *window_loadsave_open(int type, char *defaultName)
|
||||
}
|
||||
|
||||
_loadsaveType = type;
|
||||
switch (type) {
|
||||
switch (type & 0x0F) {
|
||||
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME):
|
||||
w->widgets[WIDX_TITLE].image = STR_LOAD_GAME;
|
||||
break;
|
||||
@@ -186,8 +186,8 @@ rct_window *window_loadsave_open(int type, char *defaultName)
|
||||
w->no_list_items = 0;
|
||||
w->selected_list_item = -1;
|
||||
|
||||
includeNewItem = (type & 1) == LOADSAVETYPE_SAVE;
|
||||
switch (type & 6) {
|
||||
includeNewItem = (type & 0x01) == LOADSAVETYPE_SAVE;
|
||||
switch (type & 0x0E) {
|
||||
case LOADSAVETYPE_GAME:
|
||||
platform_get_user_directory(path, "save");
|
||||
if (!platform_ensure_directory_exists(path)) {
|
||||
@@ -383,7 +383,7 @@ static void window_loadsave_scrollmousedown(rct_window *w, int scrollIndex, int
|
||||
} else {
|
||||
// TYPE_FILE
|
||||
// Load or overwrite
|
||||
if ((_loadsaveType & 1) == LOADSAVETYPE_SAVE)
|
||||
if ((_loadsaveType & 0x01) == LOADSAVETYPE_SAVE)
|
||||
window_overwrite_prompt_open(_listItems[selectedItem].name, _listItems[selectedItem].path);
|
||||
else
|
||||
window_loadsave_select(w, _listItems[selectedItem].path);
|
||||
@@ -730,103 +730,103 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co
|
||||
static void window_loadsave_select(rct_window *w, const char *path)
|
||||
{
|
||||
SDL_RWops* rw;
|
||||
switch (_loadsaveType) {
|
||||
switch (_loadsaveType & 0x0E) {
|
||||
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) :
|
||||
if (gLoadSaveTitleSequenceSave) {
|
||||
utf8 newName[MAX_PATH];
|
||||
char *extension = (char*)path_get_extension(path_get_filename(path));
|
||||
strcpy(newName, path_get_filename(path));
|
||||
if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0)
|
||||
strcat(newName, ".sv6");
|
||||
if (title_sequence_save_exists(gCurrentTitleSequence, newName)) {
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&_listItems[w->selected_list_item].name;
|
||||
window_text_input_open(w, WIDX_SCROLL, 5435, 5404, 1170, (uint32)_listItems[w->selected_list_item].name, TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1);
|
||||
}
|
||||
else {
|
||||
title_sequence_add_save(gCurrentTitleSequence, path, newName);
|
||||
window_close(w);
|
||||
}
|
||||
}
|
||||
else if (game_load_save(path)) {
|
||||
window_close(w);
|
||||
gfx_invalidate_screen();
|
||||
rct2_endupdate();
|
||||
if (gLoadSaveTitleSequenceSave) {
|
||||
utf8 newName[MAX_PATH];
|
||||
char *extension = (char*)path_get_extension(path_get_filename(path));
|
||||
strcpy(newName, path_get_filename(path));
|
||||
if (_stricmp(extension, ".sv6") != 0 && _stricmp(extension, ".sc6") != 0)
|
||||
strcat(newName, ".sv6");
|
||||
if (title_sequence_save_exists(gCurrentTitleSequence, newName)) {
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_COMMON_FORMAT_ARGS + 0, uint32) = (uint32)&_listItems[w->selected_list_item].name;
|
||||
window_text_input_open(w, WIDX_SCROLL, 5435, 5404, 1170, (uint32)_listItems[w->selected_list_item].name, TITLE_SEQUENCE_MAX_SAVE_LENGTH - 1);
|
||||
}
|
||||
else {
|
||||
// 1050, not the best message...
|
||||
window_error_open(STR_LOAD_GAME, 1050);
|
||||
title_sequence_add_save(gCurrentTitleSequence, path, newName);
|
||||
window_close(w);
|
||||
}
|
||||
break;
|
||||
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
|
||||
rw = platform_sdl_rwfromfile(path, "wb+");
|
||||
if (rw != NULL) {
|
||||
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 1 : 0);
|
||||
SDL_RWclose(rw);
|
||||
if (success) {
|
||||
window_close_by_class(WC_LOADSAVE);
|
||||
game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0);
|
||||
gfx_invalidate_screen();
|
||||
} else {
|
||||
window_error_open(STR_SAVE_GAME, 1047);
|
||||
}
|
||||
}
|
||||
else if (game_load_save(path)) {
|
||||
window_close(w);
|
||||
gfx_invalidate_screen();
|
||||
rct2_endupdate();
|
||||
}
|
||||
else {
|
||||
// 1050, not the best message...
|
||||
window_error_open(STR_LOAD_GAME, 1050);
|
||||
}
|
||||
break;
|
||||
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
|
||||
rw = platform_sdl_rwfromfile(path, "wb+");
|
||||
if (rw != NULL) {
|
||||
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 1 : 0);
|
||||
SDL_RWclose(rw);
|
||||
if (success) {
|
||||
window_close_by_class(WC_LOADSAVE);
|
||||
game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0);
|
||||
gfx_invalidate_screen();
|
||||
} else {
|
||||
window_error_open(STR_SAVE_GAME, 1047);
|
||||
}
|
||||
break;
|
||||
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
|
||||
editor_load_landscape(path);
|
||||
if (1) {
|
||||
} else {
|
||||
window_error_open(STR_SAVE_GAME, 1047);
|
||||
}
|
||||
break;
|
||||
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_LANDSCAPE) :
|
||||
editor_load_landscape(path);
|
||||
if (1) {
|
||||
gfx_invalidate_screen();
|
||||
rct2_endupdate();
|
||||
}
|
||||
else {
|
||||
// 1050, not the best message...
|
||||
window_error_open(STR_LOAD_LANDSCAPE, 1050);
|
||||
}
|
||||
break;
|
||||
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
|
||||
rw = platform_sdl_rwfromfile(path, "wb+");
|
||||
if (rw != NULL) {
|
||||
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
|
||||
SDL_RWclose(rw);
|
||||
if (success) {
|
||||
window_close_by_class(WC_LOADSAVE);
|
||||
gfx_invalidate_screen();
|
||||
rct2_endupdate();
|
||||
}
|
||||
else {
|
||||
// 1050, not the best message...
|
||||
window_error_open(STR_LOAD_LANDSCAPE, 1050);
|
||||
}
|
||||
break;
|
||||
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
|
||||
rw = platform_sdl_rwfromfile(path, "wb+");
|
||||
if (rw != NULL) {
|
||||
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
|
||||
SDL_RWclose(rw);
|
||||
if (success) {
|
||||
window_close_by_class(WC_LOADSAVE);
|
||||
gfx_invalidate_screen();
|
||||
} else {
|
||||
window_error_open(STR_SAVE_LANDSCAPE, 1049);
|
||||
}
|
||||
} else {
|
||||
window_error_open(STR_SAVE_LANDSCAPE, 1049);
|
||||
}
|
||||
break;
|
||||
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) :
|
||||
{
|
||||
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
|
||||
int parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32);
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18;
|
||||
s6Info->var_000 = 255;
|
||||
rw = platform_sdl_rwfromfile(path, "wb+");
|
||||
int success = 0;
|
||||
if (rw != NULL) {
|
||||
success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup;
|
||||
|
||||
if (success) {
|
||||
window_close_by_class(WC_LOADSAVE);
|
||||
title_load();
|
||||
} else {
|
||||
window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED);
|
||||
s6Info->var_000 = 4;
|
||||
}
|
||||
} else {
|
||||
window_error_open(STR_SAVE_LANDSCAPE, 1049);
|
||||
}
|
||||
break;
|
||||
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) :
|
||||
window_install_track_open(path);
|
||||
window_close_by_class(WC_LOADSAVE);
|
||||
break;
|
||||
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_SCENARIO) :
|
||||
{
|
||||
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
|
||||
int parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32);
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18;
|
||||
s6Info->var_000 = 255;
|
||||
rw = platform_sdl_rwfromfile(path, "wb+");
|
||||
int success = 0;
|
||||
if (rw != NULL) {
|
||||
success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup;
|
||||
|
||||
if (success) {
|
||||
window_close_by_class(WC_LOADSAVE);
|
||||
title_load();
|
||||
} else {
|
||||
window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED);
|
||||
s6Info->var_000 = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_TRACK) :
|
||||
window_install_track_open(path);
|
||||
window_close_by_class(WC_LOADSAVE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region Overwrite prompt
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "../localisation/localisation.h"
|
||||
#include "../network/network.h"
|
||||
#include "../sprites.h"
|
||||
#include "error.h"
|
||||
|
||||
#define WWIDTH_MIN 500
|
||||
#define WHEIGHT_MIN 300
|
||||
@@ -79,8 +80,6 @@ static void window_server_list_invalidate(rct_window *w);
|
||||
static void window_server_list_paint(rct_window *w, rct_drawpixelinfo *dpi);
|
||||
static void window_server_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int scrollIndex);
|
||||
|
||||
static void server_list_get_item_button(int buttonIndex, int x, int y, int width, int *outX, int *outY);
|
||||
|
||||
static rct_window_event_list window_server_list_events = {
|
||||
window_server_list_close,
|
||||
window_server_list_mouseup,
|
||||
@@ -114,10 +113,15 @@ static rct_window_event_list window_server_list_events = {
|
||||
|
||||
static int _hoverButtonIndex = -1;
|
||||
|
||||
static void server_list_get_item_button(int buttonIndex, int x, int y, int width, int *outX, int *outY);
|
||||
static void server_list_update_player_name(rct_window *w);
|
||||
static void server_list_load_saved_servers();
|
||||
static void server_list_save_saved_servers();
|
||||
static void dispose_saved_server_list();
|
||||
static void dispose_saved_server(saved_server *serverInfo);
|
||||
static void add_saved_server(char *address);
|
||||
static void remove_saved_server(int index);
|
||||
static void join_server(char *address, bool spectate);
|
||||
|
||||
void window_server_list_open()
|
||||
{
|
||||
@@ -162,11 +166,7 @@ void window_server_list_open()
|
||||
|
||||
static void window_server_list_close(rct_window *w)
|
||||
{
|
||||
if (strlen(_playerName) > 0) {
|
||||
SafeFree(gConfigNetwork.player_name);
|
||||
gConfigNetwork.player_name = _strdup(_playerName);
|
||||
config_save_default();
|
||||
}
|
||||
server_list_update_player_name(w);
|
||||
dispose_saved_server_list();
|
||||
}
|
||||
|
||||
@@ -182,6 +182,9 @@ static void window_server_list_mouseup(rct_window *w, int widgetIndex)
|
||||
case WIDX_ADD_SERVER:
|
||||
window_text_input_open(w, widgetIndex, STR_ADD_SERVER, STR_ENTER_HOSTNAME_OR_IP_ADDRESS, STR_NONE, 0, 128);
|
||||
break;
|
||||
case WIDX_START_SERVER:
|
||||
window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME | LOADSAVETYPE_NETWORK, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,15 +209,23 @@ static void window_server_list_scroll_getsize(rct_window *w, int scrollIndex, in
|
||||
|
||||
static void window_server_list_scroll_mousedown(rct_window *w, int scrollIndex, int x, int y)
|
||||
{
|
||||
if (w->selected_list_item == -1) return;
|
||||
int serverIndex = w->selected_list_item;
|
||||
if (serverIndex < 0) return;
|
||||
if (serverIndex >= _numSavedServers) return;
|
||||
|
||||
char *serverAddress = _savedServers[serverIndex].address;
|
||||
|
||||
switch (_hoverButtonIndex) {
|
||||
case WIDX_LIST_REMOVE:
|
||||
remove_saved_server(serverIndex);
|
||||
w->no_list_items = _numSavedServers;
|
||||
window_invalidate(w);
|
||||
break;
|
||||
case WIDX_LIST_SPECTATE:
|
||||
join_server(serverAddress, true);
|
||||
break;
|
||||
default:
|
||||
// Join
|
||||
join_server(serverAddress, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -251,20 +262,29 @@ static void window_server_list_scroll_mouseover(rct_window *w, int scrollIndex,
|
||||
|
||||
static void window_server_list_textinput(rct_window *w, int widgetIndex, char *text)
|
||||
{
|
||||
if (widgetIndex != WIDX_PLAYER_NAME_INPUT || text == NULL)
|
||||
return;
|
||||
if (text == NULL || text[0] == 0) return;
|
||||
|
||||
if (strcmp(_playerName, text) == 0)
|
||||
return;
|
||||
switch (widgetIndex) {
|
||||
case WIDX_PLAYER_NAME_INPUT:
|
||||
if (strcmp(_playerName, text) == 0)
|
||||
return;
|
||||
|
||||
if (strlen(text) == 0) {
|
||||
memset(_playerName, 0, sizeof(_playerName));
|
||||
} else {
|
||||
memset(_playerName, 0, sizeof(_playerName));
|
||||
strcpy(_playerName, text);
|
||||
if (strlen(text) == 0) {
|
||||
memset(_playerName, 0, sizeof(_playerName));
|
||||
} else {
|
||||
memset(_playerName, 0, sizeof(_playerName));
|
||||
strcpy(_playerName, text);
|
||||
}
|
||||
|
||||
widget_invalidate(w, WIDX_PLAYER_NAME_INPUT);
|
||||
break;
|
||||
|
||||
case WIDX_ADD_SERVER:
|
||||
add_saved_server(text);
|
||||
w->no_list_items = _numSavedServers;
|
||||
window_invalidate(w);
|
||||
break;
|
||||
}
|
||||
|
||||
widget_invalidate(w, WIDX_PLAYER_NAME_INPUT);
|
||||
}
|
||||
|
||||
static void window_server_list_invalidate(rct_window *w)
|
||||
@@ -348,6 +368,15 @@ static void server_list_get_item_button(int buttonIndex, int x, int y, int width
|
||||
*outY = y + 2;
|
||||
}
|
||||
|
||||
static void server_list_update_player_name(rct_window *w)
|
||||
{
|
||||
if (strlen(_playerName) > 0) {
|
||||
SafeFree(gConfigNetwork.player_name);
|
||||
gConfigNetwork.player_name = _strdup(_playerName);
|
||||
config_save_default();
|
||||
}
|
||||
}
|
||||
|
||||
static char *freadstralloc(FILE *file)
|
||||
{
|
||||
int capacity = 64;
|
||||
@@ -451,3 +480,56 @@ static void dispose_saved_server(saved_server *serverInfo)
|
||||
SafeFree(serverInfo->name);
|
||||
SafeFree(serverInfo->description);
|
||||
}
|
||||
|
||||
static void add_saved_server(char *address)
|
||||
{
|
||||
_numSavedServers++;
|
||||
if (_savedServers == NULL) {
|
||||
_savedServers = malloc(_numSavedServers * sizeof(saved_server));
|
||||
} else {
|
||||
_savedServers = realloc(_savedServers, _numSavedServers * sizeof(saved_server));
|
||||
}
|
||||
|
||||
int index = _numSavedServers - 1;
|
||||
_savedServers[index].address = _strdup(address);
|
||||
_savedServers[index].name = _strdup(address);
|
||||
_savedServers[index].description = NULL;
|
||||
}
|
||||
|
||||
static void remove_saved_server(int index)
|
||||
{
|
||||
if (_numSavedServers <= index) return;
|
||||
|
||||
int serversToMove = _numSavedServers - index - 1;
|
||||
memmove(&_savedServers[index], &_savedServers[index + 1], serversToMove * sizeof(saved_server));
|
||||
|
||||
_numSavedServers--;
|
||||
_savedServers = realloc(_savedServers, _numSavedServers * sizeof(saved_server));
|
||||
}
|
||||
|
||||
static char *substr(char *start, int length)
|
||||
{
|
||||
char *result = malloc(length + 1);
|
||||
memcpy(result, start, length);
|
||||
result[length] = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void join_server(char *address, bool spectate)
|
||||
{
|
||||
int port = gConfigNetwork.default_port;
|
||||
|
||||
char *colon = strchr(address, ':');
|
||||
if (colon != NULL) {
|
||||
address = substr(address, colon - address);
|
||||
sscanf(colon + 1, "%d", &port);
|
||||
}
|
||||
|
||||
if (!network_begin_client(address, port)) {
|
||||
window_error_open(STR_UNABLE_TO_CONNECT_TO_SERVER, STR_NONE);
|
||||
}
|
||||
|
||||
if (colon != NULL) {
|
||||
free(address);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user