Added support for multiple game versions (#107)

* WIP Multiversion support

* GC PAL Non-MQ support complete

* Updated OtrGui to handle different game versions

* Added version file

* Added new extract mode to ZAPD and optimized OTR gen time

* Fixed bug causing crash

* Further optimized OTRExporter, saving around ~20 seconds.

* ZAPD is now multi-threaded.

* Fixed merge issue

* Fixed memory leak and fog issue on pause screen.

* Additional fog fixes.

Co-authored-by: Jack Walker <7463599+Jack-Walker@users.noreply.github.com>
This commit is contained in:
Nicholas Estelami 2022-03-31 19:42:44 -04:00 committed by GitHub
commit c80f9fbd57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1203 changed files with 30620 additions and 501 deletions

View file

@ -2,7 +2,7 @@
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_MQ_D/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -0,0 +1,8 @@
<Root>
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_NMQ_D/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

View file

@ -0,0 +1,8 @@
<Root>
<SymbolMap File="symbols/SymbolMap_OoTMqDbg.txt"/>
<ActorList File="symbols/ActorList_OoTMqDbg.txt"/>
<ObjectList File="symbols/ObjectList_OoTMqDbg.txt"/>
<ExternalXMLFolder Path="assets/extractor/xmls/GC_NMQ_PAL_F/"/>
<TexturePool File="TexturePool.xml"/>
<ExternalFile XmlPath="objects/gameplay_keep.xml" OutPath="objects/gameplay_keep/"/>
</Root>

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@ bool single_thread = false;
bool hide_second_btn = false;
RomVersion version;
const char* patched_rom = "tmp/rom.z64";
extern bool oldExtractMode;
static std::string currentStep = "None";
@ -72,11 +73,28 @@ void OTRGame::init(){
}
}
void ExtractRom() {
const WriteResult result = ExtractBaserom(patched_rom);
void ExtractRom()
{
WriteResult result;
if (oldExtractMode)
ExtractBaserom(patched_rom);
else
result.error = NULLSTR;
if (result.error == NULLSTR) {
if (MoonUtils::exists("oot.otr")) MoonUtils::rm("oot.otr");
startWorker();
if (MoonUtils::exists("Extract")) MoonUtils::rm("Extract");
MoonUtils::mkdir("Extract");
MoonUtils::copy("tmp/baserom/Audiobank", "Extract/Audiobank");
MoonUtils::copy("tmp/baserom/Audioseq", "Extract/Audioseq");
MoonUtils::copy("tmp/baserom/Audiotable", "Extract/Audiotable");
MoonUtils::copy("tmp/baserom/version", "Extract/version");
MoonUtils::copy("assets/game/", "Extract/assets/");
startWorker(version);
extracting = true;
}
}
@ -131,7 +149,7 @@ void OTRGame::draw() {
}
// Clamp the window to the borders of the monitors
if (wndPos.x < vsX1) wndPos.x = vsX1;
if (wndPos.x < vsX1) wndPos.x = vsX1;
if (wndPos.y < vsY1) wndPos.y = vsY1;
if (wndPos.x + windowSize.x > vsX2) wndPos.x = vsX2 - windowSize.x;
@ -160,7 +178,9 @@ void OTRGame::draw() {
UIUtils::GuiShadowText(("Rom Type: " + version.version).c_str(), 32, text_y, 10, WHITE, BLACK);
UIUtils::GuiShadowText("Tool Version: 1.0", 32, text_y + 15, 10, WHITE, BLACK);
UIUtils::GuiShadowText("OTR Version: 1.0", 32, text_y + 30, 10, WHITE, BLACK);
UIUtils::GuiToggle(&single_thread, "Single Thread", 32, text_y + 40, currentStep != NULLSTR);
if (oldExtractMode)
UIUtils::GuiToggle(&single_thread, "Single Thread", 32, text_y + 40, currentStep != NULLSTR);
if (!hide_second_btn && UIUtils::GuiIconButton("Folder", "Open\nShip Folder", 109, 50, currentStep != NULLSTR, "Select your Ship of Harkinian Folder\n\nYou could use another folder\nfor development purposes")) {
const std::string path = NativeFS->LaunchFileExplorer(LaunchType::FOLDER);

View file

@ -83,37 +83,37 @@ RomVersion GetVersion(FILE* rom) {
break;
case OOT_NTSC_JP_GC:
version.version = "JP GameCube (MQ Disk)";
version.listPath = "gamecube_mq.txt";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_JP_GC;
break;
case OOT_NTSC_JP_GC_CE:
version.version = "GameCube (Collectors Edition Disk)";
version.listPath = "gamecube_mq.txt";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_JP_GC_CE;
break;
case OOT_NTSC_JP_MQ:
version.version = "JP Master Quest";
version.listPath = "gamecube_mq.txt";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_JP_MQ;
break;
case OOT_NTSC_US_MQ:
version.version = "NTSC Master Quest";
version.listPath = "gamecube_mq.txt";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_JP_MQ;
break;
case OOT_NTSC_US_GC:
version.version = "NTSC GameCube";
version.listPath = "gamecube_mq.txt";
version.listPath = "gamecube.txt";
version.offset = OOT_OFF_US_MQ;
break;
case OOT_PAL_GC:
version.version = "PAL GameCube";
version.listPath = "gamecube_mq.txt";
version.listPath = "gamecube_pal.txt";
version.offset = OOT_OFF_PAL_GC;
break;
case OOT_PAL_MQ:
version.version = "PAL Master Quest";
version.listPath = "pal_mq.txt";
version.listPath = "gamecube_pal.txt";
version.offset = OOT_OFF_PAL_MQ;
break;
case OOT_PAL_GC_DBG1:
@ -179,6 +179,8 @@ WriteResult ExtractBaserom(const char* romPath) {
const std::vector<std::string> lines = MoonUtils::split(read(MoonUtils::join("assets/extractor/filelists", version.listPath)), '\n');
std::vector<uint8_t> decompressedData(1);
for (int i = 0; i < lines.size(); i++) {
FILE* outFile = fopen(MoonUtils::join("tmp/baserom", lines[i]).c_str(), "wb");
const int romOffset = version.offset + (DMA_ENTRY_SIZE * i);
@ -196,10 +198,13 @@ WriteResult ExtractBaserom(const char* romPath) {
auto outData = new uint8_t[size];
memcpy(outData, romData + physStart, size);
if (compressed) {
std::vector<uint8_t> compressedData = yaz0_encode(outData, size);
outData = compressedData.data();
size = compressedData.size();
int decSize = virtEnd - virtStart;
decompressedData = std::vector<uint8_t>(decSize);
yaz0_decode(outData, decompressedData.data(), decSize);
outData = decompressedData.data();
size = decSize;
}
fwrite(outData, sizeof(char), size, outFile);

View file

@ -1,23 +1,7 @@
#ifndef EXTRACT_BASEROM_H_
#define EXTRACT_BASEROM_H_
#define OOT_NTSC_10 0xEC7011B7
#define OOT_NTSC_11 0xD43DA81F
#define OOT_NTSC_12 0x693BA2AE
#define OOT_PAL_10 0xB044B569
#define OOT_PAL_11 0xB2055FBD
#define OOT_NTSC_JP_GC_CE 0xF7F52DB8
#define OOT_NTSC_JP_GC 0xF611F4BA
#define OOT_NTSC_US_GC 0xF3DD35BA
#define OOT_PAL_GC 0x09465AC3
#define OOT_NTSC_JP_MQ 0xF43B45BA
#define OOT_NTSC_US_MQ 0xF034001A
#define OOT_PAL_MQ 0x1D4136F3
#define OOT_PAL_GC_DBG1 0x871E1C92 // 03-21-2002 build
#define OOT_PAL_GC_DBG2 0x87121EFE // 03-13-2002 build
#define OOT_PAL_GC_MQ_DBG 0x917D18F6
#define OOT_IQUE_TW 0x3D81FB3E
#define OOT_IQUE_CN 0xB1E1E07B
#include "../../libultraship/libultraship/GameVersions.h"
#include <cstdio>
#include <string>

View file

@ -5,6 +5,7 @@
#include "utils/mutils.h"
#include "ctpl/ctpl_stl.h"
#include <thread>
#include <impl/baserom_extractor/baserom_extractor.h>
#ifdef _WIN32
#define PLATFORM Platforms::WINDOWS
@ -13,6 +14,7 @@
#endif
namespace Util = MoonUtils;
bool oldExtractMode = false;
static int maxResources = 0;
static int extractedResources = 0;
bool buildingOtr = false;
@ -22,19 +24,29 @@ bool isWindows() {
return (PLATFORM == Platforms::WINDOWS);
}
void BuildOTR(const std::string output) {
Util::copy("tmp/baserom/Audiobank", "Extract/Audiobank");
Util::copy("tmp/baserom/Audioseq", "Extract/Audioseq");
Util::copy("tmp/baserom/Audiotable", "Extract/Audiotable");
Util::copy("assets/game/", "Extract/assets/");
std::string execStr = Util::format("assets/extractor/%s", isWindows() ? "ZAPD.exe" : "ZAPD.out") + " botr -se OTR";
ProcessResult result = NativeFS->LaunchProcess(execStr);
if(result.exitCode != 0) {
std::cout << "\nError when building the OTR file with error code: " << result.exitCode << " !" << std::endl;
std::cout << "Aborting...\n" << std::endl;
std::string GetXMLVersion(RomVersion version)
{
switch (version.crc)
{
case OOT_PAL_GC_DBG1: return "GC_NMQ_D";
case OOT_PAL_GC_DBG2: return "GC_MQ_D";
case OOT_PAL_GC: return "GC_NMQ_PAL_F";
}
return "ERROR";
}
void BuildOTR(const std::string output) {
if (oldExtractMode)
{
std::string execStr = Util::format("assets/extractor/%s", isWindows() ? "ZAPD.exe" : "ZAPD.out") + " botr -se OTR";
ProcessResult result = NativeFS->LaunchProcess(execStr);
if (result.exitCode != 0) {
std::cout << "\nError when building the OTR file with error code: " << result.exitCode << " !" << std::endl;
std::cout << "Aborting...\n" << std::endl;
}
}
setCurrentStep("Done!");
if (output == ".") return;
@ -44,9 +56,9 @@ void BuildOTR(const std::string output) {
MoonUtils::copy("oot.otr", outputPath);
}
void ExtractFile(std::string xmlPath, std::string outPath, std::string outSrcPath) {
void ExtractFile(std::string xmlPath, std::string outPath, std::string outSrcPath, RomVersion version) {
std::string execStr = Util::format("assets/extractor/%s", isWindows() ? "ZAPD.exe" : "ZAPD.out");
std::string args = Util::format(" e -eh -i %s -b tmp/baserom/ -o %s -osf %s -gsf 1 -rconf assets/extractor/Config.xml -se OTR %s", xmlPath.c_str(), outPath.c_str(), outSrcPath.c_str(), xmlPath.find("overlays") != std::string::npos ? "--static" : "");
std::string args = Util::format(" e -eh -i %s -b tmp/baserom/ -o %s -osf %s -gsf 1 -rconf assets/extractor/Config_%s.xml -se OTR %s", xmlPath.c_str(), outPath.c_str(), outSrcPath.c_str(), GetXMLVersion(version).c_str(), xmlPath.find("overlays") != std::string::npos ? "--static" : "");
ProcessResult result = NativeFS->LaunchProcess(execStr + args);
if (result.exitCode != 0) {
@ -55,49 +67,78 @@ void ExtractFile(std::string xmlPath, std::string outPath, std::string outSrcPat
}
}
void ExtractFunc(std::string fullPath) {
void ExtractFunc(std::string fullPath, RomVersion version) {
std::vector<std::string> path = Util::split(fullPath, Util::pathSeparator());
std::string outPath = Util::join(Util::join("assets/extractor/xmls/output", path[4]), Util::basename(fullPath));
Util::mkdir(outPath);
ExtractFile(fullPath, outPath, outPath);
ExtractFile(fullPath, outPath, outPath, version);
setCurrentStep("Extracting: " + Util::basename(fullPath));
extractedResources++;
}
void startWorker() {
std::string path = "assets/extractor/xmls";
std::vector<std::string> files;
Util::dirscan(path, files);
std::vector<std::string> xmlFiles;
void startWorker(RomVersion version) {
std::string path = "assets/extractor/xmls/";
const int num_threads = std::thread::hardware_concurrency();
ctpl::thread_pool pool(num_threads / 2);
for(auto &file : files) {
if (file.find(".xml") != std::string::npos) xmlFiles.push_back(file);
}
path += GetXMLVersion(version);
for (auto& file : xmlFiles) {
if(single_thread) {
ExtractFunc(file);
} else {
pool.push([file](int) {
ExtractFunc(file);
});
Util::write("tmp/baserom/version", (char*)&version.crc, sizeof(version.crc));
if (oldExtractMode)
{
std::vector<std::string> files;
Util::dirscan(path, files);
std::vector<std::string> xmlFiles;
const int num_threads = std::thread::hardware_concurrency();
ctpl::thread_pool pool(num_threads / 2);
for (auto& file : files) {
if (file.find(".xml") != std::string::npos) xmlFiles.push_back(file);
}
}
maxResources = xmlFiles.size();
for (auto& file : xmlFiles) {
if (single_thread) {
ExtractFunc(file, version);
}
else {
pool.push([file, version](int) {
ExtractFunc(file, version);
});
}
}
maxResources = xmlFiles.size();
}
else
{
std::string execStr = Util::format("assets/extractor/%s", isWindows() ? "ZAPD.exe" : "ZAPD.out");
std::string args = Util::format(" ed -eh -i %s -b tmp/rom.z64 -fl assets/extractor/filelists -o %s -osf %s -gsf 1 -rconf assets/extractor/Config_%s.xml -se OTR %s", path.c_str(), path + "../", path + "../", GetXMLVersion(version).c_str(), "");
ProcessResult result = NativeFS->LaunchProcess(execStr + args);
if (result.exitCode != 0) {
std::cout << "\nError when extracting the ROM with error code: " << result.exitCode << " !" << std::endl;
std::cout << "Aborting...\n" << std::endl;
}
else
{
printf("All done?\n");
}
maxResources = 1;
}
}
void updateWorker(const std::string& output) {
if (maxResources > 0 && !buildingOtr && extractedResources >= maxResources) {
if (maxResources > 0 && !buildingOtr && (extractedResources >= maxResources || !oldExtractMode))
{
setCurrentStep("Building OTR...");
if (skipFrames < 3) {
skipFrames++;
return;
}
buildingOtr = true;
if (single_thread){
if (single_thread || !oldExtractMode){
BuildOTR(output);
return;
}

View file

@ -5,5 +5,7 @@ enum Platforms {
WINDOWS, LINUX
};
void startWorker();
struct RomVersion;
void startWorker(RomVersion version);
void updateWorker(const std::string& output);

View file

@ -72,7 +72,11 @@ namespace MoonUtils {
vector<string> result;
stringstream ss (s);
string item;
while (getline(ss, item, delim)) {
while (getline(ss, item, delim))
{
if (item.at(item.size() - 1) == '\r')
item = item.substr(0, item.size() - 1);
result.push_back (item);
}
return result;