mcpe/source/client/common/Utils.cpp

413 lines
7.9 KiB
C++
Raw Normal View History

2023-07-30 22:22:02 +03:00
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
2023-07-30 22:41:09 +03:00
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
2023-07-30 22:22:02 +03:00
********************************************************************/
// note: not an official file name
#include "client/common/Utils.hpp"
2023-07-30 22:22:02 +03:00
#if defined(_WIN32) && !defined(_XBOX)
2023-07-30 22:22:02 +03:00
#include <Windows.h>
#include <io.h>
#include <direct.h>
2023-07-30 22:22:02 +03:00
// Why are we not using GetTickCount64()? It's simple -- getTimeMs has the exact same problem as using regular old GetTickCount.
#pragma warning(disable : 28159)
#elif defined(_XBOX)
2023-07-30 22:22:02 +03:00
#else
2023-07-30 22:22:02 +03:00
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#define XPL_ACCESS access
#define XPL_MKDIR(path, mode) mkdir(path, mode)
2023-07-30 22:22:02 +03:00
#endif
2023-07-30 22:22:02 +03:00
#include "compat/GL.hpp"
// include zlib stuff
#include "zlib.h"
2023-07-30 22:22:02 +03:00
int g_TimeSecondsOnInit = 0;
2023-08-05 01:58:24 -04:00
#ifndef USE_SDL
2023-08-02 13:15:25 +03:00
DIR* opendir(const char* name)
{
size_t len = strlen(name);
if (len == 0)
return NULL;
char buf[1024];
if (len >= 1024 - 5)
return NULL;
strcpy(buf, name);
if (name[len - 1] != '/')
strcpy(&buf[len], "/*");
else
strcpy(&buf[len], "*");
DIR* pDir = (DIR*)malloc(sizeof(DIR));
if (!pDir)
return pDir;
memset(pDir, 0, sizeof * pDir);
pDir->current = FindFirstFile(buf, &pDir->findData);
if (pDir->current == INVALID_HANDLE_VALUE)
{
free(pDir);
return NULL;
}
return pDir;
}
dirent* readdir(DIR* dir)
{
if (dir->current == INVALID_HANDLE_VALUE)
return NULL;
static dirent de;
if (!dir->returnedFirstFileData)
{
dir->returnedFirstFileData = true;
}
else
{
if (!FindNextFile(dir->current, &dir->findData))
return NULL;
}
strcpy(de.d_name, dir->findData.cFileName);
de.d_type = (dir->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? DT_DIR : DT_REG;
return &de;
}
void closedir(DIR* dir)
{
if (dir->current != INVALID_HANDLE_VALUE)
FindClose(dir->current);
free(dir);
}
2023-08-05 01:58:24 -04:00
#else
#include <sys/types.h>
#include <dirent.h>
#endif
bool createFolderIfNotExists(const char* pDir)
{
if (!XPL_ACCESS(pDir, 0))
return true;
return XPL_MKDIR(pDir, 0755) == 0;
}
2023-08-02 13:15:25 +03:00
bool DeleteDirectory(const std::string& name, bool unused)
{
DIR* dir = opendir(name.c_str());
if (!dir)
return false;
while (true)
{
dirent* de = readdir(dir);
if (!de)
break;
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
const std::string dirPath = name + de->d_name;
remove(dirPath.c_str());
2023-08-02 13:15:25 +03:00
}
closedir(dir);
return remove(name.c_str()) == 0;
}
2023-07-30 22:22:02 +03:00
const char* GetTerrainName()
{
return "terrain.png";
}
const char* GetItemsName()
{
return "gui/items.png";
}
const char* GetGUIBlocksName()
{
return "gui/gui_blocks.png";
}
// In regular mode, getTimeMs depends on getTimeS.
// In Win32 mode, it's vice versa. Cool
int getTimeMs();
float getTimeS()
{
#ifdef _WIN32
return float(getTimeMs()) / 1000.0f;
#else
// variant implemented by Mojang. This does not work on MSVC
timeval tv;
gettimeofday(&tv, NULL);
if (g_TimeSecondsOnInit == 0)
g_TimeSecondsOnInit = tv.tv_sec;
return float(tv.tv_sec - g_TimeSecondsOnInit) + float(tv.tv_usec) / 1000000.0f;
#endif
}
int getTimeMs()
{
#ifdef _WIN32
// just return GetTickCount
int time = GetTickCount();
if (g_TimeSecondsOnInit == 0)
g_TimeSecondsOnInit = time;
return time - g_TimeSecondsOnInit;
#else
return int(getTimeS() * 1000.0f);
#endif
}
time_t getRawTimeS()
{
#ifdef _WIN32
return time_t(GetTickCount() / 1000);
#else
timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec;
#endif
}
time_t getEpochTimeS()
{
return time(0);
}
#ifdef _WIN32
HINSTANCE g_hInstance = NULL;
HWND g_hWnd = NULL;
void SetInstance(HINSTANCE hinst)
{
g_hInstance = hinst;
}
HINSTANCE GetInstance()
{
return g_hInstance;
}
void SetHWND(HWND hwnd)
{
g_hWnd = hwnd;
}
HWND GetHWND()
{
return g_hWnd;
}
void CenterWindow(HWND hWnd)
{
RECT r, desk;
GetWindowRect(hWnd, &r);
GetWindowRect(GetDesktopWindow(), &desk);
int wa, ha, wb, hb;
wa = (r.right - r.left) / 2;
ha = (r.bottom - r.top) / 2;
wb = (desk.right - desk.left) / 2;
hb = (desk.bottom - desk.top) / 2;
SetWindowPos(hWnd, NULL, wb - wa, hb - ha, r.right - r.left, r.bottom - r.top, 0);
}
void EnableOpenGL(HWND hwnd, HDC* hDC, HGLRC* hRC)
{
PIXELFORMATDESCRIPTOR pfd;
int iFormat;
/* get the device context (DC) */
*hDC = GetDC(hwnd);
/* set the pixel format for the DC */
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
2023-07-30 22:22:02 +03:00
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 8;
2023-07-30 22:22:02 +03:00
pfd.iLayerType = PFD_MAIN_PLANE;
iFormat = ChoosePixelFormat(*hDC, &pfd);
SetPixelFormat(*hDC, iFormat, &pfd);
/* create and enable the render context (RC) */
*hRC = wglCreateContext(*hDC);
wglMakeCurrent(*hDC, *hRC);
}
void DisableOpenGL(HWND hwnd, HDC hDC, HGLRC hRC)
{
wglMakeCurrent(NULL, NULL);
wglDeleteContext(hRC);
ReleaseDC(hwnd, hDC);
}
void sleepMs(int ms)
{
#ifdef _WIN32
Sleep(ms);
#else
usleep(1000 * ms);
#endif
}
#endif
void drawArrayVT(GLuint buffer, int count, int stride)
{
xglBindBuffer(GL_ARRAY_BUFFER, buffer);
xglTexCoordPointer(2, GL_FLOAT, stride, (void*)12);
xglEnableClientState(GL_TEXTURE_COORD_ARRAY);
xglVertexPointer(3, GL_FLOAT, stride, nullptr);
xglEnableClientState(GL_VERTEX_ARRAY);
xglDrawArrays(GL_TRIANGLES, 0, count);
xglDisableClientState(GL_VERTEX_ARRAY);
xglDisableClientState(GL_TEXTURE_COORD_ARRAY);
2023-07-30 22:22:02 +03:00
}
void drawArrayVTC(GLuint buffer, int count, int stride)
{
xglBindBuffer(GL_ARRAY_BUFFER, buffer);
xglVertexPointer(3, GL_FLOAT, stride, nullptr);
xglTexCoordPointer(2, GL_FLOAT, stride, (void*)12);
xglColorPointer(4, GL_UNSIGNED_BYTE, stride, (void*)20);
xglEnableClientState(GL_VERTEX_ARRAY);
xglEnableClientState(GL_TEXTURE_COORD_ARRAY);
xglEnableClientState(GL_COLOR_ARRAY);
xglDrawArrays(GL_TRIANGLES, 0, count);
xglDisableClientState(GL_VERTEX_ARRAY);
xglDisableClientState(GL_TEXTURE_COORD_ARRAY);
xglDisableClientState(GL_COLOR_ARRAY);
2023-07-30 22:22:02 +03:00
}
float Max(float a, float b)
{
if (a < b)
a = b;
return a;
}
// zlib stuff
uint8_t* ZlibInflateToMemory(uint8_t* pInput, size_t compressedSize, size_t decompressedSize)
{
int ret;
z_stream strm;
memset(&strm, 0, sizeof strm);
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
// initialize the inflation state machine
ret = inflateInit(&strm);
if (ret != Z_OK)
return nullptr;
uint8_t* pDestBuff = new uint8_t[decompressedSize + 1]; //room for extra null at the end;
pDestBuff[decompressedSize] = 0; //add the extra null, if we decompressed a text file this can be useful
strm.avail_in = compressedSize;
strm.next_in = pInput;
strm.avail_out = decompressedSize;
strm.next_out = pDestBuff;
ret = inflate(&strm, Z_NO_FLUSH);
if (!(ret == Z_OK || ret == Z_STREAM_END))
{
SAFE_DELETE_ARRAY(pDestBuff);
return nullptr;
}
(void)inflateEnd(&strm);
return pDestBuff;
}
uint8_t* ZlibDeflateToMemory(uint8_t* pInput, size_t sizeBytes, size_t* compressedSizeOut)
{
return ZlibDeflateToMemoryLvl(pInput, sizeBytes, compressedSizeOut, Z_DEFAULT_COMPRESSION);
}
uint8_t* ZlibDeflateToMemoryLvl(uint8_t* pInput, size_t sizeBytes, size_t* compressedSizeOut, int level)
{
z_stream strm;
memset(&strm, 0, sizeof strm);
int ret;
// initialize deflate state
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
// initialize deflation state machine
ret = deflateInit(&strm, level);
if (ret != Z_OK)
return nullptr;
// padding bytes in case our compressed output is larger than the raw input for some reason
const int ZLIB_PADDING_BYTES = (1024 * 5);
uint8_t* pOut = new uint8_t[sizeBytes + ZLIB_PADDING_BYTES];
strm.avail_in = sizeBytes;
strm.next_in = pInput;
strm.avail_out = sizeBytes + ZLIB_PADDING_BYTES;
strm.next_out = pOut;
ret = deflate(&strm, Z_FINISH);
assert(ret != Z_STREAM_ERROR);
deflateEnd(&strm);
*compressedSizeOut = strm.total_out;
return pOut;
}