gdle/Source/Util.cpp
Morosity 0101b3ea59 Fix up client commands for starting/stopping events. Now offers more robust feedback if event string is not found.
Does not errantly declare event already active if not found or not active if event not found.
2020-03-18 21:44:35 +00:00

880 lines
19 KiB
C++
Raw Permalink Blame History

#include <StdAfx.h>
#include "TurbineFormats.h"
#include <random>
#if defined(_WIN32)
#pragma comment(lib, "psapi.lib")
#else
#include <sys/sysinfo.h>
#endif
namespace Random
{
static std::mt19937 _generator;
static std::uniform_real_distribution<double> _range_f(0.0f, 1.0f);
int m_iSeed;
void Init()
{
std::random_device rd;
_generator.seed(rd());
m_iSeed = (signed)((unsigned int)(time(0)*12345) << 2) - 144810491;
}
uint32_t GenRandom15()
{
m_iSeed = (m_iSeed * 214013) + 2531011;
uint32_t dwRandom15 = (unsigned)m_iSeed;
dwRandom15 >>= 16;
dwRandom15 &= 0x7FFF;
return dwRandom15;
}
uint32_t GenRandom32()
{
uint32_t dwRandom32 = 0;
dwRandom32 |= GenRandom15();
dwRandom32 <<= 15;
dwRandom32 |= GenRandom15();
dwRandom32 <<= 15;
dwRandom32 |= GenRandom15();
return dwRandom32;
}
uint32_t GenUInt(uint32_t min, uint32_t max)
{
if (max <= min)
return min;
std::uniform_int_distribution<uint32_t> range(min, max);
return range(_generator);
//unsigned int range = max - min;
//return (min + (GenRandom32() % (range + 1)));
}
int32_t GenInt(int32_t min, int32_t max)
{
if (max <= min)
return min;
std::uniform_int_distribution<int32_t> range(min, max);
return range(_generator);
//unsigned int range = (unsigned)(max - min);
//return (min + (int)(GenRandom32() % (range + 1)));
}
double GenFloat()
{
return _range_f(_generator);
}
double GenFloat(double min, double max)
{
if (max <= min)
return min;
double range = max - min;
//double value = min + (range * ((double)GenRandom32() / 0xFFFFFFFF));
double value = min + (range * _range_f(_generator));
return value;
}
float GenFloat(float min, float max)
{
if (max <= min)
return min;
double range = max - min;
//double value = min + (range * ((double)GenRandom32() / 0xFFFFFFFF));
double value = min + (range * _range_f(_generator));
return (float)value;
}
float RollDice(float min, float max)
{
return GenFloat(min, max);
}
}
//void EnumerateFolderFilePaths(std::list<std::string> &results, const char *basePath, const char *fileMask, bool bSubFolders)
//{
// std::string basePathStr(basePath);
// basePathStr += "\\";
//
// WIN32_FIND_DATA data;
// HANDLE hFind = FindFirstFile((basePathStr + fileMask).c_str(), &data);
//
// if (hFind != INVALID_HANDLE_VALUE)
// {
// do
// {
// if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
// {
// continue;
// }
//
// results.push_back(basePathStr + data.cFileName);
//
// } while (FindNextFile(hFind, &data));
//
// CloseHandle(INVALID_HANDLE_VALUE);
// }
//
// if (bSubFolders)
// {
// hFind = FindFirstFile((basePathStr + "*").c_str(), &data);
// if (hFind != INVALID_HANDLE_VALUE)
// {
// do
// {
// if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
// {
// if (!strcmp(data.cFileName, ".") || !strcmp(data.cFileName, ".."))
// continue;
//
// std::string subFolderStr;
// subFolderStr = basePathStr + data.cFileName;
// EnumerateFolderFilePaths(results, subFolderStr.c_str(), fileMask, true);
// continue;
// }
// } while (FindNextFile(hFind, &data));
// CloseHandle(INVALID_HANDLE_VALUE);
// }
// }
//}
char NibbleToChar(int n)
{
if (n < 10)
return '0' + n;
else
return 'a' + (n - 10);
}
char NibbleToCharUCase(int n)
{
if (n < 10)
return '0' + n;
else
return 'A' + (n - 10);
}
char *DataToHexString(const void *input, unsigned int inputlen, char *output)
{
uint8_t *data = (uint8_t *)input;
for (unsigned int i = 0; i < inputlen; i++)
{
output[(i << 1) + 0] = NibbleToChar((data[i] & 0xF0) >> 4);
output[(i << 1) + 1] = NibbleToChar((data[i] & 0x0F) >> 0);
}
output[inputlen << 1] = '\0';
return output;
}
bool LoadDataFromFile(const char *filepath, BYTE **data, uint32_t *length)
{
*data = NULL;
*length = 0;
FILE *fp = fopen(filepath, "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
long _fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (_fileSize < 0)
_fileSize = 0;
uint32_t fileSize = (uint32_t)_fileSize;
BYTE *fileData = new BYTE[fileSize];
fread(fileData, fileSize, 1, fp);
fclose(fp);
*data = fileData;
*length = fileSize;
return true;
}
return false;
}
bool LoadDataFromCompressed_(BYTE *input_data, uint32_t input_length, BYTE **data, uint32_t *length, uint32_t magic1, uint32_t magic2)
{
*data = NULL;
*length = 0;
uint32_t packing = magic1;
for (uint32_t i = 0; i < (input_length >> 2); i++) {
((uint32_t *)input_data)[i] += ((i + 1) * packing);
packing ^= magic2;
}
uint32_t decompressed_size = *((uint32_t *)input_data);
BYTE *compressed_buffer = input_data + sizeof(uint32_t);
uint32_t compressed_size = input_length - sizeof(uint32_t);
*data = new BYTE[decompressed_size];
*length = decompressed_size;
bool success = true;
uLongf ulf = decompressed_size;
if (Z_OK != uncompress(*data, &ulf, compressed_buffer, compressed_size))
{
delete[](*data);
*data = NULL;
*length = 0;
success = false;
}
*length = (uint32_t)ulf;
return success;
}
bool LoadDataFromCompressedFile(const char *filepath, BYTE **data, uint32_t *length, uint32_t magic1, uint32_t magic2)
{
*data = NULL;
*length = 0;
BYTE *input_data = NULL;
uint32_t input_length = 0;
if (LoadDataFromFile(filepath, &input_data, &input_length))
{
bool success = LoadDataFromCompressed_(input_data, input_length, data, length, magic1, magic2);
delete[] input_data;
return success;
}
return false;
}
long FindNeedle(void *haystack, unsigned int haystacklength, void *needle, unsigned int needlelength)
{
if (haystacklength < needlelength)
return -1;
if (!needlelength)
return -1;
BYTE *dataPos = (BYTE *)haystack;
BYTE *dataEnd = (dataPos + haystacklength - needlelength);
bool found = false;
while (dataPos <= dataEnd)
{
if (!memcmp(dataPos, needle, needlelength))
{
found = true;
break;
}
dataPos++;
}
if (!found)
return -1;
return (dataPos - (BYTE *)haystack);
}
// returns a string of "Xmo, Xd, Xh, Xm, Xs"
std::string TimeToString(int seconds)
{
int mo = seconds / 2629800; // seconds in a month
int leftover = seconds % 2629800;
int d = leftover / 86400; // seconds in a day
leftover %= 86400;
int h = leftover / 3600; // seconds in an hour
leftover %= 3600;
int m = leftover / 60; // seconds in a minute
leftover %= 60;
int s = leftover;
std::string out = "";
if (mo)
out += csprintf("%dmo ", mo);
if (d)
out += csprintf("%dd ", d);
if (h)
out += csprintf("%dh ", h);
if (m)
out += csprintf("%dm ", m);
out += csprintf("%ds", s);
return out;
}
bool ReplaceString(std::string& str, const std::string& from, const std::string& to) {
size_t start_pos = str.find(from);
if (start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
std::string ReplaceInString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
static char szReadBuffer[1024];
static char szWriteBuffer[600];
char* csprintf(const char *format, ...)
{
szReadBuffer[0] = 0;
va_list args;
va_start(args, format);
vsnprintf(szReadBuffer, 1024, format, args);
va_end(args);
szReadBuffer[1023] = '\0';
return szReadBuffer;
}
char *timestamp()
{
static char result[64];
tm *beef;
time_t cake;
time(&cake);
beef = localtime(&cake);
if (beef)
sprintf(result, "%.2d:%.2d:%.2d", beef->tm_hour, beef->tm_min, beef->tm_sec);
else
result[0] = 0;
return result;
}
char *timestampDateString(time_t ts)
{
static char result[64];
tm *beef;
time_t cake = ts;
beef = localtime(&cake);
if (beef)
sprintf(result, "%d/%02d/%d %02d:%02d:%02d", beef->tm_mon + 1, beef->tm_mday, beef->tm_year + 1900, beef->tm_hour, beef->tm_min, beef->tm_sec);
else
result[0] = 0;
return result;
}
char *timestampDateStringForFileName(time_t ts)
{
static char result[64];
tm *beef;
time_t cake = ts;
beef = localtime(&cake);
if (beef)
sprintf(result, "%04d_%02d_%02d__%02d_%02d_%02d", beef->tm_year + 1900, beef->tm_mon + 1, beef->tm_mday, beef->tm_hour, beef->tm_min, beef->tm_sec);
else
result[0] = 0;
return result;
}
unsigned long ResolveIPFromHost(const char *host)
{
ULONG ipaddr;
// Check if it's in IP format.
ipaddr = ::inet_addr(host);
if (ipaddr && ipaddr != INADDR_NONE)
return (unsigned long)ipaddr;
// Try to resolve an IP address.
hostent *lphost;
lphost = gethostbyname(host);
if (lphost != NULL)
{
ipaddr = ((in_addr*)lphost->h_addr)->s_addr;
if (ipaddr && ipaddr != INADDR_NONE)
return (unsigned long)ipaddr;
}
return 0;
}
unsigned long GetLocalIP()
{
char hostname[256];
gethostname(hostname, 256);
uint32_t hostaddr = *((uint32_t *)gethostbyname(hostname)->h_addr);
return *(unsigned long *)gethostbyname(hostname)->h_addr;
}
std::string GetLocalIPString()
{
unsigned long localIP = GetLocalIP();
return inet_ntoa(*(in_addr *)&localIP);
}
std::string DebugBytesToString(void *_data, unsigned int len)
{
BYTE *data = (BYTE *)_data;
std::string strBytes;
for (unsigned int i = 0; i < len; i++)
{
char temp[3];
sprintf(temp, "%02X", data[i]);
strBytes += temp;
if (!((i + 1) % 16))
strBytes += "\n";
else
strBytes += " ";
}
if (len % 16)
{
strBytes += "\n";
}
return strBytes;
}
//void MsgBox(UINT type, const char *format, ...)
//{
// szWriteBuffer[0] = 0;
//
// va_list args;
// va_start(args, format);
// _vsnprintf(szWriteBuffer, 1024, format, args);
// va_end(args);
//
// HWND hWnd = g_pGlobals ? g_pGlobals->GetWindowHandle() : NULL;
//
// MessageBox(hWnd, szWriteBuffer, "GDL", MB_OK | type);
//}
//void MsgBox(const char *format, ...)
//{
// szWriteBuffer[0] = 0;
//
// va_list args;
// va_start(args, format);
// _vsnprintf(szWriteBuffer, 1024, format, args);
// va_end(args);
//
// MessageBox(NULL, szWriteBuffer, "GDL", MB_OK);
//}
//void MsgBoxError(uint32_t dwError, const char* event)
//{
// LPVOID lpMsgBuf;
// if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
// FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
// NULL,
// GetLastError(),
// MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// (LPTSTR)&lpMsgBuf,
// 0, NULL))
// {
// MsgBox(MB_ICONHAND, "Unknown error #%lu %s", dwError, event);
// return;
// }
//
// MsgBox(MB_ICONHAND, "Error #%lu %s:\r\n%s", dwError, event, lpMsgBuf);
//
// LocalFree(lpMsgBuf);
//}
//#define REGLOC HKEY_LOCAL_MACHINE, "Software\\GDL"
//BOOL SaveConfigKey(const char* Key, uint32_t value)
//{
// BOOL bReturn = FALSE;
// HKEY hKey;
// if (RegCreateKeyEx(REGLOC, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS)
// {
// if (SUCCEEDED(RegSetValueEx(hKey, Key, NULL, REG_uint32_t, (BYTE *)&value, sizeof(uint32_t))))
// bReturn = TRUE;
// RegCloseKey(hKey);
// }
// return bReturn;
//}
//BOOL SaveConfigKey(const char* Key, const char* value)
//{
// BOOL bReturn = FALSE;
// HKEY hKey;
// if (RegCreateKeyEx(REGLOC, NULL, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL) == ERROR_SUCCESS)
// {
// if (SUCCEEDED(RegSetValueEx(hKey, Key, NULL, REG_SZ, (BYTE*)value, (uint32_t)strlen(value) + 1)))
// bReturn = TRUE;
// RegCloseKey(hKey);
// }
// return bReturn;
//}
//BOOL ReadConfigKey(const char* Key, uint32_t* value)
//{
// uint32_t type = REG_uint32_t;
// uint32_t size = sizeof(uint32_t);
// BOOL bReturn = FALSE;
// HKEY hKey;
// if (RegOpenKeyEx(REGLOC, NULL, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
// {
// if (!RegQueryValueEx(hKey, Key, NULL, &type, (BYTE*)value, &size))
// bReturn = TRUE;
// RegCloseKey(hKey);
// }
// return bReturn;
//}
//BOOL ReadConfigKey(const char* Key, char* value, uint32_t size)
//{
// uint32_t type = REG_SZ;
// BOOL bReturn = FALSE;
// HKEY hKey;
// if (RegOpenKeyEx(REGLOC, NULL, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
// {
// if (!RegQueryValueEx(hKey, Key, NULL, &type, (BYTE*)value, &size))
// bReturn = TRUE;
// RegCloseKey(hKey);
// }
// return bReturn;
//}
bool FileExists(const char *filePath)
{
if (fs::exists(filePath))
return !fs::is_directory(filePath);
return false;
//uint32_t dwAttrib = GetFileAttributes(filePath);
//return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
void strtrim(char *szText)
{
//how many left spaces are leading?
int leading = 0;
while (szText[leading] == ' ')
leading++;
if (leading) { //shift left
int i = leading;
while (1)
{
szText[i - leading] = szText[i];
if (szText[i] == 0)
break;
i++;
}
}
int pos = (int)strlen(szText) - 1; //remove trailing spaces
while ((pos >= 0) && szText[pos] == ' ')
szText[pos--] = 0;
}
BOOL strmask(const char* szTest, const char* szMask)
{
//We need to someday create a function for validating a string mask.
return FALSE;
}
long fsize(FILE* fileptr)
{
long lOld, lSize;
lOld = ftell(fileptr);
fseek(fileptr, 0, SEEK_END);
lSize = ftell(fileptr);
fseek(fileptr, lOld, SEEK_SET);
return lSize;
}
float NorthSouth(char *szCoord)
{
std::string coords = szCoord;
std::transform(coords.begin(), coords.end(), coords.begin(), ::tolower);
coords.erase(coords.begin(), std::find_if(coords.begin(), coords.end(), [](int c) { return !std::isspace(c); }));
coords.erase(std::find_if(coords.rbegin(), coords.rend(), [](int c) { return !std::isspace(c); }).base(), coords.end());
float dir = 1.0f;
int len = coords.length();
if (len < 1)
return 0;
size_t pos = coords.find(',');
if (pos == std::string::npos) // assume at the end
pos = len;
pos--;
char NS = coords[pos];
if (NS == 's')
dir = -1.0f;
coords[pos] = 0;
float coord = 0.0f;
sscanf(coords.data(), "%f", &coord);
return coord * dir;
}
float EastWest(char *szCoord)
{
std::string coords = szCoord;
std::transform(coords.begin(), coords.end(), coords.begin(), ::tolower);
coords.erase(coords.begin(), std::find_if(coords.begin(), coords.end(), [](int c) { return !std::isspace(c); }));
coords.erase(std::find_if(coords.rbegin(), coords.rend(), [](int c) { return !std::isspace(c); }).base(), coords.end());
float dir = 1.0f;
int len = coords.length();
if (len < 1)
return 0;
size_t pos = coords.find(',');
if (pos == std::string::npos) // assume at the end
pos = len;
pos--;
char EW = coords[pos];
if (EW == 'w')
dir = -1.0f;
coords[pos] = 0;
float coord = 0.0f;
sscanf(coords.data(), "%f", &coord);
return coord * dir;
}
uint32_t GetCellFromBase(uint32_t BaseX, uint32_t BaseY)
{
BYTE blockx = (BYTE)(BaseX >> 3);
BYTE blocky = (BYTE)(BaseY >> 3);
BYTE cellx = (BYTE)(BaseX & 7);
BYTE celly = (BYTE)(BaseY & 7);
WORD block = (blockx << 8) | (blocky);
WORD cell = (cellx << 3) | (celly);
uint32_t dwCell = (block << 16) | (cell + 1);
return dwCell;
}
bool GetLocation(double NS, double EW, Position &pos)
{
NS -= 0.5f;
EW -= 0.5f;
NS *= 10.0f;
EW *= 10.0f;
uint32_t basex = (uint32_t)(EW + 0x400);
uint32_t basey = (uint32_t)(NS + 0x400);
if (int32_t(basex) < 0 || int32_t(basey) < 0 || basex >= 0x7F8 || basey >= 0x7F8)
{
//Out of bounds.
pos = Position();
return false;
}
uint32_t dwCell = GetCellFromBase(basex, basey);
float xOffset = ((basex & 7) * 24.0f) + 12;
float yOffset = ((basey & 7) * 24.0f) + 12;
pos = Position(dwCell, Vector(xOffset, yOffset, CalcSurfaceZ(dwCell, xOffset, yOffset)));
return true;
}
// Water blocks are not passable!
BOOL IsWaterBlock(BlockData *pBlock)
{
for (unsigned int x = 0; x < 9; x++) {
for (unsigned int y = 0; y < 9; y++) {
if ((pBlock->wSurface[x][y] & 0x50) != 0x50)
return FALSE;
}
}
return TRUE;
}
//
BOOL IsWaterBlock(uint32_t dwCell)
{
dwCell &= 0xFFFF0000;
dwCell |= 0x0000FFFF;
TURBINEFILE *pFile = g_pCell->GetFile(dwCell);
if (!pFile)
return FALSE;
BOOL bResult = IsWaterBlock((BlockData*)pFile->GetData());
delete pFile;
return bResult;
}
BOOL HasObjectBlock(BlockData *pBlock)
{
return ((pBlock->bObject) ? TRUE : FALSE);
}
BOOL HasObjectBlock(uint32_t dwCell)
{
dwCell &= 0xFFFF0000;
dwCell |= 0x0000FFFF;
TURBINEFILE *pFile = g_pCell->GetFile(dwCell);
if (!pFile)
return FALSE;
BOOL bResult = HasObjectBlock((BlockData*)pFile->GetData());
delete pFile;
return bResult;
}
float CalcSurfaceZ(uint32_t dwCell, float xOffset, float yOffset, bool bUseLCell)
{
TURBINEFILE *pFile = g_pCell->GetFile((dwCell & 0xFFFF0000) | 0xFFFF);
if (!pFile)
return 0;
WORD cell = CELL_WORD(dwCell);
int minix = (cell >> 3) & 7;
int miniy = (cell >> 0) & 7;
if (bUseLCell)
{
xOffset -= (24 * minix);
yOffset -= (24 * miniy);
}
BlockData *pBlock = (BlockData*)pFile->GetData();
Vector P1(0, 24, LandDefs::Land_Height_Table[pBlock->bHeight[minix][miniy + 1]] + 0.005f);
Vector P2;
Vector P3(24, 0, LandDefs::Land_Height_Table[pBlock->bHeight[minix + 1][miniy]] + 0.005f);
if ((xOffset + yOffset) < 24.0f)
P2 = Vector(0, 0, LandDefs::Land_Height_Table[pBlock->bHeight[minix][miniy]] + 0.005f);
else
P2 = Vector(24, 24, LandDefs::Land_Height_Table[pBlock->bHeight[minix + 1][miniy + 1]] + 0.005f);
delete pFile;
return FindVectorZ(P1, P2, P3, xOffset, yOffset);
}
uint64_t GetProcessMemoryUsage()
{
#if defined(_WIN32)
PROCESS_MEMORY_COUNTERS_EX procMem;
memset(&procMem, 0, sizeof(procMem));
GetProcessMemoryInfo(GetCurrentProcess(), (PPROCESS_MEMORY_COUNTERS)&procMem, sizeof(procMem));
return procMem.PrivateUsage;
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
uint64_t result = 0;
FILE *fp = NULL;
if (!(fp = fopen("/proc/selt/statm", "r")))
{
fscanf(fp, "%*s%ld", &result);
fclose(fp);
}
return result * (uint64_t)sysconf(_SC_PAGESIZE);
#else
return 0;
#endif
}
uint64_t GetFreeMemory()
{
#if defined(_WIN32)
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return status.ullAvailPhys;
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
struct sysinfo si = { 0 };
sysinfo(&si);
return si.freeram;
#else
return 0;
#endif
}
uint64_t GetTotalMemory()
{
#if defined(_WIN32)
MEMORYSTATUSEX status;
status.dwLength = sizeof(status);
GlobalMemoryStatusEx(&status);
return status.ullTotalPhys;
#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
struct sysinfo si = { 0 };
sysinfo(&si);
return si.totalram;
#else
return 0;
#endif
}
// strictness 1 = chat, strictness 2 = player names, titles, allegiance names
bool containsBadCharacters(std::string input, int strictness)
{
std::string goodChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'- ";
if (strictness == 1)
{
goodChars += "!\"<EFBFBD>$%^&*()_-+={}[]:;<>,.?/@'~#`<60>|\\";
}
for (auto c : input)
{
if (goodChars.find(c) != goodChars.npos)
{
continue;
}
else
return true;
}
return false;
}