mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-22 22:34:33 +01:00
Merge pull request #2709 from OpenRCT2/set-rct2-path
Add ability to set RCT2 path by command line.
This commit is contained in:
@@ -350,7 +350,7 @@ namespace CommandLine
|
||||
}
|
||||
else if (!firstOption)
|
||||
{
|
||||
Console::WriteLineError("All options must be passed at the end of the command line.");
|
||||
Console::Error::WriteLine("All options must be passed at the end of the command line.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -383,8 +383,8 @@ namespace CommandLine
|
||||
const CommandLineOptionDefinition * option = FindOption(options, optionName);
|
||||
if (option == nullptr)
|
||||
{
|
||||
Console::WriteError("Unknown option: --");
|
||||
Console::WriteLineError(optionName);
|
||||
Console::Error::Write("Unknown option: --");
|
||||
Console::Error::WriteLine(optionName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -399,8 +399,8 @@ namespace CommandLine
|
||||
const char * valueString = nullptr;
|
||||
if (!argEnumerator->TryPopString(&valueString))
|
||||
{
|
||||
Console::WriteError("Expected value for option: ");
|
||||
Console::WriteLineError(optionName);
|
||||
Console::Error::Write("Expected value for option: ");
|
||||
Console::Error::WriteLine(optionName);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -414,8 +414,8 @@ namespace CommandLine
|
||||
{
|
||||
if (option->Type == CMDLINE_TYPE_SWITCH)
|
||||
{
|
||||
Console::WriteError("Option is a switch: ");
|
||||
Console::WriteLineError(optionName);
|
||||
Console::Error::Write("Option is a switch: ");
|
||||
Console::Error::WriteLine(optionName);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -442,9 +442,9 @@ namespace CommandLine
|
||||
option = FindOption(options, shortOption[0]);
|
||||
if (option == nullptr)
|
||||
{
|
||||
Console::WriteError("Unknown option: -");
|
||||
Console::WriteError(shortOption[0]);
|
||||
Console::WriteLineError();
|
||||
Console::Error::Write("Unknown option: -");
|
||||
Console::Error::Write(shortOption[0]);
|
||||
Console::Error::WriteLine();
|
||||
return false;
|
||||
}
|
||||
if (option->Type == CMDLINE_TYPE_SWITCH)
|
||||
@@ -469,9 +469,9 @@ namespace CommandLine
|
||||
const char * valueString = nullptr;
|
||||
if (!argEnumerator->TryPopString(&valueString))
|
||||
{
|
||||
Console::WriteError("Expected value for option: ");
|
||||
Console::WriteError(option->ShortName);
|
||||
Console::WriteLineError();
|
||||
Console::Error::Write("Expected value for option: ");
|
||||
Console::Error::Write(option->ShortName);
|
||||
Console::Error::WriteLine();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -502,8 +502,8 @@ namespace CommandLine
|
||||
*((utf8 * *)option->OutAddress) = String::Duplicate(valueString);
|
||||
return true;
|
||||
default:
|
||||
Console::WriteError("Unknown CMDLINE_TYPE for: ");
|
||||
Console::WriteLineError(option->LongName);
|
||||
Console::Error::Write("Unknown CMDLINE_TYPE for: ");
|
||||
Console::Error::WriteLine(option->LongName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../config.h"
|
||||
#include "../openrct2.h"
|
||||
}
|
||||
|
||||
#include "../core/Console.hpp"
|
||||
#include "../core/Memory.hpp"
|
||||
#include "../core/Path.hpp"
|
||||
#include "../core/String.hpp"
|
||||
#include "../network/network.h"
|
||||
#include "CommandLine.hpp"
|
||||
@@ -52,6 +54,7 @@ static exitcode_t HandleCommandEdit(CommandLineArgEnumerator * enumerator);
|
||||
static exitcode_t HandleCommandIntro(CommandLineArgEnumerator * enumerator);
|
||||
static exitcode_t HandleCommandHost(CommandLineArgEnumerator * enumerator);
|
||||
static exitcode_t HandleCommandJoin(CommandLineArgEnumerator * enumerator);
|
||||
static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator);
|
||||
|
||||
static void PrintAbout();
|
||||
static void PrintVersion();
|
||||
@@ -60,13 +63,14 @@ static void PrintLaunchInformation();
|
||||
const CommandLineCommand CommandLine::RootCommands[]
|
||||
{
|
||||
// Main commands
|
||||
DefineCommand("", "<uri>", StandardOptions, HandleNoCommand ),
|
||||
DefineCommand("edit", "<uri>", StandardOptions, HandleCommandEdit ),
|
||||
DefineCommand("intro", "", StandardOptions, HandleCommandIntro),
|
||||
#ifndef DISABLE_NETWORK
|
||||
DefineCommand("host", "<uri>", StandardOptions, HandleCommandHost ),
|
||||
DefineCommand("join", "<hostname>", StandardOptions, HandleCommandJoin ),
|
||||
DefineCommand("", "<uri>", StandardOptions, HandleNoCommand ),
|
||||
DefineCommand("edit", "<uri>", StandardOptions, HandleCommandEdit ),
|
||||
DefineCommand("intro", "", StandardOptions, HandleCommandIntro ),
|
||||
#ifndef DISABLE_NETWORK
|
||||
DefineCommand("host", "<uri>", StandardOptions, HandleCommandHost ),
|
||||
DefineCommand("join", "<hostname>", StandardOptions, HandleCommandJoin ),
|
||||
#endif
|
||||
DefineCommand("set-rct2", "<path>", StandardOptions, HandleCommandSetRCT2),
|
||||
|
||||
// Sub-commands
|
||||
DefineSubCommand("screenshot", CommandLine::ScreenshotCommands),
|
||||
@@ -163,7 +167,7 @@ exitcode_t HandleCommandEdit(CommandLineArgEnumerator * enumerator)
|
||||
const char * parkUri;
|
||||
if (!enumerator->TryPopString(&parkUri))
|
||||
{
|
||||
Console::WriteLineError("Expected path or URL to a saved park.");
|
||||
Console::Error::WriteLine("Expected path or URL to a saved park.");
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
String::Set(gOpenRCT2StartupActionPath, sizeof(gOpenRCT2StartupActionPath), parkUri);
|
||||
@@ -197,7 +201,7 @@ exitcode_t HandleCommandHost(CommandLineArgEnumerator * enumerator)
|
||||
const char * parkUri;
|
||||
if (!enumerator->TryPopString(&parkUri))
|
||||
{
|
||||
Console::WriteLineError("Expected path or URL to a saved park.");
|
||||
Console::Error::WriteLine("Expected path or URL to a saved park.");
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
|
||||
@@ -220,7 +224,7 @@ exitcode_t HandleCommandJoin(CommandLineArgEnumerator * enumerator)
|
||||
const char * hostname;
|
||||
if (!enumerator->TryPopString(&hostname))
|
||||
{
|
||||
Console::WriteLineError("Expected a hostname or IP address to the server to connect to.");
|
||||
Console::Error::WriteLine("Expected a hostname or IP address to the server to connect to.");
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
|
||||
@@ -232,6 +236,84 @@ exitcode_t HandleCommandJoin(CommandLineArgEnumerator * enumerator)
|
||||
|
||||
#endif // DISABLE_NETWORK
|
||||
|
||||
static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator)
|
||||
{
|
||||
exitcode_t result = CommandLine::HandleCommandDefault();
|
||||
if (result != EXITCODE_CONTINUE)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get the path that was passed
|
||||
const utf8 * rawPath;
|
||||
if (!enumerator->TryPopString(&rawPath))
|
||||
{
|
||||
Console::Error::WriteLine("Expected a path.");
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
|
||||
utf8 path[MAX_PATH];
|
||||
Path::GetAbsolute(path, sizeof(path), rawPath);
|
||||
|
||||
// Check if path exists
|
||||
Console::WriteLine("Checking path...");
|
||||
if (!platform_directory_exists(path))
|
||||
{
|
||||
Console::Error::WriteFormat("The path '%s' does not exist", path);
|
||||
Console::Error::WriteLine();
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
|
||||
// Check if g1.dat exists (naive but good check)
|
||||
Console::WriteLine("Checking g1.dat...");
|
||||
|
||||
utf8 pathG1Check[MAX_PATH];
|
||||
String::Set(pathG1Check, sizeof(pathG1Check), path);
|
||||
Path::Append(pathG1Check, sizeof(pathG1Check), "Data");
|
||||
Path::Append(pathG1Check, sizeof(pathG1Check), "g1.dat");
|
||||
if (!platform_file_exists(pathG1Check))
|
||||
{
|
||||
Console::Error::WriteLine("RCT2 path not valid.");
|
||||
Console::Error::WriteFormat("Unable to find %s.", pathG1Check);
|
||||
Console::Error::WriteLine();
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
|
||||
// Check user path that will contain the config
|
||||
utf8 userPath[MAX_PATH];
|
||||
platform_resolve_user_data_path();
|
||||
platform_get_user_directory(userPath, NULL);
|
||||
if (!platform_ensure_directory_exists(userPath)) {
|
||||
Console::Error::WriteFormat("Unable to access or create directory '%s'.", userPath);
|
||||
Console::Error::WriteLine();
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
|
||||
// Update RCT2 path in config
|
||||
|
||||
// TODO remove this when we get rid of config_apply_to_old_addresses
|
||||
if (!openrct2_setup_rct2_segment()) {
|
||||
Console::Error::WriteLine("Unable to load RCT2 data sector");
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
|
||||
config_set_defaults();
|
||||
config_open_default();
|
||||
String::DiscardDuplicate(&gConfigGeneral.game_path, path);
|
||||
if (config_save_default())
|
||||
{
|
||||
Console::WriteFormat("Updating RCT2 path to '%s'.", path);
|
||||
Console::WriteLine();
|
||||
Console::WriteLine("Updated config.ini");
|
||||
return EXITCODE_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::Error::WriteLine("Unable to update config.ini");
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintAbout()
|
||||
{
|
||||
PrintVersion();
|
||||
|
||||
@@ -44,24 +44,36 @@ namespace Console
|
||||
puts(str);
|
||||
}
|
||||
|
||||
void WriteError(char c)
|
||||
namespace Error
|
||||
{
|
||||
fputc(c, stderr);
|
||||
}
|
||||
void Write(char c)
|
||||
{
|
||||
fputc(c, stderr);
|
||||
}
|
||||
|
||||
void WriteError(const utf8 * str)
|
||||
{
|
||||
fputs(str, stderr);
|
||||
}
|
||||
void Write(const utf8 * str)
|
||||
{
|
||||
fputs(str, stderr);
|
||||
}
|
||||
|
||||
void WriteLineError()
|
||||
{
|
||||
fputs(platform_get_new_line(), stderr);
|
||||
}
|
||||
void WriteFormat(const utf8 * format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
void WriteLineError(const utf8 * str)
|
||||
{
|
||||
fputs(str, stderr);
|
||||
WriteLineError();
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void WriteLine()
|
||||
{
|
||||
fputs(platform_get_new_line(), stderr);
|
||||
}
|
||||
|
||||
void WriteLine(const utf8 * str)
|
||||
{
|
||||
fputs(str, stderr);
|
||||
WriteLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,13 @@ namespace Console
|
||||
void WriteFormat(const utf8 * format, ...);
|
||||
void WriteLine();
|
||||
void WriteLine(const utf8 * str);
|
||||
void WriteError(char c);
|
||||
void WriteError(const utf8 * str);
|
||||
void WriteLineError();
|
||||
void WriteLineError(const utf8 * str);
|
||||
|
||||
namespace Error
|
||||
{
|
||||
void Write(char c);
|
||||
void Write(const utf8 * str);
|
||||
void WriteFormat(const utf8 * format, ...);
|
||||
void WriteLine();
|
||||
void WriteLine(const utf8 * str);
|
||||
}
|
||||
}
|
||||
|
||||
52
src/core/Path.cpp
Normal file
52
src/core/Path.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
extern "C"
|
||||
{
|
||||
#include "../platform/platform.h"
|
||||
#include "../localisation/localisation.h"
|
||||
#include "../util/util.h"
|
||||
}
|
||||
|
||||
#include "Memory.hpp"
|
||||
#include "Path.hpp"
|
||||
#include "String.hpp"
|
||||
#include "Util.hpp"
|
||||
|
||||
namespace Path
|
||||
{
|
||||
utf8 * Append(utf8 * buffer, size_t bufferSize, const utf8 * src)
|
||||
{
|
||||
return safe_strcat_path(buffer, src, bufferSize);
|
||||
}
|
||||
|
||||
utf8 * GetAbsolute(utf8 *buffer, size_t bufferSize, const utf8 * relativePath)
|
||||
{
|
||||
#if _WIN32
|
||||
wchar_t * relativePathW = utf8_to_widechar(relativePath);
|
||||
wchar_t absolutePathW[MAX_PATH];
|
||||
DWORD length = GetFullPathNameW(relativePathW, Util::CountOf(absolutePathW), absolutePathW, NULL);
|
||||
Memory::Free(relativePathW);
|
||||
if (length == 0)
|
||||
{
|
||||
return String::Set(buffer, bufferSize, relativePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
utf8 * absolutePath = widechar_to_utf8(absolutePathW);
|
||||
String::Set(buffer, bufferSize, absolutePath);
|
||||
Memory::Free(absolutePath);
|
||||
return buffer;
|
||||
}
|
||||
#else
|
||||
utf8 * absolutePath = realpath(relativePath, NULL);
|
||||
if (absolutePath == nullptr)
|
||||
{
|
||||
return String::Set(buffer, bufferSize, relativePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
String::Set(buffer, bufferSize, absolutePath);
|
||||
Memory::Free(absolutePath);
|
||||
return buffer;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
12
src/core/Path.hpp
Normal file
12
src/core/Path.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../common.h"
|
||||
}
|
||||
|
||||
namespace Path
|
||||
{
|
||||
utf8 * Append(utf8 * buffer, size_t bufferSize, const utf8 * src);
|
||||
utf8 * GetAbsolute(utf8 *buffer, size_t bufferSize, const utf8 * relativePath);
|
||||
}
|
||||
@@ -129,4 +129,16 @@ namespace String
|
||||
size_t srcSize = SizeOf(src);
|
||||
return Memory::DuplicateArray(src, srcSize + 1);
|
||||
}
|
||||
|
||||
utf8 * DiscardUse(utf8 * * ptr, utf8 * replacement)
|
||||
{
|
||||
Memory::Free(*ptr);
|
||||
*ptr = replacement;
|
||||
return replacement;
|
||||
}
|
||||
|
||||
utf8 * DiscardDuplicate(utf8 * * ptr, utf8 * replacement)
|
||||
{
|
||||
return DiscardUse(ptr, String::Duplicate(replacement));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,14 @@ namespace String
|
||||
utf8 * Format(utf8 * buffer, size_t bufferSize, const utf8 * format, ...);
|
||||
utf8 * AppendFormat(utf8 * buffer, size_t bufferSize, const utf8 * format, ...);
|
||||
utf8 * Duplicate(const utf8 * src);
|
||||
|
||||
/**
|
||||
* Helper method to free the string a string pointer points to and set it to a replacement string.
|
||||
*/
|
||||
utf8 * DiscardUse(utf8 * * ptr, utf8 * replacement);
|
||||
|
||||
/**
|
||||
* Helper method to free the string a string pointer points to and set it to a copy of a replacement string.
|
||||
*/
|
||||
utf8 * DiscardDuplicate(utf8 * * ptr, utf8 * replacement);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ int _finished;
|
||||
static struct { sint16 x, y, z; } _spritelocations1[MAX_SPRITES], _spritelocations2[MAX_SPRITES];
|
||||
|
||||
static void openrct2_loop();
|
||||
static bool openrct2_setup_rct2_segment();
|
||||
static void openrct2_setup_rct2_hooks();
|
||||
|
||||
void openrct2_write_full_version_info(utf8 *buffer, size_t bufferSize)
|
||||
@@ -475,7 +474,7 @@ void openrct2_reset_object_tween_locations()
|
||||
* Loads RCT2's data model and remaps the addresses.
|
||||
* @returns true if the data integrity check succeeded, otherwise false.
|
||||
*/
|
||||
static bool openrct2_setup_rct2_segment()
|
||||
bool openrct2_setup_rct2_segment()
|
||||
{
|
||||
// OpenRCT2 on Linux and OS X is wired to have the original Windows PE sections loaded
|
||||
// necessary. Windows does not need to do this as OpenRCT2 runs as a DLL loaded from the Windows PE.
|
||||
|
||||
@@ -54,6 +54,7 @@ void openrct2_launch();
|
||||
void openrct2_dispose();
|
||||
void openrct2_finish();
|
||||
void openrct2_reset_object_tween_locations();
|
||||
bool openrct2_setup_rct2_segment();
|
||||
|
||||
int cmdline_run(const char **argv, int argc);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user