-
-
Save syureri/99e00fc5c42b4f32c2edbcbd24c7e6ef to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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