1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 19:13:07 +01:00

Move more platform functions (#16416)

* Upgrade platform_get_locale_measurement_format()

* Upgrade platform_get_locale_date_format()

* Upgrade platform_get_locale_temperature_format()

* Move platform_directory_delete() to Path

* Upgrade platform_process_is_elevated()

* Move platform_update_palette() to Drawing.cpp

* Upgrade platform_get_steam_dir()

* Upgrade platform_get_font_path()

* Remove now-empty platform files

* Fix formatting

* Upgrade platform_get_default_scale()

* Move remaining stuff in Android.cpp

* Use return {} instead of return ""
This commit is contained in:
Michael Steenbeek
2022-01-16 14:06:55 +01:00
committed by GitHub
25 changed files with 599 additions and 710 deletions

View File

@@ -430,7 +430,7 @@ namespace OpenRCT2
}
#endif
if (platform_process_is_elevated())
if (Platform::ProcessIsElevated())
{
std::string elevationWarning = _localisationService->GetString(STR_ADMIN_NOT_RECOMMENDED);
if (gOpenRCT2Headless)

View File

@@ -167,7 +167,7 @@ void update_palette_effects()
paletteOffset[(i * 4) + 1] = -((0xFF - g1->offset[(i * 3) + 1]) / 2) - 1;
paletteOffset[(i * 4) + 2] = -((0xFF - g1->offset[(i * 3) + 2]) / 2) - 1;
}
platform_update_palette(gGamePalette, PALETTE_OFFSET_DYNAMIC, PALETTE_LENGTH_DYNAMIC);
UpdatePalette(gGamePalette, PALETTE_OFFSET_DYNAMIC, PALETTE_LENGTH_DYNAMIC);
}
gClimateLightningFlash++;
}
@@ -286,10 +286,10 @@ void update_palette_effects()
}
}
platform_update_palette(gGamePalette, PALETTE_OFFSET_ANIMATED, PALETTE_LENGTH_ANIMATED);
UpdatePalette(gGamePalette, PALETTE_OFFSET_ANIMATED, PALETTE_LENGTH_ANIMATED);
if (gClimateLightningFlash == 2)
{
platform_update_palette(gGamePalette, PALETTE_OFFSET_DYNAMIC, PALETTE_LENGTH_DYNAMIC);
UpdatePalette(gGamePalette, PALETTE_OFFSET_DYNAMIC, PALETTE_LENGTH_DYNAMIC);
gClimateLightningFlash = 0;
}
}

View File

@@ -166,13 +166,13 @@ namespace Config
model->landscape_smoothing = reader->GetBoolean("landscape_smoothing", true);
model->language = reader->GetEnum<int32_t>("language", Platform::GetLocaleLanguage(), Enum_LanguageEnum);
model->measurement_format = reader->GetEnum<MeasurementFormat>(
"measurement_format", platform_get_locale_measurement_format(), Enum_MeasurementFormat);
"measurement_format", Platform::GetLocaleMeasurementFormat(), Enum_MeasurementFormat);
model->play_intro = reader->GetBoolean("play_intro", false);
model->save_plugin_data = reader->GetBoolean("save_plugin_data", true);
model->debugging_tools = reader->GetBoolean("debugging_tools", false);
model->show_height_as_units = reader->GetBoolean("show_height_as_units", false);
model->temperature_format = reader->GetEnum<TemperatureUnit>(
"temperature_format", platform_get_locale_temperature_format(), Enum_Temperature);
"temperature_format", Platform::GetLocaleTemperatureFormat(), Enum_Temperature);
model->window_height = reader->GetInt32("window_height", -1);
model->window_snap_proximity = reader->GetInt32("window_snap_proximity", 5);
model->window_width = reader->GetInt32("window_width", -1);
@@ -183,7 +183,7 @@ namespace Config
model->use_vsync = reader->GetBoolean("use_vsync", true);
model->virtual_floor_style = reader->GetEnum<VirtualFloorStyles>(
"virtual_floor_style", VirtualFloorStyles::Glassy, Enum_VirtualFloorStyle);
model->date_format = reader->GetEnum<int32_t>("date_format", platform_get_locale_date_format(), Enum_DateFormat);
model->date_format = reader->GetEnum<int32_t>("date_format", Platform::GetLocaleDateFormat(), Enum_DateFormat);
model->auto_staff_placement = reader->GetBoolean("auto_staff", true);
model->handymen_mow_default = reader->GetBoolean("handymen_mow_default", false);
model->default_inspection_interval = reader->GetInt32("default_inspection_interval", 2);
@@ -202,7 +202,7 @@ namespace Config
model->disable_lightning_effect = reader->GetBoolean("disable_lightning_effect", false);
model->allow_loading_with_incorrect_checksum = reader->GetBoolean("allow_loading_with_incorrect_checksum", true);
model->steam_overlay_pause = reader->GetBoolean("steam_overlay_pause", true);
model->window_scale = reader->GetFloat("window_scale", platform_get_default_scale());
model->window_scale = reader->GetFloat("window_scale", Platform::GetDefaultScale());
model->scale_quality = reader->GetEnum<ScaleQuality>(
"scale_quality", ScaleQuality::SmoothNearestNeighbour, Enum_ScaleQuality);
model->show_fps = reader->GetBoolean("show_fps", false);
@@ -652,8 +652,8 @@ namespace Config
}
}
utf8 steamPath[2048] = { 0 };
if (platform_get_steam_path(steamPath, sizeof(steamPath)))
auto steamPath = Platform::GetSteamPath();
if (!steamPath.empty())
{
std::string location = Path::Combine(steamPath, platform_get_rct1_steam_dir());
if (RCT1DataPresentAtLocation(location.c_str()))
@@ -701,8 +701,8 @@ namespace Config
}
}
utf8 steamPath[2048] = { 0 };
if (platform_get_steam_path(steamPath, sizeof(steamPath)))
auto steamPath = Platform::GetSteamPath();
if (!steamPath.empty())
{
std::string location = Path::Combine(steamPath, platform_get_rct2_steam_dir());
if (Platform::OriginalGameDataExists(location))

View File

@@ -104,4 +104,9 @@ namespace Path
{
return Platform::ResolveCasing(path, File::Exists(path));
}
bool DeleteDirectory(std::string_view path)
{
return fs::remove_all(u8path(path)) > 0;
}
} // namespace Path

View File

@@ -26,6 +26,7 @@ namespace Path
std::string GetDirectory(std::string_view path);
void CreateDirectory(std::string_view path);
bool DirectoryExists(std::string_view path);
bool DeleteDirectory(std::string_view path);
std::string GetFileName(std::string_view origPath);
std::string GetFileNameWithoutExtension(std::string_view path);
std::string GetExtension(std::string_view path);

View File

