mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-27 01:13:13 +08:00
532 lines
20 KiB
C++
532 lines
20 KiB
C++
// Released under the MIT License. See LICENSE for details.
|
|
|
|
#include "ballistica/generic/utils.h"
|
|
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
#include "ballistica/app/app.h"
|
|
#include "ballistica/generic/huffman.h"
|
|
#include "ballistica/generic/json.h"
|
|
#include "ballistica/generic/utf8.h"
|
|
#include "ballistica/math/vector3f.h"
|
|
#include "ballistica/platform/platform.h"
|
|
#include "ballistica/scene/scene.h"
|
|
|
|
// FIXME: Cleaner to add the lib to the project(s) instead?
|
|
#if BA_OSTYPE_WINDOWS
|
|
#pragma comment(lib, "Ws2_32.lib")
|
|
#endif
|
|
|
|
namespace ballistica {
|
|
|
|
#define USE_BAKED_RANDS 1
|
|
|
|
#if BA_OSTYPE_WINDOWS
|
|
#endif
|
|
|
|
#if USE_BAKED_RANDS
|
|
float Utils::precalc_rands_1_[kPrecalcRandsCount] = {
|
|
0.00424972f, 0.0470216f, 0.545227f, 0.538243f, 0.214183f, 0.627205f,
|
|
0.194698f, 0.917583f, 0.468622f, 0.0779965f, 0.304211f, 0.773231f,
|
|
0.522742f, 0.378898f, 0.404598f, 0.468434f, 0.081512f, 0.408348f,
|
|
0.0808838f, 0.427364f, 0.226629f, 0.234887f, 0.516467f, 0.0457478f,
|
|
0.455418f, 0.194083f, 0.502244f, 0.0733989f, 0.458193f, 0.898715f,
|
|
0.624819f, 0.70762f, 0.759858f, 0.559276f, 0.956318f, 0.408562f,
|
|
0.206264f, 0.322909f, 0.293165f, 0.524073f, 0.407753f, 0.961242f,
|
|
0.278234f, 0.423968f, 0.631937f, 0.534858f, 0.842336f, 0.786993f,
|
|
0.934668f, 0.739984f, 0.968577f, 0.468159f, 0.804702f, 0.0686368f,
|
|
0.397594f, 0.60871f, 0.485322f, 0.907066f, 0.587516f, 0.364387f,
|
|
0.791611f, 0.899199f, 0.0186556f, 0.446891f, 0.0138f, 0.999024f,
|
|
0.556364f, 0.29821f, 0.23943f, 0.338024f, 0.157135f, 0.25299f,
|
|
0.791138f, 0.367175f, 0.584245f, 0.496136f, 0.358228f, 0.280143f,
|
|
0.538658f, 0.190721f, 0.656737f, 0.010905f, 0.520343f, 0.678249f,
|
|
0.930145f, 0.823978f, 0.457201f, 0.988418f, 0.854635f, 0.955912f,
|
|
0.0226999f, 0.183605f, 0.838141f, 0.210646f, 0.160344f, 0.111269f,
|
|
0.348488f, 0.648031f, 0.844362f, 0.65157f, 0.0598469f, 0.952439f,
|
|
0.265193f, 0.768256f, 0.773861f, 0.723251f, 0.53157f, 0.36183f,
|
|
0.485393f, 0.348683f, 0.551617f, 0.648207f, 0.656125f, 0.879799f,
|
|
0.0674501f, 0.000782927f, 0.607129f, 0.116035f, 0.67095f, 0.692934f,
|
|
0.276618f, 0.137535f, 0.771033f, 0.278625f, 0.686023f, 0.873823f,
|
|
0.254666f, 0.75378f};
|
|
float Utils::precalc_rands_2_[kPrecalcRandsCount] = {
|
|
0.425019f, 0.29261f, 0.623541f, 0.241628f, 0.772656f, 0.434116f,
|
|
0.295335f, 0.814317f, 0.122326f, 0.887651f, 0.873536f, 0.692463f,
|
|
0.730894f, 0.142115f, 0.0722184f, 0.977652f, 0.971393f, 0.111517f,
|
|
0.41341f, 0.699999f, 0.955932f, 0.746667f, 0.267962f, 0.883952f,
|
|
0.202871f, 0.952115f, 0.221069f, 0.616162f, 0.842076f, 0.705628f,
|
|
0.332754f, 0.974675f, 0.940277f, 0.756059f, 0.831943f, 0.70631f,
|
|
0.674705f, 0.13903f, 0.22751f, 0.0875125f, 0.101364f, 0.593826f,
|
|
0.271567f, 0.63593f, 0.970994f, 0.359381f, 0.147583f, 0.987353f,
|
|
0.960315f, 0.904639f, 0.874661f, 0.352573f, 0.630782f, 0.578075f,
|
|
0.364932f, 0.588095f, 0.799978f, 0.0502811f, 0.379093f, 0.252171f,
|
|
0.598992f, 0.843808f, 0.544584f, 0.895444f, 0.935885f, 0.592526f,
|
|
0.810681f, 0.0200064f, 0.0986983f, 0.164623f, 0.975185f, 0.0102097f,
|
|
0.648763f, 0.114897f, 0.400273f, 0.549732f, 0.732205f, 0.363931f,
|
|
0.223837f, 0.4427f, 0.770981f, 0.280827f, 0.407232f, 0.323108f,
|
|
0.9429f, 0.594368f, 0.175995f, 0.34f, 0.857507f, 0.016013f,
|
|
0.516969f, 0.847756f, 0.638805f, 0.324338f, 0.897038f, 0.0950314f,
|
|
0.0460401f, 0.449791f, 0.189096f, 0.931966f, 0.846644f, 0.64728f,
|
|
0.096389f, 0.075902f, 0.27798f, 0.673576f, 0.102553f, 0.275159f,
|
|
0.00170948f, 0.319388f, 0.0328678f, 0.411649f, 0.496922f, 0.778794f,
|
|
0.634341f, 0.158655f, 0.0157559f, 0.195268f, 0.663882f, 0.148622f,
|
|
0.118159f, 0.552174f, 0.757064f, 0.854851f, 0.991449f, 0.349681f,
|
|
0.17858f, 0.774876f};
|
|
float Utils::precalc_rands_3_[kPrecalcRandsCount] = {
|
|
0.29369f, 0.894838f, 0.857948f, 0.04309f, 0.0296678f, 0.180115f,
|
|
0.694884f, 0.227017f, 0.936936f, 0.746493f, 0.511976f, 0.231185f,
|
|
0.1333f, 0.524805f, 0.774586f, 0.395971f, 0.206664f, 0.274414f,
|
|
0.178939f, 0.88643f, 0.346536f, 0.22934f, 0.635988f, 0.589186f,
|
|
0.652835f, 0.195603f, 0.504794f, 0.831229f, 0.769911f, 0.494712f,
|
|
0.60128f, 0.367987f, 0.239279f, 0.0791311f, 0.469948f, 0.948189f,
|
|
0.760893f, 0.670452f, 0.753765f, 0.822003f, 0.628783f, 0.432039f,
|
|
0.226478f, 0.0678665f, 0.497384f, 0.110421f, 0.428975f, 0.446298f,
|
|
0.00813589f, 0.2634f, 0.434728f, 0.693152f, 0.547276f, 0.702469f,
|
|
0.407723f, 0.11742f, 0.235373f, 0.0738137f, 0.410148f, 0.231855f,
|
|
0.256911f, 0.879873f, 0.818198f, 0.73404f, 0.423038f, 0.577114f,
|
|
0.116636f, 0.247292f, 0.822178f, 0.817466f, 0.940992f, 0.593788f,
|
|
0.751732f, 0.0681611f, 0.38832f, 0.352672f, 0.174289f, 0.582884f,
|
|
0.0338663f, 0.460085f, 0.869757f, 0.854794f, 0.35513f, 0.477297f,
|
|
0.31343f, 0.545157f, 0.943892f, 0.383522f, 0.121732f, 0.131018f,
|
|
0.690497f, 0.231025f, 0.395681f, 0.144711f, 0.521456f, 0.192024f,
|
|
0.796611f, 0.64258f, 0.13998f, 0.560008f, 0.549709f, 0.831634f,
|
|
0.010101f, 0.684939f, 0.00884889f, 0.796426f, 0.603282f, 0.591985f,
|
|
0.731204f, 0.950351f, 0.408559f, 0.592352f, 0.76991f, 0.196648f,
|
|
0.376926f, 0.508574f, 0.809908f, 0.862359f, 0.863431f, 0.884588f,
|
|
0.895885f, 0.391311f, 0.976098f, 0.473118f, 0.286659f, 0.0946781f,
|
|
0.402437f, 0.347471f};
|
|
#else // USE_BAKED_RANDS
|
|
float Utils::precalc_rands_1_[kPrecalcRandsCount];
|
|
float Utils::precalc_rands_2_[kPrecalcRandsCount];
|
|
float Utils::precalc_rands_3_[kPrecalcRandsCount];
|
|
#endif // USE_BAKED_RANDS
|
|
|
|
Utils::Utils() {
|
|
// Is this gonna be consistent cross-platform?... :-/
|
|
srand(543); // NOLINT
|
|
|
|
// Test our static-type-name functionality.
|
|
// This code runs at compile time and extracts human readable type names using
|
|
// __PRETTY_FUNCTION__ type functionality. However, it is dependent on
|
|
// specific compiler output and so could break easily if anything changes.
|
|
// Here we add some compile-time checks to alert us if that happens.
|
|
|
|
// Remember that results can vary per compiler; make sure we match
|
|
// any one of the expected formats.
|
|
static_assert(
|
|
static_type_name_constexpr<decltype(g_app)>() == "ballistica::App *"
|
|
|| static_type_name_constexpr<decltype(g_app)>() == "ballistica::App*"
|
|
|| static_type_name_constexpr<decltype(g_app)>()
|
|
== "class ballistica::App*"
|
|
|| static_type_name_constexpr<decltype(g_app)>() == "App*");
|
|
Object::Ref<Node> testnode{};
|
|
static_assert(
|
|
static_type_name_constexpr<decltype(testnode)>()
|
|
== "ballistica::Object::Ref<ballistica::Node>"
|
|
|| static_type_name_constexpr<decltype(testnode)>()
|
|
== "class ballistica::Object::Ref<class ballistica::Node>"
|
|
|| static_type_name_constexpr<decltype(testnode)>()
|
|
== "Object::Ref<Node>");
|
|
|
|
// int testint{};
|
|
// static_assert(static_type_name_constexpr<decltype(testint)>() == "int");
|
|
|
|
// If anything above breaks, enable this code to debug/fix it.
|
|
// This will print a calculated type name as well as the full string
|
|
// it was parsed from. Use this to adjust the filtering as necessary so
|
|
// the resulting type name matches what is expected.
|
|
if (explicit_bool(false)) {
|
|
Log(LogLevel::kError,
|
|
"static_type_name check; name is '"
|
|
+ static_type_name<decltype(testnode)>() + "' debug_full is '"
|
|
+ static_type_name<decltype(testnode)>(true) + "'");
|
|
}
|
|
|
|
// We now bake these in so they match across platforms...
|
|
#if USE_BAKED_RANDS
|
|
#else
|
|
// set up our precalculated rand vals
|
|
for (int i = 0; i < kPrecalcRandsCount; i++) {
|
|
precalc_rands_1_[i] = static_cast<float>(rand()) / RAND_MAX; // NOLINT
|
|
precalc_rands_2_[i] = static_cast<float>(rand()) / RAND_MAX; // NOLINT
|
|
precalc_rands_3_[i] = static_cast<float>(rand()) / RAND_MAX; // NOLINT
|
|
}
|
|
#endif
|
|
huffman_ = std::make_unique<Huffman>();
|
|
}
|
|
|
|
Utils::~Utils() = default;
|
|
|
|
auto Utils::StringReplaceOne(std::string* target, const std::string& key,
|
|
const std::string& replacement) -> bool {
|
|
assert(target != nullptr);
|
|
size_t pos = target->find(key);
|
|
if (pos != std::string::npos) {
|
|
target->replace(pos, key.size(), replacement);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// from https://stackoverflow.com/questions/5343190/
|
|
// how-do-i-replace-all-instances-of-a-string-with-another-string/14678800
|
|
auto Utils::StringReplaceAll(std::string* target, const std::string& key,
|
|
const std::string& replacement) -> void {
|
|
assert(target != nullptr);
|
|
if (key.empty()) {
|
|
return;
|
|
}
|
|
std::string ws_ret;
|
|
ws_ret.reserve(target->length());
|
|
size_t start_pos = 0, pos;
|
|
while ((pos = target->find(key, start_pos)) != std::string::npos) {
|
|
ws_ret += target->substr(start_pos, pos - start_pos);
|
|
ws_ret += replacement;
|
|
pos += key.length();
|
|
start_pos = pos;
|
|
}
|
|
ws_ret += target->substr(start_pos);
|
|
target->swap(ws_ret); // faster than str = ws_ret;
|
|
}
|
|
|
|
auto Utils::IsValidUTF8(const std::string& val) -> bool {
|
|
std::string out = Utils::GetValidUTF8(val.c_str(), "bsivu8");
|
|
return (out == val);
|
|
}
|
|
|
|
static auto utf8_check_is_valid(const std::string& string) -> bool {
|
|
int c, i, ix, n, j;
|
|
for (i = 0, ix = static_cast<int>(string.length()); i < ix; i++) {
|
|
c = (unsigned char)string[i];
|
|
// if (c==0x09 || c==0x0a || c==0x0d
|
|
// || (0x20 <= c && c <= 0x7e) ) n = 0; // is_printable_ascii
|
|
if (0x00 <= c && c <= 0x7f) {
|
|
n = 0; // 0bbbbbbb
|
|
} else if ((c & 0xE0) == 0xC0) { // NOLINT
|
|
n = 1; // 110bbbbb
|
|
} else if (c == 0xed && i < (ix - 1)
|
|
&& ((unsigned char)string[i + 1] & 0xa0) == 0xa0) { // NOLINT
|
|
return false; // U+d800 to U+dfff
|
|
} else if ((c & 0xF0) == 0xE0) { // NOLINT
|
|
n = 2; // 1110bbbb
|
|
} else if ((c & 0xF8) == 0xF0) { // NOLINT
|
|
n = 3; // 11110bbb
|
|
} else {
|
|
// else if (($c & 0xFC) == 0xF8)
|
|
// n=4; // 111110bb //byte 5, unnecessary in 4 byte UTF-8
|
|
// else if (($c & 0xFE) == 0xFC)
|
|
// n=5; // 1111110b //byte 6, unnecessary in 4 byte UTF-8
|
|
|
|
return false;
|
|
}
|
|
for (j = 0; j < n && i < ix; j++) { // n bytes matching 10bbbbbb follow ?
|
|
// NOLINTNEXTLINE
|
|
if ((++i == ix) || (((unsigned char)string[i] & 0xC0) != 0x80)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// added by ericf from http://stackoverflow.com/questions/17316506/
|
|
// strip-invalid-utf8-from-string-in-c-c
|
|
// static std::string correct_non_utf_8(std::string *str) {
|
|
auto Utils::GetValidUTF8(const char* str, const char* loc) -> std::string {
|
|
int i, f_size = static_cast<int>(strlen(str));
|
|
unsigned char c, c2 = 0, c3, c4;
|
|
std::string to;
|
|
to.reserve(static_cast<size_t>(f_size));
|
|
|
|
// ok, it seems we're somehow letting some funky utf8 through that's
|
|
// causing crashes.. for now lets try this all-or-nothing func and return
|
|
// ascii only if it fails
|
|
if (!utf8_check_is_valid(str)) {
|
|
// now strip out anything but normal ascii...
|
|
for (i = 0; i < f_size; i++) {
|
|
c = (unsigned char)(str)[i];
|
|
if (c < 127) { // normal ASCII
|
|
to.append(1, static_cast<char>(c));
|
|
}
|
|
}
|
|
|
|
// phone home a few times for bad strings
|
|
static int logged_count = 0;
|
|
if (logged_count < 10) {
|
|
std::string log_str;
|
|
for (i = 0; i < f_size; i++) {
|
|
c = (unsigned char)(str)[i];
|
|
log_str += std::to_string(static_cast<int>(c));
|
|
if (i + 1 < f_size) {
|
|
log_str += ',';
|
|
}
|
|
}
|
|
logged_count++;
|
|
Log(LogLevel::kError, "GOT INVALID UTF8 SEQUENCE: (" + log_str
|
|
+ "); RETURNING '" + to + "'; LOC '" + loc
|
|
+ "'");
|
|
}
|
|
|
|
} else {
|
|
for (i = 0; i < f_size; i++) {
|
|
c = (unsigned char)(str)[i];
|
|
if (c < 32) { // control char
|
|
if (c == 9 || c == 10 || c == 13) { // allow only \t \n \r
|
|
to.append(1, static_cast<char>(c));
|
|
}
|
|
continue;
|
|
} else if (c < 127) { // normal ASCII
|
|
to.append(1, static_cast<char>(c));
|
|
continue;
|
|
} else if (c < 160) {
|
|
// control char (nothing should be defined here either
|
|
// ASCI, ISO_8859-1 or UTF8, so skipping)
|
|
if (c2 == 128) { // fix microsoft mess, add euro
|
|
to.append(1, static_cast<char>((unsigned char)(226)));
|
|
to.append(1, static_cast<char>((unsigned char)(130)));
|
|
to.append(1, static_cast<char>((unsigned char)(172)));
|
|
}
|
|
if (c2 == 133) { // fix IBM mess, add NEL = \n\r
|
|
to.append(1, 10);
|
|
to.append(1, 13);
|
|
}
|
|
continue;
|
|
} else if (c < 192) { // invalid for UTF8, converting ASCII
|
|
to.append(1, static_cast<char>((unsigned char)194));
|
|
to.append(1, static_cast<char>(c));
|
|
continue;
|
|
} else if (c < 194) { // invalid for UTF8, converting ASCII
|
|
to.append(1, static_cast<char>((unsigned char)195));
|
|
to.append(1, c - 64);
|
|
continue;
|
|
} else if (c < 224 && i + 1 < f_size) { // possibly 2byte UTF8
|
|
c2 = (unsigned char)(str)[i + 1];
|
|
if (c2 > 127 && c2 < 192) { // valid 2byte UTF8
|
|
if (c == 194 && c2 < 160) { // control char, skipping
|
|
} else {
|
|
to.append(1, static_cast<char>(c));
|
|
to.append(1, static_cast<char>(c2));
|
|
}
|
|
i++;
|
|
continue;
|
|
}
|
|
} else if (c < 240 && i + 2 < f_size) { // possibly 3byte UTF8
|
|
c2 = (unsigned char)(str)[i + 1];
|
|
c3 = (unsigned char)(str)[i + 2];
|
|
if (c2 > 127 && c2 < 192 && c3 > 127 && c3 < 192) { // valid 3byte UTF8
|
|
to.append(1, static_cast<char>(c));
|
|
to.append(1, static_cast<char>(c2));
|
|
to.append(1, static_cast<char>(c3));
|
|
i += 2;
|
|
continue;
|
|
}
|
|
} else if (c < 245 && i + 3 < f_size) { // possibly 4byte UTF8
|
|
c2 = (unsigned char)(str)[i + 1];
|
|
c3 = (unsigned char)(str)[i + 2];
|
|
c4 = (unsigned char)(str)[i + 3];
|
|
if (c2 > 127 && c2 < 192 && c3 > 127 && c3 < 192 && c4 > 127
|
|
&& c4 < 192) {
|
|
// valid 4byte UTF8
|
|
to.append(1, static_cast<char>(c));
|
|
to.append(1, static_cast<char>(c2));
|
|
to.append(1, static_cast<char>(c3));
|
|
to.append(1, static_cast<char>(c4));
|
|
i += 3;
|
|
continue;
|
|
}
|
|
}
|
|
// invalid UTF8, converting ASCII
|
|
// (c>245 || string too short for multi-byte))
|
|
to.append(1, static_cast<char>((unsigned char)195));
|
|
to.append(1, c - 64);
|
|
}
|
|
}
|
|
return to;
|
|
}
|
|
|
|
auto Utils::UTF8StringLength(const char* val) -> int {
|
|
std::string valid_str = GetValidUTF8(val, "gusl1");
|
|
return u8_strlen(valid_str.c_str());
|
|
}
|
|
|
|
auto Utils::GetUTF8Value(const char* c) -> uint32_t {
|
|
int offset = 0;
|
|
uint32_t val = u8_nextchar(c, &offset);
|
|
|
|
// Hack: allow showing euro even if we don't support unicode font rendering.
|
|
if (!g_buildconfig.enable_os_font_rendering()) {
|
|
if (val == 8364) {
|
|
val = 0xE000;
|
|
}
|
|
}
|
|
return val;
|
|
}
|
|
|
|
auto Utils::UTF8FromUnicode(std::vector<uint32_t> unichars) -> std::string {
|
|
int buffer_size = static_cast<int>(unichars.size() * 4 + 1);
|
|
// at most 4 chars per unichar plus ending zero
|
|
std::vector<char> buffer(static_cast<size_t>(buffer_size));
|
|
int len = u8_toutf8(buffer.data(), buffer_size, unichars.data(),
|
|
static_cast<int>(unichars.size()));
|
|
assert(len == unichars.size());
|
|
buffer.resize(strlen(buffer.data()) + 1);
|
|
return buffer.data();
|
|
}
|
|
|
|
auto Utils::UnicodeFromUTF8(const std::string& s_in, const char* loc)
|
|
-> std::vector<uint32_t> {
|
|
std::string s = GetValidUTF8(s_in.c_str(), loc);
|
|
// worst case every char is a character (plus trailing 0)
|
|
std::vector<uint32_t> vals(s.size() + 1);
|
|
int converted = u8_toucs(&vals[0], static_cast<int>(vals.size()), s.c_str(),
|
|
static_cast<int>(s.size()));
|
|
vals.resize(static_cast<size_t>(converted));
|
|
return vals;
|
|
}
|
|
|
|
auto Utils::UTF8FromUnicodeChar(uint32_t c) -> std::string {
|
|
char buffer[10];
|
|
u8_toutf8(buffer, sizeof(buffer), &c, 1);
|
|
return buffer;
|
|
}
|
|
|
|
void Utils::AdvanceUTF8(const char** c) {
|
|
int offset = 0;
|
|
u8_nextchar(*c, &offset);
|
|
*c += offset;
|
|
}
|
|
|
|
auto Utils::GetJSONString(const char* s) -> std::string {
|
|
std::string str;
|
|
cJSON* str_obj = cJSON_CreateString(s);
|
|
char* str_buffer = cJSON_PrintUnformatted(str_obj);
|
|
str = str_buffer;
|
|
free(str_buffer);
|
|
cJSON_Delete(str_obj);
|
|
return str;
|
|
}
|
|
|
|
auto Utils::PtrToString(const void* val) -> std::string {
|
|
char buffer[128];
|
|
snprintf(buffer, sizeof(buffer), "%p", val);
|
|
return buffer;
|
|
}
|
|
|
|
// FIXME: This should not live here.
|
|
static const char* g_default_random_names[] = {
|
|
"Flopsy", "Skippy", "Boomer", "Jolly", "Zeus", "Garth",
|
|
"Dizzy", "Mullet", "Ogre", "Ginger", "Nippy", "Murphy",
|
|
"Crom", "Sparky", "Wedge", "Arthur", "Benji", "Pan",
|
|
"Wallace", "Hamish", "Luke", "Cowboy", "Uncas", "Magua",
|
|
"Robin", "Lancelot", "Mad Dog", "Maximus", "Leonidas", "Don Quixote",
|
|
"Beowulf", "Gilgamesh", "Conan", "Cicero", "Elmer", "Flynn",
|
|
"Duck", "Uther", "Darkness", "Sunshine", "Willy", "Elvis",
|
|
"Dolph", "Rico", "Magoogan", "Willow", "Rose", "Egg",
|
|
"Thunder", "Jack", "Dude", "Walter", "Donny", "Larry",
|
|
"Chunk", "Socrates", nullptr};
|
|
|
|
static std::list<std::string>* g_random_names_list = nullptr;
|
|
|
|
auto Utils::GetRandomNameList() -> const std::list<std::string>& {
|
|
assert(InLogicThread());
|
|
if (g_random_names_list == nullptr) {
|
|
// This will init the list with our default english names.
|
|
SetRandomNameList(std::list<std::string>(1, "DEFAULT_NAMES"));
|
|
}
|
|
|
|
// Clion incorrectly thinks this might be null.
|
|
#pragma clang diagnostic push
|
|
#pragma ide diagnostic ignored "NullDereferences"
|
|
if (g_random_names_list != nullptr) {
|
|
return *g_random_names_list;
|
|
}
|
|
throw Exception("random name list uninited");
|
|
#pragma clang diagnostic pop
|
|
}
|
|
|
|
void Utils::SetRandomNameList(const std::list<std::string>& custom_names) {
|
|
assert(InLogicThread());
|
|
if (!g_random_names_list) {
|
|
g_random_names_list = new std::list<std::string>;
|
|
} else {
|
|
g_random_names_list->clear();
|
|
}
|
|
bool add_default_names = false;
|
|
if (custom_names.empty()) {
|
|
add_default_names = true;
|
|
}
|
|
for (const auto& custom_name : custom_names) {
|
|
if (custom_name == "DEFAULT_NAMES") {
|
|
add_default_names = true;
|
|
} else {
|
|
g_random_names_list->push_back(custom_name);
|
|
}
|
|
}
|
|
if (add_default_names) {
|
|
for (const char** c = g_default_random_names; *c != nullptr; c++) {
|
|
g_random_names_list->push_back(*c);
|
|
}
|
|
}
|
|
}
|
|
|
|
auto Utils::Sphrand(float radius) -> Vector3f {
|
|
while (true) {
|
|
float x = RandomFloat();
|
|
float y = RandomFloat();
|
|
float z = RandomFloat();
|
|
x = -1.0f + x * 2.0f;
|
|
y = -1.0f + y * 2.0f;
|
|
z = -1.0f + z * 2.0f;
|
|
if (x * x + y * y + z * z <= 1.0f) {
|
|
return {x * radius, y * radius, z * radius};
|
|
}
|
|
}
|
|
}
|
|
|
|
auto Utils::FileToString(const std::string& file_name) -> std::string {
|
|
std::ifstream file_stream{file_name};
|
|
if (file_stream.fail()) {
|
|
throw Exception("Error opening file for reading: '" + file_name + "'");
|
|
}
|
|
std::ostringstream str_stream{};
|
|
file_stream >> str_stream.rdbuf();
|
|
if (file_stream.fail() && !file_stream.eof()) {
|
|
throw Exception("Error reading file: '" + file_name + "'");
|
|
}
|
|
return str_stream.str();
|
|
}
|
|
|
|
static void WaitThenDie(millisecs_t wait, const std::string& action) {
|
|
Platform::SleepMS(wait);
|
|
throw std::runtime_error("Timed out waiting for " + action + "; aborting.");
|
|
}
|
|
|
|
void Utils::StartSuicideTimer(const std::string& action, millisecs_t delay) {
|
|
if (!g_app->started_suicide) {
|
|
new std::thread(WaitThenDie, delay, action);
|
|
g_app->started_suicide = true;
|
|
}
|
|
}
|
|
|
|
auto Utils::BaseName(const std::string& val) -> std::string {
|
|
const char* c = val.c_str();
|
|
const char* lastvalid = c;
|
|
while (*c != 0) {
|
|
if (*c == '/' || *c == '\\') {
|
|
lastvalid = c + 1;
|
|
}
|
|
++c;
|
|
}
|
|
return lastvalid;
|
|
}
|
|
|
|
auto Utils::StripNonAsciiFromUTF8(const std::string& str) -> std::string {
|
|
auto uni = UnicodeFromUTF8(str, "wGcwe87");
|
|
uni.erase(
|
|
std::remove_if(uni.begin(), uni.end(), [](int i) { return i > 127; }),
|
|
uni.end());
|
|
return UTF8FromUnicode(uni);
|
|
}
|
|
|
|
} // namespace ballistica
|