Implement built in Extractor for Windows (#2730)

* wip

* const

* split zapd into two targets

* Workingish.

* fix working dir and copy xmls on build (#2)

* dont change current working dir with dialog prompts

* copy asset xmls to target dir

* make zpadlib public

* Messagebox.

* Check for WIN32

* threading

* Cleanups to the exporter and main.

* Multi extraction.

* Fix byteswap header includes.

* Fix another byteswap include.

* fix again.

* stddef size_t

* Add other targets for ZAPDLib

* Non windows.

* IDYES IDNO

* Linux fixes

* hopefully remove switch and wiiu from building extractor

* Please?

* validate roms and add another valid rom

* ifdef out extract.h for switch and wiiu

* Maybe update lux

* Remove ZAPDlib from switch and WiiU

* more rules

* Update soh/soh/Extractor/Extract.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update ZAPDTR/ZAPD/ExecutableMain.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update ZAPDTR/ZAPD/CMakeLists.txt

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update ZAPDTR/ZAPD/GameConfig.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update ZAPDTR/ZAPD/Globals.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update ZAPDTR/ZAPD/Main.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update soh/CMakeLists.txt

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update soh/soh/Extractor/Extract.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update soh/soh/Extractor/Extract.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* Update soh/soh/Extractor/Extract.cpp

Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>

* the last fix

* Add context to a comment

---------

Co-authored-by: Adam Bird <archez39@me.com>
Co-authored-by: Adam Bird <Archez@users.noreply.github.com>
Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com>
This commit is contained in:
louist103 2023-04-25 00:01:17 -04:00 committed by GitHub
parent 44d3f1ccbb
commit aea46e7cb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 2759 additions and 51 deletions

View File

@ -111,7 +111,7 @@ add_custom_target(
# CMake versions prior to 3.17 do not have the rm command, use remove instead for older versions
COMMAND ${CMAKE_COMMAND} -E $<IF:$<VERSION_LESS:${CMAKE_VERSION},3.17>,remove,rm> -f oot.otr oot-mq.otr soh.otr
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter/extract_assets.py -z "$<TARGET_FILE:ZAPD>" --non-interactive
COMMAND ${CMAKE_COMMAND} -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DTARGET_DIR="$<TARGET_FILE_DIR:soh>" -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBINARY_DIR=${CMAKE_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/copy-existing-otrs.cmake
COMMAND ${CMAKE_COMMAND} -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME} -DTARGET_DIR="$<TARGET_FILE_DIR:ZAPD>" -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DBINARY_DIR=${CMAKE_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/copy-existing-otrs.cmake
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/OTRExporter
COMMENT "Running asset extraction..."
DEPENDS ZAPD

View File

@ -107,8 +107,13 @@ static void ExporterProgramEnd()
}
}
otrArchive = nullptr;
delete fileWriter;
files.clear();
// Add any additional files that need to be manually copied...
if (File::Exists("soh.otr")) {
return;
}
const auto& lst = Directory::ListFiles("Extract");
std::shared_ptr<Ship::Archive> sohOtr = Ship::Archive::CreateArchive("soh.otr", 4096);
//sohOtr->AddFile("version", (uintptr_t)versionStream->ToVector().data(), versionStream->GetLength());
@ -273,7 +278,7 @@ void AddFile(std::string fName, std::vector<char> data)
}
}
static void ImportExporters()
void ImportExporters()
{
// In this example we set up a new exporter called "EXAMPLE".
// By running ZAPD with the argument -se EXAMPLE, we tell it that we want to use this exporter for our resources.
@ -312,6 +317,3 @@ static void ImportExporters()
InitVersionInfo();
}
// When ZAPD starts up, it will automatically call the below function, which in turn sets up our exporters.
REGISTER_EXPORTER(ImportExporters);

View File

