mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-23 15:52:55 +01:00
allow host to specify password #2072
This commit is contained in:
@@ -3904,6 +3904,8 @@ STR_5562 :WARNING!
|
||||
STR_5563 :This feature is currently unstable, take extra caution.
|
||||
STR_5564 :Insert Corrupt Element
|
||||
STR_5565 :{SMALLFONT}{BLACK}Inserts a corrupt map element at top of tile. This will hide any element above the corrupt element.
|
||||
STR_5566 :Password:
|
||||
STR_5567 :Advertise
|
||||
|
||||
#####################
|
||||
# Rides/attractions #
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
<ClCompile Include="..\src\windows\network_status.c" />
|
||||
<ClCompile Include="..\src\windows\player_list.c" />
|
||||
<ClCompile Include="..\src\windows\server_list.c" />
|
||||
<ClCompile Include="..\src\windows\server_start.c" />
|
||||
<ClCompile Include="..\src\windows\title_command_editor.c" />
|
||||
<ClCompile Include="..\src\windows\title_editor.c" />
|
||||
<ClCompile Include="..\src\windows\maze_construction.c" />
|
||||
|
||||
@@ -546,6 +546,9 @@
|
||||
<ClCompile Include="..\src\platform\linux.c">
|
||||
<Filter>Source\Platform</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\windows\server_start.c">
|
||||
<Filter>Source\Windows</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\management\award.h">
|
||||
|
||||
@@ -239,7 +239,8 @@ 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, NETWORK_DEFAULT_PORT, NULL },
|
||||
{ offsetof(network_configuration, stay_connected), "stay_connected", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL },
|
||||
{ offsetof(network_configuration, stay_connected), "stay_connected", CONFIG_VALUE_TYPE_BOOLEAN, true, NULL },
|
||||
{ offsetof(network_configuration, advertise), "advertise", CONFIG_VALUE_TYPE_BOOLEAN, false, NULL },
|
||||
};
|
||||
|
||||
config_section_definition _sectionDefinitions[] = {
|
||||
|
||||
@@ -214,6 +214,7 @@ typedef struct {
|
||||
utf8string player_name;
|
||||
uint32 default_port;
|
||||
uint8 stay_connected;
|
||||
uint8 advertise;
|
||||
} network_configuration;
|
||||
|
||||
typedef struct theme_window {
|
||||
|
||||
@@ -450,6 +450,7 @@ enum {
|
||||
WC_PLAYER_LIST = 125,
|
||||
WC_NETWORK_STATUS = 126,
|
||||
WC_SERVER_LIST = 127,
|
||||
WC_SERVER_START = 128,
|
||||
|
||||
// Only used for colour schemes
|
||||
WC_STAFF = 220,
|
||||
@@ -629,6 +630,7 @@ void window_player_list_open();
|
||||
void window_network_status_open(const char* text);
|
||||
void window_network_status_close();
|
||||
void window_server_list_open();
|
||||
void window_server_start_open();
|
||||
|
||||
void window_research_open();
|
||||
void window_research_development_page_paint(rct_window *w, rct_drawpixelinfo *dpi, int baseWidgetIndex);
|
||||
|
||||
@@ -2154,6 +2154,9 @@ enum {
|
||||
STR_INSERT_CORRUPT = 5564,
|
||||
STR_INSERT_CORRUPT_TIP = 5565,
|
||||
|
||||
STR_PASSWORD = 5566,
|
||||
STR_ADVERTISE = 5567,
|
||||
|
||||
// Have to include resource strings (from scenarios and objects) for the time being now that language is partially working
|
||||
STR_COUNT = 32768
|
||||
};
|
||||
|
||||
@@ -67,7 +67,8 @@ enum {
|
||||
NETWORK_COMMAND_PING,
|
||||
NETWORK_COMMAND_PINGLIST,
|
||||
NETWORK_COMMAND_SETDISCONNECTMSG,
|
||||
NETWORK_COMMAND_MAX
|
||||
NETWORK_COMMAND_MAX,
|
||||
NETWORK_COMMAND_INVALID = -1
|
||||
};
|
||||
|
||||
const char *NetworkCommandNames[] = {
|
||||
@@ -104,6 +105,15 @@ uint8* NetworkPacket::GetData()
|
||||
return &(*data)[0];
|
||||
}
|
||||
|
||||
uint32 NetworkPacket::GetCommand()
|
||||
{
|
||||
if (data->size() >= sizeof(uint32)) {
|
||||
return ByteSwapBE(*(uint32*)(&(*data)[0]));
|
||||
} else {
|
||||
return NETWORK_COMMAND_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkPacket::Write(uint8* bytes, unsigned int size)
|
||||
{
|
||||
data->insert(data->end(), bytes, bytes + size);
|
||||
@@ -147,6 +157,18 @@ void NetworkPacket::Clear()
|
||||
data->clear();
|
||||
}
|
||||
|
||||
bool NetworkPacket::CommandRequiresAuth()
|
||||
{
|
||||
switch (GetCommand()) {
|
||||
case NETWORK_COMMAND_PING:
|
||||
return false;
|
||||
case NETWORK_COMMAND_AUTH:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkPlayer::NetworkPlayer(const char* name)
|
||||
{
|
||||
safe_strncpy((char*)NetworkPlayer::name, name, sizeof(NetworkPlayer::name));
|
||||
@@ -234,7 +256,7 @@ bool NetworkConnection::SendPacket(NetworkPacket& packet)
|
||||
|
||||
void NetworkConnection::QueuePacket(std::unique_ptr<NetworkPacket> packet)
|
||||
{
|
||||
if (authstatus == NETWORK_AUTH_OK || authstatus == NETWORK_AUTH_REQUESTED) {
|
||||
if (authstatus == NETWORK_AUTH_OK || !packet->CommandRequiresAuth()) {
|
||||
packet->size = (uint16)packet->data->size();
|
||||
outboundpackets.push_back(std::move(packet));
|
||||
}
|
||||
@@ -573,7 +595,7 @@ void Network::UpdateClient()
|
||||
bool connectfailed = false;
|
||||
switch(status){
|
||||
case NETWORK_STATUS_RESOLVING:{
|
||||
if(server_address.GetResolveStatus() == NetworkAddress::RESOLVE_OK){
|
||||
if (server_address.GetResolveStatus() == NetworkAddress::RESOLVE_OK) {
|
||||
server_connection.socket = socket(server_address.ss->ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (server_connection.socket == INVALID_SOCKET) {
|
||||
log_error("Unable to create socket.");
|
||||
@@ -606,8 +628,7 @@ void Network::UpdateClient()
|
||||
int error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
int result = getsockopt(server_connection.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
|
||||
if (result != 0)
|
||||
{
|
||||
if (result != 0) {
|
||||
log_error("getsockopt failed with error %d", LAST_SOCKET_ERROR());
|
||||
break;
|
||||
}
|
||||
@@ -631,8 +652,7 @@ void Network::UpdateClient()
|
||||
error = 0;
|
||||
socklen_t len = sizeof(error);
|
||||
result = getsockopt(server_connection.socket, SOL_SOCKET, SO_ERROR, (char*)&error, &len);
|
||||
if (result != 0)
|
||||
{
|
||||
if (result != 0) {
|
||||
log_error("getsockopt failed with error %d", LAST_SOCKET_ERROR());
|
||||
break;
|
||||
}
|
||||
@@ -728,6 +748,26 @@ bool Network::CheckSRAND(uint32 tick, uint32 srand0)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Network::KickPlayer(int playerId)
|
||||
{
|
||||
NetworkPlayer *player = GetPlayerByID(playerId);
|
||||
for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) {
|
||||
if ((*it)->player->id == playerId) {
|
||||
// Disconnect the client gracefully
|
||||
(*it)->last_disconnect_reason = "Kicked";
|
||||
Server_Send_SETDISCONNECTMSG(*(*it), "Get out of the server!");
|
||||
shutdown((*it)->socket, SHUT_RD);
|
||||
(*it)->SendQueuedPackets();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Network::SetPassword(const char* password)
|
||||
{
|
||||
safe_strncpy(Network::password, password, sizeof(Network::password));
|
||||
}
|
||||
|
||||
void Network::Client_Send_AUTH(const char* gameversion, const char* name, const char* password)
|
||||
{
|
||||
std::unique_ptr<NetworkPacket> packet = std::move(NetworkPacket::Allocate());
|
||||
@@ -846,7 +886,6 @@ void Network::Server_Send_SETDISCONNECTMSG(NetworkConnection& connection, const
|
||||
|
||||
bool Network::ProcessConnection(NetworkConnection& connection)
|
||||
{
|
||||
connection.SendQueuedPackets();
|
||||
int packetStatus;
|
||||
do {
|
||||
packetStatus = connection.ReadPacket();
|
||||
@@ -871,12 +910,11 @@ bool Network::ProcessConnection(NetworkConnection& connection)
|
||||
break;
|
||||
}
|
||||
} while (packetStatus == NETWORK_READPACKET_MORE_DATA || packetStatus == NETWORK_READPACKET_SUCCESS);
|
||||
#if !DEBUG
|
||||
connection.SendQueuedPackets();
|
||||
if (!connection.ReceivedPacketRecently()) {
|
||||
connection.last_disconnect_reason = "No Data";
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -991,6 +1029,20 @@ void Network::PrintError()
|
||||
int Network::Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet)
|
||||
{
|
||||
packet >> (uint32&)connection.authstatus >> (uint8&)player_id;
|
||||
switch(connection.authstatus) {
|
||||
case NETWORK_AUTH_BADNAME:
|
||||
connection.last_disconnect_reason = "Bad Player Name";
|
||||
shutdown(connection.socket, SHUT_RDWR);
|
||||
break;
|
||||
case NETWORK_AUTH_BADVERSION:
|
||||
connection.last_disconnect_reason = "Incorrect Software Version";
|
||||
shutdown(connection.socket, SHUT_RDWR);
|
||||
break;
|
||||
case NETWORK_AUTH_BADPASSWORD:
|
||||
connection.last_disconnect_reason = "Bad Password";
|
||||
shutdown(connection.socket, SHUT_RDWR);
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1028,6 +1080,10 @@ int Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& pa
|
||||
std::unique_ptr<NetworkPacket> responsepacket = std::move(NetworkPacket::Allocate());
|
||||
*responsepacket << (uint32)NETWORK_COMMAND_AUTH << (uint32)connection.authstatus << (uint8)playerid;
|
||||
connection.QueuePacket(std::move(responsepacket));
|
||||
if (connection.authstatus != NETWORK_AUTH_OK) {
|
||||
shutdown(connection.socket, SHUT_RD);
|
||||
connection.SendQueuedPackets();
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -1300,25 +1356,16 @@ void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32
|
||||
}
|
||||
}
|
||||
|
||||
void Network::KickPlayer(int playerId)
|
||||
{
|
||||
NetworkPlayer *player = GetPlayerByID(playerId);
|
||||
for(auto it = client_connection_list.begin(); it != client_connection_list.end(); it++) {
|
||||
if ((*it)->player->id == playerId) {
|
||||
// Disconnect the client gracefully
|
||||
(*it)->last_disconnect_reason = "Kicked";
|
||||
Server_Send_SETDISCONNECTMSG(*(*it), "Get out of the server!");
|
||||
shutdown((*it)->socket, SHUT_RD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void network_kick_player(int playerId)
|
||||
{
|
||||
gNetwork.KickPlayer(playerId);
|
||||
}
|
||||
|
||||
void network_set_password(const char* password)
|
||||
{
|
||||
gNetwork.SetPassword(password);
|
||||
}
|
||||
|
||||
#else
|
||||
int network_get_mode() { return NETWORK_MODE_NONE; }
|
||||
int network_get_status() { return NETWORK_STATUS_NONE; }
|
||||
@@ -1335,6 +1382,7 @@ int network_get_player_ping(unsigned int index) { return 0; }
|
||||
int network_get_player_id(unsigned int index) { return 0; }
|
||||
void network_send_chat(const char* text) {}
|
||||
void network_close() {}
|
||||
void network_kick_player(int playerId) { }
|
||||
void network_kick_player(int playerId) {}
|
||||
void network_set_password(const char* password) {}
|
||||
uint8 network_get_current_player_id() { return 0; }
|
||||
#endif /* DISABLE_NETWORK */
|
||||
|
||||
@@ -69,6 +69,9 @@ extern "C" {
|
||||
#ifndef SHUT_RD
|
||||
#define SHUT_RD SD_RECEIVE
|
||||
#endif
|
||||
#ifndef SHUT_RDWR
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#endif
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
@@ -109,6 +112,7 @@ public:
|
||||
static std::unique_ptr<NetworkPacket> Allocate();
|
||||
static std::unique_ptr<NetworkPacket> Duplicate(NetworkPacket& packet);
|
||||
uint8* GetData();
|
||||
uint32 GetCommand();
|
||||
template <typename T>
|
||||
NetworkPacket& operator<<(T value) { T swapped = ByteSwapBE(value); uint8* bytes = (uint8*)&swapped; data->insert(data->end(), bytes, bytes + sizeof(value)); return *this; }
|
||||
void Write(uint8* bytes, unsigned int size);
|
||||
@@ -118,6 +122,7 @@ public:
|
||||
const uint8* Read(unsigned int size);
|
||||
const char* ReadString();
|
||||
void Clear();
|
||||
bool CommandRequiresAuth();
|
||||
|
||||
uint16 size;
|
||||
std::shared_ptr<std::vector<uint8>> data;
|
||||
@@ -209,6 +214,7 @@ public:
|
||||
void SendPacketToClients(NetworkPacket& packet);
|
||||
bool CheckSRAND(uint32 tick, uint32 srand0);
|
||||
void KickPlayer(int playerId);
|
||||
void SetPassword(const char* password);
|
||||
|
||||
void Client_Send_AUTH(const char* gameversion, const char* name, const char* password);
|
||||
void Server_Send_MAP(NetworkConnection* connection = nullptr);
|
||||
@@ -314,6 +320,7 @@ void network_send_chat(const char* text);
|
||||
void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback);
|
||||
|
||||
void network_kick_player(int playerId);
|
||||
void network_set_password(const char* password);
|
||||
|
||||
void network_print_error();
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ static void window_server_list_mouseup(rct_window *w, int widgetIndex)
|
||||
break;
|
||||
case WIDX_START_SERVER:
|
||||
server_list_update_player_name();
|
||||
window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME | LOADSAVETYPE_NETWORK, NULL);
|
||||
window_server_start_open();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
190
src/windows/server_start.c
Normal file
190
src/windows/server_start.c
Normal file
@@ -0,0 +1,190 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014 Ted John
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* This file is part of OpenRCT2.
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "../config.h"
|
||||
#include "../interface/themes.h"
|
||||
#include "../interface/widget.h"
|
||||
#include "../interface/window.h"
|
||||
#include "../localisation/localisation.h"
|
||||
#include "../network/network.h"
|
||||
#include "../sprites.h"
|
||||
#include "../util/util.h"
|
||||
#include "error.h"
|
||||
|
||||
char _password[33];
|
||||
|
||||
enum {
|
||||
WIDX_BACKGROUND,
|
||||
WIDX_TITLE,
|
||||
WIDX_CLOSE,
|
||||
WIDX_PASSWORD_INPUT,
|
||||
WIDX_ADVERTISE_CHECKBOX,
|
||||
WIDX_START_SERVER
|
||||
};
|
||||
|
||||
#define WW 300
|
||||
#define WH 100
|
||||
|
||||
static rct_widget window_server_start_widgets[] = {
|
||||
{ WWT_FRAME, 0, 0, WW-1, 0, WH-1, 0xFFFFFFFF, STR_NONE }, // panel / background
|
||||
{ WWT_CAPTION, 0, 1, WW-2, 1, 14, STR_START_SERVER, STR_WINDOW_TITLE_TIP }, // title bar
|
||||
{ WWT_CLOSEBOX, 0, WW-13, WW-3, 2, 13, STR_CLOSE_X, STR_CLOSE_WINDOW_TIP }, // close x button
|
||||
{ WWT_TEXT_BOX, 1, 150, WW-8, 20, 32, (uint32)_password, STR_NONE }, // password text box
|
||||
{ WWT_CHECKBOX, 1, 6, WW-8, 36, 45, STR_ADVERTISE, STR_NONE }, // advertise checkbox
|
||||
{ WWT_DROPDOWN_BUTTON, 1, 6, 106, WH-6-11, WH-6, STR_START_SERVER, STR_NONE }, // start server button
|
||||
{ WIDGETS_END },
|
||||
};
|
||||
|
||||
static void window_server_start_close(rct_window *w);
|
||||
static void window_server_start_mouseup(rct_window *w, int widgetIndex);
|
||||
static void window_server_start_update(rct_window *w);
|
||||
static void window_server_start_textinput(rct_window *w, int widgetIndex, char *text);
|
||||
static void window_server_start_invalidate(rct_window *w);
|
||||
static void window_server_start_paint(rct_window *w, rct_drawpixelinfo *dpi);
|
||||
|
||||
static rct_window_event_list window_server_start_events = {
|
||||
window_server_start_close,
|
||||
window_server_start_mouseup,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
window_server_start_update,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
window_server_start_textinput,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
window_server_start_invalidate,
|
||||
window_server_start_paint,
|
||||
NULL
|
||||
};
|
||||
|
||||
void window_server_start_open()
|
||||
{
|
||||
rct_window* window;
|
||||
|
||||
// Check if window is already open
|
||||
window = window_bring_to_front_by_class(WC_SERVER_START);
|
||||
if (window != NULL)
|
||||
return;
|
||||
|
||||
window = window_create_centred(WW, WH, &window_server_start_events, WC_SERVER_START, WF_10);
|
||||
|
||||
window->widgets = window_server_start_widgets;
|
||||
window->enabled_widgets = (
|
||||
(1 << WIDX_CLOSE) |
|
||||
(1 << WIDX_PASSWORD_INPUT) |
|
||||
(1 << WIDX_ADVERTISE_CHECKBOX) |
|
||||
(1 << WIDX_START_SERVER)
|
||||
);
|
||||
window_init_scroll_widgets(window);
|
||||
window->no_list_items = 0;
|
||||
window->selected_list_item = -1;
|
||||
window->frame_no = 0;
|
||||
window->min_width = window->width;
|
||||
window->min_height = window->height;
|
||||
window->max_width = window->min_width;
|
||||
window->max_height = window->min_height;
|
||||
|
||||
window->page = 0;
|
||||
window->list_information_type = 0;
|
||||
window->colours[0] = 1;
|
||||
window->colours[1] = 26;
|
||||
window->colours[2] = 26;
|
||||
}
|
||||
|
||||
static void window_server_start_close(rct_window *w)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void window_server_start_mouseup(rct_window *w, int widgetIndex)
|
||||
{
|
||||
switch (widgetIndex) {
|
||||
case WIDX_CLOSE:
|
||||
window_close(w);
|
||||
break;
|
||||
case WIDX_PASSWORD_INPUT:
|
||||
window_start_textbox(w, widgetIndex, 1170, (uint32)_password, 32);
|
||||
break;
|
||||
case WIDX_ADVERTISE_CHECKBOX:
|
||||
gConfigNetwork.advertise = !gConfigNetwork.advertise;
|
||||
config_save_default();
|
||||
window_invalidate(w);
|
||||
break;
|
||||
case WIDX_START_SERVER:
|
||||
network_set_password(_password);
|
||||
window_loadsave_open(LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME | LOADSAVETYPE_NETWORK, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void window_server_start_update(rct_window *w)
|
||||
{
|
||||
if (gCurrentTextBox.window.classification == w->classification && gCurrentTextBox.window.number == w->number) {
|
||||
window_update_textbox_caret();
|
||||
widget_invalidate(w, WIDX_PASSWORD_INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
static void window_server_start_textinput(rct_window *w, int widgetIndex, char *text)
|
||||
{
|
||||
if (text == NULL) return;
|
||||
|
||||
switch (widgetIndex) {
|
||||
case WIDX_PASSWORD_INPUT:
|
||||
if (strcmp(_password, text) == 0)
|
||||
return;
|
||||
|
||||
memset(_password, 0, sizeof(_password));
|
||||
if (strlen(text) > 0) {
|
||||
safe_strncpy(_password, text, sizeof(_password));
|
||||
}
|
||||
|
||||
widget_invalidate(w, WIDX_PASSWORD_INPUT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void window_server_start_invalidate(rct_window *w)
|
||||
{
|
||||
widget_set_checkbox_value(w, WIDX_ADVERTISE_CHECKBOX, gConfigNetwork.advertise);
|
||||
}
|
||||
|
||||
static void window_server_start_paint(rct_window *w, rct_drawpixelinfo *dpi)
|
||||
{
|
||||
window_draw_widgets(w, dpi);
|
||||
|
||||
gfx_draw_string_left(dpi, STR_PASSWORD, NULL, w->colours[1], w->x + 6, w->y + w->widgets[WIDX_PASSWORD_INPUT].top);
|
||||
}
|
||||
Reference in New Issue
Block a user