Skip to content

Instantly share code, notes, and snippets.

@syureri
Last active August 12, 2020 18:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save syureri/99e00fc5c42b4f32c2edbcbd24c7e6ef to your computer and use it in GitHub Desktop.
Save syureri/99e00fc5c42b4f32c2edbcbd24c7e6ef to your computer and use it in GitHub Desktop.
#include <Windows.h>
#include <string>
#include <iostream>
#include <cstdlib>
#include <filesystem>
namespace
{
constexpr LPCWSTR WindowClassName = L"RGSS Player";
constexpr int ScreenWidth = 544;
constexpr int ScreenHeight = 416;
typedef BOOL(*RGSSSetupRTP)(LPCWSTR lpIniPath, LPWSTR lpErrorMessageBuffer, int nBufferLength);
typedef void(*RGSSSetupFonts)();
typedef void(*RGSSInitialize3)(HMODULE hRgssDLL);
typedef int(*RGSSEval)(const char* pScript);
typedef void(*RGSSGameMain)(HWND hWnd, LPCWSTR lpScriptNames, LPWSTR* lpRgssadName);
typedef BOOL(*RGSSExInitialize)(HWND hWnd);
void ShowError(HWND hWnd, LPCWSTR title, LPCWSTR format, ...)
{
TCHAR error[1024];
va_list ap;
va_start(ap, format);
vswprintf_s(error, format, ap);
va_end(ap);
MessageBoxW(hWnd, error, title, MB_OK | MB_ICONERROR);
}
HWND _windowHandle = nullptr;
HMODULE _rgssDLL = nullptr;
RGSSSetupRTP _RGSSSetupRTP = nullptr;
RGSSSetupFonts _RGSSSetupFonts = nullptr;
RGSSInitialize3 _RGSSInitialize3 = nullptr;
RGSSEval _RGSSEval = nullptr;
RGSSGameMain _RGSSGameMain = nullptr;
RGSSExInitialize _RGSSExInitialize = nullptr;
}
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR pCmdLine, _In_ int nCmdShow)
{
std::wstring executableLocation;
std::wstring iniLocation;
std::wstring rgssadLocation;
std::wstring library;
std::wstring title;
std::wstring scripts;
wchar_t* rgssad = 0;
bool showConsole = false;
bool isTest = false;
bool isBattleTest = false;
TCHAR buffer[MAX_PATH];
DWORD bufferLength = sizeof(buffer) / sizeof(*buffer);
// Obtains the full path to the executable.
GetModuleFileNameW(nullptr, buffer, bufferLength);
std::filesystem::path path = buffer;
executableLocation = path.wstring();
// Obtains the full path to the ini file.
iniLocation = path.replace_extension(".ini").wstring();
// Obtains the full path to the rgss3a file.
rgssadLocation = path.replace_extension(".rgss3a").wstring();
// Clear the buffer.
memset(buffer, 0, bufferLength);
// Obtain ini keys.
// The value of the Library key of the [Game] section. Defaults to System\\RGSS301.dll.
GetPrivateProfileStringW(L"Game", L"Library", LR"(System\RGSS301.dll)", buffer, bufferLength, iniLocation.c_str());
library = buffer;
// The value of the Title key of the [Game] section. Defaults to the game's title.
GetPrivateProfileStringW(L"Game", L"Title", L"Untitled", buffer, bufferLength, iniLocation.c_str());
title = buffer;
// The value of the Scripts key of the [Game] section. Defaults to Data\\Scripts.rvdata2.
GetPrivateProfileStringW(L"Game", L"Scripts", LR"(Data\Scripts.rvdata2)", buffer, bufferLength, iniLocation.c_str());
scripts = buffer;
// Query for the existence of the rgssad file.
if (GetFileAttributesW(rgssadLocation.c_str()) != INVALID_FILE_ATTRIBUTES)
rgssad = rgssadLocation.data();
// Create the window class.
WNDCLASSW windowClass;
// CS_DBLCLKS - Allows mouse double click events.
// CS_OWNDC - Allocates a unique device context for each window in the class. This will essentially create the D3D context.
// CS_HREDRAW - Redraws the entire window if a movement or size adjustment changes the width of the client area.
// CS_VREDRAW - Same as CS_HREDRAW, but vertically.
windowClass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
windowClass.lpfnWndProc = DefWindowProc;
windowClass.cbClsExtra = 0;
windowClass.cbWndExtra = 0;
windowClass.hInstance = hInstance;
windowClass.hIcon = LoadIconW(hInstance, MAKEINTRESOURCE(101));
windowClass.hCursor = LoadCursorW(nullptr, IDC_ARROW);
windowClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
windowClass.lpszMenuName = nullptr;
windowClass.lpszClassName = WindowClassName;
// Register the window class.
if (!RegisterClassW(&windowClass))
{
ShowError(nullptr, title.c_str(), L"Failed to register window class.");
return -1;
}
// Calculate the full window size given the client size.
int width = ScreenWidth + GetSystemMetrics(SM_CXFIXEDFRAME) * 2;
int height = ScreenHeight + GetSystemMetrics(SM_CYFIXEDFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION);
RECT rect;
rect.left = (GetSystemMetrics(SM_CXSCREEN) - width) / 2;
rect.top = (GetSystemMetrics(SM_CYMAXIMIZED) - ScreenHeight) / 2 - GetSystemMetrics(SM_CYCAPTION);
rect.right = rect.left + width;
rect.bottom = rect.top + height;
// Create the window style.
// WS_POPUP - The window is a popup window.
// WS_CAPTION - The widow has a title bar.
// WS_SYSMENU - The window has a window menu on its title bar. WS_CAPTION must also be specified.
// WS_MINIMIZEBOX - The window has a minimize button.
DWORD style = WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
// Create the window.
_windowHandle = CreateWindowEx(
WS_EX_WINDOWEDGE,
WindowClassName,
title.c_str(),
style,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
0,
0,
hInstance,
0
);
if (!_windowHandle)
{
// Failed to create window. Perform cleanup and exit.
ShowError(_windowHandle, title.c_str(), L"Failed to create window.");
UnregisterClassW(WindowClassName, hInstance);
return -1;
}
// Obtain command line information.
int numArgs = 0;
LPWSTR* args = CommandLineToArgvW(pCmdLine, &numArgs);
for (int i = 0; i < numArgs; ++i)
{
if (lstrcmpW(args[i], L"console") == 0)
showConsole = true;
else if (lstrcmpW(args[i], L"test") == 0)
isTest = true;
else if (lstrcmpW(args[i], L"btest") == 0)
isBattleTest = true;
}
LocalFree(args);
// Display console.
if (showConsole)
{
if (AllocConsole())
{
SetConsoleTitleW(L"RGSS Console");
FILE* dummy = nullptr;
freopen_s(&dummy, "conout$", "w", stdout);
}
}
// Display the window.
ShowWindow(_windowHandle, SW_SHOW);
// Load the RGSS library.
_rgssDLL = LoadLibraryW(library.c_str());
if (!_rgssDLL)
{
// Failed to load the RGSS dll. Perform cleanup and exit.
DestroyWindow(_windowHandle);
UnregisterClassW(WindowClassName, hInstance);
ShowError(_windowHandle, title.c_str(), L"Failed to load RGSS library %s", library.c_str());
return -1;
}
// Load the exported functions from the library.
_RGSSExInitialize = (RGSSExInitialize)GetProcAddress(_rgssDLL, "RGSSExInitialize");
// Defines a helpful macro to load the required functions and gracefully exit in case an error ocurrs.
#define LOAD_RGSS_FUNCTION(function) do \
{ \
_##function = (function)GetProcAddress(_rgssDLL, #function); \
if (!_##function) \
{ \
ShowError(_windowHandle, title.c_str(), L"Failed to obtain procedure address for RGSS function %s", #function); \
FreeLibrary(_rgssDLL); \
DestroyWindow(_windowHandle); \
UnregisterClassW(WindowClassName, hInstance); \
return -1; \
} \
} while (0)
LOAD_RGSS_FUNCTION(RGSSSetupRTP);
LOAD_RGSS_FUNCTION(RGSSSetupFonts);
LOAD_RGSS_FUNCTION(RGSSInitialize3);
LOAD_RGSS_FUNCTION(RGSSEval);
LOAD_RGSS_FUNCTION(RGSSGameMain);
#undef LOAD_RGSS_FUNCTION
// Setup the RGSS RTP.
memset(buffer, 0, bufferLength);
if (!_RGSSSetupRTP(iniLocation.c_str(), buffer, bufferLength))
{
std::wstring rtpName = buffer;
ShowError(_windowHandle, title.c_str(), L"Unable to find RGSS-RTP %s", rtpName.c_str());
FreeLibrary(_rgssDLL);
DestroyWindow(_windowHandle);
UnregisterClassW(WindowClassName, hInstance);
return -1;
}
// Initialize the RGSS engine.
_RGSSInitialize3(_rgssDLL);
// Call the extra initialize function, if available.
if (_RGSSExInitialize)
{
if (!_RGSSExInitialize(_windowHandle))
{
ShowError(_windowHandle, title.c_str(), L"RGSS EX failed to initialize.");
FreeLibrary(_rgssDLL);
DestroyWindow(_windowHandle);
UnregisterClassW(WindowClassName, hInstance);
return -1;
}
}
// Setup Fonts.
_RGSSSetupFonts();
// Set global variables.
if (isBattleTest)
{
rgssad = 0; // Game is not compressed if battle testing.
_RGSSEval("$TEST = true");
_RGSSEval("$BTEST = true");
}
else
{
if (isTest)
{
rgssad = 0;
_RGSSEval("$TEST = true");
}
else
{
_RGSSEval("$TEST = false");
}
_RGSSEval("$BTEST = false");
}
// Start the game loop.
_RGSSGameMain(
_windowHandle,
scripts.c_str(),
(rgssad ? (wchar_t**)rgssad : &rgssad)
);
// Perform cleanup and exit.
FreeLibrary(_rgssDLL);
DestroyWindow(_windowHandle);
UnregisterClassW(WindowClassName, hInstance);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment