diff --git a/assets/xml/overlays/ovl_Arrow_Ice.xml b/assets/xml/overlays/ovl_Arrow_Ice.xml
index e130bdd055..96c0f25220 100644
--- a/assets/xml/overlays/ovl_Arrow_Ice.xml
+++ b/assets/xml/overlays/ovl_Arrow_Ice.xml
@@ -1,5 +1,5 @@
-
+
@@ -8,4 +8,4 @@
-
\ No newline at end of file
+
diff --git a/assets/xml/overlays/ovl_En_Clear_Tag.xml b/assets/xml/overlays/ovl_En_Clear_Tag.xml
index 82a1e2fe8a..0cbfcf80ae 100644
--- a/assets/xml/overlays/ovl_En_Clear_Tag.xml
+++ b/assets/xml/overlays/ovl_En_Clear_Tag.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/assets/xml/overlays/ovl_En_Holl.xml b/assets/xml/overlays/ovl_En_Holl.xml
index 5679e16059..2baa5737c5 100644
--- a/assets/xml/overlays/ovl_En_Holl.xml
+++ b/assets/xml/overlays/ovl_En_Holl.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/format.sh b/format.sh
index c705e9affe..ed830a5025 100755
--- a/format.sh
+++ b/format.sh
@@ -25,4 +25,5 @@ echo "Running clang-tidy..."
clang-tidy ${TIDY_OPTS} src/**/*.c -- ${COMPILER_OPTS} &> /dev/null
echo "Adding missing final new lines..."
find src/ -type f -name "*.c" -exec sed -i -e '$a\' {} \;
+find assets/xml/ -type f -name "*.xml" -exec sed -i -e '$a\' {} \;
echo "Done formatting all files."
diff --git a/tools/ZAPD/.gitignore b/tools/ZAPD/.gitignore
index 00ec03b0f2..68c502e36a 100644
--- a/tools/ZAPD/.gitignore
+++ b/tools/ZAPD/.gitignore
@@ -338,3 +338,4 @@ ZAPDUtils/ZAPDUtils.a
.vscode/
build/
ZAPDUtils/build/
+ZAPD/BuildInfo.h
diff --git a/tools/ZAPD/.gitrepo b/tools/ZAPD/.gitrepo
index 7201aacd35..94da913d0d 100644
--- a/tools/ZAPD/.gitrepo
+++ b/tools/ZAPD/.gitrepo
@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/zeldaret/ZAPD.git
branch = master
- commit = 623d779f8ea111cb8cbb78a218c8454e819c4c13
- parent = 9f2368dd710e740ced0f8086de91228b87f41512
+ commit = 4f7b8393ec8a3abd59649c2ba669e951fb61f3d2
+ parent = 346df1bbc8ca21673fe63d884b6734c23a4d9f4b
method = merge
cmdver = 0.4.3
diff --git a/tools/ZAPD/ExporterTest/CollisionExporter.cpp b/tools/ZAPD/ExporterTest/CollisionExporter.cpp
index 81a9b5464f..e00f5c1b0b 100644
--- a/tools/ZAPD/ExporterTest/CollisionExporter.cpp
+++ b/tools/ZAPD/ExporterTest/CollisionExporter.cpp
@@ -1,6 +1,7 @@
#include "CollisionExporter.h"
-void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]]fs::path outPath, BinaryWriter* writer)
+void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] fs::path outPath,
+ BinaryWriter* writer)
{
ZCollisionHeader* col = (ZCollisionHeader*)res;
@@ -35,9 +36,10 @@ void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]]fs::path ou
for (uint16_t i = 0; i < col->vertices.size(); i++)
{
- writer->Write(col->vertices[i].x);
- writer->Write(col->vertices[i].y);
- writer->Write(col->vertices[i].z);
+ for (uint32_t j = 0; j < col->vertices[i].dimensions; j++)
+ {
+ writer->Write(col->vertices[i].scalars[j].scalarData.s16);
+ }
}
writer->Seek(col->polySegmentOffset, SeekOffsetType::Start);
diff --git a/tools/ZAPD/ExporterTest/CollisionExporter.h b/tools/ZAPD/ExporterTest/CollisionExporter.h
index 2828995d04..5f48e6557e 100644
--- a/tools/ZAPD/ExporterTest/CollisionExporter.h
+++ b/tools/ZAPD/ExporterTest/CollisionExporter.h
@@ -1,7 +1,7 @@
#pragma once
-#include "ZResource.h"
#include "ZCollision.h"
+#include "ZResource.h"
class ExporterExample_Collision : public ZResourceExporter
{
diff --git a/tools/ZAPD/ExporterTest/Main.cpp b/tools/ZAPD/ExporterTest/Main.cpp
index 1fb6bea77a..4f683a1ba3 100644
--- a/tools/ZAPD/ExporterTest/Main.cpp
+++ b/tools/ZAPD/ExporterTest/Main.cpp
@@ -1,7 +1,7 @@
-#include
-#include
#include
#include
+#include
+#include
enum class ExporterFileMode
{
@@ -10,7 +10,7 @@ enum class ExporterFileMode
ModeExample3 = (int)ZFileMode::Custom + 3,
};
-static void ExporterParseFileMode(std::string buildMode, ZFileMode& fileMode)
+static void ExporterParseFileMode(const std::string& buildMode, ZFileMode& fileMode)
{
if (buildMode == "me1")
fileMode = (ZFileMode)ExporterFileMode::ModeExample1;
@@ -20,17 +20,15 @@ static void ExporterParseFileMode(std::string buildMode, ZFileMode& fileMode)
fileMode = (ZFileMode)ExporterFileMode::ModeExample3;
}
-static void ExporterParseArgs([[maybe_unused]]int argc, char* argv[], int& i)
+static void ExporterParseArgs([[maybe_unused]] int argc, char* argv[], int& i)
{
std::string arg = argv[i];
if (arg == "--do-x")
{
-
}
else if (arg == "--do-y")
{
-
}
}
@@ -61,7 +59,8 @@ static void ExporterFileEnd(ZFile* file)
static 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.
+ // By running ZAPD with the argument -se EXAMPLE, we tell it that we want to use this exporter
+ // for our resources.
ExporterSet* exporterSet = new ExporterSet();
exporterSet->processFileModeFunc = ExporterProcessFileMode;
exporterSet->parseFileModeFunc = ExporterParseFileMode;
@@ -75,5 +74,6 @@ static void ImportExporters()
Globals::AddExporter("EXAMPLE", exporterSet);
}
-// When ZAPD starts up, it will automatically call the below function, which in turn sets up our exporters.
-REGISTER_EXPORTER(ImportExporters)
\ No newline at end of file
+// When ZAPD starts up, it will automatically call the below function, which in turn sets up our
+// exporters.
+REGISTER_EXPORTER(ImportExporters);
diff --git a/tools/ZAPD/ExporterTest/RoomExporter.cpp b/tools/ZAPD/ExporterTest/RoomExporter.cpp
index dc8c82302c..c4a6844fb5 100644
--- a/tools/ZAPD/ExporterTest/RoomExporter.cpp
+++ b/tools/ZAPD/ExporterTest/RoomExporter.cpp
@@ -1,41 +1,41 @@
#include "RoomExporter.h"
+#include
#include
-#include
#include
-#include
-#include
-#include
-#include
+#include
#include
+#include
+#include
+#include
+#include
+#include
#include
#include
-#include
#include
-#include
-#include
+#include
+#include
+#include
#include
#include
-#include
-#include
-#include
-#include
+#include
+#include
void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter* writer)
{
- ZRoom* room = (ZRoom*)res;
+ ZRoom* room = dynamic_cast(res);
- //MemoryStream* memStream = new MemoryStream();
- //BinaryWriter* writer = new BinaryWriter(memStream);
+ // MemoryStream* memStream = new MemoryStream();
+ // BinaryWriter* writer = new BinaryWriter(memStream);
- for (uint i = 0; i < room->commands.size() * 8; i++)
+ for (size_t i = 0; i < room->commands.size() * 8; i++)
writer->Write((uint8_t)0);
- for (uint i = 0; i < room->commands.size(); i++)
+ for (size_t i = 0; i < room->commands.size(); i++)
{
ZRoomCommand* cmd = room->commands[i];
-
+
writer->Seek(i * 8, SeekOffsetType::Start);
-
+
writer->Write((uint8_t)cmd->cmdID);
switch (cmd->cmdID)
@@ -44,115 +44,115 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
{
SetWind* cmdSetWind = (SetWind*)cmd;
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)0); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
- writer->Write(cmdSetWind->windWest); // 0x04
- writer->Write(cmdSetWind->windVertical); // 0x05
- writer->Write(cmdSetWind->windSouth); // 0x06
- writer->Write(cmdSetWind->clothFlappingStrength); // 0x07
+ writer->Write(cmdSetWind->windWest); // 0x04
+ writer->Write(cmdSetWind->windVertical); // 0x05
+ writer->Write(cmdSetWind->windSouth); // 0x06
+ writer->Write(cmdSetWind->clothFlappingStrength); // 0x07
}
- break;
+ break;
case RoomCommand::SetTimeSettings:
{
SetTimeSettings* cmdTime = (SetTimeSettings*)cmd;
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)0); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
- writer->Write(cmdTime->hour); // 0x04
- writer->Write(cmdTime->min); // 0x05
- writer->Write(cmdTime->unk); // 0x06
- writer->Write((uint8_t)0); // 0x07
+ writer->Write(cmdTime->hour); // 0x04
+ writer->Write(cmdTime->min); // 0x05
+ writer->Write(cmdTime->unk); // 0x06
+ writer->Write((uint8_t)0); // 0x07
}
break;
case RoomCommand::SetSkyboxModifier:
{
SetSkyboxModifier* cmdSkybox = (SetSkyboxModifier*)cmd;
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)0); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
- writer->Write(cmdSkybox->disableSky); // 0x04
- writer->Write(cmdSkybox->disableSunMoon); // 0x05
- writer->Write((uint8_t)0); // 0x06
- writer->Write((uint8_t)0); // 0x07
+ writer->Write(cmdSkybox->disableSky); // 0x04
+ writer->Write(cmdSkybox->disableSunMoon); // 0x05
+ writer->Write((uint8_t)0); // 0x06
+ writer->Write((uint8_t)0); // 0x07
}
break;
case RoomCommand::SetEchoSettings:
{
SetEchoSettings* cmdEcho = (SetEchoSettings*)cmd;
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write((uint8_t)0); // 0x04
- writer->Write((uint8_t)0); // 0x05
- writer->Write((uint8_t)0); // 0x06
- writer->Write((uint8_t)cmdEcho->echo); // 0x07
+ writer->Write((uint8_t)0); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)0); // 0x04
+ writer->Write((uint8_t)0); // 0x05
+ writer->Write((uint8_t)0); // 0x06
+ writer->Write((uint8_t)cmdEcho->echo); // 0x07
}
break;
case RoomCommand::SetSoundSettings:
{
SetSoundSettings* cmdSound = (SetSoundSettings*)cmd;
- writer->Write((uint8_t)cmdSound->reverb); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write((uint8_t)0); // 0x04
- writer->Write((uint8_t)0); // 0x05
+ writer->Write((uint8_t)cmdSound->reverb); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)0); // 0x04
+ writer->Write((uint8_t)0); // 0x05
- writer->Write(cmdSound->nightTimeSFX); // 0x06
- writer->Write(cmdSound->musicSequence); // 0x07
+ writer->Write(cmdSound->nightTimeSFX); // 0x06
+ writer->Write(cmdSound->musicSequence); // 0x07
}
break;
case RoomCommand::SetSkyboxSettings:
{
SetSkyboxSettings* cmdSkybox = (SetSkyboxSettings*)cmd;
- writer->Write((uint8_t)cmdSkybox->unk1); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write((uint8_t)cmdSkybox->skyboxNumber); // 0x04
- writer->Write((uint8_t)cmdSkybox->cloudsType); // 0x05
- writer->Write((uint8_t)cmdSkybox->isIndoors); // 0x06
+ writer->Write((uint8_t)cmdSkybox->unk1); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)cmdSkybox->skyboxNumber); // 0x04
+ writer->Write((uint8_t)cmdSkybox->cloudsType); // 0x05
+ writer->Write((uint8_t)cmdSkybox->isIndoors); // 0x06
}
break;
case RoomCommand::SetRoomBehavior:
{
SetRoomBehavior* cmdRoom = (SetRoomBehavior*)cmd;
- writer->Write((uint8_t)cmdRoom->gameplayFlags); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write(cmdRoom->gameplayFlags2); // 0x04
+ writer->Write((uint8_t)cmdRoom->gameplayFlags); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write(cmdRoom->gameplayFlags2); // 0x04
}
break;
case RoomCommand::SetCsCamera:
{
SetCsCamera* cmdCsCam = (SetCsCamera*)cmd;
- writer->Write((uint8_t)cmdCsCam->cameras.size()); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)cmdCsCam->cameras.size()); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
- writer->Write(cmdCsCam->segmentOffset); // 0x04
+ writer->Write(cmdCsCam->segmentOffset); // 0x04
}
break;
case RoomCommand::SetMesh:
{
SetMesh* cmdMesh = (SetMesh*)cmd;
-
+
int baseStreamEnd = writer->GetStream().get()->GetLength();
- writer->Write((uint8_t)cmdMesh->data); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)cmdMesh->data); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
- writer->Write(baseStreamEnd); // 0x04
+ writer->Write(baseStreamEnd); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(baseStreamEnd, SeekOffsetType::Start);
@@ -163,15 +163,13 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
if (cmdMesh->meshHeaderType == 0)
{
- //writer->Write(cmdMesh->)
+ // writer->Write(cmdMesh->)
}
else if (cmdMesh->meshHeaderType == 1)
{
-
}
else if (cmdMesh->meshHeaderType == 2)
{
-
}
writer->Seek(oldOffset, SeekOffsetType::Start);
@@ -181,20 +179,20 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
{
SetCameraSettings* cmdCam = (SetCameraSettings*)cmd;
- writer->Write((uint8_t)cmdCam->cameraMovement); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write(cmdCam->mapHighlight); // 0x04
+ writer->Write((uint8_t)cmdCam->cameraMovement); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write(cmdCam->mapHighlight); // 0x04
}
break;
case RoomCommand::SetLightingSettings:
{
SetLightingSettings* cmdLight = (SetLightingSettings*)cmd;
- writer->Write((uint8_t)cmdLight->settings.size()); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write(cmdLight->segmentOffset); // 0x04
+ writer->Write((uint8_t)cmdLight->settings.size()); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write(cmdLight->segmentOffset); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(cmdLight->segmentOffset, SeekOffsetType::Start);
@@ -236,17 +234,17 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
{
SetRoomList* cmdRoom = (SetRoomList*)cmd;
- writer->Write((uint8_t)cmdRoom->rooms.size()); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)cmdRoom->romfile->rooms.size()); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
- int baseStreamEnd = writer->GetLength();
- writer->Write(baseStreamEnd); // 0x04
+ auto baseStreamEnd = writer->GetLength();
+ writer->Write(baseStreamEnd); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(baseStreamEnd, SeekOffsetType::Start);
- for (RoomEntry entry : cmdRoom->rooms)
+ for (const auto& entry : cmdRoom->romfile->rooms)
{
writer->Write(entry.virtualAddressStart);
writer->Write(entry.virtualAddressEnd);
@@ -261,10 +259,10 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
int streamEnd = writer->GetStream().get()->GetLength();
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write(streamEnd); // 0x04
+ writer->Write((uint8_t)0); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write(streamEnd); // 0x04
// TODO: NOT DONE
@@ -284,10 +282,10 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
uint32_t baseStreamEnd = writer->GetStream().get()->GetLength();
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write(baseStreamEnd); // 0x04
+ writer->Write((uint8_t)0); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write(baseStreamEnd); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(baseStreamEnd, SeekOffsetType::Start);
@@ -305,12 +303,12 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
{
SetSpecialObjects* cmdSpecObj = (SetSpecialObjects*)cmd;
- writer->Write((uint8_t)cmdSpecObj->elfMessage); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write((uint8_t)0); // 0x04
- writer->Write((uint8_t)0); // 0x05
- writer->Write((uint16_t)cmdSpecObj->globalObject); // 0x06
+ writer->Write((uint8_t)cmdSpecObj->elfMessage); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)0); // 0x04
+ writer->Write((uint8_t)0); // 0x05
+ writer->Write((uint16_t)cmdSpecObj->globalObject); // 0x06
}
break;
case RoomCommand::SetStartPositionList:
@@ -319,10 +317,10 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
uint32_t baseStreamEnd = writer->GetStream().get()->GetLength();
- writer->Write((uint8_t)cmdStartPos->actors.size()); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write(baseStreamEnd); // 0x04
+ writer->Write((uint8_t)cmdStartPos->actors.size()); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write(baseStreamEnd); // 0x04
uint32_t oldOffset = writer->GetBaseAddress();
writer->Seek(baseStreamEnd, SeekOffsetType::Start);
@@ -344,30 +342,31 @@ void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter*
break;
case RoomCommand::EndMarker:
{
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write((uint8_t)0); // 0x04
- writer->Write((uint8_t)0); // 0x05
- writer->Write((uint8_t)0); // 0x06
- writer->Write((uint8_t)0); // 0x07
+ writer->Write((uint8_t)0); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)0); // 0x04
+ writer->Write((uint8_t)0); // 0x05
+ writer->Write((uint8_t)0); // 0x06
+ writer->Write((uint8_t)0); // 0x07
}
break;
default:
printf("UNIMPLEMENTED COMMAND: %i\n", (int)cmd->cmdID);
- writer->Write((uint8_t)0); // 0x01
- writer->Write((uint8_t)0); // 0x02
- writer->Write((uint8_t)0); // 0x03
- writer->Write((uint8_t)0); // 0x04
- writer->Write((uint8_t)0); // 0x05
- writer->Write((uint8_t)0); // 0x06
- writer->Write((uint8_t)0); // 0x07
+ writer->Write((uint8_t)0); // 0x01
+ writer->Write((uint8_t)0); // 0x02
+ writer->Write((uint8_t)0); // 0x03
+ writer->Write((uint8_t)0); // 0x04
+ writer->Write((uint8_t)0); // 0x05
+ writer->Write((uint8_t)0); // 0x06
+ writer->Write((uint8_t)0); // 0x07
break;
}
}
- //writer->Close();
- //File::WriteAllBytes(StringHelper::Sprintf("%s", res->GetName().c_str()), memStream->ToVector());
+ // writer->Close();
+ // File::WriteAllBytes(StringHelper::Sprintf("%s", res->GetName().c_str()),
+ // memStream->ToVector());
}
diff --git a/tools/ZAPD/ExporterTest/TextureExporter.cpp b/tools/ZAPD/ExporterTest/TextureExporter.cpp
index 95d84b8f7b..6488bed3a2 100644
--- a/tools/ZAPD/ExporterTest/TextureExporter.cpp
+++ b/tools/ZAPD/ExporterTest/TextureExporter.cpp
@@ -1,12 +1,14 @@
#include "TextureExporter.h"
#include "../ZAPD/ZFile.h"
-void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]]fs::path outPath, BinaryWriter* writer)
+void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] fs::path outPath,
+ BinaryWriter* writer)
{
ZTexture* tex = (ZTexture*)res;
auto data = tex->parent->GetRawData();
- for (uint i = tex->GetRawDataIndex(); i < tex->GetRawDataIndex() + tex->GetRawDataSize(); i++)
+ for (offset_t i = tex->GetRawDataIndex(); i < tex->GetRawDataIndex() + tex->GetRawDataSize();
+ i++)
writer->Write(data[i]);
-}
\ No newline at end of file
+}
diff --git a/tools/ZAPD/ExporterTest/TextureExporter.h b/tools/ZAPD/ExporterTest/TextureExporter.h
index fcee8be5ad..ffe6001dca 100644
--- a/tools/ZAPD/ExporterTest/TextureExporter.h
+++ b/tools/ZAPD/ExporterTest/TextureExporter.h
@@ -1,8 +1,8 @@
#pragma once
+#include
#include "ZResource.h"
#include "ZTexture.h"
-#include
class ExporterExample_Texture : public ZResourceExporter
{
diff --git a/tools/ZAPD/Makefile b/tools/ZAPD/Makefile
index e8f6c92a38..737b85ecf7 100644
--- a/tools/ZAPD/Makefile
+++ b/tools/ZAPD/Makefile
@@ -5,17 +5,22 @@ ASAN ?= 0
DEPRECATION_ON ?= 1
DEBUG ?= 0
COPYCHECK_ARGS ?=
-# Set LLD=1 to use ld.lld as the linker
LLD ?= 0
-CXX := g++
+# Use clang++ if available, else use g++
+ifeq ($(shell command -v clang++ >/dev/null 2>&1; echo $$?),0)
+ CXX := clang++
+else
+ CXX := g++
+endif
+
INC := -I ZAPD -I lib/elfio -I lib/libgfxd -I lib/tinyxml2 -I ZAPDUtils
CXXFLAGS := -fpic -std=c++17 -Wall -Wextra -fno-omit-frame-pointer
OPTFLAGS :=
ifneq ($(DEBUG),0)
OPTIMIZATION_ON = 0
- DEPRECATION_OFF = 1
+ CXXFLAGS += -g3 -DDEVELOPMENT -D_DEBUG
COPYCHECK_ARGS += --devel
DEPRECATION_ON = 0
else
@@ -29,7 +34,7 @@ else
endif
ifneq ($(ASAN),0)
- CXXFLAGS += -fsanitize=address
+ CXXFLAGS += -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=undefined
endif
ifneq ($(DEPRECATION_ON),0)
CXXFLAGS += -DDEPRECATION_ON
@@ -38,6 +43,11 @@ endif
LDFLAGS := -lm -ldl -lpng
+# Use LLD if available. Set LLD=0 to not use it
+ifeq ($(shell command -v ld.lld >/dev/null 2>&1; echo $$?),0)
+ LLD := 1
+endif
+
ifneq ($(LLD),0)
LDFLAGS += -fuse-ld=lld
endif
@@ -105,4 +115,4 @@ ZAPDUtils:
# Linking
ZAPD.out: $(O_FILES) lib/libgfxd/libgfxd.a ExporterTest ZAPDUtils
- $(CXX) $(O_FILES) lib/libgfxd/libgfxd.a ZAPDUtils/ZAPDUtils.a -Wl,--whole-archive ExporterTest/ExporterTest.a -Wl,--no-whole-archive $(LDFLAGS) $(OUTPUT_OPTION)
+ $(CXX) $(CXXFLAGS) $(O_FILES) lib/libgfxd/libgfxd.a ZAPDUtils/ZAPDUtils.a -Wl,--whole-archive ExporterTest/ExporterTest.a -Wl,--no-whole-archive $(LDFLAGS) $(OUTPUT_OPTION)
diff --git a/tools/ZAPD/README.md b/tools/ZAPD/README.md
index 4d7ade27e1..e2764b6277 100644
--- a/tools/ZAPD/README.md
+++ b/tools/ZAPD/README.md
@@ -30,7 +30,7 @@ You can configure a bit your ZAPD build with the following options:
- `DEBUG`: If non-zero, ZAPD will be compiled in _development mode_. This implies the following:
- Debugging symbols enabled (`-g3`). They are disabled by default.
- `OPTIMIZATION_ON=0`: Disables optimizations (`-O0`).
- - `DEPRECATION_OFF=1`: Disables deprecation warnings.
+ - `DEPRECATION_ON=0`: Disables deprecation warnings.
- `LLD=1`: builds with the LLVM linker `ld.lld` instead of the system default.
As an example, if you want to build ZAPD with optimizations disabled and use the address sanitizer, you could use the following command:
@@ -110,8 +110,10 @@ ZAPD also accepts the following list of extra parameters:
- Can be used only in `e` or `bsf` modes.
- `-tm MODE`: Test Mode (enables certain experimental features). To enable it, set `MODE` to `1`.
- `-wno` / `--warn-no-offsets` : Enable warnings for nodes that dont have offsets specified. Takes priority over `-eno`/ `--error-no-offsets`.
-- `-eno`/ `--error-no-offsets` : Enable errors for nodes that dont have offsets specified.
+- `-eno` / `--error-no-offsets` : Enable errors for nodes that dont have offsets specified.
- `-se` / `--set-exporter` : Sets which exporter to use.
- `--gcc-compat` : Enables GCC compatible mode. Slower.
+- `-s` / `--static` : Mark every asset as `static`.
+ - This behaviour can be overridden per asset using `Static=` in the respective XML node.
Additionally, you can pass the flag `--version` to see the current ZAPD version. If that flag is passed, ZAPD will ignore any other parameter passed.
diff --git a/tools/ZAPD/ZAPD/Declaration.cpp b/tools/ZAPD/ZAPD/Declaration.cpp
index 63a3918050..d2a86ffcc5 100644
--- a/tools/ZAPD/ZAPD/Declaration.cpp
+++ b/tools/ZAPD/ZAPD/Declaration.cpp
@@ -1,37 +1,31 @@
#include "Declaration.h"
-Declaration::Declaration(DeclarationAlignment nAlignment, DeclarationPadding nPadding, size_t nSize,
- std::string nText)
+#include "Globals.h"
+#include "Utils/StringHelper.h"
+
+Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nText)
{
+ address = nAddress;
alignment = nAlignment;
- padding = nPadding;
size = nSize;
text = nText;
}
-Declaration::Declaration(DeclarationAlignment nAlignment, size_t nSize, std::string nVarType,
- std::string nVarName, bool nIsArray, std::string nText)
- : Declaration(nAlignment, DeclarationPadding::None, nSize, nText)
+Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName, bool nIsArray,
+ const std::string& nText)
+ : Declaration(nAddress, nAlignment, nSize, nText)
{
varType = nVarType;
varName = nVarName;
isArray = nIsArray;
}
-Declaration::Declaration(DeclarationAlignment nAlignment, DeclarationPadding nPadding, size_t nSize,
- std::string nVarType, std::string nVarName, bool nIsArray,
- std::string nText)
- : Declaration(nAlignment, nPadding, nSize, nText)
-{
- varType = nVarType;
- varName = nVarName;
- isArray = nIsArray;
-}
-
-Declaration::Declaration(DeclarationAlignment nAlignment, size_t nSize, std::string nVarType,
- std::string nVarName, bool nIsArray, size_t nArrayItemCnt,
- std::string nText)
- : Declaration(nAlignment, DeclarationPadding::None, nSize, nText)
+Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName, bool nIsArray,
+ size_t nArrayItemCnt, const std::string& nText)
+ : Declaration(nAddress, nAlignment, nSize, nText)
{
varType = nVarType;
varName = nVarName;
@@ -39,10 +33,10 @@ Declaration::Declaration(DeclarationAlignment nAlignment, size_t nSize, std::str
arrayItemCnt = nArrayItemCnt;
}
-Declaration::Declaration(DeclarationAlignment nAlignment, size_t nSize, std::string nVarType,
- std::string nVarName, bool nIsArray, std::string nArrayItemCntStr,
- std::string nText)
- : Declaration(nAlignment, DeclarationPadding::None, nSize, nText)
+Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName, bool nIsArray,
+ const std::string& nArrayItemCntStr, const std::string& nText)
+ : Declaration(nAddress, nAlignment, nSize, nText)
{
varType = nVarType;
varName = nVarName;
@@ -50,30 +44,179 @@ Declaration::Declaration(DeclarationAlignment nAlignment, size_t nSize, std::str
arrayItemCntStr = nArrayItemCntStr;
}
-Declaration::Declaration(DeclarationAlignment nAlignment, size_t nSize, std::string nVarType,
- std::string nVarName, bool nIsArray, size_t nArrayItemCnt,
- std::string nText, bool nIsExternal)
- : Declaration(nAlignment, nSize, nVarType, nVarName, nIsArray, nArrayItemCnt, nText)
+Declaration::Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName, bool nIsArray,
+ size_t nArrayItemCnt, const std::string& nText, bool nIsExternal)
+ : Declaration(nAddress, nAlignment, nSize, nVarType, nVarName, nIsArray, nArrayItemCnt, nText)
{
isExternal = nIsExternal;
}
-Declaration::Declaration(DeclarationAlignment nAlignment, DeclarationPadding nPadding, size_t nSize,
- std::string nVarType, std::string nVarName, bool nIsArray,
- size_t nArrayItemCnt, std::string nText)
- : Declaration(nAlignment, nPadding, nSize, nText)
-{
- varType = nVarType;
- varName = nVarName;
- isArray = nIsArray;
- arrayItemCnt = nArrayItemCnt;
-}
-
-Declaration::Declaration(std::string nIncludePath, size_t nSize, std::string nVarType,
- std::string nVarName)
- : Declaration(DeclarationAlignment::None, DeclarationPadding::None, nSize, "")
+Declaration::Declaration(offset_t nAddress, const std::string& nIncludePath, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName)
+ : Declaration(nAddress, DeclarationAlignment::Align4, nSize, "")
{
includePath = nIncludePath;
varType = nVarType;
varName = nVarName;
}
+
+bool Declaration::IsStatic() const
+{
+ switch (staticConf)
+ {
+ case StaticConfig::Off:
+ return false;
+
+ case StaticConfig::Global:
+ return Globals::Instance->forceStatic;
+
+ case StaticConfig::On:
+ return true;
+ }
+
+ return false;
+}
+
+std::string Declaration::GetNormalDeclarationStr() const
+{
+ std::string output;
+
+ if (preText != "")
+ output += preText + "\n";
+
+ if (IsStatic())
+ {
+ output += "static ";
+ }
+
+ if (isArray)
+ {
+ if (arrayItemCntStr != "")
+ {
+ output += StringHelper::Sprintf("%s %s[%s];\n", varType.c_str(), varName.c_str(),
+ arrayItemCntStr.c_str());
+ }
+ else if (arrayItemCnt == 0)
+ {
+ output += StringHelper::Sprintf("%s %s[] = {\n", varType.c_str(), varName.c_str());
+ }
+ else
+ {
+ output += StringHelper::Sprintf("%s %s[%i] = {\n", varType.c_str(), varName.c_str(),
+ arrayItemCnt);
+ }
+
+ output += text + "\n";
+ }
+ else
+ {
+ output += StringHelper::Sprintf("%s %s = { ", varType.c_str(), varName.c_str());
+ output += text;
+ }
+
+ if (output.back() == '\n')
+ output += "};";
+ else
+ output += " };";
+
+ if (rightText != "")
+ output += " " + rightText + "";
+
+ output += "\n";
+
+ if (postText != "")
+ output += postText + "\n";
+
+ output += "\n";
+
+ return output;
+}
+
+std::string Declaration::GetExternalDeclarationStr() const
+{
+ std::string output;
+
+ if (preText != "")
+ output += preText + "\n";
+
+ if (IsStatic())
+ {
+ output += "static ";
+ }
+
+ if (arrayItemCntStr != "")
+ output +=
+ StringHelper::Sprintf("%s %s[%s] = {\n#include \"%s\"\n};", varType.c_str(),
+ varName.c_str(), arrayItemCntStr.c_str(), includePath.c_str());
+ else if (arrayItemCnt != 0)
+ output += StringHelper::Sprintf("%s %s[%i] = {\n#include \"%s\"\n};", varType.c_str(),
+ varName.c_str(), arrayItemCnt, includePath.c_str());
+ else
+ output += StringHelper::Sprintf("%s %s[] = {\n#include \"%s\"\n};", varType.c_str(),
+ varName.c_str(), includePath.c_str());
+
+ if (rightText != "")
+ output += " " + rightText + "";
+
+ output += "\n";
+
+ if (postText != "")
+ output += postText + "\n";
+
+ output += "\n";
+
+ return output;
+}
+
+std::string Declaration::GetExternStr() const
+{
+ if (IsStatic() || varType == "")
+ {
+ return "";
+ }
+
+ if (isArray)
+ {
+ if (arrayItemCntStr != "")
+ {
+ return StringHelper::Sprintf("extern %s %s[%s];\n", varType.c_str(), varName.c_str(),
+ arrayItemCntStr.c_str());
+ }
+ else if (arrayItemCnt != 0)
+ return StringHelper::Sprintf("extern %s %s[%i];\n", varType.c_str(), varName.c_str(),
+ arrayItemCnt);
+ else
+ return StringHelper::Sprintf("extern %s %s[];\n", varType.c_str(), varName.c_str());
+ }
+
+ return StringHelper::Sprintf("extern %s %s;\n", varType.c_str(), varName.c_str());
+}
+
+std::string Declaration::GetStaticForwardDeclarationStr() const
+{
+ if (!IsStatic() || isUnaccounted)
+ return "";
+
+ if (isArray)
+ {
+ if (arrayItemCntStr == "" && arrayItemCnt == 0)
+ {
+ // Forward declaring static arrays without specifying the size is not allowed.
+ return "";
+ }
+
+ if (arrayItemCntStr != "")
+ {
+ return StringHelper::Sprintf("static %s %s[%s];\n", varType.c_str(), varName.c_str(),
+ arrayItemCntStr.c_str());
+ }
+ else
+ {
+ return StringHelper::Sprintf("static %s %s[%i];\n", varType.c_str(), varName.c_str(),
+ arrayItemCnt);
+ }
+ }
+
+ return StringHelper::Sprintf("static %s %s;\n", varType.c_str(), varName.c_str());
+}
diff --git a/tools/ZAPD/ZAPD/Declaration.h b/tools/ZAPD/ZAPD/Declaration.h
index f955110e78..138524a4c2 100644
--- a/tools/ZAPD/ZAPD/Declaration.h
+++ b/tools/ZAPD/ZAPD/Declaration.h
@@ -3,63 +3,77 @@
#include
#include
+// TODO: should we drop the `_t` suffix because of UNIX compliance?
+typedef uint32_t segptr_t;
+typedef uint32_t offset_t;
+
+#define SEGMENTED_NULL ((segptr_t)0)
+
enum class DeclarationAlignment
{
- None,
Align4,
Align8,
Align16
};
-enum class DeclarationPadding
+enum class StaticConfig
{
- None,
- Pad4,
- Pad8,
- Pad16
+ Off,
+ Global,
+ On
};
class Declaration
{
public:
+ offset_t address;
DeclarationAlignment alignment;
- DeclarationPadding padding;
size_t size;
- std::string preText = "";
- std::string text = "";
- std::string rightText = "";
- std::string postText = "";
- std::string preComment = "";
- std::string postComment = "";
- std::string varType = "";
- std::string varName = "";
- std::string includePath = "";
+ std::string preText;
+ std::string text;
+ std::string rightText;
+ std::string postText;
+ std::string preComment;
+ std::string postComment;
+ std::string varType;
+ std::string varName;
+ std::string includePath;
bool isExternal = false;
bool isArray = false;
size_t arrayItemCnt = 0;
- std::string arrayItemCntStr = "";
- std::vector references;
+ std::string arrayItemCntStr;
+ std::vector references;
bool isUnaccounted = false;
bool isPlaceholder = false;
+ bool declaredInXml = false;
+ StaticConfig staticConf = StaticConfig::Global;
- Declaration(DeclarationAlignment nAlignment, size_t nSize, std::string nVarType,
- std::string nVarName, bool nIsArray, std::string nText);
- Declaration(DeclarationAlignment nAlignment, DeclarationPadding nPadding, size_t nSize,
- std::string nVarType, std::string nVarName, bool nIsArray, std::string nText);
- Declaration(DeclarationAlignment nAlignment, size_t nSize, std::string nVarType,
- std::string nVarName, bool nIsArray, size_t nArrayItemCnt, std::string nText);
- Declaration(DeclarationAlignment nAlignment, size_t nSize, std::string nVarType,
- std::string nVarName, bool nIsArray, std::string nArrayItemCntStr,
- std::string nText);
- Declaration(DeclarationAlignment nAlignment, size_t nSize, std::string nVarType,
- std::string nVarName, bool nIsArray, size_t nArrayItemCnt, std::string nText,
- bool nIsExternal);
- Declaration(DeclarationAlignment nAlignment, DeclarationPadding nPadding, size_t nSize,
- std::string nVarType, std::string nVarName, bool nIsArray, size_t nArrayItemCnt,
- std::string nText);
- Declaration(std::string nIncludePath, size_t nSize, std::string nVarType, std::string nVarName);
+ Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName, bool nIsArray,
+ const std::string& nText);
+ Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName, bool nIsArray,
+ size_t nArrayItemCnt, const std::string& nText);
+ Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName, bool nIsArray,
+ const std::string& nArrayItemCntStr, const std::string& nText);
+ Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName, bool nIsArray,
+ size_t nArrayItemCnt, const std::string& nText, bool nIsExternal);
+
+ Declaration(offset_t nAddress, const std::string& nIncludePath, size_t nSize,
+ const std::string& nVarType, const std::string& nVarName);
+
+ bool IsStatic() const;
+
+ std::string GetNormalDeclarationStr() const;
+ std::string GetExternalDeclarationStr() const;
+
+ std::string GetExternStr() const;
+
+ std::string GetStaticForwardDeclarationStr() const;
protected:
- Declaration(DeclarationAlignment nAlignment, DeclarationPadding nPadding, size_t nSize,
- std::string nText);
-};
\ No newline at end of file
+ Declaration(offset_t nAddress, DeclarationAlignment nAlignment, size_t nSize,
+ const std::string& nText);
+};
diff --git a/tools/ZAPD/ZAPD/GameConfig.cpp b/tools/ZAPD/ZAPD/GameConfig.cpp
new file mode 100644
index 0000000000..f197493a4a
--- /dev/null
+++ b/tools/ZAPD/ZAPD/GameConfig.cpp
@@ -0,0 +1,184 @@
+#include "GameConfig.h"
+
+#include
+#include
+
+#include "Utils/Directory.h"
+#include "Utils/File.h"
+#include "Utils/Path.h"
+#include "ZFile.h"
+#include "tinyxml2.h"
+
+using ConfigFunc = void (GameConfig::*)(const tinyxml2::XMLElement&);
+
+GameConfig::~GameConfig()
+{
+ for (auto& declPair : segmentRefFiles)
+ {
+ for (auto& file : declPair.second)
+ {
+ delete file;
+ }
+ }
+}
+
+void GameConfig::ReadTexturePool(const fs::path& texturePoolXmlPath)
+{
+ tinyxml2::XMLDocument doc;
+ tinyxml2::XMLError eResult = doc.LoadFile(texturePoolXmlPath.c_str());
+
+ if (eResult != tinyxml2::XML_SUCCESS)
+ {
+ fprintf(stderr, "Warning: Unable to read texture pool XML with error code %i\n", eResult);
+ return;
+ }
+
+ tinyxml2::XMLNode* root = doc.FirstChild();
+
+ if (root == nullptr)
+ return;
+
+ for (tinyxml2::XMLElement* child = root->FirstChildElement(); child != nullptr;
+ child = child->NextSiblingElement())
+ {
+ if (std::string_view(child->Name()) == "Texture")
+ {
+ std::string crcStr = child->Attribute("CRC");
+ fs::path texPath = child->Attribute("Path");
+ std::string texName;
+
+ uint32_t crc = strtoul(crcStr.c_str(), nullptr, 16);
+
+ texturePool[crc].path = texPath;
+ }
+ }
+}
+
+void GameConfig::GenSymbolMap(const fs::path& symbolMapPath)
+{
+ auto symbolLines = File::ReadAllLines(symbolMapPath);
+
+ for (std::string& symbolLine : symbolLines)
+ {
+ auto split = StringHelper::Split(symbolLine, " ");
+ uint32_t addr = strtoul(split[0].c_str(), nullptr, 16);
+ std::string symbolName = split[1];
+
+ symbolMap[addr] = std::move(symbolName);
+ }
+}
+
+void GameConfig::ConfigFunc_SymbolMap(const tinyxml2::XMLElement& element)
+{
+ std::string fileName = element.Attribute("File");
+ GenSymbolMap(Path::GetDirectoryName(configFilePath) / fileName);
+}
+
+void GameConfig::ConfigFunc_ActorList(const tinyxml2::XMLElement& element)
+{
+ std::string fileName = element.Attribute("File");
+ std::vector lines =
+ File::ReadAllLines(Path::GetDirectoryName(configFilePath) / fileName);
+
+ for (auto& line : lines)
+ actorList.emplace_back(std::move(line));
+}
+
+void GameConfig::ConfigFunc_ObjectList(const tinyxml2::XMLElement& element)
+{
+ std::string fileName = element.Attribute("File");
+ std::vector lines =
+ File::ReadAllLines(Path::GetDirectoryName(configFilePath) / fileName);
+
+ for (auto& line : lines)
+ objectList.emplace_back(std::move(line));
+}
+
+void GameConfig::ConfigFunc_TexturePool(const tinyxml2::XMLElement& element)
+{
+ std::string fileName = element.Attribute("File");
+ ReadTexturePool(Path::GetDirectoryName(configFilePath) / fileName);
+}
+
+void GameConfig::ConfigFunc_BGConfig(const tinyxml2::XMLElement& element)
+{
+ bgScreenWidth = element.IntAttribute("ScreenWidth", 320);
+ bgScreenHeight = element.IntAttribute("ScreenHeight", 240);
+}
+
+void GameConfig::ConfigFunc_ExternalXMLFolder(const tinyxml2::XMLElement& element)
+{
+ const char* pathValue = element.Attribute("Path");
+ if (pathValue == nullptr)
+ {
+ throw std::runtime_error(
+ StringHelper::Sprintf("Parse: Fatal error in configuration file.\n"
+ "\t Missing 'Path' attribute in `ExternalXMLFolder` element.\n"));
+ }
+ if (externalXmlFolder != "")
+ {
+ throw std::runtime_error(StringHelper::Sprintf("Parse: Fatal error in configuration file.\n"
+ "\t `ExternalXMLFolder` is duplicated.\n"));
+ }
+ externalXmlFolder = pathValue;
+}
+
+void GameConfig::ConfigFunc_ExternalFile(const tinyxml2::XMLElement& element)
+{
+ const char* xmlPathValue = element.Attribute("XmlPath");
+ if (xmlPathValue == nullptr)
+ {
+ throw std::runtime_error(
+ StringHelper::Sprintf("Parse: Fatal error in configuration file.\n"
+ "\t Missing 'XmlPath' attribute in `ExternalFile` element.\n"));
+ }
+ const char* outPathValue = element.Attribute("OutPath");
+ if (outPathValue == nullptr)
+ {
+ throw std::runtime_error(
+ StringHelper::Sprintf("Parse: Fatal error in configuration file.\n"
+ "\t Missing 'OutPath' attribute in `ExternalFile` element.\n"));
+ }
+
+ externalFiles.push_back(ExternalFile(fs::path(xmlPathValue), fs::path(outPathValue)));
+}
+
+void GameConfig::ReadConfigFile(const fs::path& argConfigFilePath)
+{
+ static const std::map ConfigFuncDictionary = {
+ {"SymbolMap", &GameConfig::ConfigFunc_SymbolMap},
+ {"ActorList", &GameConfig::ConfigFunc_ActorList},
+ {"ObjectList", &GameConfig::ConfigFunc_ObjectList},
+ {"TexturePool", &GameConfig::ConfigFunc_TexturePool},
+ {"BGConfig", &GameConfig::ConfigFunc_BGConfig},
+ {"ExternalXMLFolder", &GameConfig::ConfigFunc_ExternalXMLFolder},
+ {"ExternalFile", &GameConfig::ConfigFunc_ExternalFile},
+ };
+
+ configFilePath = argConfigFilePath;
+ tinyxml2::XMLDocument doc;
+ tinyxml2::XMLError eResult = doc.LoadFile(configFilePath.c_str());
+
+ if (eResult != tinyxml2::XML_SUCCESS)
+ {
+ throw std::runtime_error("Error: Unable to read config file.");
+ }
+
+ tinyxml2::XMLNode* root = doc.FirstChild();
+
+ if (root == nullptr)
+ return;
+
+ for (tinyxml2::XMLElement* child = root->FirstChildElement(); child != nullptr;
+ child = child->NextSiblingElement())
+ {
+ auto it = ConfigFuncDictionary.find(child->Name());
+ if (it == ConfigFuncDictionary.end())
+ {
+ fprintf(stderr, "Unsupported configuration variable: %s\n", child->Name());
+ continue;
+ }
+
+ std::invoke(it->second, *this, *child);
+ }
+}
diff --git a/tools/ZAPD/ZAPD/GameConfig.h b/tools/ZAPD/ZAPD/GameConfig.h
new file mode 100644
index 0000000000..c478d16ceb
--- /dev/null
+++ b/tools/ZAPD/ZAPD/GameConfig.h
@@ -0,0 +1,58 @@
+#pragma once
+
+#include
+#include