/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program 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 .
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Commando *
* *
* $Archive:: /Commando/Code/Commando/ServerSettings.cpp $*
* *
* $Author:: Steve_t $*
* *
* $Modtime:: 8/09/02 2:12p $*
* *
* $Revision:: 17 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "ServerSettings.h"
#include "slavemaster.h"
#include "wwdebug.h"
#include "gamedata.h"
#include "gdcnc.h"
#include "ini.h"
#include "registry.h"
#include "rawfile.h"
#include "consolemode.h"
#include "specialbuilds.h"
#include "_globals.h"
#include "bandwidth.h"
#include "mpsettingsmgr.h"
#include "wwonline\wolserver.h"
#include "useroptions.h"
#include "gamespyadmin.h"
#include "servercontrol.h"
#include "gamesideservercontrol.h"
#include "autostart.h"
#include "GameSpy_QnR.h"
#include "bandwidthcheck.h"
const char *ConfigSettingsName = "Config";
const char *MasterServerSection = "Server";
const char *SlaveServerSection = "Slave";
#define ENCRYPTION_STRING_LENGTH 128
#define KEY_SLAVE_SERIAL "Serial"
char ServerSettingsClass::SettingsFile[MAX_PATH];
bool ServerSettingsClass::IsActive = false;
char ServerSettingsClass::MasterPassword[128];
ServerSettingsClass::GameModeTypeEnum ServerSettingsClass::GameMode = MODE_NONE;
unsigned long ServerSettingsClass::MasterBandwidth = 0;
char ServerSettingsClass::PreferredLoginServer[256];
int ServerSettingsClass::DiskLogSize = -1;
const char *ServerListTag = "Available Westwood Servers:";
const char *ServerListEnd = "; End generated section.";
/***********************************************************************************************
* ServerSettingsClass::Set_Settings_File_Name -- Set the name of the settings file *
* *
* *
* *
* INPUT: File name *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/1/2002 12:07PM ST : Created *
*=============================================================================================*/
void ServerSettingsClass::Set_Settings_File_Name(char *filename)
{
if (strlen(filename) < sizeof(SettingsFile)) {
strcpy(SettingsFile, filename);
IsActive = true;
}
}
/***********************************************************************************************
* ServerSettingsClass::Parse -- Pull the server info out of the settings file *
* *
* *
* *
* INPUT: True if we should apply the settings. False to parse for errors only. *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/1/2002 12:07PM ST : Created *
*=============================================================================================*/
bool ServerSettingsClass::Parse(bool apply)
{
char master_settings[MAX_PATH];
char slave_settings[MAX_PATH];
char slave_section[256];
char slave_nick[128];
char slave_serial[128];
char slave_pass[128];
int slave_port;
int slave_bw;
char master_nick[128];
char master_serial[128];
int master_port;
int master_bw;
char master_pass[128];
char remote_admin_pass[128];
char game_type[32];
char heartbeat_list[512];
bool wol = true;
char remote_admin_ip[128];
MasterPassword[0] = 0;
/*
** IsActive is set when the settigns file name is set.
*/
if (IsActive) {
WWASSERT(The_Game() || !apply);
if (apply) {
WWDEBUG_SAY(("Applying server settings\n"));
ConsoleBox.Print("Applying server settings\n");
}
/*
** Make sure the server config file is there. It should be since it's verified at command line parsing time.
*/
RawFileClass file(SettingsFile);
if (!file.Is_Available()) {
WWDEBUG_SAY(("Server startup file '%s' not found\n", SettingsFile));
ConsoleBox.Print("Error - server startup file '%s' not found - aborting\n", SettingsFile);
ConsoleBox.Wait_For_Keypress();
return(false);
}
/*
** Get the name of the master server settings file.
*/
INIClass ini(file);
ini.Get_String(MasterServerSection, ConfigSettingsName, "", master_settings, sizeof(master_settings));
if (strlen(master_settings) == 0) {
if (apply) {
WWDEBUG_SAY(("No master server settings specified - using defaults\n"));
ConsoleBox.Print("No master server settings specified - using defaults\n");
}
}
/*
** Load the master server settings from the ini file.
*/
/*
** Game Type.
*/
ini.Get_String(MasterServerSection, "GameType", "WOL", game_type, sizeof(game_type));
if (cGameSpyAdmin::Get_Is_Server_Gamespy_Listed()) {
strcpy(game_type, "GameSpy");
}
if (stricmp(game_type, "WOL") == 0) {
GameMode = MODE_WOL;
} else if (stricmp(game_type, "LAN") == 0) {
wol = false;
GameMode = MODE_LAN;
} else if (stricmp(game_type, "GameSpy") == 0) {
wol = false;
cGameSpyAdmin::Set_Is_Server_Gamespy_Listed(true);
GameSpyQnR.Enable_Reporting(true);
GameMode = MODE_GAMESPY;
} else {
WWDEBUG_SAY(("Bad game type specified in server.ini\n"));
ConsoleBox.Print("Error - Unknown game type in server settings. Use 'LAN', 'WOL', or 'GameSpy' - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
/*
** Parse the list of GameSpy Style Master servers from the HeartBeat List
*/
heartbeat_list[sizeof(heartbeat_list)-1] = 0;
ini.Get_String(MasterServerSection, "HeartBeatServers", GameSpyQnR.Get_Default_HeartBeat_List(), heartbeat_list, sizeof(heartbeat_list)-1);
if (!GameSpyQnR.Parse_HeartBeat_List(heartbeat_list)) {
GameSpyQnR.Parse_HeartBeat_List(GameSpyQnR.Get_Default_HeartBeat_List());
}
/*
** Make sure the master server settings file is there.
*/
char filename[MAX_PATH];
sprintf(filename, "data\\%s", master_settings);
file.Set_Name(filename);
if (!file.Is_Available()) {
WWDEBUG_SAY(("Server settings file '%s' not found\n", filename));
ConsoleBox.Print("Error - server settings file '%s' not found - aborting\n", filename);
ConsoleBox.Wait_For_Keypress();;
return(false);
} else {
if (!Check_Game_Settings_File(master_settings)) {
WWDEBUG_SAY(("Server settings file '%s' not usable\n", master_settings));
ConsoleBox.Print("Error - server settings file '%s' contains errors - aborting\n", master_settings);
ConsoleBox.Wait_For_Keypress();;
return(false);
}
if (apply && The_Game()) {
The_Game()->Set_Ini_Filename(master_settings);
}
}
/*
** Restart Flag
*/
RegistryClass restart_reg(APPLICATION_SUB_KEY_NAME_WOLSETTINGS);
if (restart_reg.Is_Valid ()) {
restart_reg.Set_Int(AutoRestartClass::REG_VALUE_AUTO_RESTART_FLAG, 1);
switch (GameMode) {
case MODE_WOL:
restart_reg.Set_Int(AutoRestartClass::REG_VALUE_AUTO_RESTART_TYPE, 1);
break;
case MODE_LAN:
case MODE_GAMESPY:
restart_reg.Set_Int(AutoRestartClass::REG_VALUE_AUTO_RESTART_TYPE, 0);
break;
}
}
/*
** Nickname.
*/
ini.Get_String(MasterServerSection, "Nickname", "", master_nick, sizeof(master_nick));
#ifdef FREEDEDICATEDSERVER
/*
** We only need to validate this for the FDS. The regular game can allow the login name to be specified in the registry.
*/
if (wol && strlen(master_nick) == 0) {
WWDEBUG_SAY(("Error - No login nickname specified for master server - aborting\n"));
ConsoleBox.Print("Error - No login nickname specified for master server - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
#endif //FREEDEDICATEDSERVER
/*
** Password.
*/
ini.Get_String(MasterServerSection, "Password", "", master_pass, sizeof(master_pass));
#ifdef FREEDEDICATEDSERVER
/*
** We only need to validate this for the FDS. The regular game can allow the login name to be specified in the registry.
*/
if (wol && strlen(master_pass) == 0) {
WWDEBUG_SAY(("Error - No login password specified for master server - aborting\n"));
ConsoleBox.Print("Error - No login password specified for master server - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
#endif //FREEDEDICATEDSERVER
/*
** Serial number.
*/
ini.Get_String(MasterServerSection, "Serial", "", master_serial, sizeof(master_serial));
#ifdef FREEDEDICATEDSERVER
/*
** We only need to validate the serial number if we are the FDS. For the regular game, the master serial will be stored
** in the registry.
*/
if (wol && strlen(master_serial) == 0) {
WWDEBUG_SAY(("Error - No serial number specified for master server - aborting\n"));
ConsoleBox.Print("Error - No serial number specified for master server - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
#endif //FREEDEDICATEDSERVER
/*
** Get the port number.
*/
master_port = ini.Get_Int(MasterServerSection, "Port", 0xffffffff);
if (wol && master_port != 0xffffffff && (master_port < 0 || master_port > 0xffff)) {
WWDEBUG_SAY(("Error - Invalid port number %d specified for master server - aborting\n", master_port));
ConsoleBox.Print("Error - Invalid port number %d specified for master server - aborting\n", master_port);
ConsoleBox.Wait_For_Keypress();
return(false);
}
/*
** Get the GameSpy Query port number.
*/
int gsqport = cUserOptions::GameSpyQueryPort.Get();
gsqport = ini.Get_Int(MasterServerSection, "GameSpyQueryPort", gsqport);
if (!gsqport) gsqport = cUserOptions::GameSpyQueryPort.Get();
if (gsqport < 0 || gsqport > 0xffff) {
WWDEBUG_SAY(("Error - Invalid port number %d specified for GameSpy Query Port - aborting\n", gsqport));
ConsoleBox.Print("Error - Invalid port number %d specified for GameSpy Query Port - aborting\n", gsqport);
ConsoleBox.Wait_For_Keypress();;
return(false);
}
cUserOptions::GameSpyQueryPort.Set(gsqport);
/*
** Get the GameSpy Game port number.
*/
int gsgport = cUserOptions::GameSpyGamePort.Get();
gsgport = ini.Get_Int(MasterServerSection, "GameSpyGamePort", gsgport);
if (!gsgport) gsgport = cUserOptions::GameSpyGamePort.Get();
if (gsgport < 0 || gsgport > 0xffff || gsgport == gsqport) {
WWDEBUG_SAY(("Error - Invalid port number %d specified for GameSpy Game Port - aborting\n", gsgport));
ConsoleBox.Print("Error - Invalid port number %d specified for GameSpy Game Port - aborting\n", gsgport);
ConsoleBox.Wait_For_Keypress();;
return(false);
}
cUserOptions::GameSpyGamePort.Set(gsgport);
/*
** Get the bandwidth allowance.
*/
master_bw = ini.Get_Int(MasterServerSection, "BandwidthUp", 0xffffffff);
if (master_bw != 0 && master_bw != 0xffffffff && master_bw < 33600) {
WWDEBUG_SAY(("Error - Insufficient bandwidth specified for master server - aborting\n"));
ConsoleBox.Print("Error - Insufficient bandwidth specified for master server - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
MasterBandwidth = master_bw;
/*
** Get the max size of the disk log in days.
*/
DiskLogSize = ini.Get_Int(MasterServerSection, "DiskLogSize", 7);
if (DiskLogSize > 365) {
WWDEBUG_SAY(("Error - Disk log size too large - aborting\n"));
ConsoleBox.Print("Error - Disk log size too large - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
/*
** Get the preferred login server. No preference means use default from ping profile.
*/
ini.Get_String(MasterServerSection, "LoginServer", "", PreferredLoginServer, sizeof(PreferredLoginServer));
/*
** Get the Network Update Rate override.
*/
int nur = ini.Get_Int(MasterServerSection, "NetUpdateRate", 8);
if (nur < 5 || nur > 30) {
WWDEBUG_SAY(("Error - Bad NetUpdateRate specified - aborting\n"));
ConsoleBox.Print("Error - NetUpdateRate must be between 5 and 30 - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
cUserOptions::NetUpdateRate.Set(nur);
/*
** Get the remote admin settings.
*/
bool allow_remote = ini.Get_Bool(MasterServerSection, "AllowRemoteAdmin", false);
RegistryClass reg_remote(APPLICATION_SUB_KEY_NAME_NET_SERVER_CONTROL);
if (allow_remote) {
ini.Get_String(MasterServerSection, "RemoteAdminPassword", "", remote_admin_pass, sizeof(remote_admin_pass));
int len = strlen(remote_admin_pass);
if (len == 0) {
ConsoleBox.Print("Error - Remote admin password must be specified - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
} else {
if (len > 31) {
ConsoleBox.Print("Error - Remote admin password too long - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
}
int admin_port = ini.Get_Int(MasterServerSection, "RemoteAdminPort", 0);
if (admin_port != 0 && (admin_port < 1024 || admin_port > 65535-8)) {
ConsoleBox.Print("Error - Remote admin port number out of range - aborting\n");
ConsoleBox.Wait_For_Keypress();;
return(false);
}
ServerControl.Allow_Remote_Admin(true);
/*
** Set the port number into the registry.
*/
if (admin_port == 0) {
admin_port = DEFAULT_SERVER_CONTROL_PORT;
}
reg_remote.Set_Int(SERVER_CONTROL_PORT_KEY, admin_port);
/*
** Set the password into the registry.
*/
reg_remote.Set_String(SERVER_CONTROL_PASSWORD_KEY, remote_admin_pass);
/*
** We need to bind to more than just the loopback address when listening for control messages.
*/
reg_remote.Set_Int(SERVER_CONTROL_LOOPBACK_KEY, 0);
/*
** There may be an IP override specified.
*/
ini.Get_String(MasterServerSection, "RemoteAdminIP", "0.0.0.0", remote_admin_ip, sizeof(remote_admin_ip));
unsigned long admin_ip_long = ntohl(inet_addr(remote_admin_ip));
reg_remote.Set_Int(SERVER_CONTROL_IP_KEY, admin_ip_long);
} else {
/*
** Only listen to control messages on the loopback address.
*/
reg_remote.Set_Int(SERVER_CONTROL_LOOPBACK_KEY, 1);
ServerControl.Allow_Remote_Admin(false);
}
/*
** Set the master settings into the registry.
*/
//if (apply) {
/*
** Serial number.
*/
if (wol) {
if (strlen(master_serial)) {
StringClass serial(master_serial, true);
StringClass encrypted_serial;
Encrypt_Serial(serial, encrypted_serial);
RegistryClass reg_base(APPLICATION_SUB_KEY_NAME);
if (reg_base.Is_Valid()) {
reg_base.Set_String(KEY_SLAVE_SERIAL, encrypted_serial.Peek_Buffer());
}
}
/*
** Nickname.
*/
if (strlen(master_nick)) {
RegistryClass reg_wol(APPLICATION_SUB_KEY_NAME_WOLSETTINGS);
if (reg_wol.Is_Valid()) {
reg_wol.Set_String("AutoLogin", master_nick);
reg_wol.Set_String("LastLogin", master_nick);
reg_wol.Set_Int("AutoLoginPrompt", 0);
MPSettingsMgrClass::Set_Auto_Login(master_nick);
}
}
/*
** Password.
*/
MPSettingsMgrClass::Set_Auto_Password(master_pass);
/*
** Port number.
*/
if (master_port != 0xffffffff) {
RegistryClass reg_fw(APPLICATION_SUB_KEY_NAME_NET_FIREWALL);
reg_fw.Set_Int("ForcePort", master_port);
}
}
/*
** Bandwidth.
*/
if (master_bw != 0xffffffff) {
RegistryClass reg_netopt(APPLICATION_SUB_KEY_NAME_NETOPTIONS);
if (reg_netopt.Is_Valid()) {
if (cGameSpyAdmin::Is_Gamespy_Game()) {
if (master_bw == 0) master_bw = 1000000;
cUserOptions::Set_Bandwidth_Bps(master_bw);
} else {
if (wol) {
reg_netopt.Set_Int("BandwidthType", BANDWIDTH_AUTO);
/*
** We want this to be set always on the first time through, but not neccessarily on the second, apply, pass.
*/
if (master_bw != 0 || !apply) {
RegistryClass reg_bw(APPLICATION_SUB_KEY_NAME_BANDTEST);
if (reg_bw.Is_Valid()) {
reg_bw.Set_Int("Up", master_bw);
reg_bw.Set_Int("Down", master_bw);
}
}
} else {
cUserOptions::Set_Bandwidth_Type(BANDWIDTH_LANT1);
}
}
}
}
//}
if (apply) {
SlaveMaster.Reset();
}
/*
** Read the slave server info.
*/
for (int i=0 ; i 0xffff) {
WWDEBUG_SAY(("Error - Invalid port number %d specified for slave %d - aborting\n", slave_port, i+1));
ConsoleBox.Print("Error - Invalid port number %d specified for slave %d - aborting\n", slave_port, i+1);
ConsoleBox.Wait_For_Keypress();;
return(false);
}
/*
** Get the bandwidth allowance.
*/
slave_bw = ini.Get_Int(slave_section, "BandwidthUp", 0xffffffff);
if (slave_bw != 0 && slave_bw != 0xffffffff && slave_bw < 33600) {
WWDEBUG_SAY(("Error - Insufficient bandwidth specified for slave %d - aborting\n", i+1));
ConsoleBox.Print("Error - Insufficient bandwidth specified for slave %d - aborting\n", i+1);
ConsoleBox.Wait_For_Keypress();;
return(false);
}
}
/*
** Apply the settings.
*/
if (apply) {
SlaveMaster.Add_Slave(enabled, slave_nick, slave_serial, (unsigned short)slave_port, slave_settings, slave_bw, slave_pass);
}
}
if (apply) {
SlaveMaster.Save();
}
}
return(true);
}
/***********************************************************************************************
* ServerSettingsClass::Encrypt_Serial -- Serial number encryption/decryption *
* *
* *
* *
* INPUT: Input serial number *
* Reference to output serial number *
* Encrypt flag - true to encrypt, false to decrypt *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/1/2002 12:08PM ST : Created *
*=============================================================================================*/
void ServerSettingsClass::Encrypt_Serial(StringClass serial_in, StringClass &serial_out, bool encrypt)
{
char *s;
int numberlength = serial_in.Get_Length();
unsigned long bytesread;
char stringbuffer[ENCRYPTION_STRING_LENGTH];
int p;
WWASSERT(numberlength);
s = new char [numberlength + 1];
memcpy(s, serial_in.Peek_Buffer(), numberlength + 1);
/*
** See if the key file is available. If not, don't bother encrypting.
*/
HANDLE handle = CreateFile ("woldata.key", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE) {
delete [] s;
serial_out = serial_in;
return;
}
/*
** Read the key.
*/
if (!ReadFile(handle, stringbuffer, sizeof (stringbuffer), &bytesread, NULL)) {
WWDEBUG_SAY(("Unable to read serial encryption key file\n"));
delete [] s;
serial_out = serial_in;
return;
}
int sign = encrypt ? 1 : -1;
p = 0;
for (unsigned i = 0; i < ENCRYPTION_STRING_LENGTH; i++) {
int t;
char c;
t = s[p] - '0';
t %= 10;
t += (sign * stringbuffer[i]);
t += 1000;
t %= 10;
c = t + '0';
s[p] = c;
p++;
if (p == numberlength) {
p = 0;
}
}
serial_out = StringClass(s, true);
delete [] s;
}
/***********************************************************************************************
* ServerSettingsClass::Decrypt_Serial -- Serial number decryption *
* *
* *
* *
* INPUT: Input serial number *
* Reference to output serial number *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/1/2002 12:08PM ST : Created *
*=============================================================================================*/
void ServerSettingsClass::Decrypt_Serial(StringClass serial_in, StringClass &serial_out)
{
Encrypt_Serial(serial_in, serial_out, false);
}
/***********************************************************************************************
* ServerSettingsClass::Get_Preferred_Server -- Get the users specified server *
* *
* *
* *
* INPUT: Server list from servserv *
* *
* OUTPUT: Name of preferred server *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/1/2002 1:18PM ST : Created *
*=============================================================================================*/
char *ServerSettingsClass::Get_Preferred_Server(const WWOnline::IRCServerList &server_list)
{
if (IsActive && server_list.size()) {
Write_Server_List(server_list);
}
return(PreferredLoginServer);
}
/***********************************************************************************************
* ServerSettingsClass::Write_Server_List -- Write the server list into the settings ini file *
* *
* *
* *
* INPUT: Server list *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/1/2002 1:19PM ST : Created *
*=============================================================================================*/
void ServerSettingsClass::Write_Server_List(const WWOnline::IRCServerList &server_list)
{
WWASSERT(server_list.size());
WWASSERT(strlen(SettingsFile) != 0);
char temp[256];
if (server_list.size()) {
RawFileClass file(SettingsFile);
/*
** This is a bit hacky. Basically we just want the .ini file commented with the latest server list.
**
** We will do this by reading in the file, looking for a tag that tells us where to write the server list, then writing
** the file back out with the server list in place.
*/
if (file.Is_Available()) {
unsigned long size = file.Size();
if (size) {
/*
** Read the file.
*/
char *file_buffer = new char[size + 8192];
#ifdef WWDEBUG
unsigned long read_size =
#endif //WWDEBUG
file.Read(file_buffer, size);
WWASSERT(read_size == size);
file.Close();
/*
** Find the placeholder tag.
*/
char *tag = strstr(file_buffer, ServerListTag);
char *end_tag = strstr(file_buffer, ServerListEnd);
if (tag && end_tag) {
/*
** Write out the first portion of the file unchanged.
*/
file.Open(FileClass::WRITE);
file.Write(file_buffer, (tag - file_buffer) + strlen(ServerListTag));
/*
** Insert the server list.
*/
char *server_list_text = new char [8192];
strcpy(server_list_text, "\r\n;\r\n");
for (unsigned int i = 0; i < server_list.size(); i++) {
const RefPtr &server = server_list[i];
if (server->HasLanguageCode()) {
const char *server_name = server->GetName();
sprintf(temp, "; %s\r\n", server_name);
strcat(server_list_text, temp);
}
}
strcat(server_list_text, ";\r\n");
file.Write(server_list_text, strlen(server_list_text));
/*
** Write out the post server list sections of the original file.
*/
file.Write(end_tag, (file_buffer + size) - end_tag);
file.Close();
}
}
}
}
}
/***********************************************************************************************
* ServerSettingsClass::Check_Game_Settings_File -- Check game settings for validity *
* *
* *
* *
* INPUT: Game settings .ini file name *
* *
* OUTPUT: True if valid. *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/3/2002 9:37PM ST : Created *
*=============================================================================================*/
bool ServerSettingsClass::Check_Game_Settings_File(char *config_file)
{
cGameDataCnc *game_settings = (cGameDataCnc*) cGameData::Create_Game_Of_Type(cGameData::GAME_TYPE_CNC);
WWASSERT(game_settings != NULL);
if (game_settings) {
game_settings->Set_Ini_Filename(config_file);
game_settings->Load_From_Server_Config();
WideStringClass outMsg;
bool ok = game_settings->Is_Valid_Settings(outMsg, true);
delete game_settings;
return(ok);
}
return(false);
}