@ -1,4 +1,4 @@
set(PROJECT_NAME ZAPD)
set(PROJECT_NAME ZAPDLib)
set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use")
#set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use")
@ -260,10 +260,17 @@ set(ALL_FILES
################################################################################
# Target
################################################################################
add_executable(${PROJECT_NAME} ${ALL_FILES})
add_library(${PROJECT_NAME} STATIC ${ALL_FILES})
add_executable(ZAPD ExecutableMain.cpp)
target_link_libraries(ZAPD ${PROJECT_NAME})
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
use_props(${PROJECT_NAME} "${CMAKE_CONFIGURATION_TYPES}" "${DEFAULT_CXX_PROPS}")
use_props(ZAPD "${CMAKE_CONFIGURATION_TYPES}" "${DEFAULT_CXX_PROPS}")
endif()
################################################################################
# Includes for CMake from *.props
@ -282,7 +289,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
)
endif()
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux|Darwin")
set_target_properties(${PROJECT_NAME} PROPERTIES
set_target_properties(ZAPD PROPERTIES
OUTPUT_NAME "ZAPD.out"
)
endif()
@ -290,7 +297,8 @@ endif()
# MSVC runtime library
################################################################################
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
get_property(MSVC_RUNTIME_LIBRARY_DEFAULT TARGET ${PROJECT_NAME} PROPERTY MSVC_RUNTIME_LIBRARY)
foreach(ZTarget ${PROJECT_NAME} ZAPD)
get_property(MSVC_RUNTIME_LIBRARY_DEFAULT TARGET ${ZTarget} PROPERTY MSVC_RUNTIME_LIBRARY)
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64")
string(CONCAT "MSVC_RUNTIME_LIBRARY_STR"
$<$<CONFIG:Debug>:
@ -302,7 +310,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
$<$<NOT:$<OR:$<CONFIG:Debug>,$<CONFIG:Release>>>:${MSVC_RUNTIME_LIBRARY_DEFAULT}>
)
endif()
set_target_properties(${PROJECT_NAME} PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY_STR})
set_target_properties(${ZTarget} PROPERTIES MSVC_RUNTIME_LIBRARY ${MSVC_RUNTIME_LIBRARY_STR})
endforeach()
endif()
################################################################################
# Compile definitions
@ -404,7 +413,7 @@ if(MSVC)
endif()
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
target_compile_options(${PROJECT_NAME} PRIVATE
target_compile_options(${PROJECT_NAME} PUBLIC
-Wall -Wextra -Wno-error
-Wno-unused-parameter
-Wno-unused-function
@ -417,11 +426,11 @@ if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang|AppleClang")
)
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
target_link_options(${PROJECT_NAME} PRIVATE
target_link_options(${PROJECT_NAME} PUBLIC
-pthread
)
else()
target_link_options(${PROJECT_NAME} PRIVATE
target_link_options(${PROJECT_NAME} PUBLIC
-pthread
-Wl,-export-dynamic
)
@ -491,7 +500,7 @@ endif()
if(CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
add_library(pathconf OBJECT pathconf.c)
target_link_libraries(${PROJECT_NAME} PRIVATE "${ADDITIONAL_LIBRARY_DEPENDENCIES}" $<TARGET_OBJECTS:pathconf> )
target_link_libraries(${PROJECT_NAME} PUBLIC "${ADDITIONAL_LIBRARY_DEPENDENCIES}" $<TARGET_OBJECTS:pathconf> )
else()
target_link_libraries(${PROJECT_NAME} PRIVATE "${ADDITIONAL_LIBRARY_DEPENDENCIES}")
target_link_libraries(${PROJECT_NAME} PUBLIC "${ADDITIONAL_LIBRARY_DEPENDENCIES}")
endif()

View File

@ -0,0 +1,5 @@
extern "C" int zapd_main(int argc, char* argv[]);
int main(int argc, char* argv[]) {
return zapd_main(argc, argv);
}

View File

@ -27,11 +27,14 @@ Globals::Globals()
Globals::~Globals()
{
auto& exporters = GetExporterMap();
for (auto& it : exporters)
for (const auto& w : workerData)
{
delete it.second;
delete w.second;
}
if (rom != nullptr)
{
delete rom;
}
}

View File

@ -67,7 +67,7 @@ public:
bool buildRawTexture = false;
bool onlyGenSohOtr = false;
ZRom* rom;
ZRom* rom = nullptr;
std::vector<ZFile*> files;
std::vector<ZFile*> externalFiles;
std::vector<int32_t> segments;

View File

@ -4,9 +4,71 @@
#include "Utils/File.h"
#include "Utils/Path.h"
#include "WarningHandler.h"
#include "ZAnimation.h"
ZNormalAnimation nAnim(nullptr);
ZCurveAnimation cAnim(nullptr);
ZLinkAnimation lAnim(nullptr);
ZLegacyAnimation lAnim2(nullptr);
#include "ZArray.h"
ZArray arr(nullptr);
#include "ZAudio.h"
ZAudio audio(nullptr);
#include "ZBackground.h"
ZBackground back(nullptr);
#include "ZBlob.h"
ZBlob blob(nullptr);
#include "ZCollision.h"
ZCollisionHeader colHeader(nullptr);
#include "ZCutscene.h"
ZCutscene cs(nullptr);
#include "ZLimb.h"
ZLimb limb(nullptr);
#include "ZMtx.h"
ZMtx mtx(nullptr);
#include "ZPath.h"
ZPath path(nullptr);
#include "ZPlayerAnimationData.h"
ZPlayerAnimationData pAnimData(nullptr);
#include "ZScalar.h"
ZScalar scalar(nullptr);
#include "ZSkeleton.h"
ZLimbTable limbTbl(nullptr);
ZSkeleton skel(nullptr);
#include "ZString.h"
ZString str(nullptr);
#include "ZSymbol.h"
ZSymbol sym(nullptr);
#include "ZText.h"
ZText txt(nullptr);
#include "ZTexture.h"
ZTexture tex(nullptr);
#include "ZVector.h"
ZVector vec(nullptr);
#include "ZVtx.h"
ZVtx vtx(nullptr);
#include "ZRoom/ZRoom.h"
ZRoom room(nullptr);
#include "ZFile.h"
#include "ZTexture.h"
@ -29,29 +91,6 @@
const char gBuildHash[] = "";
// LINUX_TODO: remove, those are because of soh <-> lus dependency problems
float divisor_num = 0.0f;
extern "C" void Audio_SetGameVolume(int player_id, float volume)
{
}
extern "C" int ResourceMgr_OTRSigCheck(char* imgData)
{
return 0;
}
void DebugConsole_SaveCVars()
{
}
void DebugConsole_LoadCVars()
{
}
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
ZFileMode fileMode, int workerID);
@ -119,7 +158,9 @@ void ErrorHandler(int sig)
}
#endif
int main(int argc, char* argv[])
extern void ImportExporters();
extern "C" int zapd_main(int argc, char* argv[])
{
// Syntax: ZAPD.out [mode (btex/bovl/e)] (Arbritrary Number of Arguments)
@ -242,6 +283,7 @@ int main(int argc, char* argv[])
}
else if (arg == "-se" || arg == "--set-exporter") // Set Current Exporter
{
ImportExporters();
Globals::Instance->currentExporter = argv[++i];
}
else if (arg == "--gcc-compat") // GCC compatibility
@ -434,6 +476,9 @@ int main(int argc, char* argv[])
exporterSet->endProgramFunc();
end:
delete exporterSet;
//Globals::Instance->GetExporterSet() = nullptr; //TODO NULL this out. Compiler complains about lvalue assignment.
delete g;
return 0;

View File

@ -96,6 +96,10 @@ if (NOT TARGET ZAPDUtils)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPDUtils ${CMAKE_BINARY_DIR}/ZAPDUtils)
endif()
if (NOT TARGET ZAPDLib)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ZAPDTR/ZAPD ${CMAKE_BINARY_DIR}/ZAPD)
endif()
set(PROJECT_NAME soh)
################################################################################
@ -176,6 +180,23 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
endif()
# }}}
if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
# soh/Extractor {{{
file(GLOB_RECURSE soh__Extractor RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
"soh/Extractor/*.c"
"soh/Extractor/*.cpp"
"soh/Extractor/*.h"
"soh/Extractor/*.hpp"
)
# }}}
else()
file(GLOB_RECURSE soh__Extractor RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
"soh/Extractor/*.h"
"soh/Extractor/*.hpp"
)
# }}}
endif()
# soh/resource {{{
file(GLOB_RECURSE soh__Resource RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "soh/resource/*.cpp" "soh/resource/*.h")
@ -224,6 +245,7 @@ set(ALL_FILES
${Header_Files__include}
${soh__}
${soh__Enhancements}
${soh__Extractor}
${soh__Resource}
${src__}
)
@ -477,7 +499,7 @@ if(MSVC)
/FORCE:MULTIPLE
>
/DEBUG;
/SUBSYSTEM:WINDOWS
/SUBSYSTEM:WINDOWS
)
elseif("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "Win32")
target_link_options(${PROJECT_NAME} PRIVATE
@ -599,6 +621,17 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
COMMAND $<CONFIG:Debug> copy /b $<SHELL_PATH:${CMAKE_BINARY_DIR}/>build.c +,,
)
endif()
if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMENT "Copying asset xmls..."
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/OTRGui/assets $<TARGET_FILE_DIR:soh>/assets
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/soh/assets/xml $<TARGET_FILE_DIR:soh>/assets/extractor/xmls
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/OTRExporter/assets $<TARGET_FILE_DIR:soh>/Extract/assets
)
endif()
################################################################################
# Dependencies
################################################################################
@ -606,12 +639,18 @@ add_dependencies(${PROJECT_NAME}
ZAPDUtils
libultraship
)
if(NOT CMAKE_SYSTEM_NAME MATCHES "NintendoSwitch|CafeOS")
add_dependencies(${PROJECT_NAME}
ZAPDLib
)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "x64")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;"
"ZAPDUtils;"
"ZAPDLib;"
"glu32;"
"SDL2::SDL2;"
"SDL2::SDL2main;"
@ -626,6 +665,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;"
"ZAPDUtils;"
"ZAPDLib;"
"glu32;"
"SDL2::SDL2;"
"SDL2::SDL2main;"
@ -651,7 +691,6 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "CafeOS")
find_package(SDL2 REQUIRED)
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;"
"ZAPDUtils;"
SDL2::SDL2-static
"$<$<CONFIG:Debug>:-Wl,--wrap=abort>"
@ -666,6 +705,7 @@ else()
set(ADDITIONAL_LIBRARY_DEPENDENCIES
"libultraship;"
"ZAPDUtils;"
"ZAPDLib;"
SDL2::SDL2
"$<$<BOOL:${BUILD_CROWD_CONTROL}>:SDL2_net::SDL2_net>"
${CMAKE_DL_LIBS}

View File

@ -0,0 +1,42 @@
#include <stdint.h>
#include <stdlib.h>
#ifdef _MSC_VER
#define BSWAP32 _byteswap_ulong
#define BSWAP16 _byteswap_ushort
#elif __has_include(<byteswap.h>)
#include <byteswap.h>
#define BSWAP32 bswap_32
#define BSWAP16 bswap_16
#else
#define BSWAP16(value) ((((value)&0xff) << 8) | ((value) >> 8))
#define BSWAP32(value) \
(((uint32_t)BSWAP16((uint16_t)((value)&0xffff)) << 16) | (uint32_t)BSWAP16((uint16_t)((value) >> 16)))
#endif
#ifdef __cplusplus
extern "C" {
#endif
void RomToBigEndian(void* rom, size_t romSize) {
uint8_t firstbyte = ((uint8_t*)rom)[0];
switch (firstbyte) {
case 0x80: // BE
return; // Already BE, no need to swap
case 0x37:
for (size_t pos = 0; pos < (romSize / 2); pos++) {
((uint16_t*)rom)[pos] = BSWAP16(((uint16_t*)rom)[pos]);
}
return;
case 0x40:
for (size_t pos = 0; pos < (romSize / 4); pos++) {
((uint32_t*)rom)[pos] = BSWAP32(((uint32_t*)rom)[pos]);
}
}
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,476 @@
#ifdef _WIN32
#include <Windows.h>
#include <winuser.h>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#endif
#include "Extract.h"
#include "portable-file-dialogs.h"
#ifdef unix
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
#ifdef _MSC_VER
#define BSWAP32 _byteswap_ulong
#define BSWAP16 _byteswap_ushort
#elif __has_include(<byteswap.h>)
#include <byteswap.h>
#define BSWAP32 bswap_32
#define BSWAP16 bswap_16
#else
#define BSWAP16(value) ((((value)&0xff) << 8) | ((value) >> 8))
#define BSWAP32(value) \
(((uint32_t)BSWAP16((uint16_t)((value)&0xffff)) << 16) | (uint32_t)BSWAP16((uint16_t)((value) >> 16)))
#endif
#if defined(_MSC_VER)
#define UNREACHABLE __assume(0)
#elif __llvm__
#define UNREACHABLE __builtin_assume(0)
#else
#define UNREACHABLE __builtin_unreachable();
#endif
#include <stdlib.h>
#include <SDL2/SDL_messagebox.h>
#include <array>
#include <fstream>
#include <filesystem>
#include <unordered_map>
extern "C" uint32_t CRC32C(unsigned char* data, size_t dataSize);
extern "C" void RomToBigEndian(void* rom, size_t romSize);
static constexpr uint32_t OOT_PAL_GC = 0x09465AC3;
static constexpr uint32_t OOT_PAL_GC_DBG1 = 0x871E1C92; // 03-21-2002 build
static constexpr uint32_t OOT_PAL_GC_DBG2 = 0x87121EFE; // 03-13-2002 build
static constexpr uint32_t OOT_PAL_GC_MQ_DBG = 0x917D18F6;
static const std::unordered_map<uint32_t, const char*> verMap = {
{ OOT_PAL_GC, "Pal Gamecube" },
{ OOT_PAL_GC_DBG1, "PAL Debug 1" },
{ OOT_PAL_GC_DBG2, "PAL Debug 2" },
{ OOT_PAL_GC_MQ_DBG, "PAL MQ Debug" },
};
// TODO only check the first 54MB of the rom.
static constexpr std::array<const uint32_t, 7> goodCrcs = {
0xfa8c0555, // MQ DBG 64MB (Original overdump)
0x8652ac4c, // MQ DBG 64MB
0x5B8A1EB7, // MQ DBG 64MB (Empty overdump)
0x1f731ffe, // MQ DBG 54MB
0x044b3982, // NMQ DBG 54MB
0xEB15D7B9, // NMQ DBG 64MB
0xDA8E61BF, // GC PAL
};
enum class ButtonId : int {
YES,
NO,
FIND,
};
void Extractor::ShowErrorBox(const char* title, const char* text) {
#ifdef _WIN32
MessageBoxA(nullptr, text, title, MB_OK | MB_ICONERROR);
#else
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, text, nullptr);
#endif
}
void Extractor::ShowSizeErrorBox() const {
std::unique_ptr<char[]> boxBuffer = std::make_unique<char[]>(mCurrentRomPath.size() + 100);
snprintf(boxBuffer.get(), mCurrentRomPath.size() + 100,
"The rom file %s was not a valid size. Was %zu MB, expecting 32, 54, or 64MB.", mCurrentRomPath.c_str(),
mCurRomSize / MB_BASE);
ShowErrorBox("Invalid Rom Size", boxBuffer.get());
}
void Extractor::ShowCrcErrorBox() const {
ShowErrorBox("Rom CRC invalid", "Rom CRC did not match the list of known good roms. Please find another.");
}
int Extractor::ShowRomPickBox(uint32_t verCrc) const {
std::unique_ptr<char[]> boxBuffer = std::make_unique<char[]>(mCurrentRomPath.size() + 100);
SDL_MessageBoxData boxData = { 0 };
SDL_MessageBoxButtonData buttons[3] = { { 0 } };
int ret;
buttons[0].buttonid = 0;
buttons[0].text = "Yes";
buttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
buttons[1].buttonid = 1;
buttons[1].text = "No";
buttons[1].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
buttons[2].buttonid = 2;
buttons[2].text = "Find ROM";
boxData.numbuttons = 3;
boxData.flags = SDL_MESSAGEBOX_INFORMATION;
boxData.message = boxBuffer.get();
boxData.title = "Rom Detected";
boxData.window = nullptr;
boxData.buttons = buttons;
snprintf(boxBuffer.get(), mCurrentRomPath.size() + 100,
"Rom detected: %s, Header CRC32: %8X. It appears to be: %s. Use this rom?", mCurrentRomPath.c_str(),
verCrc, verMap.at(verCrc));
SDL_ShowMessageBox(&boxData, &ret);
return ret;
}
int Extractor::ShowYesNoBox(const char* title, const char* box) {
int ret;
#ifdef _WIN32
ret = MessageBoxA(nullptr, box, title, MB_YESNO | MB_ICONQUESTION);
#else
SDL_MessageBoxData boxData = { 0 };
SDL_MessageBoxButtonData buttons[2] = { { 0 } };
buttons[0].buttonid = IDYES;
buttons[0].text = "Yes";
buttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
buttons[1].buttonid = IDNO;
buttons[1].text = "No";
buttons[1].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
boxData.numbuttons = 2;
boxData.flags = SDL_MESSAGEBOX_INFORMATION;
boxData.message = box;
boxData.title = title;
boxData.buttons = buttons;
SDL_ShowMessageBox(&boxData, &ret);
#endif
return ret;
}
void Extractor::SetRomInfo(const std::string& path) {
mCurrentRomPath = path;
mCurRomSize = GetCurRomSize();
}
void Extractor::GetRoms(std::vector<std::string>& roms) {
#ifdef _WIN32
WIN32_FIND_DATAA ffd;
HANDLE h = FindFirstFileA(".\\*", &ffd);
do {
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
char* ext = PathFindExtensionA(ffd.cFileName);
// Check for any standard N64 rom file extensions.
if ((strcmp(ext, ".z64") == 0) || (strcmp(ext, ".n64") == 0) || (strcmp(ext, ".v64") == 0))
roms.push_back(ffd.cFileName);
}
} while (FindNextFileA(h, &ffd) != 0);
// if (h != nullptr) {
// CloseHandle(h);
//}
#elif unix
// Open the directory of the app.
DIR* d = opendir(".");
struct dirent* dir;
if (d != NULL) {
// Go through each file in the directory
while ((dir = readdir(d)) != NULL) {
struct stat path;
// Check if current entry is not folder
stat(dir->d_name, &path);
if (S_ISREG(path.st_mode)) {
// Get the position of the extension character.
char* ext = strchr(dir->d_name, '.');
if (ext != NULL && (strcmp(ext, ".z64") == 0) && (strcmp(ext, ".n64") == 0) &&
(strcmp(ext, ".v64") == 0)) {
roms.push_back(dir->d_name);
}
}
}
}
closedir(d);
#else
for (const auto& file : std::filesystem::directory_iterator("./")) {
if (file.is_directory())
continue;
if ((file.path().extension() == ".n64") || (file.path().extension() == ".z64") ||
(file.path().extension() == ".v64")) {
roms.push_back((file.path()));
}
}
#endif
}
bool Extractor::GetRomPathFromBox() {
#ifdef _WIN32
OPENFILENAMEA box = { 0 };
char nameBuffer[512];
nameBuffer[0] = 0;
box.lStructSize = sizeof(box);
box.lpstrFile = nameBuffer;
box.nMaxFile = sizeof(nameBuffer) / sizeof(nameBuffer[0]);
box.lpstrTitle = "Open Rom";
box.Flags = OFN_NOCHANGEDIR | OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_LONGNAMES | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
box.lpstrFilter = "N64 Roms\0*.z64;*.v64;*.n64\0\0";
if (!GetOpenFileNameA(&box)) {
DWORD err = CommDlgExtendedError();
// GetOpenFileName will return 0 but no error is set if the user just closes the box.
if (err != 0) {
const char* errStr = nullptr;
switch (err) {
case FNERR_BUFFERTOOSMALL:
errStr = "Path buffer too small. Move file closer to root of your drive";
break;
case FNERR_INVALIDFILENAME:
errStr = "File name for rom provided is invalid.";
break;
case FNERR_SUBCLASSFAILURE:
errStr = "Failed to open a filebox because there is not enough RAM to do so.";
break;
}
MessageBoxA(nullptr, "Box Error", errStr, MB_OK | MB_ICONERROR);
return false;
}
}
// The box was closed without something being selected.
if (nameBuffer[0] == 0) {
return false;
}
mCurrentRomPath = nameBuffer;
#else
auto selection = pfd::open_file("Select a file", ".", { "N64 Roms", "*.z64 *.n64 *.v64" }).result();
if (selection.empty()) {
return false;
}
mCurrentRomPath = selection[0];
#endif
mCurRomSize = GetCurRomSize();
return true;
}
uint32_t Extractor::GetRomVerCrc() const {
return BSWAP32(((uint32_t*)mRomData.get())[4]);
}
size_t Extractor::GetCurRomSize() const {
return std::filesystem::file_size(mCurrentRomPath);
}
bool Extractor::ValidateAndFixRom() {
// The MQ debug rom sometimes has the header patched to look like a US rom. Change it back
if (GetRomVerCrc() == OOT_PAL_GC_MQ_DBG) {
mRomData[0x3E] = 'P';
}
const uint32_t actualCrc = CRC32C(mRomData.get(), mCurRomSize);
for (const uint32_t crc : goodCrcs) {
if (actualCrc == crc) {
return true;
}
}
return false;
}
bool Extractor::ValidateRomSize() const {
if (mCurRomSize != MB32 && mCurRomSize != MB54 && mCurRomSize != MB64) {
return false;
}
return true;
}
bool Extractor::ValidateRom(bool skipCrcTextBox) {
if (!ValidateRomSize()) {
ShowSizeErrorBox();
return false;
}
if (!ValidateAndFixRom()) {
if (!skipCrcTextBox) {
ShowCrcErrorBox();
}
return false;
}
return true;
}
bool Extractor::Run() {
std::vector<std::string> roms;
std::ifstream inFile;
uint32_t verCrc;
GetRoms(roms);
if (roms.empty()) {
int ret = ShowYesNoBox("No roms found", "No roms found. Look for one?");
switch (ret) {
case IDYES:
if (!GetRomPathFromBox()) {
ShowErrorBox("No rom selected", "No rom selected. Exiting");
return false;
}
inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary);
if (!inFile.is_open()) {
return false; // TODO Handle error
}
inFile.read((char*)mRomData.get(), mCurRomSize);
if (!ValidateRom()) {
return false;
}
break;
case IDNO:
ShowErrorBox("No rom selected", "No rom selected. Exiting");
return false;
default:
UNREACHABLE;
break;
}
}
for (const auto& rom : roms) {
int option;
SetRomInfo(rom);
if (inFile.is_open()) {
inFile.close();
}
inFile.open(rom, std::ios::in | std::ios::binary);
if (!ValidateRomSize()) {
ShowSizeErrorBox();
continue;
}
inFile.read((char*)mRomData.get(), mCurRomSize);
RomToBigEndian(mRomData.get(), mCurRomSize);
verCrc = GetRomVerCrc();
// Rom doesn't claim to be valid
if (!verMap.contains(verCrc)) {
continue;
}
option = ShowRomPickBox(verCrc);
if (option == (int)ButtonId::YES) {
if (!ValidateRom(true)) {
if (rom == roms.back()) {
ShowCrcErrorBox();
} else {
ShowErrorBox("Rom CRC invalid",
"Rom CRC did not match the list of known good roms. Trying the next one...");
}
continue;
}
break;
} else if (option == (int)ButtonId::FIND) {
if (!GetRomPathFromBox()) {
ShowErrorBox("No rom selected", "No Rom selected. Exiting");
return false;
}
inFile.open(mCurrentRomPath, std::ios::in | std::ios::binary);
if (!inFile.is_open()) {
return false; // TODO Handle error
}
inFile.read((char*)mRomData.get(), mCurRomSize);
if (!ValidateRom()) {
return false;
}
break;
} else if (option == (int)ButtonId::NO) {
inFile.close();
if (rom == roms.back()) {
ShowErrorBox("No rom provided", "No rom provided. Exiting");
return false;
}
continue;
}
break;
}
return true;
}
bool Extractor::IsMasterQuest() const {
switch (GetRomVerCrc()) {
case OOT_PAL_GC_MQ_DBG:
return true;
case OOT_PAL_GC:
case OOT_PAL_GC_DBG1:
return false;
default:
UNREACHABLE;
}
}
const char* Extractor::GetZapdVerStr() const {
switch (GetRomVerCrc()) {
case OOT_PAL_GC:
return "GC_NMQ_PAL_F";
case OOT_PAL_GC_DBG1:
return "GC_NMQ_D";
case OOT_PAL_GC_MQ_DBG:
return "GC_MQ_D";
default:
// We should never be in a state where this path happens.
UNREACHABLE;
break;
}
}
extern "C" int zapd_main(int argc, char** argv);
bool Extractor::CallZapd() {
constexpr int argc = 16;
char xmlPath[100];
char baseromPath[100];
char confPath[100];
std::array<const char*, argc> argv;
const char* version = GetZapdVerStr();
snprintf(xmlPath, 100, "assets/extractor/xmls/%s", version);
snprintf(baseromPath, 100, "%s", mCurrentRomPath.c_str());
snprintf(confPath, 100, "assets/extractor/Config_%s.xml", version);
argv[0] = "ZAPD";
argv[1] = "ed";
argv[2] = "-i";
argv[3] = xmlPath;
argv[4] = "-b";
argv[5] = baseromPath;
argv[6] = "-fl";
argv[7] = "assets/extractor/filelists";
argv[8] = "-gsf";
argv[9] = "1";
argv[10] = "-rconf";
argv[11] = confPath;
argv[12] = "-se";
argv[13] = "OTR";
argv[14] = "--otrfile";
argv[15] = IsMasterQuest() ? "oot-mq.otr" : "oot.otr";
#ifdef _WIN32
// Grab a handle to the command window.
HWND cmdWindow = GetConsoleWindow();
// Normally the command window is hidden. We want the window to be shown here so the user can see the progess of the extraction.
ShowWindow(cmdWindow, SW_SHOW);
SetWindowPos(cmdWindow, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
#endif
zapd_main(argc, (char**)argv.data());
#ifdef _WIN32
// Hide the command window again.
ShowWindow(cmdWindow, SW_HIDE);
#endif
return 0;
}

View File

@ -0,0 +1,54 @@
#ifndef EXTRACT_H
#define EXTRACT_H
#include <stdint.h>
#include <string>
#include <memory>
#include <vector>
// Values come from windows.h
#ifndef IDYES
#define IDYES 6
#endif
#ifndef IDNO
#define IDNO 7
#endif
static constexpr size_t MB_BASE = 1024 * 1024;
static constexpr size_t MB32 = 32 * MB_BASE;
static constexpr size_t MB54 = 54 * MB_BASE;
static constexpr size_t MB64 = 64 * MB_BASE;
class Extractor {
std::unique_ptr<unsigned char[]> mRomData = std::make_unique<unsigned char[]>(MB64);
std::string mCurrentRomPath;
size_t mCurRomSize = 0;
bool GetRomPathFromBox();
uint32_t GetRomVerCrc() const;
size_t GetCurRomSize() const;
bool ValidateAndFixRom();
bool ValidateRomSize() const;
bool ValidateRom(bool skipCrcBox = false);
const char* GetZapdVerStr() const;
bool IsMasterQuest() const;
void SetRomInfo(const std::string& path);
void GetRoms(std::vector<std::string>& roms);
void ShowSizeErrorBox() const;
void ShowCrcErrorBox() const;
int ShowRomPickBox(uint32_t verCrc) const;
public:
//TODO create some kind of abstraction for message boxes.
static int ShowYesNoBox(const char* title, const char* text);
static void ShowErrorBox(const char* title, const char* text);
bool Run();
bool CallZapd();
const char* GetZapdStr();
};
#endif

View File

@ -0,0 +1,110 @@
#include <stdint.h>
#include <stddef.h>
#ifdef _WIN32
#include <immintrin.h>
#elif ((defined(__GNUC__) && defined(__x86_64__) || defined(__i386__)) && defined(__SSE4_2__))
#include <nmmintrin.h>
#elif defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
// Nothing cause its a compiler builtin
#else
#define USE_CRC_TABLE
#endif
#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)
#define INTRIN_CRC32_64(crc, value) __asm__("crc32cx %w[c], %w[c], %x[v]" : [c] "+r"(crc) : [v] "r"(value))
#define INTRIN_CRC32_32(crc, value) __asm__("crc32cw %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value))
#define INTRIN_CRC32_16(crc, value) __asm__("crc32ch %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value))
#define INTRIN_CRC32_8(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]" : [c] "+r"(crc) : [v] "r"(value))
#elif defined(__SSE4_2__) || defined(_MSC_VER)
#define INTRIN_CRC32_64(crc, data) crc = _mm_crc32_u64(crc, data)
#define INTRIN_CRC32_32(crc, data) crc = _mm_crc32_u32(crc, data)
#define INTRIN_CRC32_16(crc, data) crc = _mm_crc32_u16(crc, data)
#define INTRIN_CRC32_8(crc, data) crc = _mm_crc32_u8(crc, data)
#endif
#ifdef USE_CRC_TABLE
static const uint32_t crc32Table[256] = {
0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, 0x8AD958CFL,
0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, 0x105EC76FL, 0xE235446CL,
0xF165B798L, 0x030E349BL, 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L,
0x89D76C54L, 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, 0x6DFE410EL,
0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, 0xF779DEAEL, 0x05125DADL,
0x1642AE59L, 0xE4292D5AL, 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L,
0x6EF07595L, 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, 0x5125DAD3L,
0xA34E59D0L, 0xB01EAA24L, 0x42752927L, 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, 0xDBFC821CL, 0x2997011FL,
0x3AC7F2EBL, 0xC8AC71E8L, 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, 0x61C69362L, 0x93AD1061L, 0x80FDE395L,
0x72966096L, 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, 0xB602C312L,
0x44694011L, 0x5739B3E5L, 0xA55230E6L, 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, 0x3CDB9BDDL, 0xCEB018DEL,
0xDDE0EB2AL, 0x2F8B6829L, 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, 0x456CAC67L, 0xB7072F64L, 0xA457DC90L,
0x563C5F93L, 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, 0x1871A4D8L,
0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, 0xA24BB5A6L, 0x502036A5L,
0x4370C551L, 0xB11B4652L, 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL,
0x3BC21E9DL, 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, 0xFF56BD19L,
0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, 0x0417B1DBL, 0xF67C32D8L,
0xE52CC12CL, 0x1747422FL, 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L,
0x9D9E1AE0L, 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, 0xE330A81AL,
0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, 0x69E9F0D5L, 0x9B8273D6L,
0x88D28022L, 0x7AB90321L, 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, 0xF36E6F75L, 0x0105EC76L, 0x12551F82L,
0xE03E9C81L, 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef USE_CRC_TABLE
uint32_t CRC32C(unsigned char* data, size_t dataSize) {
uint32_t ret = 0xFFFFFFFF;
int64_t sizeSigned = dataSize;
#if defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__)
while ((sizeSigned -= sizeof(uint64_t)) >= 0) {
INTRIN_CRC32_64(ret, *(uint64_t*)data);
data += sizeof(uint64_t);
}
if (sizeSigned & sizeof(uint32_t)) {
INTRIN_CRC32_32(ret, *(uint32_t*)data);
data += sizeof(uint32_t);
}
#elif defined(_M_IX86) || defined(__i386__)
while ((sizeSigned -= sizeof(uint32_t)) >= 0) {
INTRIN_CRC32_32(ret, *(uint32_t*)data);
data += sizeof(uint32_t);
}
#endif
if (sizeSigned & sizeof(uint16_t)) {
INTRIN_CRC32_16(ret, *(uint16_t*)data);
data += sizeof(uint16_t);
}
if (sizeSigned & sizeof(uint8_t)) {
INTRIN_CRC32_8(ret, *data);
}
return ~ret;
}
#else
uint32_t CRC32C(const void* buf, size_t size) {
const uint8_t* p = buf;
uint32_t crc = 0xFFFFFFFF;
while (size--)
crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8);
return ~crc;
}
#endif
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,10 @@
#include <Hooks.h>
#include "Enhancements/custom-message/CustomMessageManager.h"
#if not defined (__SWITCH__) && not defined(__WIIU__)
#include "Extractor/Extract.h"
#endif
#include <Fast3D/gfx_pc.h>
#include <Fast3D/gfx_rendering_api.h>
@ -703,6 +707,28 @@ extern "C" void OTRExtScanner() {
}
extern "C" void InitOTR() {
#if not defined (__SWITCH__) && not defined(__WIIU__)
if (!std::filesystem::exists(Ship::Window::GetPathRelativeToAppDirectory("oot-mq.otr")) &&
!std::filesystem::exists(Ship::Window::GetPathRelativeToAppDirectory("oot.otr"))){
if (Extractor::ShowYesNoBox("No OTR Files", "No OTR files found. Generate one now?") == IDYES) {
Extractor extract;
if (!extract.Run()) {
Extractor::ShowErrorBox("Error", "An error occured, no OTR file was generated. Exiting...");
exit(1);
}
extract.CallZapd();
}
if (Extractor::ShowYesNoBox("Extraction Complete", "ROM Extracted. Extract another?") == IDYES) {
Extractor extract;
if (!extract.Run()) {
Extractor::ShowErrorBox("Error", "An error occured, an OTR file may have been generated by a different step. Continuing...");
} else {
extract.CallZapd();
}
}
}
#endif
#ifdef __SWITCH__
Ship::Switch::Init(Ship::PreInitPhase);
#elif defined(__WIIU__)

View File

@ -10,7 +10,6 @@
#include <libultraship/bridge.h>
#include "soh/CrashHandlerExp.h"
s32 gScreenWidth = SCREEN_WIDTH;
s32 gScreenHeight = SCREEN_HEIGHT;
size_t gSystemHeapSize = 0;
@ -44,11 +43,21 @@ void Main_LogSystemHeap(void) {
}
#ifdef _WIN32
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow)
#else
int main(int argc, char** argv)
#endif
int SDL_main(int argc, char** argv)
{
AllocConsole();
(void)freopen("CONIN$", "r", stdin);
(void)freopen("CONOUT$", "w", stdout);
(void)freopen("CONOUT$", "w", stderr);
#ifndef _DEBUG
ShowWindow(GetConsoleWindow(), SW_HIDE);
#endif
#else //_WIN32
int main(int argc, char** argv)
{
#endif
GameConsole_Init();
InitOTR();
// TODO: Was moved to below InitOTR because it requires window to be setup. But will be late to catch crashes.