@@ -9,6 +9,7 @@
#ifdef __ANDROID__
# include "../platform/Platform2.h"
# include "../platform/platform.h"
# include "IStream.hpp"
# include "MemoryStream.h"
@@ -30,7 +31,7 @@ public:
// retrieve the JNI environment.
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
jclass jniClass = platform_android_find_class(env, "io/openrct2/ZipArchive");
jclass jniClass = Platform::AndroidFindClass(env, "io/openrct2/ZipArchive");
jmethodID constructor = env->GetMethodID(jniClass, "<init>", "(Ljava/lang/String;)V");
jstring jniPath = env->NewStringUTF(path.data());

View File

@@ -10,6 +10,7 @@
#include "Drawing.h"
#include "../Context.h"
#include "../Game.h"
#include "../OpenRCT2.h"
#include "../common.h"
#include "../core/Guard.hpp"
@@ -17,8 +18,10 @@
#include "../platform/platform.h"
#include "../sprites.h"
#include "../util/Util.h"
#include "../world/Climate.h"
#include "../world/Location.hpp"
#include "../world/Water.h"
#include "LightFX.h"
#include <cstring>
@@ -600,7 +603,7 @@ void gfx_transpose_palette(int32_t pal, uint8_t product)
source_pointer += 3;
dest_pointer += 4;
}
platform_update_palette(gGamePalette, 10, 236);
UpdatePalette(gGamePalette, 10, 236);
}
}
@@ -641,7 +644,7 @@ void load_palette()
dst += 4;
}
}
platform_update_palette(gGamePalette, 10, 236);
UpdatePalette(gGamePalette, 10, 236);
gfx_invalidate_screen();
}
@@ -787,3 +790,49 @@ FilterPaletteID GetGlassPaletteId(colour_t c)
{
return GlassPaletteIds[c];
}
void UpdatePalette(const uint8_t* colours, int32_t start_index, int32_t num_colours)
{
colours += start_index * 4;
for (int32_t i = start_index; i < num_colours + start_index; i++)
{
uint8_t r = colours[2];
uint8_t g = colours[1];
uint8_t b = colours[0];
#ifdef __ENABLE_LIGHTFX__
if (lightfx_is_available())
{
lightfx_apply_palette_filter(i, &r, &g, &b);
}
else
#endif
{
float night = gDayNightCycle;
if (night >= 0 && gClimateLightningFlash == 0)
{
r = lerp(r, soft_light(r, 8), night);
g = lerp(g, soft_light(g, 8), night);
b = lerp(b, soft_light(b, 128), night);
}
}
gPalette[i].Red = r;
gPalette[i].Green = g;
gPalette[i].Blue = b;
gPalette[i].Alpha = 0;
colours += 4;
}
// Fix #1749 and #6535: rainbow path, donut shop and pause button contain black spots that should be white.
gPalette[255].Alpha = 0;
gPalette[255].Red = 255;
gPalette[255].Green = 255;
gPalette[255].Blue = 255;
if (!gOpenRCT2Headless)
{
drawing_engine_set_palette(gPalette);
}
}

View File

@@ -599,5 +599,6 @@ extern void (*mask_fn)(
std::optional<uint32_t> GetPaletteG1Index(colour_t paletteId);
std::optional<PaletteMap> GetPaletteMapForColour(colour_t paletteId);
void UpdatePalette(const uint8_t* colours, int32_t start_index, int32_t num_colours);
#include "NewDrawing.h"

View File

@@ -23,6 +23,7 @@
# include "../core/String.hpp"
# include "../localisation/Localisation.h"
# include "../localisation/LocalisationService.h"
# include "../platform/Platform2.h"
# include "../platform/platform.h"
# include "TTF.h"
@@ -125,17 +126,17 @@ bool ttf_initialise()
{
TTFFontDescriptor* fontDesc = &(gCurrentTTFFontSet->size[i]);
utf8 fontPath[MAX_PATH];
if (!platform_get_font_path(fontDesc, fontPath, sizeof(fontPath)))
auto fontPath = Platform::GetFontPath(*fontDesc);
if (fontPath.empty())
{
log_verbose("Unable to load font '%s'", fontDesc->font_name);
return false;
}
fontDesc->font = ttf_open_font(fontPath, fontDesc->ptSize);
fontDesc->font = ttf_open_font(fontPath.c_str(), fontDesc->ptSize);
if (fontDesc->font == nullptr)
{
log_verbose("Unable to load '%s'", fontPath);
log_verbose("Unable to load '%s'", fontPath.c_str());
return false;
}
}

View File

@@ -783,9 +783,7 @@
<ClCompile Include="peep\PeepData.cpp" />
<ClCompile Include="peep\RideUseSystem.cpp" />
<ClCompile Include="PlatformEnvironment.cpp" />
<ClCompile Include="platform\Android.cpp" />
<ClCompile Include="platform\Crash.cpp" />
<ClCompile Include="platform\Linux.cpp" />
<ClCompile Include="platform\Platform.Android.cpp" />
<ClCompile Include="platform\Platform.Linux.cpp" />
<ClCompile Include="platform\Platform.Posix.cpp" />

View File

@@ -1,111 +0,0 @@
/*****************************************************************************
* Copyright (c) 2014-2020 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#ifdef __ANDROID__
# include "../config/Config.h"
# include "../localisation/Language.h"
# include "../util/Util.h"
# include "platform.h"
# include <SDL.h>
# include <jni.h>
# include <wchar.h>
# ifndef NO_TTF
bool platform_get_font_path(TTFFontDescriptor* font, utf8* buffer, size_t size)
{
STUB();
return false;
}
# endif
MeasurementFormat platform_get_locale_measurement_format()
{
return MeasurementFormat::Metric;
}
float platform_get_default_scale()
{
JNIEnv* env = static_cast<JNIEnv*>(SDL_AndroidGetJNIEnv());
jobject activity = static_cast<jobject>(SDL_AndroidGetActivity());
jclass activityClass = env->GetObjectClass(activity);
jmethodID getDefaultScale = env->GetMethodID(activityClass, "getDefaultScale", "()F");
jfloat displayScale = env->CallFloatMethod(activity, getDefaultScale);
env->DeleteLocalRef(activity);
env->DeleteLocalRef(activityClass);
return displayScale;
}
bool platform_get_steam_path(utf8* outPath, size_t outSize)
{
return false;
}
AndroidClassLoader::AndroidClassLoader()
{
log_info("Obtaining JNI class loader");
// This is a workaround to be able to call JNI's ClassLoader from non-main
// thread, based on https://stackoverflow.com/a/16302771
// Apparently it's OK to use it from across different thread, but JNI
// only looks for ClassLoader in the _current_ thread and fails to find
// it when searched for from a native library's non-main thread.
// The solution below works by obtaining a ClassLoader reference in main
// thread and caching it for future use from any thread, instead of using
// it via env->FindClass(). ClassLoader itself is abstract, so we cannot
// create it directly; instead we take an arbitrary class and call
// getClassLoader() on it to create a reference that way.
// If we're here, SDL's JNI_OnLoad has already been called and set env
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
// Take an arbitrary class. While the class does not really matter, it
// makes sense to use one that's most likely already loaded and is unlikely
// to be removed from code.
auto randomClass = env->FindClass("io/openrct2/MainActivity");
jclass classClass = env->GetObjectClass(randomClass);
// Get its class loader
auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
// Store the class loader and its findClass method for future use
_classLoader = env->NewGlobalRef(env->CallObjectMethod(randomClass, getClassLoaderMethod));
_findClassMethod = env->GetMethodID(classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
}
AndroidClassLoader::~AndroidClassLoader()
{
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
env->DeleteGlobalRef(_classLoader);
}
jobject AndroidClassLoader::_classLoader;
jmethodID AndroidClassLoader::_findClassMethod;
static std::shared_ptr<AndroidClassLoader> acl;
void platform_android_init_class_loader()
{
acl = std::make_shared<AndroidClassLoader>();
}
jclass platform_android_find_class(JNIEnv* env, const char* name)
{
return static_cast<jclass>(
env->CallObjectMethod(AndroidClassLoader::_classLoader, AndroidClassLoader::_findClassMethod, env->NewStringUTF(name)));
}
#endif

View File

@@ -1,168 +0,0 @@
/*****************************************************************************
* Copyright (c) 2014-2020 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../common.h"
// Despite the name, this file contains support for more OSs besides Linux, provided the necessary ifdefs remain small.
// Otherwise, they should be spun off into their own files.
#if defined(__unix__) && !defined(__ANDROID__) && !defined(__APPLE__)
# ifdef __FreeBSD__
# include <sys/sysctl.h>
# endif
# include <cstring>
# include <ctype.h>
# include <dlfcn.h>
# include <errno.h>
# ifndef NO_TTF
# include <fontconfig/fontconfig.h>
# endif // NO_TTF
# include "../config/Config.h"
# include "../core/File.h"
# include "../core/Path.hpp"
# include "../localisation/Language.h"
# include "../localisation/StringIds.h"
# include "../util/Util.h"
# include "platform.h"
# include <fnmatch.h>
# include <locale.h>
# include <pwd.h>
MeasurementFormat platform_get_locale_measurement_format()
{
// LC_MEASUREMENT is GNU specific.
# ifdef LC_MEASUREMENT
const char* langstring = setlocale(LC_MEASUREMENT, "");
# else
const char* langstring = setlocale(LC_ALL, "");
# endif
if (langstring != nullptr)
{
// using https://en.wikipedia.org/wiki/Metrication#Chronology_and_status_of_conversion_by_country as reference
if (!fnmatch("*_US*", langstring, 0) || !fnmatch("*_MM*", langstring, 0) || !fnmatch("*_LR*", langstring, 0))
{
return MeasurementFormat::Imperial;
}
}
return MeasurementFormat::Metric;
}
bool platform_get_steam_path(utf8* outPath, size_t outSize)
{
const char* steamRoot = getenv("STEAMROOT");
if (steamRoot != nullptr)
{
safe_strcpy(outPath, steamRoot, outSize);
safe_strcat_path(outPath, "ubuntu12_32/steamapps/content", outSize);
return true;
}
char steamPath[1024] = { 0 };
const char* localSharePath = getenv("XDG_DATA_HOME");
if (localSharePath != nullptr)
{
safe_strcpy(steamPath, localSharePath, sizeof(steamPath));
safe_strcat_path(steamPath, "Steam/ubuntu12_32/steamapps/content", sizeof(steamPath));
if (Path::DirectoryExists(steamPath))
{
safe_strcpy(outPath, steamPath, outSize);
return true;
}
}
const char* homeDir = getpwuid(getuid())->pw_dir;
if (homeDir != nullptr)
{
safe_strcpy(steamPath, homeDir, sizeof(steamPath));
safe_strcat_path(steamPath, ".local/share/Steam/ubuntu12_32/steamapps/content", sizeof(steamPath));
if (Path::DirectoryExists(steamPath))
{
safe_strcpy(outPath, steamPath, outSize);
return true;
}
std::fill_n(steamPath, sizeof(steamPath), 0x00);
safe_strcpy(steamPath, homeDir, sizeof(steamPath));
safe_strcat_path(steamPath, ".steam/steam/ubuntu12_32/steamapps/content", sizeof(steamPath));
if (Path::DirectoryExists(steamPath))
{
safe_strcpy(outPath, steamPath, outSize);
return true;
}
}
return false;
}
# ifndef NO_TTF
bool platform_get_font_path(TTFFontDescriptor* font, utf8* buffer, size_t size)
{
assert(buffer != nullptr);
assert(font != nullptr);
log_verbose("Looking for font %s with FontConfig.", font->font_name);
FcConfig* config = FcInitLoadConfigAndFonts();
if (!config)
{
log_error("Failed to initialize FontConfig library");
FcFini();
return false;
}
FcPattern* pat = FcNameParse(reinterpret_cast<const FcChar8*>(font->font_name));
FcConfigSubstitute(config, pat, FcMatchPattern);
FcDefaultSubstitute(pat);
bool found = false;
FcResult result = FcResultNoMatch;
FcPattern* match = FcFontMatch(config, pat, &result);
if (match)
{
bool is_substitute = false;
// FontConfig implicitly falls back to any default font it is configured to handle.
// In our implementation, this cannot account for supported character sets, leading
// to unrendered characters (tofu) when trying to render e.g. CJK characters using a
// Western (sans-)serif font. We therefore ignore substitutions FontConfig provides,
// and instead rely on exact matches on the fonts predefined for each font family.
FcChar8* matched_font_face = nullptr;
if (FcPatternGetString(match, FC_FULLNAME, 0, &matched_font_face) == FcResultMatch
&& strcmp(font->font_name, reinterpret_cast<const char*>(matched_font_face)) != 0)
{
log_verbose("FontConfig provided substitute font %s -- disregarding.", matched_font_face);
is_substitute = true;
}
FcChar8* filename = nullptr;
if (!is_substitute && FcPatternGetString(match, FC_FILE, 0, &filename) == FcResultMatch)
{
found = true;
safe_strcpy(buffer, reinterpret_cast<utf8*>(filename), size);
log_verbose("FontConfig provided font %s", filename);
}
FcPatternDestroy(match);
}
else
{
log_warning("Failed to find required font.");
}
FcPatternDestroy(pat);
FcConfigDestroy(config);
FcFini();
return found;
}
# endif // NO_TTF
#endif

View File

@@ -13,6 +13,20 @@
# include "../localisation/Language.h"
# include "Platform2.h"
# include <SDL.h>
# include <jni.h>
AndroidClassLoader::~AndroidClassLoader()
{
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
env->DeleteGlobalRef(_classLoader);
}
jobject AndroidClassLoader::_classLoader;
jmethodID AndroidClassLoader::_findClassMethod;
static std::shared_ptr<AndroidClassLoader> acl;
namespace Platform
{
std::string GetFolderPath(SPECIAL_FOLDER folder)
@@ -65,6 +79,87 @@ namespace Platform
{
return Platform::GetCurrencyValue(NULL);
}
MeasurementFormat GetLocaleMeasurementFormat()
{
return MeasurementFormat::Metric;
}
std::string GetSteamPath()
{
return {};
}
# ifndef NO_TTF
std::string GetFontPath(const TTFFontDescriptor& font)
{
STUB();
return {};
}
# endif
float GetDefaultScale()
{
JNIEnv* env = static_cast<JNIEnv*>(SDL_AndroidGetJNIEnv());
jobject activity = static_cast<jobject>(SDL_AndroidGetActivity());
jclass activityClass = env->GetObjectClass(activity);
jmethodID getDefaultScale = env->GetMethodID(activityClass, "getDefaultScale", "()F");
jfloat displayScale = env->CallFloatMethod(activity, getDefaultScale);
env->DeleteLocalRef(activity);
env->DeleteLocalRef(activityClass);
return displayScale;
}
void AndroidInitClassLoader()
{
acl = std::make_shared<AndroidClassLoader>();
}
jclass AndroidFindClass(JNIEnv* env, std::string_view name)
{
return static_cast<jclass>(env->CallObjectMethod(
AndroidClassLoader::_classLoader, AndroidClassLoader::_findClassMethod,
env->NewStringUTF(std::string(name).c_str())));
}
} // namespace Platform
AndroidClassLoader::AndroidClassLoader()
{
log_info("Obtaining JNI class loader");
// This is a workaround to be able to call JNI's ClassLoader from non-main
// thread, based on https://stackoverflow.com/a/16302771
// Apparently it's OK to use it from across different thread, but JNI
// only looks for ClassLoader in the _current_ thread and fails to find
// it when searched for from a native library's non-main thread.
// The solution below works by obtaining a ClassLoader reference in main
// thread and caching it for future use from any thread, instead of using
// it via env->FindClass(). ClassLoader itself is abstract, so we cannot
// create it directly; instead we take an arbitrary class and call
// getClassLoader() on it to create a reference that way.
// If we're here, SDL's JNI_OnLoad has already been called and set env
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();
// Take an arbitrary class. While the class does not really matter, it
// makes sense to use one that's most likely already loaded and is unlikely
// to be removed from code.
auto randomClass = env->FindClass("io/openrct2/MainActivity");
jclass classClass = env->GetObjectClass(randomClass);
// Get its class loader
auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader", "()Ljava/lang/ClassLoader;");
// Store the class loader and its findClass method for future use
_classLoader = env->NewGlobalRef(env->CallObjectMethod(randomClass, getClassLoaderMethod));
_findClassMethod = env->GetMethodID(classLoaderClass, "findClass", "(Ljava/lang/String;)Ljava/lang/Class;");
}
#endif

View File

@@ -12,6 +12,7 @@
# include <cstring>
# include <fnmatch.h>
# include <limits.h>
# include <locale.h>
# include <pwd.h>
# include <vector>
# if defined(__FreeBSD__) || defined(__NetBSD__)
@@ -23,6 +24,10 @@
// for PATH_MAX
# include <linux/limits.h>
# endif // __linux__
# ifndef NO_TTF
# include <fontconfig/fontconfig.h>
# endif // NO_TTF
# include "../OpenRCT2.h"
# include "../core/Path.hpp"
# include "../localisation/Language.h"
@@ -250,6 +255,122 @@ namespace Platform
return Platform::GetCurrencyValue(lc->int_curr_symbol);
}
MeasurementFormat GetLocaleMeasurementFormat()
{
// LC_MEASUREMENT is GNU specific.
# ifdef LC_MEASUREMENT
const char* langstring = setlocale(LC_MEASUREMENT, "");
# else
const char* langstring = setlocale(LC_ALL, "");
# endif
if (langstring != nullptr)
{
// using https://en.wikipedia.org/wiki/Metrication#Chronology_and_status_of_conversion_by_country as reference
if (!fnmatch("*_US*", langstring, 0) || !fnmatch("*_MM*", langstring, 0) || !fnmatch("*_LR*", langstring, 0))
{
return MeasurementFormat::Imperial;
}
}
return MeasurementFormat::Metric;
}
std::string GetSteamPath()
{
const char* steamRoot = getenv("STEAMROOT");
if (steamRoot != nullptr)
{
return Path::Combine(steamRoot, "ubuntu12_32/steamapps/content");
}
const char* localSharePath = getenv("XDG_DATA_HOME");
if (localSharePath != nullptr)
{
auto steamPath = Path::Combine(localSharePath, "Steam/ubuntu12_32/steamapps/content");
if (Path::DirectoryExists(steamPath))
{
return steamPath;
}
}
const char* homeDir = getpwuid(getuid())->pw_dir;
if (homeDir == nullptr)
{
return {};
}
auto steamPath = Path::Combine(homeDir, ".local/share/Steam/ubuntu12_32/steamapps/content");
if (Path::DirectoryExists(steamPath))
{
return steamPath;
}
steamPath = Path::Combine(homeDir, ".steam/steam/ubuntu12_32/steamapps/content");
if (Path::DirectoryExists(steamPath))
{
return steamPath;
}
return {};
}
std::string GetFontPath(const TTFFontDescriptor& font)
{
log_verbose("Looking for font %s with FontConfig.", font.font_name);
FcConfig* config = FcInitLoadConfigAndFonts();
if (!config)
{
log_error("Failed to initialize FontConfig library");
FcFini();
return {};
}
FcPattern* pat = FcNameParse(reinterpret_cast<const FcChar8*>(font.font_name));
FcConfigSubstitute(config, pat, FcMatchPattern);
FcDefaultSubstitute(pat);
std::string path = "";
FcResult result = FcResultNoMatch;
FcPattern* match = FcFontMatch(config, pat, &result);
if (match)
{
bool is_substitute = false;
// FontConfig implicitly falls back to any default font it is configured to handle.
// In our implementation, this cannot account for supported character sets, leading
// to unrendered characters (tofu) when trying to render e.g. CJK characters using a
// Western (sans-)serif font. We therefore ignore substitutions FontConfig provides,
// and instead rely on exact matches on the fonts predefined for each font family.
FcChar8* matched_font_face = nullptr;
if (FcPatternGetString(match, FC_FULLNAME, 0, &matched_font_face) == FcResultMatch
&& strcmp(font.font_name, reinterpret_cast<const char*>(matched_font_face)) != 0)
{
log_verbose("FontConfig provided substitute font %s -- disregarding.", matched_font_face);
is_substitute = true;
}
FcChar8* filename = nullptr;
if (!is_substitute && FcPatternGetString(match, FC_FILE, 0, &filename) == FcResultMatch)
{
path = reinterpret_cast<utf8*>(filename);
log_verbose("FontConfig provided font %s", filename);
}
FcPatternDestroy(match);
}
else
{
log_warning("Failed to find required font.");
}
FcPatternDestroy(pat);
FcConfigDestroy(config);
FcFini();
return path;
}
} // namespace Platform
#endif

View File

@@ -14,6 +14,7 @@
# include "../core/Memory.hpp"
# include "../core/Path.hpp"
# include "../core/String.hpp"
# include "../localisation/Date.h"
# include "Platform2.h"
# include <cerrno>
@@ -22,6 +23,8 @@
# include <cstring>
# include <ctime>
# include <dirent.h>
# include <fnmatch.h>
# include <locale>
# include <pwd.h>
# include <sys/stat.h>
@@ -267,6 +270,55 @@ namespace Platform
}
return result;
}
uint8_t GetLocaleDateFormat()
{
const std::time_base::dateorder dateorder = std::use_facet<std::time_get<char>>(std::locale()).date_order();
switch (dateorder)
{
case std::time_base::mdy:
return DATE_FORMAT_MONTH_DAY_YEAR;
case std::time_base::ymd:
return DATE_FORMAT_YEAR_MONTH_DAY;
case std::time_base::ydm:
return DATE_FORMAT_YEAR_DAY_MONTH;
default:
return DATE_FORMAT_DAY_MONTH_YEAR;
}
}
TemperatureUnit GetLocaleTemperatureFormat()
{
// LC_MEASUREMENT is GNU specific.
# ifdef LC_MEASUREMENT
const char* langstring = setlocale(LC_MEASUREMENT, "");
# else
const char* langstring = setlocale(LC_ALL, "");
# endif
if (langstring != nullptr)
{
if (!fnmatch("*_US*", langstring, 0) || !fnmatch("*_BS*", langstring, 0) || !fnmatch("*_BZ*", langstring, 0)
|| !fnmatch("*_PW*", langstring, 0))
{
return TemperatureUnit::Fahrenheit;
}
}
return TemperatureUnit::Celsius;
}
bool ProcessIsElevated()
{
# ifndef __EMSCRIPTEN__
return (geteuid() == 0);
# else
return false;
# endif // __EMSCRIPTEN__
}
} // namespace Platform
#endif

View File

@@ -34,11 +34,13 @@
# include "../common.h"
# include "../core/Path.hpp"
# include "../core/String.hpp"
# include "../localisation/Date.h"
# include "../localisation/Language.h"
# include "Platform2.h"
# include "platform.h"
# include <iterator>
# include <locale>
# if _WIN32_WINNT < 0x600
# define swprintf_s(a, b, c, d, ...) swprintf(a, b, c, ##__VA_ARGS__)
@@ -707,6 +709,169 @@ namespace Platform
return Platform::GetCurrencyValue(currCode);
}
MeasurementFormat GetLocaleMeasurementFormat()
{
UINT measurement_system;
if (GetLocaleInfo(
LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, reinterpret_cast<LPSTR>(&measurement_system),
sizeof(measurement_system))
== 0)
{
return MeasurementFormat::Metric;
}
switch (measurement_system)
{
case 1:
return MeasurementFormat::Imperial;
case 0:
default:
return MeasurementFormat::Metric;
}
}
uint8_t GetLocaleDateFormat()
{
# if _WIN32_WINNT >= 0x0600
// Retrieve short date format, eg "MM/dd/yyyy"
wchar_t dateFormat[20];
if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SSHORTDATE, dateFormat, static_cast<int>(std::size(dateFormat)))
== 0)
{
return DATE_FORMAT_DAY_MONTH_YEAR;
}
// The only valid characters for format types are: dgyM
// We try to find 3 strings of format types, ignore any characters in between.
// We also ignore 'g', as it represents 'era' and we don't have that concept
// in our date formats.
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd317787(v=vs.85).aspx
//
wchar_t first[sizeof(dateFormat)];
wchar_t second[sizeof(dateFormat)];
if (swscanf_s(
dateFormat, L"%l[dyM]%*l[^dyM]%l[dyM]%*l[^dyM]%*l[dyM]", first, static_cast<uint32_t>(std::size(first)), second,
static_cast<uint32_t>(std::size(second)))
!= 2)
{
return DATE_FORMAT_DAY_MONTH_YEAR;
}
if (wcsncmp(L"d", first, 1) == 0)
{
return DATE_FORMAT_DAY_MONTH_YEAR;
}
if (wcsncmp(L"M", first, 1) == 0)
{
return DATE_FORMAT_MONTH_DAY_YEAR;
}
if (wcsncmp(L"y", first, 1) == 0)
{
if (wcsncmp(L"d", second, 1) == 0)
{
return DATE_FORMAT_YEAR_DAY_MONTH;
}
// Closest possible option
return DATE_FORMAT_YEAR_MONTH_DAY;
}
# endif
// Default fallback
return DATE_FORMAT_DAY_MONTH_YEAR;
}
TemperatureUnit GetLocaleTemperatureFormat()
{
UINT fahrenheit;
// GetLocaleInfo will set fahrenheit to 1 if the locale on this computer
// uses the United States measurement system or 0 otherwise.
if (GetLocaleInfo(
LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, reinterpret_cast<LPSTR>(&fahrenheit),
sizeof(fahrenheit))
== 0)
{
// Assume celsius by default if function call fails
return TemperatureUnit::Celsius;
}
if (fahrenheit)
return TemperatureUnit::Fahrenheit;
return TemperatureUnit::Celsius;
}
bool ProcessIsElevated()
{
BOOL isElevated = FALSE;
HANDLE hToken = nullptr;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
TOKEN_ELEVATION Elevation;
DWORD tokenSize = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &tokenSize))
{
isElevated = Elevation.TokenIsElevated;
}
}
if (hToken)
{
CloseHandle(hToken);
}
return isElevated;
}
std::string GetSteamPath()
{
wchar_t* wSteamPath;
HKEY hKey;
DWORD type, size;
LRESULT result;
if (RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", &hKey) != ERROR_SUCCESS)
return {};
// Get the size of the path first
if (RegQueryValueExW(hKey, L"SteamPath", nullptr, &type, nullptr, &size) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return {};
}
std::string outPath = "";
wSteamPath = reinterpret_cast<wchar_t*>(malloc(size));
result = RegQueryValueExW(hKey, L"SteamPath", nullptr, &type, reinterpret_cast<LPBYTE>(wSteamPath), &size);
if (result == ERROR_SUCCESS)
{
auto utf8SteamPath = String::ToUtf8(wSteamPath);
outPath = Path::Combine(utf8SteamPath, "steamapps", "common");
}
free(wSteamPath);
RegCloseKey(hKey);
return outPath;
}
std::string GetFontPath(const TTFFontDescriptor& font)
{
# if !defined(__MINGW32__) && ((NTDDI_VERSION >= NTDDI_VISTA) && !defined(_USING_V110_SDK71_) && !defined(_ATL_XP_TARGETING))
wchar_t* fontFolder;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Fonts, 0, nullptr, &fontFolder)))
{
// Convert wchar to utf8, then copy the font folder path to the buffer.
auto outPathTemp = String::ToUtf8(fontFolder);
CoTaskMemFree(fontFolder);
return Path::Combine(outPathTemp, font.filename);
}
return {};
# else
log_warning("Compatibility hack: falling back to C:\\Windows\\Fonts");
return Path::Combine("C:\\Windows\\Fonts\\", font.filename);
# endif
}
} // namespace Platform
#endif

View File

@@ -19,8 +19,10 @@
# undef interface
# undef abstract
# include <CoreText/CoreText.h>
# include <Foundation/Foundation.h>
# include <mach-o/dyld.h>
# include <pwd.h>
namespace Platform
{
@@ -216,6 +218,58 @@ namespace Platform
return Platform::GetCurrencyValue(currencyCode.UTF8String);
}
}
MeasurementFormat GetLocaleMeasurementFormat()
{
@autoreleasepool
{
NSNumber* metricSystem = [[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem];
if (metricSystem.boolValue)
{
return MeasurementFormat::Metric;
}
return MeasurementFormat::Imperial;
}
}
std::string GetSteamPath()
{
const char* homeDir = getpwuid(getuid())->pw_dir;
if (homeDir == nullptr)
{
return {};
}
auto steamPath = Path::Combine(
homeDir, "Library/Application Support/Steam/Steam.AppBundle/Steam/Contents/MacOS/steamapps");
if (Path::DirectoryExists(steamPath))
{
return steamPath;
}
return {};
}
std::string GetFontPath(const TTFFontDescriptor& font)
{
@autoreleasepool
{
CTFontDescriptorRef fontRef = CTFontDescriptorCreateWithNameAndSize(
static_cast<CFStringRef>([NSString stringWithUTF8String:font.font_name]), 0.0);
CFURLRef url = static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(fontRef, kCTFontURLAttribute));
if (url)
{
NSString* fontPath = [NSString stringWithString:[static_cast<NSURL*>(CFBridgingRelease(url)) path]];
return fontPath.UTF8String;
}
else
{
return {};
}
}
}
}
#endif

View File

@@ -45,20 +45,29 @@ namespace Platform
uint16_t GetLocaleLanguage();
CurrencyType GetLocaleCurrency();
CurrencyType GetCurrencyValue(const char* currCode);
MeasurementFormat GetLocaleMeasurementFormat();
uint8_t GetLocaleDateFormat();
TemperatureUnit GetLocaleTemperatureFormat();
rct2_time GetTimeLocal();
rct2_date GetDateLocal();
bool FindApp(std::string_view app, std::string* output);
int32_t Execute(std::string_view command, std::string* output = nullptr);
bool ProcessIsElevated();
float GetDefaultScale();
bool OriginalGameDataExists(std::string_view path);
std::string GetUsername();
std::string GetSteamPath();
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__)
std::string GetEnvironmentPath(const char* name);
std::string GetHomePath();
#endif
#ifndef NO_TTF
std::string GetFontPath(const TTFFontDescriptor& font);
#endif // NO_TTF
std::string FormatShortDate(std::time_t timestamp);
std::string FormatTime(std::time_t timestamp);
@@ -71,6 +80,10 @@ namespace Platform
const uint32_t iconIndex);
void RemoveFileAssociations();
#endif
#ifdef __ANDROID__
void AndroidInitClassLoader();
jclass AndroidFindClass(JNIEnv* env, std::string_view name);
#endif
bool IsRunningInWine();
bool IsColourTerminalSupported();
@@ -78,3 +91,15 @@ namespace Platform
utf8* StrDecompToPrecomp(utf8* input);
bool RequireNewWindow(bool openGL);
} // namespace Platform
#ifdef __ANDROID__
class AndroidClassLoader
{
public:
AndroidClassLoader();
~AndroidClassLoader();
static jobject _classLoader;
static jmethodID _findClassMethod;
};
#endif // __ANDROID__

View File

@@ -89,11 +89,6 @@ bool platform_ensure_directory_exists(const utf8* path)
return true;
}
bool platform_directory_delete(const utf8* path)
{
return fs::remove_all(u8path(path)) > 0;
}
std::string platform_get_absolute_path(const utf8* relative_path, const utf8* base_path)
{
std::string result;
@@ -174,46 +169,6 @@ time_t platform_file_get_modified_time(const utf8* path)
return 100;
}
TemperatureUnit platform_get_locale_temperature_format()
{
// LC_MEASUREMENT is GNU specific.
# ifdef LC_MEASUREMENT
const char* langstring = setlocale(LC_MEASUREMENT, "");
# else
const char* langstring = setlocale(LC_ALL, "");
# endif
if (langstring != nullptr)
{
if (!fnmatch("*_US*", langstring, 0) || !fnmatch("*_BS*", langstring, 0) || !fnmatch("*_BZ*", langstring, 0)
|| !fnmatch("*_PW*", langstring, 0))
{
return TemperatureUnit::Fahrenheit;
}
}
return TemperatureUnit::Celsius;
}
uint8_t platform_get_locale_date_format()
{
const std::time_base::dateorder dateorder = std::use_facet<std::time_get<char>>(std::locale()).date_order();
switch (dateorder)
{
case std::time_base::mdy:
return DATE_FORMAT_MONTH_DAY_YEAR;
case std::time_base::ymd:
return DATE_FORMAT_YEAR_MONTH_DAY;
case std::time_base::ydm:
return DATE_FORMAT_YEAR_DAY_MONTH;
default:
return DATE_FORMAT_DAY_MONTH_YEAR;
}
}
datetime64 platform_get_datetime_now_utc()
{
const datetime64 epochAsTicks = 621355968000000000;
@@ -228,15 +183,6 @@ datetime64 platform_get_datetime_now_utc()
return utcNow;
}
bool platform_process_is_elevated()
{
# ifndef __EMSCRIPTEN__
return (geteuid() == 0);
# else
return false;
# endif // __EMSCRIPTEN__
}
std::string platform_get_rct1_steam_dir()
{
return "app_285310" PATH_SEPARATOR "depot_285311";

View File

@@ -137,56 +137,17 @@ namespace Platform
sanitised = String::Trim(sanitised);
return sanitised;
}
#ifndef __ANDROID__
float GetDefaultScale()
{
return 1;
}
#endif
} // namespace Platform
GamePalette gPalette;
void platform_update_palette(const uint8_t* colours, int32_t start_index, int32_t num_colours)
{
colours += start_index * 4;
for (int32_t i = start_index; i < num_colours + start_index; i++)
{
uint8_t r = colours[2];
uint8_t g = colours[1];
uint8_t b = colours[0];
#ifdef __ENABLE_LIGHTFX__
if (lightfx_is_available())
{
lightfx_apply_palette_filter(i, &r, &g, &b);
}
else
#endif
{
float night = gDayNightCycle;
if (night >= 0 && gClimateLightningFlash == 0)
{
r = lerp(r, soft_light(r, 8), night);
g = lerp(g, soft_light(g, 8), night);
b = lerp(b, soft_light(b, 128), night);
}
}
gPalette[i].Red = r;
gPalette[i].Green = g;
gPalette[i].Blue = b;
gPalette[i].Alpha = 0;
colours += 4;
}
// Fix #1749 and #6535: rainbow path, donut shop and pause button contain black spots that should be white.
gPalette[255].Alpha = 0;
gPalette[255].Red = 255;
gPalette[255].Green = 255;
gPalette[255].Blue = 255;
if (!gOpenRCT2Headless)
{
drawing_engine_set_palette(gPalette);
}
}
void platform_toggle_windowed_mode()
{
int32_t targetMode = gConfigGeneral.fullscreen_mode == 0 ? 2 : 0;
@@ -254,13 +215,6 @@ void platform_sleep(uint32_t ms)
#endif
}
#ifndef __ANDROID__
float platform_get_default_scale()
{
return 1;
}
#endif
void core_init()
{
static bool initialised = false;
@@ -269,7 +223,7 @@ void core_init()
initialised = true;
#ifdef __ANDROID__
platform_android_init_class_loader();
Platform::AndroidInitClassLoader();
#endif // __ANDROID__
platform_ticks_init();

View File

@@ -70,26 +70,6 @@ bool platform_ensure_directory_exists(const utf8* path)
return success != FALSE;
}
bool platform_directory_delete(const utf8* path)
{
// Needs to be double-null terminated as pFrom is a null terminated array of strings
auto wPath = String::ToWideChar(path) + L"\0";
SHFILEOPSTRUCTW fileop;
fileop.hwnd = nullptr; // no status display
fileop.wFunc = FO_DELETE; // delete operation
fileop.pFrom = wPath.c_str(); // source file name as double null terminated string
fileop.pTo = nullptr; // no destination needed
fileop.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; // do not prompt the user
fileop.fAnyOperationsAborted = FALSE;
fileop.lpszProgressTitle = nullptr;
fileop.hNameMappings = nullptr;
int32_t ret = SHFileOperationW(&fileop);
return (ret == 0);
}
bool platform_lock_single_instance()
{
HANDLE mutex, status;
@@ -116,36 +96,6 @@ int32_t platform_get_drives()
return GetLogicalDrives();
}
bool platform_get_steam_path(utf8* outPath, size_t outSize)
{
wchar_t* wSteamPath;
HKEY hKey;
DWORD type, size;
LRESULT result;
if (RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", &hKey) != ERROR_SUCCESS)
return false;
// Get the size of the path first
if (RegQueryValueExW(hKey, L"SteamPath", nullptr, &type, nullptr, &size) != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return false;
}
wSteamPath = reinterpret_cast<wchar_t*>(malloc(size));
result = RegQueryValueExW(hKey, L"SteamPath", nullptr, &type, reinterpret_cast<LPBYTE>(wSteamPath), &size);
if (result == ERROR_SUCCESS)
{
auto utf8SteamPath = String::ToUtf8(wSteamPath);
safe_strcpy(outPath, utf8SteamPath.c_str(), outSize);
safe_strcat_path(outPath, "steamapps\\common", outSize);
}
free(wSteamPath);
RegCloseKey(hKey);
return result == ERROR_SUCCESS;
}
std::string platform_get_rct1_steam_dir()
{
return "Rollercoaster Tycoon Deluxe";
@@ -176,127 +126,6 @@ time_t platform_file_get_modified_time(const utf8* path)
return 0;
}
MeasurementFormat platform_get_locale_measurement_format()
{
UINT measurement_system;
if (GetLocaleInfo(
LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, reinterpret_cast<LPSTR>(&measurement_system),
sizeof(measurement_system))
== 0)
{
return MeasurementFormat::Metric;
}
switch (measurement_system)
{
case 1:
return MeasurementFormat::Imperial;
case 0:
default:
return MeasurementFormat::Metric;
}
}
TemperatureUnit platform_get_locale_temperature_format()
{
UINT fahrenheit;
// GetLocaleInfo will set fahrenheit to 1 if the locale on this computer
// uses the United States measurement system or 0 otherwise.
if (GetLocaleInfo(
LOCALE_USER_DEFAULT, LOCALE_IMEASURE | LOCALE_RETURN_NUMBER, reinterpret_cast<LPSTR>(&fahrenheit),
sizeof(fahrenheit))
== 0)
{
// Assume celsius by default if function call fails
return TemperatureUnit::Celsius;
}
if (fahrenheit)
return TemperatureUnit::Fahrenheit;
return TemperatureUnit::Celsius;
}
uint8_t platform_get_locale_date_format()
{
# if _WIN32_WINNT >= 0x0600
// Retrieve short date format, eg "MM/dd/yyyy"
wchar_t dateFormat[20];
if (GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SSHORTDATE, dateFormat, static_cast<int>(std::size(dateFormat))) == 0)
{
return DATE_FORMAT_DAY_MONTH_YEAR;
}
// The only valid characters for format types are: dgyM
// We try to find 3 strings of format types, ignore any characters in between.
// We also ignore 'g', as it represents 'era' and we don't have that concept
// in our date formats.
// https://msdn.microsoft.com/en-us/library/windows/desktop/dd317787(v=vs.85).aspx
//
wchar_t first[sizeof(dateFormat)];
wchar_t second[sizeof(dateFormat)];
if (swscanf_s(
dateFormat, L"%l[dyM]%*l[^dyM]%l[dyM]%*l[^dyM]%*l[dyM]", first, static_cast<uint32_t>(std::size(first)), second,
static_cast<uint32_t>(std::size(second)))
!= 2)
{
return DATE_FORMAT_DAY_MONTH_YEAR;
}
if (wcsncmp(L"d", first, 1) == 0)
{
return DATE_FORMAT_DAY_MONTH_YEAR;
}
if (wcsncmp(L"M", first, 1) == 0)
{
return DATE_FORMAT_MONTH_DAY_YEAR;
}
if (wcsncmp(L"y", first, 1) == 0)
{
if (wcsncmp(L"d", second, 1) == 0)
{
return DATE_FORMAT_YEAR_DAY_MONTH;
}
// Closest possible option
return DATE_FORMAT_YEAR_MONTH_DAY;
}
# endif
// Default fallback
return DATE_FORMAT_DAY_MONTH_YEAR;
}
# ifndef NO_TTF
bool platform_get_font_path(TTFFontDescriptor* font, utf8* buffer, size_t size)
{
# if !defined(__MINGW32__) \
&& ((NTDDI_VERSION >= NTDDI_VISTA) && !defined(_USING_V110_SDK71_) && !defined(_ATL_XP_TARGETING))
wchar_t* fontFolder;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Fonts, 0, nullptr, &fontFolder)))
{
// Convert wchar to utf8, then copy the font folder path to the buffer.
auto outPathTemp = String::ToUtf8(fontFolder);
safe_strcpy(buffer, outPathTemp.c_str(), size);
CoTaskMemFree(fontFolder);
// Append the requested font's file name.
safe_strcat_path(buffer, font->filename, size);
return true;
}
return false;
# else
log_warning("Compatibility hack: falling back to C:\\Windows\\Fonts");
safe_strcpy(buffer, "C:\\Windows\\Fonts\\", size);
safe_strcat_path(buffer, font->filename, size);
return true;
# endif
}
# endif // NO_TTF
std::string platform_get_absolute_path(const utf8* relativePath, const utf8* basePath)
{
std::string result;
@@ -338,26 +167,6 @@ datetime64 platform_get_datetime_now_utc()
return utcNow;
}
bool platform_process_is_elevated()
{
BOOL isElevated = FALSE;
HANDLE hToken = nullptr;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
{
TOKEN_ELEVATION Elevation;
DWORD tokenSize = sizeof(TOKEN_ELEVATION);
if (GetTokenInformation(hToken, TokenElevation, &Elevation, sizeof(Elevation), &tokenSize))
{
isElevated = Elevation.TokenIsElevated;
}
}
if (hToken)
{
CloseHandle(hToken);
}
return isElevated;
}
///////////////////////////////////////////////////////////////////////////////
// URI protocol association setup
///////////////////////////////////////////////////////////////////////////////

View File

@@ -1,82 +0,0 @@
/*****************************************************************************
* Copyright (c) 2014-2020 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#if defined(__APPLE__) && defined(__MACH__)
# include "../config/Config.h"
# include "../core/Path.hpp"
# include "../localisation/Language.h"
# include "../util/Util.h"
# include "platform.h"
// undefine `interface` and `abstract`, because it's causing conflicts with Objective-C's keywords
# undef interface
# undef abstract
# import <AppKit/AppKit.h>
# import <Foundation/Foundation.h>
# include <mach-o/dyld.h>
# include <pwd.h>
# ifndef NO_TTF
bool platform_get_font_path(TTFFontDescriptor* font, utf8* buffer, size_t size)
{
@autoreleasepool
{
CTFontDescriptorRef fontRef = CTFontDescriptorCreateWithNameAndSize(
static_cast<CFStringRef>([NSString stringWithUTF8String:font->font_name]), 0.0);
CFURLRef url = static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(fontRef, kCTFontURLAttribute));
if (url)
{
NSString* fontPath = [NSString stringWithString:[static_cast<NSURL*>(CFBridgingRelease(url)) path]];
safe_strcpy(buffer, fontPath.UTF8String, size);
return true;
}
else
{
return false;
}
}
}
# endif // NO_TTF
MeasurementFormat platform_get_locale_measurement_format()
{
@autoreleasepool
{
NSNumber* metricSystem = [[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem];
if (metricSystem.boolValue)
{
return MeasurementFormat::Metric;
}
return MeasurementFormat::Imperial;
}
}
bool platform_get_steam_path(utf8* outPath, size_t outSize)
{
char steamPath[1024] = { 0 };
const char* homeDir = getpwuid(getuid())->pw_dir;
if (homeDir != NULL)
{
safe_strcpy(steamPath, homeDir, sizeof(steamPath));
safe_strcat_path(
steamPath, "Library/Application Support/Steam/Steam.AppBundle/Steam/Contents/MacOS/steamapps", sizeof(steamPath));
if (Path::DirectoryExists(steamPath))
{
safe_strcpy(outPath, steamPath, outSize);
return true;
}
}
return false;
}
#endif

View File

@@ -82,14 +82,12 @@ struct file_dialog_desc
};
// Platform shared definitions
void platform_update_palette(const uint8_t* colours, int32_t start_index, int32_t num_colours);
void platform_toggle_windowed_mode();
void platform_refresh_video(bool recreate_window);
// Platform specific definitions
time_t platform_file_get_modified_time(const utf8* path);
bool platform_ensure_directory_exists(const utf8* path);
bool platform_directory_delete(const utf8* path);
std::string platform_get_absolute_path(const utf8* relative_path, const utf8* base_path);
bool platform_lock_single_instance();
@@ -100,22 +98,11 @@ void platform_sleep(uint32_t ms);
void platform_get_user_directory(utf8* outPath, const utf8* subDirectory, size_t outSize);
bool platform_open_common_file_dialog(utf8* outFilename, file_dialog_desc* desc, size_t outSize);
utf8* platform_open_directory_browser(const utf8* title);
MeasurementFormat platform_get_locale_measurement_format();
TemperatureUnit platform_get_locale_temperature_format();
uint8_t platform_get_locale_date_format();
bool platform_process_is_elevated();
bool platform_get_steam_path(utf8* outPath, size_t outSize);
std::string platform_get_rct1_steam_dir();
std::string platform_get_rct2_steam_dir();
#ifndef NO_TTF
bool platform_get_font_path(TTFFontDescriptor* font, utf8* buffer, size_t size);
#endif // NO_TTF
datetime64 platform_get_datetime_now_utc();
float platform_get_default_scale();
// Called very early in the program before parsing commandline arguments.
void core_init();
@@ -137,17 +124,3 @@ bool platform_setup_uri_protocol();
// as it requires external linkage, which 'static' prevents
__declspec(dllexport) int32_t StartOpenRCT2(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int32_t nCmdShow);
#endif // _WIN32
#ifdef __ANDROID__
class AndroidClassLoader
{
public:
AndroidClassLoader();
~AndroidClassLoader();
static jobject _classLoader;
static jmethodID _findClassMethod;
};
void platform_android_init_class_loader();
jclass platform_android_find_class(JNIEnv* env, const char* name);
#endif // __ANDROID__

View File

@@ -389,7 +389,7 @@ static void scenario_update_daynight_cycle()
// Only update palette if day / night cycle has changed
if (gDayNightCycle != currentDayNightCycle)
{
platform_update_palette(gGamePalette, 10, 236);
UpdatePalette(gGamePalette, 10, 236);
}
}

View File

@@ -90,7 +90,7 @@ namespace TitleSequenceManager
}
else
{
platform_directory_delete(path);
Path::DeleteDirectory(path);
}
_items.erase(_items.begin() + i);
}