Linux/GCC Support (#28)

* Initial Linux/GCC support commit

* Add instructins for linux in the README

* apply suggestions by @Erotemic and @Emill

* Fix python 3.10 symlink line

* Fix func_80041E80 type mismatch (#3)

Type mismatch functions.h:664

* Makefile: clean OTRExporter/libultraship/ZAPDTR with distclean and fix CXX_FILES

* Makefile: find C/CXX_FILES automatically

* Makefile: remove ugly conditions in find commands

* cleanup _MSC_VER usage

* fix Windows build

* cleanup extraction scripts

* fix Windows build

* Fix Windows path separator issue

* fix rumble support for linux

* use glew-cmake in dockerfile

* add pulseaudio backend

* fix ZAPDTR linkage

* Check for "soh.elf" in directory (#6)

hide second button if `soh.exe` or `soh.elf` is present

* Fix hardcoded segment addresses (#5)

* fix condition

* hack lus -> soh dep for ZAPDTR

Co-authored-by: sholdee <102821812+sholdee@users.noreply.github.com>
Co-authored-by: qurious-pixel <62252937+qurious-pixel@users.noreply.github.com>
Co-authored-by: GaryOderNichts <12049776+GaryOderNichts@users.noreply.github.com>
This commit is contained in:
Random 2022-05-12 02:18:24 +09:00 committed by GitHub
parent 2e1a0b5144
commit 09432ee7f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
116 changed files with 1403 additions and 4054 deletions

1
.gitignore vendored
View File

@ -395,6 +395,7 @@ ExporterTest/ExporterTest.a
ZAPDUtils/ZAPDUtils.a
.vscode/
build/
external/
ZAPDUtils/build/
ZAPD/BuildInfo.h

View File

@ -1,5 +1,7 @@
# Building Ship of Harkinian
## Windows
1. Install [Python](https://www.python.org/ftp/python/3.10.2/python-3.10.2-amd64.exe)
2. Install [Visual Studio 2022 Community Edition](https://visualstudio.microsoft.com/vs/community/)
2b. In the Visual Studio Installer, install `MSVC v142 - VS 2019 C++`.
@ -15,7 +17,36 @@
13. Copy the `OTRExporter/oot.otr` archive file to `soh/Release`.
14. Launch `soh.exe`.
## Compatible Roms
## Linux
```bash
# Clone the repo
git clone git@github.com:HarbourMasters/ShipWright.git
cd ShipWright
# Copy the baserom to the OTRExporter folder
cp <path to your ROM> OTRExporter
# Build the docker image
sudo docker build . -t soh
# Run the docker image with the working directory mounted to /soh
sudo docker run --rm -it -v $(pwd):/soh soh /bin/bash
```
Inside the Docker container:
```bash
# Clone and build StormLib
git clone https://github.com/ladislav-zezula/StormLib external/StormLib
cmake -B external/StormLib/build -S external/StormLib
cmake --build external/StormLib/build
cp external/StormLib/build/libstorm.a external
cp /usr/local/lib/libGLEW.a external
cd soh
# Extract the assets/Compile the exporter/Run the exporter
make setup -j$(nproc)
# Compile the code
make -j $(nproc)
```
# Compatible Roms
```
OOT_PAL_GC checksum 0x09465AC3
OOT_PAL_GC_DBG1 checksum 0x871E1C92 (debug non-master quest)

38
Dockerfile Normal file
View File

@ -0,0 +1,38 @@
FROM ubuntu:21.04 as build
ENV LANG C.UTF-8
ARG DEBIAN_FRONTEND=noninteractive
RUN dpkg --add-architecture i386 && \
apt-get update && \
apt-get upgrade -y && \
apt-get install -y \
binutils:i386 \
gcc-10:i386 \
g++-10:i386 \
python3.10 \
python \
make \
cmake \
git \
lld \
libsdl2-dev:i386 \
zlib1g-dev:i386 \
libbz2-dev:i386 \
libpng-dev:i386 \
libgles2-mesa-dev && \
ln -sf /usr/bin/python3.10 /usr/bin/python3 && \
ln -s /usr/bin/gcc-10 /usr/bin/gcc && \
ln -s /usr/bin/gcc-10 /usr/bin/cc && \
ln -s /usr/bin/g++-10 /usr/bin/g++ && \
ln -s /usr/bin/g++-10 /usr/bin/c++
RUN git clone https://github.com/Perlmint/glew-cmake.git && \
cmake glew-cmake && \
make -j$(nproc) && \
make install ARCH64=false
RUN mkdir /soh
WORKDIR /soh

View File

@ -49,12 +49,12 @@ void OTRExporter_Animation::Save(ZResource* res, const fs::path& outPath, Binary
writer->Write((uint32_t)normalAnim->rotationValues.size());
for (int i = 0; i < normalAnim->rotationValues.size(); i++)
for (size_t i = 0; i < normalAnim->rotationValues.size(); i++)
writer->Write(normalAnim->rotationValues[i]);
writer->Write((uint32_t)normalAnim->rotationIndices.size());
for (int i = 0; i < normalAnim->rotationIndices.size(); i++)
for (size_t i = 0; i < normalAnim->rotationIndices.size(); i++)
{
writer->Write(normalAnim->rotationIndices[i].x);
writer->Write(normalAnim->rotationIndices[i].y);

View File

@ -10,7 +10,7 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit
writer->Write((uint32_t)arr->resList[0]->GetResourceType());
writer->Write((uint32_t)arr->arrayCnt);
for (int i = 0; i < arr->arrayCnt; i++)
for (size_t i = 0; i < arr->arrayCnt; i++)
{
if (arr->resList[i]->GetResourceType() == ZResourceType::Vertex)
{
@ -32,7 +32,7 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit
writer->Write((uint32_t)vec->scalarType);
writer->Write((uint32_t)vec->dimensions);
for (int k = 0; k < vec->dimensions; k++)
for (size_t k = 0; k < vec->dimensions; k++)
{
// OTRTODO: Duplicate code here. Cleanup at a later date...
switch (vec->scalarType)
@ -62,6 +62,8 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit
writer->Write(vec->scalars[k].scalarData.u64);
break;
// OTRTODO: ADD OTHER TYPES
default:
break;
}
}
}
@ -98,6 +100,8 @@ void OTRExporter_Array::Save(ZResource* res, const fs::path& outPath, BinaryWrit
writer->Write(scal->scalarData.u64);
break;
// OTRTODO: ADD OTHER TYPES
default:
break;
}
}
}

View File

@ -29,7 +29,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW
for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries)
{
writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame));
writer->Write(CMD_F(e->viewAngle));
writer->Write(e->viewAngle);
writer->Write(CMD_HH(e->posX, e->posY));
writer->Write(CMD_HH(e->posZ, e->unused));
}
@ -46,7 +46,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW
for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries)
{
writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame));
writer->Write(CMD_F(e->viewAngle));
writer->Write(e->viewAngle);
writer->Write(CMD_HH(e->posX, e->posY));
writer->Write(CMD_HH(e->posZ, e->unused));
}
@ -105,7 +105,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW
for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries)
{
writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame));
writer->Write(CMD_F(e->viewAngle));
writer->Write(e->viewAngle);
writer->Write(CMD_HH(e->posX, e->posY));
writer->Write(CMD_HH(e->posZ, e->unused));
}
@ -122,7 +122,7 @@ void OTRExporter_Cutscene::Save(ZResource* res, const fs::path& outPath, BinaryW
for (auto& e : ((CutsceneCommandSetCameraPos*)cs->commands[i])->entries)
{
writer->Write(CMD_BBH(e->continueFlag, e->cameraRoll, e->nextPointFrame));
writer->Write(CMD_F(e->viewAngle));
writer->Write(e->viewAngle);
writer->Write(CMD_HH(e->posX, e->posY));
writer->Write(CMD_HH(e->posZ, e->unused));
}

View File

@ -29,20 +29,6 @@
Ab1, Ad1)) \
}
typedef int32_t Mtx_t[4][4];
typedef union Mtx
{
//_Alignas(8)
Mtx_t m;
int32_t l[16];
struct
{
int16_t i[16];
uint16_t f[16];
};
} Mtx;
#define gsSPBranchLessZraw2(dl, vtx, zval) \
{ _SHIFTL(G_BRANCH_Z,24,8)|_SHIFTL((vtx)*5,12,12)|_SHIFTL((vtx)*2,0,12),\
(unsigned int)(zval), }
@ -71,7 +57,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
// DEBUG: Write in a marker
Declaration* dbgDecl = dList->parent->GetDeclaration(dList->GetRawDataIndex());
std::string dbgName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dbgDecl->varName.c_str());
std::string dbgName = StringHelper::Sprintf("%s/%s", GetParentFolderName(res).c_str(), dbgDecl->varName.c_str());
uint64_t hash = CRC64(dbgName.c_str());
writer->Write((uint32_t)(G_MARKER << 24));
writer->Write((uint32_t)0xBEEFBEEF);
@ -81,7 +67,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
auto dlStart = std::chrono::steady_clock::now();
//for (auto data : dList->instructions)
for (int dataIdx = 0; dataIdx < dList->instructions.size(); dataIdx++)
for (size_t dataIdx = 0; dataIdx < dList->instructions.size(); dataIdx++)
{
auto data = dList->instructions[dataIdx];
uint32_t word0 = 0;
@ -216,7 +202,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
pp ^= G_MTX_PUSH;
mm = (mm & 0x0FFFFFFF) + 0xF0000000;
mm = (mm & 0x0FFFFFFF) + 1;
Gfx value = gsSPMatrix(mm, pp);
word0 = value.words.w0;
@ -243,7 +229,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
if (mtxDecl != nullptr)
{
std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), mtxDecl->varName.c_str());
std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), mtxDecl->varName.c_str());
uint64_t hash = CRC64(vName.c_str());
@ -347,7 +333,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
if (dListDecl != nullptr)
{
std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str());
std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str());
uint64_t hash = CRC64(vName.c_str());
@ -370,7 +356,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
//std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dListDecl2->varName.c_str());
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->varName.c_str());
if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName))
if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName))
{
MemoryStream* dlStream = new MemoryStream();
BinaryWriter dlWriter = BinaryWriter(dlStream);
@ -383,7 +369,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
#endif
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract\\" + fName, dlStream->ToVector());
File::WriteAllBytes("Extract/" + fName, dlStream->ToVector());
else
files[fName] = dlStream->ToVector();
@ -411,7 +397,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
Gfx value;
u32 dListVal = (data & 0x0FFFFFFF) + 0xF0000000;
u32 dListVal = (data & 0x0FFFFFFF) + 1;
if (pp != 0)
value = gsSPBranchList(dListVal);
@ -444,7 +430,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
if (dListDecl != nullptr)
{
std::string vName = StringHelper::Sprintf("%s\\%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str());
std::string vName = StringHelper::Sprintf("%s/%s", (GetParentFolderName(res).c_str()), dListDecl->varName.c_str());
uint64_t hash = CRC64(vName.c_str());
@ -467,7 +453,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
//std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), dListDecl2->varName.c_str());
std::string fName = OTRExporter_DisplayList::GetPathToRes(res, dListDecl2->varName.c_str());
if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName))
if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName))
{
MemoryStream* dlStream = new MemoryStream();
BinaryWriter dlWriter = BinaryWriter(dlStream);
@ -475,7 +461,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
Save(dList->otherDLists[i], outPath, &dlWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract\\" + fName, dlStream->ToVector());
File::WriteAllBytes("Extract/" + fName, dlStream->ToVector());
else
files[fName] = dlStream->ToVector();
}
@ -689,7 +675,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
uint32_t fmt = (__ & 0xE0) >> 5;
uint32_t siz = (__ & 0x18) >> 3;
Gfx value = gsDPSetTextureImage(fmt, siz, www + 1, (seg & 0x0FFFFFFF) + 0xF0000000);
Gfx value = gsDPSetTextureImage(fmt, siz, www + 1, (seg & 0x0FFFFFFF) + 1);
word0 = value.words.w0;
word1 = value.words.w1;
@ -753,7 +739,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
Gfx value = gsSPVertex(data & 0xFFFFFFFF, nn, ((aa >> 1) - nn));
word0 = value.words.w0;
word1 = value.words.w1 | 0xF0000000;
word1 = value.words.w1 | 1;
}
else
{
@ -790,7 +776,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
word0 = hash >> 32;
word1 = hash & 0xFFFFFFFF;
if (files.find(fName) == files.end() && !File::Exists("Extract\\" + fName))
if (files.find(fName) == files.end() && !File::Exists("Extract/" + fName))
{
// Write vertices to file
MemoryStream* vtxStream = new MemoryStream();
@ -800,7 +786,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
auto split = StringHelper::Split(vtxDecl->text, "\n");
for (int i = 0; i < split.size(); i++)
for (size_t i = 0; i < split.size(); i++)
{
std::string line = split[i];
@ -842,7 +828,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
}
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract\\" + fName, vtxStream->ToVector());
File::WriteAllBytes("Extract/" + fName, vtxStream->ToVector());
else
files[fName] = vtxStream->ToVector();
@ -872,7 +858,7 @@ void OTRExporter_DisplayList::Save(ZResource* res, const fs::path& outPath, Bina
std::string OTRExporter_DisplayList::GetPathToRes(ZResource* res, std::string varName)
{
std::string prefix = GetPrefix(res);
std::string fName = StringHelper::Sprintf("%s\\%s", GetParentFolderName(res).c_str(), varName.c_str());
std::string fName = StringHelper::Sprintf("%s/%s", GetParentFolderName(res).c_str(), varName.c_str());
return fName;
}
@ -886,7 +872,7 @@ std::string OTRExporter_DisplayList::GetParentFolderName(ZResource* res)
{
auto split = StringHelper::Split(oName, "_");
oName = "";
for (int i = 0; i < split.size() - 1; i++)
for (size_t i = 0; i < split.size() - 1; i++)
oName += split[i] + "_";
oName += "scene";
@ -897,7 +883,7 @@ std::string OTRExporter_DisplayList::GetParentFolderName(ZResource* res)
}
if (prefix != "")
oName = prefix + "\\" + oName;
oName = prefix + "/" + oName;
return oName;
}

View File

@ -52,7 +52,7 @@ static void ExporterParseFileMode(const std::string& buildMode, ZFileMode& fileM
for (auto item : lst)
{
auto fileData = File::ReadAllBytes(item);
otrArchive->AddFile(StringHelper::Split(item, "Extract\\")[1], (uintptr_t)fileData.data(), fileData.size());
otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size());
}
}
}
@ -76,7 +76,7 @@ static void ExporterProgramEnd()
for (auto item : lst)
{
auto fileData = File::ReadAllBytes(item);
otrArchive->AddFile(StringHelper::Split(item, "Extract\\")[1], (uintptr_t)fileData.data(), fileData.size());
otrArchive->AddFile(StringHelper::Split(item, "Extract/")[1], (uintptr_t)fileData.data(), fileData.size());
}
otrArchive->AddFile("Audiobank", (uintptr_t)Globals::Instance->GetBaseromFile("Audiobank").data(), Globals::Instance->GetBaseromFile("Audiobank").size());
@ -117,7 +117,7 @@ static void ExporterFileBegin(ZFile* file)
static void ExporterFileEnd(ZFile* file)
{
int bp = 0;
// delete fileWriter;
}
static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer)
@ -140,7 +140,7 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer)
{
auto split = StringHelper::Split(oName, "_");
oName = "";
for (int i = 0; i < split.size() - 1; i++)
for (size_t i = 0; i < split.size() - 1; i++)
oName += split[i] + "_";
oName += "scene";
@ -153,14 +153,14 @@ static void ExporterResourceEnd(ZResource* res, BinaryWriter& writer)
std::string fName = "";
if (prefix != "")
fName = StringHelper::Sprintf("%s\\%s\\%s", prefix.c_str(), oName.c_str(), rName.c_str());
fName = StringHelper::Sprintf("%s/%s/%s", prefix.c_str(), oName.c_str(), rName.c_str());
else
fName = StringHelper::Sprintf("%s\\%s", oName.c_str(), rName.c_str());
fName = StringHelper::Sprintf("%s/%s", oName.c_str(), rName.c_str());
if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
files[fName] = strem->ToVector();
else
File::WriteAllBytes("Extract\\" + fName, strem->ToVector());
File::WriteAllBytes("Extract/" + fName, strem->ToVector());
}
auto end = std::chrono::steady_clock::now();

View File

@ -39,13 +39,13 @@ D_FILES := $(O_FILES:%.o=%.d)
LIB := OTRExporter.a
INC_DIRS := $(addprefix -I, \
../../ZAPD/ZAPD \
../../ZAPD/lib/tinyxml2 \
../../ZAPD/lib/libgfxd \
../../ZAPD/ZAPDUtils \
../../OtrLib/otrlib \
../../OtrLib/otrlib/Lib/spdlog/include \
../../OtrLib/otrlib/Lib/Fast3D/U64 \
../../ZAPDTR/ZAPD \
../../ZAPDTR/lib/tinyxml2 \
../../ZAPDTR/lib/libgfxd \
../../ZAPDTR/ZAPDUtils \
../../libultraship/libultraship \
../../libultraship/libultraship/Lib/spdlog/include \
../../libultraship/libultraship/Lib/Fast3D/U64 \
)
# create build directories

View File

@ -9,11 +9,11 @@ void OTRExporter_Path::Save(ZResource* res, const fs::path& outPath, BinaryWrite
writer->Write((uint32_t)path->pathways.size());
for (int k = 0; k < path->pathways.size(); k++)
for (size_t k = 0; k < path->pathways.size(); k++)
{
writer->Write((uint32_t)path->pathways[k].points.size());
for (int i = 0; i < path->pathways[k].points.size(); i++)
for (size_t i = 0; i < path->pathways[k].points.size(); i++)
{
writer->Write(path->pathways[k].points[i].scalars[0].scalarData.s16);
writer->Write(path->pathways[k].points[i].scalars[1].scalarData.s16);

View File

@ -172,7 +172,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
writer->Write((uint32_t)cmdCsCam->points.size());
for (int i = 0; i < cmdCsCam->points.size(); i++)
for (size_t i = 0; i < cmdCsCam->points.size(); i++)
{
writer->Write(cmdCsCam->points[i].scalars[0].scalarData.s16);
writer->Write(cmdCsCam->points[i].scalars[1].scalarData.s16);
@ -207,12 +207,12 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
Declaration* dListDeclXlu = poly->parent->GetDeclaration(GETSEGOFFSET(test->xlu));
if (test->opa != 0)
writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str()));
writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str()));
else
writer->Write("");
if (test->xlu != 0)
writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->varName.c_str()));
writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclXlu->varName.c_str()));
else
writer->Write("");
@ -338,7 +338,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
for (size_t i = 0;i < cmdRoom->romfile->numRooms; i++)
{
//std::string roomName = StringHelper::Sprintf("%s\\%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i);
//std::string roomName = StringHelper::Sprintf("%s/%s_room_%i", (StringHelper::Split(room->GetName(), "_")[0] + "_scene").c_str(), StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i);
std::string roomName = OTRExporter_DisplayList::GetPathToRes(room, StringHelper::Sprintf("%s_room_%i", StringHelper::Split(room->GetName(), "_scene")[0].c_str(), i));
writer->Write(roomName);
writer->Write(cmdRoom->romfile->rooms[i].virtualAddressStart);
@ -454,7 +454,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
cs.Save(cmdSetCutscenes->cutscenes[0], "", &csWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract\\" + fName, csStream->ToVector());
File::WriteAllBytes("Extract/" + fName, csStream->ToVector());
else
files[fName] = csStream->ToVector();
@ -468,7 +468,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
writer->Write((uint32_t)cmdSetPathways->pathwayList.pathways.size());
for (int i = 0; i < cmdSetPathways->pathwayList.pathways.size(); i++)
for (size_t i = 0; i < cmdSetPathways->pathwayList.pathways.size(); i++)
{
Declaration* decl = room->parent->GetDeclaration(GETSEGOFFSET(cmdSetPathways->pathwayList.pathways[i].listSegmentAddress));
//std::string path = StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), decl->varName.c_str());
@ -481,7 +481,7 @@ void OTRExporter_Room::Save(ZResource* res, const fs::path& outPath, BinaryWrite
pathExp.Save(&cmdSetPathways->pathwayList, outPath, &pathWriter);
if (Globals::Instance->fileMode != ZFileMode::ExtractDirectory)
File::WriteAllBytes("Extract\\" + path, pathStream->ToVector());
File::WriteAllBytes("Extract/" + path, pathStream->ToVector());
else
files[path] = pathStream->ToVector();
@ -514,12 +514,12 @@ void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, Polygon
writer->Write(dlist->unk_06);
[[fallthrough]];
default:
//writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str()));
//writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(res).c_str(), dListDeclOpa->varName.c_str()));
if (dlist->opaDList != nullptr)
{
auto opaDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->opaDList->GetRawDataIndex()));
writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->varName.c_str()));
writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), opaDecl->varName.c_str()));
}
else
writer->Write("");
@ -527,7 +527,7 @@ void OTRExporter_Room::WritePolyDList(BinaryWriter* writer, ZRoom* room, Polygon
if (dlist->xluDList != nullptr)
{
auto xluDecl = room->parent->GetDeclaration(GETSEGOFFSET(dlist->xluDList->GetRawDataIndex()));
writer->Write(StringHelper::Sprintf("%s\\%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->varName.c_str()));
writer->Write(StringHelper::Sprintf("%s/%s", OTRExporter_DisplayList::GetParentFolderName(room).c_str(), xluDecl->varName.c_str()));
}
else
writer->Write("");

View File

@ -9,7 +9,7 @@ void OTRExporter_Text::Save(ZResource* res, const fs::path& outPath, BinaryWrite
writer->Write((uint32_t)txt->messages.size());
for (int i = 0; i < txt->messages.size(); i++)
for (size_t i = 0; i < txt->messages.size(); i++)
{
writer->Write(txt->messages[i].id);
writer->Write(txt->messages[i].textboxType);

View File

@ -5,21 +5,23 @@ std::map<Ship::ResourceType, uint32_t> resourceVersions;
void InitVersionInfo()
{
resourceVersions[Ship::ResourceType::Animation] = 0;
resourceVersions[Ship::ResourceType::Model] = 0;
resourceVersions[Ship::ResourceType::Texture] = 0;
resourceVersions[Ship::ResourceType::Material] = 0;
resourceVersions[Ship::ResourceType::PlayerAnimation] = 0;
resourceVersions[Ship::ResourceType::DisplayList] = 0;
resourceVersions[Ship::ResourceType::Room] = 0;
resourceVersions[Ship::ResourceType::CollisionHeader] = 0;
resourceVersions[Ship::ResourceType::Skeleton] = 0;
resourceVersions[Ship::ResourceType::SkeletonLimb] = 0;
resourceVersions[Ship::ResourceType::Matrix] = 0;
resourceVersions[Ship::ResourceType::Path] = 0;
resourceVersions[Ship::ResourceType::Vertex] = 0;
resourceVersions[Ship::ResourceType::Cutscene] = 0;
resourceVersions[Ship::ResourceType::Array] = 0;
resourceVersions[Ship::ResourceType::Text] = 0;
resourceVersions[Ship::ResourceType::Blob] = 0;
resourceVersions = {
{ Ship::ResourceType::Animation, 0 },
{ Ship::ResourceType::Model, 0 },
{ Ship::ResourceType::Texture, 0 },
{ Ship::ResourceType::Material, 0 },
{ Ship::ResourceType::PlayerAnimation, 0 },
{ Ship::ResourceType::DisplayList, 0 },
{ Ship::ResourceType::Room, 0 },
{ Ship::ResourceType::CollisionHeader, 0 },
{ Ship::ResourceType::Skeleton, 0 },
{ Ship::ResourceType::SkeletonLimb, 0 },
{ Ship::ResourceType::Matrix, 0 },
{ Ship::ResourceType::Path, 0 },
{ Ship::ResourceType::Vertex, 0 },
{ Ship::ResourceType::Cutscene, 0 },
{ Ship::ResourceType::Array, 0 },
{ Ship::ResourceType::Text, 0 },
{ Ship::ResourceType::Blob, 0 },
};
}

View File

@ -1,51 +1,15 @@
#!/usr/bin/env python3
# How to use:
# Place a rom in this directory then run the script.
# If you are using multiple roms, the script will let you choose one.
# To choose with a commandline argument:
# Python3 extract_assets.py <number>
# Invalid input results in the first rom being selected
import json, os, signal, time, sys, shutil, glob
from multiprocessing import Pool, cpu_count, Event, Manager, ProcessError
from enum import Enum
import os, sys, shutil
import shutil
romVer = "..\\soh\\baserom_non_mq.z64"
roms = [];
checksums = ["", "", ""];
class Checksums(Enum):
OOT_NTSC_10 = "EC7011B7"
OOT_NTSC_11 = "D43DA81F"
OOT_NTSC_12 = "693BA2AE"
OOT_PAL_10 = "B044B569"
OOT_PAL_11 = "B2055FBD"
OOT_NTSC_JP_GC_CE = "F7F52DB8"
OOT_NTSC_JP_GC = "F611F4BA"
OOT_NTSC_US_GC = "F3DD35BA"
OOT_PAL_GC = "09465AC3"
OOT_NTSC_JP_MQ = "F43B45BA"
OOT_NTSC_US_MQ = "F034001A"
OOT_PAL_MQ = "1D4136F3"
OOT_PAL_GC_DBG1 = "871E1C92"
OOT_PAL_GC_DBG2 = "87121EFE"
OOT_PAL_GC_MQ_DBG = "917D18F6"
OOT_IQUE_TW = "3D81FB3E"
OOT_IQUE_CN = "B1E1E07B"
OOT_UNKNOWN = "FFFFFFFF"
CompatibleChecksums = [
Checksums.OOT_PAL_GC,
Checksums.OOT_PAL_GC_DBG1
]
from rom_info import Z64Rom
import rom_chooser
def BuildOTR(xmlPath, rom):
shutil.copytree("assets", "Extract/assets")
execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPD/ZAPD.out"
execStr += " ed -i %s -b %s -fl CFG\\filelists -o placeholder -osf placeholder -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, rom)
execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPDTR/ZAPD.out"
execStr += " ed -i %s -b %s -fl CFG/filelists -o placeholder -osf placeholder -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, rom)
print(execStr)
exitValue = os.system(execStr)
@ -55,95 +19,14 @@ def BuildOTR(xmlPath, rom):
print("Aborting...", file=os.sys.stderr)
print("\n")
def checkChecksum(rom):
r = open(rom, "rb")
r.seek(16)
bytes = r.read(4).hex().upper()
r.close()
for checksum in Checksums:
if (checksum.value == bytes):
for compat in CompatibleChecksums:
if (checksum.name == compat.name):
print("Compatible rom found!")
return checksum
print("Valid oot rom found. However, not compatible with SoH.")
print("Compatible roms:")
for compat in CompatibleChecksums:
print(compat.name+" | 0x"+compat.value)
sys.exit(1)
print("Wrong rom! No valid checksum found")
sys.exit(1)
def main():
romToUse = "";
for file in glob.glob("*.z64"):
roms.append(file)
if not (roms):
print("Error: No roms located, place one in the OTRExporter directory", file=os.sys.stderr)
sys.exit(1)
if (len(roms) > 1):
# If commandline args exist
if (len(sys.argv) > 1):
try:
if ((int(sys.argv[1]) - 1) < 1):
romToUse = roms[0]
elif ((int(sys.argv[1]) - 1) > len(roms)):
romToUse = roms[len(roms) - 1]
else:
romToUse = roms[int(sys.argv[1]) - 1]
except:
romToUse = roms[0]
# No commandline args, select rom using user input
else:
print(str(len(roms))+" roms found, please select one by pressing 1-"+str(len(roms)))
count = 1
for list in range(len(roms)):
print(str(count)+". "+roms[list])
count += 1
while(1):
try:
selection = int(input())
except:
print("Bad input. Try again with the number keys.")
continue
if (selection < 1 or selection > len(roms)):
print("Bad input. Try again.")
continue
else: break
romToUse = roms[selection - 1]
else:
romToUse = roms[0]
match checkChecksum(romToUse):
case Checksums.OOT_PAL_GC:
xmlVer = "GC_NMQ_PAL_F"
case Checksums.OOT_PAL_GC_DBG1:
xmlVer = "GC_NMQ_D"
case _: # default case
xmlVer = "GC_MQ_D"
rom_path = rom_chooser.chooseROM()
rom = Z64Rom(rom_path)
if (os.path.exists("Extract")):
shutil.rmtree("Extract")
BuildOTR("..\\soh\\assets\\xml\\" + xmlVer + "\\", romToUse)
BuildOTR("../soh/assets/xml/" + rom.version.xml_ver + "/", rom_path)
if __name__ == "__main__":
main()

View File

@ -1,125 +0,0 @@
#!/usr/bin/env python3
import argparse, json, os, signal, time, sys, shutil
from multiprocessing import Pool, cpu_count, Event, Manager, ProcessError
import shutil
def SignalHandler(sig, frame):
print(f'Signal {sig} received. Aborting...')
mainAbort.set()
# Don't exit immediately to update the extracted assets file.
def BuildOTR():
shutil.copyfile("baserom/Audiobank", "Extract/Audiobank")
shutil.copyfile("baserom/Audioseq", "Extract/Audioseq")
shutil.copyfile("baserom/Audiotable", "Extract/Audiotable")
shutil.copytree("assets", "Extract/assets")
execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPD/ZAPD.out"
execStr += " botr -se OTR"
print(execStr)
exitValue = os.system(execStr)
if exitValue != 0:
print("\n")
print("Error when building the OTR file...", file=os.sys.stderr)
print("Aborting...", file=os.sys.stderr)
print("\n")
def ExtractFile(xmlPath, outputPath, outputSourcePath):
execStr = "x64\\Release\\ZAPD.exe" if sys.platform == "win32" else "../ZAPD/ZAPD.out"
execStr += " e -eh -i %s -b baserom/ -o %s -osf %s -gsf 1 -rconf CFG/Config.xml -se OTR" % (xmlPath, outputPath, outputSourcePath)
if "overlays" in xmlPath:
execStr += " --static"
print(execStr)
exitValue = os.system(execStr)
#exitValue = 0
if exitValue != 0:
print("\n")
print("Error when extracting from file " + xmlPath, file=os.sys.stderr)
print("Aborting...", file=os.sys.stderr)
print("\n")
def ExtractFunc(fullPath):
*pathList, xmlName = fullPath.split(os.sep)
objectName = os.path.splitext(xmlName)[0]
outPath = os.path.join("..\\soh\\assets\\", *pathList[5:], objectName)
os.makedirs(outPath, exist_ok=True)
outSourcePath = outPath
ExtractFile(fullPath, outPath, outSourcePath)
def initializeWorker(abort, test):
global globalAbort
globalAbort = abort
def main():
parser = argparse.ArgumentParser(description="baserom asset extractor")
parser.add_argument("-s", "--single", help="asset path relative to assets/, e.g. objects/gameplay_keep")
parser.add_argument("-f", "--force", help="Force the extraction of every xml instead of checking the touched ones.", action="store_true")
parser.add_argument("-u", "--unaccounted", help="Enables ZAPD unaccounted detector warning system.", action="store_true")
parser.add_argument("-v", "--version", help="Sets game version.")
args = parser.parse_args()
global mainAbort
mainAbort = Event()
manager = Manager()
signal.signal(signal.SIGINT, SignalHandler)
extractedAssetsTracker = manager.dict()
xmlVer = "GC_NMQ_D"
if (args.version == "gc_pal_nmpq"):
xmlVer = "GC_NMQ_PAL_F"
elif (args.version == "dbg_mq"):
xmlVer = "GC_MQ_D"
asset_path = args.single
if asset_path is not None:
fullPath = os.path.join("..\\soh\\assets", "xml", asset_path + ".xml")
if not os.path.exists(fullPath):
print(f"Error. File {fullPath} doesn't exists.", file=os.sys.stderr)
exit(1)
ExtractFunc(fullPath)
else:
extract_text_path = "assets/text/message_data.h"
if os.path.isfile(extract_text_path):
extract_text_path = None
extract_staff_text_path = "assets/text/message_data_staff.h"
if os.path.isfile(extract_staff_text_path):
extract_staff_text_path = None
xmlFiles = []
for currentPath, _, files in os.walk(os.path.join("..\\soh\\assets\\xml\\", xmlVer)):
for file in files:
fullPath = os.path.join(currentPath, file)
if file.endswith(".xml"):
xmlFiles.append(fullPath)
try:
numCores = 2
print("Extracting assets with " + str(numCores) + " CPU cores.")
with Pool(numCores, initializer=initializeWorker, initargs=(mainAbort, 0)) as p:
p.map(ExtractFunc, xmlFiles)
except Exception as e:
print("Warning: Multiprocessing exception ocurred.", file=os.sys.stderr)
print("Disabling mutliprocessing.", file=os.sys.stderr)
initializeWorker(mainAbort, 0)
for singlePath in xmlFiles:
ExtractFunc(singlePath)
BuildOTR()
shutil.rmtree("Extract")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,53 @@
#!/usr/bin/python3
import os
import sys
import struct
from multiprocessing import Pool, cpu_count
from rom_info import Z64Rom
import rom_chooser
rom = None
def initialize_worker(input_rom):
global rom
rom = input_rom
def ExtractFunc(i):
dma_file = rom.getDmaEntryByIndex(i)
dma_data = rom.readDmaEntry(dma_file)
filename = '../soh/baserom/' + rom.version.file_table[i]
print('extracting ' + filename + " (0x%08X, 0x%08X)" % (dma_file.virtStart, dma_file.virtEnd))
try:
with open(filename, 'wb') as f:
f.write(dma_data)
except IOError:
print('failed to write file ' + filename)
# TODO: handle this better
if dma_file.compressed:
os.system('tools/yaz0 -d ' + filename + ' ' + filename)
#####################################################################
def main():
try:
os.mkdir('../soh/baserom')
except:
pass
rom_path = rom_chooser.chooseROM()
input_rom = Z64Rom(rom_path)
# extract files
num_cores = cpu_count()
print("Extracting baserom with " + str(num_cores) + " CPU cores.")
with Pool(num_cores, initialize_worker, (input_rom,)) as p:
p.map(ExtractFunc, range(len(input_rom.version.file_table)))
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
import os, sys, glob
from rom_info import Z64Rom
def chooseROM():
roms = []
for file in glob.glob("*.z64"):
if Z64Rom.isValidRom(file):
roms.append(file)
if not (roms):
print("Error: No roms located, place one in the OTRExporter directory", file=os.sys.stderr)
sys.exit(1)
if (len(roms) == 1):
return roms[0]
print(str(len(roms))+ " roms found, please select one by pressing 1-"+str(len(roms)))
for i in range(len(roms)):
print(str(i+1)+ ". " + roms[i])
while(1):
try:
selection = int(input())
except:
print("Bad input. Try again with the number keys.")
continue
if (selection < 1 or selection > len(roms)):
print("Bad input. Try again.")
continue
else: break
return roms[selection - 1]

87
OTRExporter/rom_info.py Normal file
View File

@ -0,0 +1,87 @@
from enum import Enum
from tabnanny import check
import struct
class Checksums(Enum):
OOT_NTSC_10 = "EC7011B7"
OOT_NTSC_11 = "D43DA81F"
OOT_NTSC_12 = "693BA2AE"
OOT_PAL_10 = "B044B569"
OOT_PAL_11 = "B2055FBD"
OOT_NTSC_JP_GC_CE = "F7F52DB8"
OOT_NTSC_JP_GC = "F611F4BA"
OOT_NTSC_US_GC = "F3DD35BA"
OOT_PAL_GC = "09465AC3"
OOT_NTSC_JP_MQ = "F43B45BA"
OOT_NTSC_US_MQ = "F034001A"
OOT_PAL_MQ = "1D4136F3"
OOT_PAL_GC_DBG1 = "871E1C92"
OOT_PAL_GC_DBG2 = "87121EFE"
OOT_PAL_GC_MQ_DBG = "917D18F6"
OOT_IQUE_TW = "3D81FB3E"
OOT_IQUE_CN = "B1E1E07B"
OOT_UNKNOWN = "FFFFFFFF"
@classmethod
def has_value(self, value):
return value in self._value2member_map_
class RomVersion:
def __init__(self, file_table_path, file_table_off, xml_ver):
self.file_table_off = file_table_off
self.xml_ver = xml_ver
with open(file_table_path, 'r') as f:
self.file_table = [line.strip('\n') for line in f]
ROM_INFO_TABLE = dict()
ROM_INFO_TABLE[Checksums.OOT_PAL_GC] = RomVersion("CFG/filelists/gamecube_pal.txt", 0x7170, "GC_NMQ_PAL_F")
ROM_INFO_TABLE[Checksums.OOT_PAL_GC_DBG1] = RomVersion("CFG/filelists/dbg.txt", 0x12F70, "GC_NMQ_D")
class RomDmaEntry:
def __init__(self, rom, i):
off = rom.version.file_table_off + 16 * i
(self.virtStart, \
self.virtEnd, \
self.physStart, \
self.physEnd) = struct.unpack('>IIII', rom.rom_data[off:off+4*4])
self.compressed = self.physEnd != 0
self.size = self.physEnd - self.physStart \
if self.compressed \
else self.virtEnd - self.virtStart
self.name = rom.version.file_table[i]
class Z64Rom:
def __init__(self, file_path):
self.file_path = file_path
with open(file_path, 'rb') as f:
self.rom_data = f.read()
self.is_valid = len(self.rom_data) > 20 * 1024 * 1024
if not self.is_valid:
return
# get checkum
checksum_str = self.rom_data[16:16+4].hex().upper()
self.checksum = Checksums(checksum_str) if Checksums.has_value(checksum_str) else Checksums.OOT_UNKNOWN
if self.checksum == Checksums.OOT_UNKNOWN:
self.is_valid = False
return
# get rom version
self.version = ROM_INFO_TABLE[self.checksum]
def getDmaEntryByIndex(self, i):
return RomDmaEntry(self, i)
def readDmaEntry(self, entry):
return self.rom_data[entry.physStart:entry.physStart + entry.size]
@staticmethod
def isValidRom(rom_path):
return Z64Rom(rom_path).is_valid

View File

@ -67,7 +67,7 @@ void OTRGame::init(){
mat.shader = shader;
}
if(fs::exists("soh.exe") && !fs::exists("oot.otr")) {
if((fs::exists("soh.exe") || fs::exists("soh.elf")) && !fs::exists("oot.otr")) {
hide_second_btn = true;
sohFolder = ".";
}

View File

@ -1,6 +1,6 @@
#include "CollisionExporter.h"
void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] fs::path outPath,
void ExporterExample_Collision::Save(ZResource* res, [[maybe_unused]] const fs::path& outPath,
BinaryWriter* writer)
{
ZCollisionHeader* col = (ZCollisionHeader*)res;

View File

@ -6,5 +6,5 @@
class ExporterExample_Collision : public ZResourceExporter
{
public:
void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override;
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
};

View File

@ -20,7 +20,7 @@
#include "ZRoom/Commands/SetTimeSettings.h"
#include "ZRoom/Commands/SetWind.h"
void ExporterExample_Room::Save(ZResource* res, fs::path outPath, BinaryWriter* writer)
void ExporterExample_Room::Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer)
{
ZRoom* room = dynamic_cast<ZRoom*>(res);

View File

@ -6,5 +6,5 @@
class ExporterExample_Room : public ZResourceExporter
{
public:
void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override;
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
};

View File

@ -1,7 +1,7 @@
#include "TextureExporter.h"
#include "../ZAPD/ZFile.h"
void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] fs::path outPath,
void ExporterExample_Texture::Save(ZResource* res, [[maybe_unused]] const fs::path& outPath,
BinaryWriter* writer)
{
ZTexture* tex = (ZTexture*)res;

View File

@ -7,5 +7,5 @@
class ExporterExample_Texture : public ZResourceExporter
{
public:
void Save(ZResource* res, fs::path outPath, BinaryWriter* writer) override;
void Save(ZResource* res, const fs::path& outPath, BinaryWriter* writer) override;
};

View File

@ -44,7 +44,8 @@ ifneq ($(DEPRECATION_ON),0)
endif
# CXXFLAGS += -DTEXTURE_DEBUG
LDFLAGS := -lm -ldl -lpng
LDFLAGS := -lm -ldl -lpng \
-L../external -L../libultraship -lz -lbz2 -pthread -lpulse -lultraship -lstorm -lSDL2 -lGLEW -lGL -lX11
# Use LLD if available. Set LLD=0 to not use it
ifeq ($(shell command -v ld.lld >/dev/null 2>&1; echo $$?),0)
@ -59,9 +60,9 @@ UNAME := $(shell uname)
UNAMEM := $(shell uname -m)
ifneq ($(UNAME), Darwin)
LDFLAGS += -Wl,-export-dynamic -lstdc++fs
EXPORTERS := -Wl,--whole-archive ExporterTest/ExporterTest.a -Wl,--no-whole-archive
EXPORTERS := -Wl,--whole-archive ../OTRExporter/OTRExporter/OTRExporter.a -Wl,--no-whole-archive
else
EXPORTERS := -Wl,-force_load ExporterTest/ExporterTest.a
EXPORTERS := -Wl,-force_load ../OTRExporter/OTRExporter/OTRExporter.a
ifeq ($(UNAMEM),arm64)
ifeq ($(shell brew list libpng > /dev/null 2>&1; echo $$?),0)
LDFLAGS += -L $(shell brew --prefix)/lib

View File

@ -10,7 +10,7 @@
#include "ZFile.h"
#include "ZTexture.h"
#if !defined(_MSC_VER) && !defined(__CYGWIN__)
#ifdef __linux__
#include <csignal>
#include <cstdlib>
#include <ctime>
@ -28,6 +28,31 @@
//extern const char gBuildHash[];
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)
{
}
void DebugConsole_SaveCVars()
{
}
void DebugConsole_LoadCVars()
{
}
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,
ZFileMode fileMode, int workerID);
@ -38,7 +63,7 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM
volatile int numWorkersLeft = 0;
#if !defined(_MSC_VER) && !defined(__CYGWIN__)
#ifdef __linux__
#define ARRAY_COUNT(arr) (sizeof(arr) / sizeof(arr[0]))
void ErrorHandler(int sig)
{
@ -196,7 +221,7 @@ int main(int argc, char* argv[])
}
else if (arg == "-eh") // Enable Error Handler
{
#if !defined(_MSC_VER) && !defined(__CYGWIN__)
#ifdef __linux__
signal(SIGSEGV, ErrorHandler);
signal(SIGABRT, ErrorHandler);
#else
@ -453,6 +478,7 @@ int ExtractFunc(int workerID, int fileListSize, std::string fileListItem, ZFileM
numWorkersLeft--;
}
return 0;
}
bool Parse(const fs::path& xmlFilePath, const fs::path& basePath, const fs::path& outPath,

View File

@ -96,7 +96,7 @@ int OutputFormatter::Write(const std::string& buf)
return Write(buf.data(), buf.size());
}
__declspec(thread) OutputFormatter* OutputFormatter::Instance;
thread_local OutputFormatter* OutputFormatter::Instance;
int OutputFormatter::WriteStatic(const char* buf, int count)
{

View File

@ -25,7 +25,7 @@ private:
void Flush();
static __declspec(thread) OutputFormatter* Instance;
static thread_local OutputFormatter* Instance;
static int WriteStatic(const char* buf, int count);
public:

View File

@ -15,6 +15,124 @@
#include "WarningHandler.h"
#include "gfxd.h"
#define G_MDSFT_ALPHACOMPARE 0
#define G_MDSFT_ZSRCSEL 2
#define G_MDSFT_RENDERMODE 3
#define G_MDSFT_BLENDER 16
#define G_RM_FOG_SHADE_A 0xC8000000
#define G_RM_FOG_PRIM_A 0xC4000000
#define G_RM_PASS 0x0C080000
#define G_RM_AA_ZB_OPA_SURF 0x442078
#define G_RM_AA_ZB_OPA_SURF2 0x112078
#define G_RM_AA_ZB_XLU_SURF 0x4049D8
#define G_RM_AA_ZB_XLU_SURF2 0x1049D8
#define G_RM_AA_ZB_OPA_DECAL 0x442D58
#define G_RM_AA_ZB_OPA_DECAL2 0x112D58
#define G_RM_AA_ZB_XLU_DECAL 0x404DD8
#define G_RM_AA_ZB_XLU_DECAL2 0x104DD8
#define G_RM_AA_ZB_OPA_INTER 0x442478
#define G_RM_AA_ZB_OPA_INTER2 0x112478
#define G_RM_AA_ZB_XLU_INTER 0x4045D8
#define G_RM_AA_ZB_XLU_INTER2 0x1045D8
#define G_RM_AA_ZB_XLU_LINE 0x407858
#define G_RM_AA_ZB_XLU_LINE2 0x107858
#define G_RM_AA_ZB_DEC_LINE 0x407F58
#define G_RM_AA_ZB_DEC_LINE2 0x107F58
#define G_RM_AA_ZB_TEX_EDGE 0x443078
#define G_RM_AA_ZB_TEX_EDGE2 0x113078
#define G_RM_AA_ZB_TEX_INTER 0x443478
#define G_RM_AA_ZB_TEX_INTER2 0x113478
#define G_RM_AA_ZB_SUB_SURF 0x442878
#define G_RM_AA_ZB_SUB_SURF2 0x112278
#define G_RM_AA_ZB_PCL_SURF 0x40007B
#define G_RM_AA_ZB_PCL_SURF2 0x10007B
#define G_RM_AA_ZB_OPA_TERR 0x402078
#define G_RM_AA_ZB_OPA_TERR2 0x102078
#define G_RM_AA_ZB_TEX_TERR 0x403078
#define G_RM_AA_ZB_TEX_TERR2 0x103078
#define G_RM_AA_ZB_SUB_TERR 0x402278
#define G_RM_AA_ZB_SUB_TERR2 0x102278
#define G_RM_RA_ZB_OPA_SURF 0x442038
#define G_RM_RA_ZB_OPA_SURF2 0x112038
#define G_RM_RA_ZB_OPA_DECAL 0x442D18
#define G_RM_RA_ZB_OPA_DECAL2 0x112D18
#define G_RM_RA_ZB_OPA_INTER 0x442438
#define G_RM_RA_ZB_OPA_INTER2 0x112438
#define G_RM_AA_OPA_SURF 0x442048
#define G_RM_AA_OPA_SURF2 0x112048
#define G_RM_AA_XLU_SURF 0x4041C8
#define G_RM_AA_XLU_SURF2 0x1041C8
#define G_RM_AA_XLU_LINE 0x407048
#define G_RM_AA_XLU_LINE2 0x107048
#define G_RM_AA_DEC_LINE 0x407248
#define G_RM_AA_DEC_LINE2 0x107248
#define G_RM_AA_TEX_EDGE 0x443048
#define G_RM_AA_TEX_EDGE2 0x113048
#define G_RM_AA_SUB_SURF 0x442248
#define G_RM_AA_SUB_SURF2 0x112248
#define G_RM_AA_PCL_SURF 0x40004B
#define G_RM_AA_PCL_SURF2 0x10004B
#define G_RM_AA_OPA_TERR 0x402048
#define G_RM_AA_OPA_TERR2 0x102048
#define G_RM_AA_TEX_TERR 0x403048
#define G_RM_AA_TEX_TERR2 0x103048
#define G_RM_AA_SUB_TERR 0x402248
#define G_RM_AA_SUB_TERR2 0x102248
#define G_RM_RA_OPA_SURF 0x442008
#define G_RM_RA_OPA_SURF2 0x112008
#define G_RM_ZB_OPA_SURF 0x442230
#define G_RM_ZB_OPA_SURF2 0x112230
#define G_RM_ZB_XLU_SURF 0x404A50
#define G_RM_ZB_XLU_SURF2 0x104A50
#define G_RM_ZB_OPA_DECAL 0x442E10
#define G_RM_ZB_OPA_DECAL2 0x112E10
#define G_RM_ZB_XLU_DECAL 0x404E50
#define G_RM_ZB_XLU_DECAL2 0x104E50
#define G_RM_ZB_CLD_SURF 0x404B50
#define G_RM_ZB_CLD_SURF2 0x104B50
#define G_RM_ZB_OVL_SURF 0x404F50
#define G_RM_ZB_OVL_SURF2 0x104F50
#define G_RM_ZB_PCL_SURF 0x0C080233
#define G_RM_ZB_PCL_SURF2 0x03020233
#define G_RM_OPA_SURF 0x0C084000
#define G_RM_OPA_SURF2 0x03024000
#define G_RM_XLU_SURF 0x00404200
#define G_RM_XLU_SURF2 0x00104240
#define G_RM_CLD_SURF 0x00404340
#define G_RM_CLD_SURF2 0x00104340
#define G_RM_TEX_EDGE 0x0C087008
#define G_RM_TEX_EDGE2 0x03027008
#define G_RM_PCL_SURF 0x0C084203
#define G_RM_PCL_SURF2 0x03024203
#define G_RM_ADD 0x04484340
#define G_RM_ADD2 0x01124340
#define G_RM_NOOP 0x00000000
#define G_RM_NOOP2 0x00000000
#define G_RM_VISCVG 0x0C844040
#define G_RM_VISCVG2 0x03214040
#define G_RM_OPA_CI 0x0C080000
#define G_RM_OPA_CI2 0x03020000
#define AA_EN 0x8
#define Z_CMP 0x10
#define Z_UPD 0x20
#define IM_RD 0x40
#define CLR_ON_CVG 0x80
#define CVG_DST_CLAMP 0
#define CVG_DST_WRAP 0x100
#define CVG_DST_FULL 0x200
#define CVG_DST_SAVE 0x300
#define ZMODE_OPA 0
#define ZMODE_INTER 0x400
#define ZMODE_XLU 0x800
#define ZMODE_DEC 0xc00
#define CVG_X_ALPHA 0x1000
#define ALPHA_CVG_SEL 0x2000
#define FORCE_BL 0x4000
#define TEX_EDGE 0x0000
REGISTER_ZFILENODE(DList, ZDisplayList);
ZDisplayList::ZDisplayList(ZFile* nParent) : ZResource(nParent)

View File

@ -166,122 +166,6 @@ enum class OoTSegments
FrameBuffer = 16,
};
#define G_MDSFT_ALPHACOMPARE 0
#define G_MDSFT_ZSRCSEL 2
#define G_MDSFT_RENDERMODE 3
#define G_MDSFT_BLENDER 16
#define G_RM_FOG_SHADE_A 0xC8000000
#define G_RM_FOG_PRIM_A 0xC4000000
#define G_RM_PASS 0x0C080000
#define G_RM_AA_ZB_OPA_SURF 0x442078
#define G_RM_AA_ZB_OPA_SURF2 0x112078
#define G_RM_AA_ZB_XLU_SURF 0x4049D8
#define G_RM_AA_ZB_XLU_SURF2 0x1049D8
#define G_RM_AA_ZB_OPA_DECAL 0x442D58
#define G_RM_AA_ZB_OPA_DECAL2 0x112D58
#define G_RM_AA_ZB_XLU_DECAL 0x404DD8
#define G_RM_AA_ZB_XLU_DECAL2 0x104DD8
#define G_RM_AA_ZB_OPA_INTER 0x442478
#define G_RM_AA_ZB_OPA_INTER2 0x112478
#define G_RM_AA_ZB_XLU_INTER 0x4045D8
#define G_RM_AA_ZB_XLU_INTER2 0x1045D8
#define G_RM_AA_ZB_XLU_LINE 0x407858
#define G_RM_AA_ZB_XLU_LINE2 0x107858
#define G_RM_AA_ZB_DEC_LINE 0x407F58
#define G_RM_AA_ZB_DEC_LINE2 0x107F58
#define G_RM_AA_ZB_TEX_EDGE 0x443078
#define G_RM_AA_ZB_TEX_EDGE2 0x113078
#define G_RM_AA_ZB_TEX_INTER 0x443478
#define G_RM_AA_ZB_TEX_INTER2 0x113478
#define G_RM_AA_ZB_SUB_SURF 0x442878
#define G_RM_AA_ZB_SUB_SURF2 0x112278
#define G_RM_AA_ZB_PCL_SURF 0x40007B
#define G_RM_AA_ZB_PCL_SURF2 0x10007B
#define G_RM_AA_ZB_OPA_TERR 0x402078
#define G_RM_AA_ZB_OPA_TERR2 0x102078
#define G_RM_AA_ZB_TEX_TERR 0x403078
#define G_RM_AA_ZB_TEX_TERR2 0x103078
#define G_RM_AA_ZB_SUB_TERR 0x402278
#define G_RM_AA_ZB_SUB_TERR2 0x102278
#define G_RM_RA_ZB_OPA_SURF 0x442038
#define G_RM_RA_ZB_OPA_SURF2 0x112038
#define G_RM_RA_ZB_OPA_DECAL 0x442D18
#define G_RM_RA_ZB_OPA_DECAL2 0x112D18
#define G_RM_RA_ZB_OPA_INTER 0x442438
#define G_RM_RA_ZB_OPA_INTER2 0x112438
#define G_RM_AA_OPA_SURF 0x442048
#define G_RM_AA_OPA_SURF2 0x112048
#define G_RM_AA_XLU_SURF 0x4041C8
#define G_RM_AA_XLU_SURF2 0x1041C8
#define G_RM_AA_XLU_LINE 0x407048
#define G_RM_AA_XLU_LINE2 0x107048
#define G_RM_AA_DEC_LINE 0x407248
#define G_RM_AA_DEC_LINE2 0x107248
#define G_RM_AA_TEX_EDGE 0x443048
#define G_RM_AA_TEX_EDGE2 0x113048
#define G_RM_AA_SUB_SURF 0x442248
#define G_RM_AA_SUB_SURF2 0x112248
#define G_RM_AA_PCL_SURF 0x40004B
#define G_RM_AA_PCL_SURF2 0x10004B
#define G_RM_AA_OPA_TERR 0x402048
#define G_RM_AA_OPA_TERR2 0x102048
#define G_RM_AA_TEX_TERR 0x403048
#define G_RM_AA_TEX_TERR2 0x103048
#define G_RM_AA_SUB_TERR 0x402248
#define G_RM_AA_SUB_TERR2 0x102248
#define G_RM_RA_OPA_SURF 0x442008
#define G_RM_RA_OPA_SURF2 0x112008
#define G_RM_ZB_OPA_SURF 0x442230
#define G_RM_ZB_OPA_SURF2 0x112230
#define G_RM_ZB_XLU_SURF 0x404A50
#define G_RM_ZB_XLU_SURF2 0x104A50
#define G_RM_ZB_OPA_DECAL 0x442E10
#define G_RM_ZB_OPA_DECAL2 0x112E10
#define G_RM_ZB_XLU_DECAL 0x404E50
#define G_RM_ZB_XLU_DECAL2 0x104E50
#define G_RM_ZB_CLD_SURF 0x404B50
#define G_RM_ZB_CLD_SURF2 0x104B50
#define G_RM_ZB_OVL_SURF 0x404F50
#define G_RM_ZB_OVL_SURF2 0x104F50
#define G_RM_ZB_PCL_SURF 0x0C080233
#define G_RM_ZB_PCL_SURF2 0x03020233
#define G_RM_OPA_SURF 0x0C084000
#define G_RM_OPA_SURF2 0x03024000
#define G_RM_XLU_SURF 0x00404200
#define G_RM_XLU_SURF2 0x00104240
#define G_RM_CLD_SURF 0x00404340
#define G_RM_CLD_SURF2 0x00104340
#define G_RM_TEX_EDGE 0x0C087008
#define G_RM_TEX_EDGE2 0x03027008
#define G_RM_PCL_SURF 0x0C084203
#define G_RM_PCL_SURF2 0x03024203
#define G_RM_ADD 0x04484340
#define G_RM_ADD2 0x01124340
#define G_RM_NOOP 0x00000000
#define G_RM_NOOP2 0x00000000
#define G_RM_VISCVG 0x0C844040
#define G_RM_VISCVG2 0x03214040
#define G_RM_OPA_CI 0x0C080000
#define G_RM_OPA_CI2 0x03020000
#define AA_EN 0x8
#define Z_CMP 0x10
#define Z_UPD 0x20
#define IM_RD 0x40
#define CLR_ON_CVG 0x80
#define CVG_DST_CLAMP 0
#define CVG_DST_WRAP 0x100
#define CVG_DST_FULL 0x200
#define CVG_DST_SAVE 0x300
#define ZMODE_OPA 0
#define ZMODE_INTER 0x400
#define ZMODE_XLU 0x800
#define ZMODE_DEC 0xc00
#define CVG_X_ALPHA 0x1000
#define ALPHA_CVG_SEL 0x2000
#define FORCE_BL 0x4000
#define TEX_EDGE 0x0000
class ZDisplayList : public ZResource
{

View File

@ -25,19 +25,19 @@ public:
ZLimbSkinType skinSegmentType = ZLimbSkinType::SkinType_0; // Skin only
segptr_t skinSegment = 0; // Skin only
Struct_800A5E28 segmentStruct; // Skin only
Struct_800A5E28 segmentStruct = {0}; // Skin only
// Legacy only
float legTransX, legTransY, legTransZ; // Vec3f
uint16_t rotX, rotY, rotZ; // Vec3s
segptr_t childPtr; // LegacyLimb*
segptr_t siblingPtr; // LegacyLimb*
float legTransX = 0, legTransY = 0, legTransZ = 0; // Vec3f
uint16_t rotX = 0, rotY = 0, rotZ = 0; // Vec3s
segptr_t childPtr = 0; // LegacyLimb*
segptr_t siblingPtr = 0; // LegacyLimb*
segptr_t dListPtr = 0;
segptr_t dList2Ptr = 0; // LOD and Curve Only
int16_t transX, transY, transZ;
uint8_t childIndex, siblingIndex;
int16_t transX = 0, transY = 0, transZ = 0;
uint8_t childIndex = 0, siblingIndex = 0;
ZLimb(ZFile* nParent);

View File

@ -3,6 +3,7 @@
#include <cstdint>
#include <limits>
#include <vector>
#include <cstring>
class BitConverter
{

View File

@ -52,7 +52,7 @@ public:
for (auto& p : fs::recursive_directory_iterator(dir))
{
if (!p.is_directory())
lst.push_back(p.path().string());
lst.push_back(p.path().generic_string());
}
}

View File

@ -3,6 +3,10 @@
#pragma optimize("2", on)
#define _CRT_SECURE_NO_WARNINGS
#ifndef _MSC_VER
#define vsprintf_s vsprintf
#endif
std::vector<std::string> StringHelper::Split(std::string s, const std::string& delimiter)
{
std::vector<std::string> result;

View File

@ -354,3 +354,5 @@ MigrationBackup/
!libultraship/Lib/**
libultraship/DebugObj/*
build/
libultraship.a

View File

@ -1,15 +1,78 @@
# Only used for standalone compilation, usually inherits these from the main makefile
CXXFLAGS ?= -Wall -Wextra -O2 -g -std=c++17
CXX := g++
CC := gcc
AR := ar
FORMAT := clang-format-11
ASAN ?= 0
DEBUG ?= 1
OPTFLAGS ?= -O0
LTO ?= 0
WARN := -Wall -Wextra -Werror \
-Wno-unused-variable \
-Wno-unused-parameter \
-Wno-unused-function \
-Wno-parentheses \
-Wno-narrowing \
-Wno-missing-field-initializers
CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0 -m32
CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -DENABLE_OPENGL -DSPDLOG_ACTIVE_LEVEL=0 -m32
CPPFLAGS := -MMD
ifneq ($(DEBUG),0)
CXXFLAGS += -g -D_DEBUG
CFLAGS += -g -D_DEBUG
endif
ifneq ($(ASAN),0)
CXXFLAGS += -fsanitize=address
CFLAGS += -fsanitize=address
endif
ifneq ($(LTO),0)
CXXFLAGS += -flto
CFLAGS += -flto
endif
SRC_DIRS := $(shell find -type d -not -path "*build*")
CPP_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.cpp))
H_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.h))
O_FILES := $(foreach f,$(CPP_FILES:.cpp=.o),build/$f)
LIB := otrlib.a
CXX_FILES := \
$(shell find libultraship/Factories -name *.cpp) \
$(shell find libultraship/Lib/Fast3D -name *.cpp) \
$(shell find libultraship -maxdepth 1 -name *.cpp) \
$(shell find libultraship/Lib/ImGui -maxdepth 1 -name *.cpp) \
libultraship/Lib/ImGui/backends/imgui_impl_opengl3.cpp \
libultraship/Lib/ImGui/backends/imgui_impl_sdl.cpp \
libultraship/Lib/StrHash64.cpp \
libultraship/Lib/tinyxml2/tinyxml2.cpp
C_FILES := \
libultraship/mixer.c \
libultraship/Lib/stb/stb_impl.c
FMT_FILES := $(shell find libultraship/ -type f \( -name *.cpp -o -name *.h \) -a -not -path "libultraship/Lib/*")
O_FILES := \
$(CXX_FILES:%.cpp=build/%.o) \
$(C_FILES:%.c=build/%.o)
D_FILES := $(O_FILES:%.o=%.d)
LIB := libultraship.a
INC_DIRS := $(addprefix -I, \
../ZAPDTR/ZAPDUtils \
libultraship/Lib/Fast3D/U64 \
libultraship/Lib/spdlog \
libultraship/Lib/spdlog/include \
libultraship \
)
# create build directories
$(shell mkdir -p $(foreach dir,$(SRC_DIRS),build/$(dir)))
$(shell mkdir -p $(SRC_DIRS:%=build/%))
all: $(LIB)
@ -17,12 +80,17 @@ clean:
rm -rf build $(LIB)
format:
clang-format-11 -i $(CPP_FILES) $(H_FILES)
$(FORMAT) -i $(FMT_FILES)
.PHONY: all clean format
build/%.o: %.cpp
$(CXX) $(CXXFLAGS) $(OPTFLAGS) -I ./ -I ../ZAPD/ZAPD -I ../ZAPD/ZAPDUtils -I ../../ZAPD/lib/tinyxml2 -I otrlib/Lib/spdlog/include -c $(OUTPUT_OPTION) $<
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@
build/%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) -c $< -o $@
$(LIB): $(O_FILES)
$(AR) rcs $@ $^
-include $(D_FILES)

View File

@ -21,7 +21,7 @@ void Ship::AnimationV0::ParseFileBinary(BinaryReader* reader, Resource* res)
uint32_t rotIndCnt = reader->ReadUInt32();
anim->rotationIndices.reserve(rotIndCnt);
for (int i = 0; i < rotIndCnt; i++)
for (size_t i = 0; i < rotIndCnt; i++)
{
uint16_t x = reader->ReadUInt16();
uint16_t y = reader->ReadUInt16();

View File

@ -28,7 +28,7 @@ namespace Ship {
std::shared_ptr<Archive> Archive::CreateArchive(const std::string& archivePath, int fileCapacity)
{
Archive* archive = new Archive(archivePath, true);
auto archive = std::make_shared<Archive>(archivePath, true);
TCHAR* t_filename = new TCHAR[archivePath.size() + 1];
t_filename[archivePath.size()] = 0;
@ -37,10 +37,15 @@ namespace Ship {
bool success = SFileCreateArchive(t_filename, MPQ_CREATE_LISTFILE | MPQ_CREATE_ATTRIBUTES | MPQ_CREATE_ARCHIVE_V2, fileCapacity, &archive->mainMPQ);
int error = GetLastError();
if (success) {
delete[] t_filename;
if (success)
{
archive->mpqHandles[archivePath] = archive->mainMPQ;
return std::make_shared<Archive>(*archive);
} else {
return archive;
}
else
{
SPDLOG_ERROR("({}) We tried to create an archive, but it has fallen and cannot get up.");
return nullptr;
}
@ -139,13 +144,16 @@ namespace Ship {
bool Archive::AddFile(const std::string& path, uintptr_t fileData, DWORD dwFileSize) {
HANDLE hFile;
#ifdef _WIN32
SYSTEMTIME sysTime;
GetSystemTime(&sysTime);
FILETIME t;
SystemTimeToFileTime(&sysTime, &t);
ULONGLONG stupidHack = static_cast<uint64_t>(t.dwHighDateTime) << (sizeof(t.dwHighDateTime) * 8) | t.dwLowDateTime;
#else
time_t stupidHack;
time(&stupidHack);
#endif
if (!SFileCreateFile(mainMPQ, path.c_str(), stupidHack, dwFileSize, 0, MPQ_FILE_COMPRESS, &hFile)) {
SPDLOG_ERROR("({}) Failed to create file of {} bytes {} in archive {}", GetLastError(), dwFileSize, path.c_str(), MainPath.c_str());
return false;
@ -302,11 +310,16 @@ namespace Ship {
bool Archive::LoadMainMPQ(bool enableWriting, bool genCRCMap) {
HANDLE mpqHandle = NULL;
#ifdef _WIN32
std::wstring wfullPath = std::filesystem::absolute(MainPath).wstring();
#endif
std::string fullPath = std::filesystem::absolute(MainPath).string();
std::wstring wFileName = std::filesystem::absolute(MainPath).wstring();
if (!SFileOpenArchive(wFileName.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) {
#ifdef _WIN32
if (!SFileOpenArchive(wfullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) {
#else
if (!SFileOpenArchive(fullPath.c_str(), 0, enableWriting ? 0 : MPQ_OPEN_READ_ONLY, &mpqHandle)) {
#endif
SPDLOG_ERROR("({}) Failed to open main mpq file {}.", GetLastError(), fullPath.c_str());
return false;
}
@ -340,12 +353,19 @@ namespace Ship {
std::wstring wPath = std::filesystem::absolute(path).wstring();
#ifdef _WIN32
if (!SFileOpenArchive(wPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &patchHandle)) {
#else
if (!SFileOpenArchive(fullPath.c_str(), 0, MPQ_OPEN_READ_ONLY, &patchHandle)) {
#endif
SPDLOG_ERROR("({}) Failed to open patch mpq file {} while applying to {}.", GetLastError(), path.c_str(), MainPath.c_str());
return false;
}
#ifdef _WIN32
if (!SFileOpenPatchArchive(mainMPQ, wPath.c_str(), "", 0)) {
#else
if (!SFileOpenPatchArchive(mainMPQ, fullPath.c_str(), "", 0)) {
#endif
SPDLOG_ERROR("({}) Failed to apply patch mpq file {} to main mpq {}.", GetLastError(), path.c_str(), MainPath.c_str());
return false;
}

View File

@ -51,6 +51,8 @@ namespace Ship
data.u16 = reader->ReadUInt16();
break;
// OTRTODO: IMPLEMENT OTHER TYPES!
default:
break;
}
arr->scalars.push_back(data);

View File

@ -29,9 +29,9 @@ namespace Ship {
bool CreateDefaultConfig();
private:
mINI::INIFile File;
mINI::INIStructure Val;
std::weak_ptr<GlobalCtx2> Context;
std::string Path;
mINI::INIFile File;
};
}

View File

@ -1,4 +1,4 @@
#include "cvar.h"
#include "Cvar.h"
#include <map>
#include <string>
#include <PR/ultra64/gbi.h>

View File

@ -1,71 +0,0 @@
#include "OTRResourceLoader.h"
#include "OTRMaterialFactory.h"
#include "OTRSceneFactory.h"
#include "OTRCollisionHeaderFactory.h"
#include "OTRDisplayListFactory.h"
#include "OTRPlayerAnimationFactory.h"
#include "OTRSkeletonFactory.h"
#include "OTRSkeletonLimbFactory.h"
#include "OTRAnimationFactory.h"
#include "OTRVtxFactory.h"
#include "OTRCutsceneFactory.h"
#include "OTRArrayFactory.h"
#include "OTRPathFactory.h"
namespace OtrLib
{
OTRResource* OTRResourceLoader::LoadResource(BinaryReader* reader)
{
Endianess endianess = (Endianess)reader->ReadByte();
// TODO: Setup the binaryreader to use the resource's endianess
ResourceType resourceType = (ResourceType)reader->ReadUInt32();
OTRResource* result = nullptr;
switch (resourceType)
{
case ResourceType::OTRMaterial:
result = OTRMaterialFactory::ReadMaterial(reader);
break;
case ResourceType::OTRRoom:
result = OTRSceneFactory::ReadScene(reader);
break;
case ResourceType::OTRCollisionHeader:
result = OTRCollisionHeaderFactory::ReadCollisionHeader(reader);
break;
case ResourceType::OTRDisplayList:
result = OTRDisplayListFactory::ReadDisplayList(reader);
break;
case ResourceType::OTRPlayerAnimation:
result = OTRPlayerAnimationFactory::ReadPlayerAnimation(reader);
break;
case ResourceType::OTRSkeleton:
result = OTRSkeletonFactory::ReadSkeleton(reader);
break;
case ResourceType::OTRSkeletonLimb:
result = OTRSkeletonLimbFactory::ReadSkeletonLimb(reader);
break;
case ResourceType::OTRVtx:
result = OTRVtxFactory::ReadVtx(reader);
break;
case ResourceType::OTRAnimation:
result = OTRAnimationFactory::ReadAnimation(reader);
break;
case ResourceType::OTRCutscene:
result = OTRCutsceneFactory::ReadCutscene(reader);
break;
case ResourceType::OTRArray:
result = OTRArrayFactory::ReadArray(reader);
break;
case ResourceType::OTRPath:
result = OTRPathFactory::ReadPath(reader);
break;
default:
// RESOURCE TYPE NOT SUPPORTED
break;
}
return result;
}
}

View File

@ -1,10 +1,11 @@
#include "GameSettings.h"
// Audio
#include <cstddef>
#include <PR/ultra64/types.h>
#include <PR/ultra64/sptask.h>
#include <PR/ultra64/pi.h>
#include <PR/ultra64/message.h>
#include <PR/ultra64/types.h>
#include "ConfigFile.h"
#include "Cvar.h"

View File

@ -54,7 +54,11 @@ namespace Ship {
if (!ResMan->DidLoadSuccessfully())
{
#ifdef _WIN32
MessageBox(NULL, L"Main OTR file not found!", L"Uh oh", MB_OK);
#else
SPDLOG_ERROR("Main OTR file not found!");
#endif
exit(1);
}
INSTANCE = new ModManager(ResMan);

View File

@ -1004,7 +1004,7 @@
#define G_DL_PUSH 0x00
#define G_DL_NOPUSH 0x01
#if _MSC_VER
#if defined(_MSC_VER) || defined(__GNUC__)
#define _LANGUAGE_C
#endif
@ -3132,7 +3132,7 @@ _DW({ \
#endif
*/
#ifdef _MSC_VER
#if defined(_MSC_VER)
#define CALL_2(A,B) A B
#define CALL_3(A,B,C) A B C
@ -3143,12 +3143,12 @@ _DW({ \
#define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b)
#endif
#if _MSC_VER
#if defined(_MSC_VER) || defined(__GNUC__)
#define CALL_2(A,B) A B
#define CALL_3(A,B,C) A B C
#define gsDPSetCombineMode(a, b) CALL_2(gsDPSetCombineLERP, (a, b))
//#define gsDPSetCombineMode(a, b) _SHIFTL(0, 24, 8), 0
// #define gsDPSetCombineMode(a, b) CALL_2(gsDPSetCombineLERP, (a, b))
// #define gsDPSetCombineMode(a, b) _SHIFTL(0, 24, 8), 0
#else
#define gsDPSetCombineMode(a, b) gsDPSetCombineLERP(a, b)
#endif

View File

@ -33,6 +33,7 @@
#define G_OFF (0)
#include <stdint.h>
#include "types.h"
#include "gbi.h"
#include "abi.h"

View File

@ -158,7 +158,7 @@ static LARGE_INTEGER last_time, accumulated_time, frequency;
int gfx_d3d11_create_framebuffer(void);
void create_depth_stencil_objects(uint32_t width, uint32_t height, uint32_t msaa_count, ID3D11DepthStencilView **view, ID3D11ShaderResourceView **srv) {
static void create_depth_stencil_objects(uint32_t width, uint32_t height, uint32_t msaa_count, ID3D11DepthStencilView **view, ID3D11ShaderResourceView **srv) {
D3D11_TEXTURE2D_DESC texture_desc;
texture_desc.Width = width;
texture_desc.Height = height;
@ -992,8 +992,8 @@ std::map<std::pair<float, float>, uint16_t> gfx_d3d11_get_pixel_depth(int fb_id,
} // namespace
ImTextureID SohImGui::GetTextureByID(int id) {
return impl.backend == Backend::DX11 ? d3d.textures[id].resource_view.Get() : reinterpret_cast<ImTextureID>(id);
ImTextureID gfx_d3d11_get_texture_by_id(int id) {
return d3d.textures[id].resource_view.Get();
}
struct GfxRenderingAPI gfx_direct3d11_api = {

View File

@ -276,7 +276,7 @@ static void gfx_glx_set_fullscreen_state(bool on, bool call_callback) {
xev.xclient.data.l[2] = 0;
xev.xclient.data.l[3] = 0;
XSendEvent(glx.dpy, glx.root, 0, SubstructureNotifyMask | SubstructureRedirectMask, &xev);
gfx_glx_ShowHideMouse(on);
gfx_glx_show_cursor(on);
if (glx.on_fullscreen_changed != NULL && call_callback) {
glx.on_fullscreen_changed(on);
@ -439,7 +439,7 @@ static void gfx_glx_handle_events(void) {
}
}
}
if (xev.type == ClientMessage && xev.xclient.data.l[0] == glx.atom_wm_delete_window) {
if (xev.type == ClientMessage && (Atom)xev.xclient.data.l[0] == glx.atom_wm_delete_window) {
exit(0);
}
}
@ -458,7 +458,7 @@ static void gfx_glx_swap_buffers_begin(void) {
uint64_t target = glx.wanted_ust / FRAME_INTERVAL_US_DENOMINATOR;
uint64_t now;
while (target > (now = (uint64_t)get_time() - glx.ust0)) {
struct timespec ts = {(target - now) / 1000000, ((target - now) % 1000000) * 1000};
struct timespec ts = {(time_t)((target - now) / 1000000), (time_t)(((target - now) % 1000000) * 1000)};
if (nanosleep(&ts, NULL) == 0) {
break;
}
@ -600,6 +600,10 @@ static double gfx_glx_get_time(void) {
return 0.0;
}
static void gfx_glx_set_frame_divisor(int divisor) {
// TODO
}
struct GfxWindowManagerAPI gfx_glx = {
gfx_glx_init,
gfx_glx_set_keyboard_callbacks,
@ -612,7 +616,8 @@ struct GfxWindowManagerAPI gfx_glx = {
gfx_glx_start_frame,
gfx_glx_swap_buffers_begin,
gfx_glx_swap_buffers_end,
gfx_glx_get_time
gfx_glx_get_time,
gfx_glx_set_frame_divisor,
};
#endif

View File

@ -3,6 +3,6 @@
#include "gfx_window_manager_api.h"
struct GfxWindowManagerAPI gfx_glx;
extern struct GfxWindowManagerAPI gfx_glx;
#endif

View File

@ -29,8 +29,9 @@
#include "SDL_opengl.h"
#else
#include <SDL2/SDL.h>
#include <GL/glew.h>
#define GL_GLEXT_PROTOTYPES 1
#include <SDL2/SDL_opengles2.h>
// #include <SDL2/SDL_opengles2.h>
#endif
#include "gfx_cc.h"
@ -178,6 +179,7 @@ static const char *shader_item_to_str(uint32_t item, bool with_alpha, bool only_
return "texel.a";
}
}
return "";
}
static void append_formula(char *buf, size_t *len, uint8_t c[2][4], bool do_single, bool do_multiply, bool do_mix, bool with_alpha, bool only_alpha, bool opt_alpha) {
@ -571,6 +573,7 @@ static uint32_t gfx_cm_to_opengl(uint32_t val) {
case G_TX_NOMIRROR | G_TX_WRAP:
return GL_REPEAT;
}
return 0;
}
static void gfx_opengl_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {

View File

@ -10,6 +10,7 @@
#include <set>
#include <unordered_map>
#include <vector>
#include <list>
#ifndef _LANGUAGE_C
#define _LANGUAGE_C
@ -45,6 +46,8 @@ extern "C" {
using namespace std;
#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1)
#define SUPPORT_CHECK(x) assert(x)
// SCALE_M_N: upscale/downscale M-bit integer to N-bit
@ -209,7 +212,7 @@ static map<int, FBInfo> framebuffers;
static set<pair<float, float>> get_pixel_depth_pending;
static map<pair<float, float>, uint16_t> get_pixel_depth_cached;
#ifdef _MSC_VER
#ifdef _WIN32
// TODO: Properly implement for MSVC
static unsigned long get_time(void)
{
@ -447,15 +450,15 @@ static void gfx_generate_cc(struct ColorCombiner *comb, uint64_t cc_id) {
val = SHADER_COMBINED;
break;
}
// fallthrough for G_ACMUX_LOD_FRACTION
c[i][1][j] = G_CCMUX_LOD_FRACTION;
[[fallthrough]]; // for G_ACMUX_LOD_FRACTION
case G_ACMUX_1:
//case G_ACMUX_PRIM_LOD_FRAC: same numerical value
if (j != 2) {
val = SHADER_1;
break;
}
// fallthrough for G_ACMUX_PRIM_LOD_FRAC
[[fallthrough]]; // for G_ACMUX_PRIM_LOD_FRAC
case G_ACMUX_PRIMITIVE:
case G_ACMUX_SHADE:
case G_ACMUX_ENVIRONMENT:
@ -564,7 +567,7 @@ static void gfx_texture_cache_delete(const uint8_t* orig_addr)
if (it->first.texture_addr == orig_addr) {
gfx_texture_cache.lru.erase(*(list<TextureCacheMap::iterator>::iterator*)&it->second.lru_location);
gfx_texture_cache.free_texture_ids.push_back(it->second.texture_id);
gfx_texture_cache.map.erase(it);
gfx_texture_cache.map.erase(it->first);
again = true;
break;
}
@ -1692,7 +1695,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t
SUPPORT_CHECK(ult == 0);
// The lrs field rather seems to be number of pixels to load
uint32_t word_size_shift;
uint32_t word_size_shift = 0;
switch (rdp.texture_to_load.siz) {
case G_IM_SIZ_4b:
word_size_shift = 0; // Or -1? It's unused in SM64 anyway.
@ -1720,7 +1723,7 @@ static void gfx_dp_load_block(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t
static void gfx_dp_load_tile(uint8_t tile, uint32_t uls, uint32_t ult, uint32_t lrs, uint32_t lrt) {
SUPPORT_CHECK(tile == G_TX_LOADTILE);
uint32_t word_size_shift;
uint32_t word_size_shift = 0;
switch (rdp.texture_to_load.siz) {
case G_IM_SIZ_4b:
word_size_shift = 0;
@ -2060,12 +2063,11 @@ static void gfx_s2dex_bg_copy(const uObjBg* bg) {
static inline void* seg_addr(uintptr_t w1)
{
// Segmented?
if (w1 >= 0xF0000000)
if (w1 & 1)
{
uint32_t segNum = (w1 >> 24);
segNum -= 0xF0;
uint32_t offset = w1 & 0x00FFFFFF;
uint32_t offset = w1 & 0x00FFFFFE;
//offset = 0; // Cursed Malon bug
if (segmentPointers[segNum] != 0)
@ -2082,7 +2084,7 @@ static inline void* seg_addr(uintptr_t w1)
#define C0(pos, width) ((cmd->words.w0 >> (pos)) & ((1U << width) - 1))
#define C1(pos, width) ((cmd->words.w1 >> (pos)) & ((1U << width) - 1))
int dListBP;
unsigned int dListBP;
int matrixBP;
uintptr_t clearMtx;
@ -2149,7 +2151,7 @@ static void gfx_run_dl(Gfx* cmd) {
uintptr_t mtxAddr = cmd->words.w1;
// OTRTODO: Temp way of dealing with gMtxClear. Need something more elegant in the future...
if (mtxAddr == 0xF012DB20 || mtxAddr == 0xF012DB40)
if (mtxAddr == SEG_ADDR(0, 0x12DB20) || mtxAddr == SEG_ADDR(0, 0x12DB40))
mtxAddr = clearMtx;
#ifdef F3DEX_GBI_2
@ -2250,7 +2252,7 @@ static void gfx_run_dl(Gfx* cmd) {
cmd--;
if (ourHash != -1)
if (ourHash != (uint64_t)-1)
ResourceMgr_RegisterResourcePatch(ourHash, cmd - dListStart, cmd->words.w1);
cmd->words.w1 = (uintptr_t)vtx;
@ -2368,7 +2370,7 @@ static void gfx_run_dl(Gfx* cmd) {
case G_QUAD:
{
int bp = 0;
// fallthrough
[[fallthrough]];
}
#endif
#if defined(F3DEX_GBI) || defined(F3DLP_GBI)
@ -2398,7 +2400,7 @@ static void gfx_run_dl(Gfx* cmd) {
char* imgData = (char*)i;
if ((i & 0xF0000000) != 0xF0000000)
if ((i & 1) != 1)
if (ResourceMgr_OTRSigCheck(imgData) == 1)
i = (uintptr_t)ResourceMgr_LoadTexByName(imgData);
@ -2419,7 +2421,7 @@ static void gfx_run_dl(Gfx* cmd) {
char* tex = NULL;
#endif
if (addr != NULL)
if (addr != 0)
{
tex = (char*)addr;
}
@ -2433,7 +2435,7 @@ static void gfx_run_dl(Gfx* cmd) {
uintptr_t oldData = cmd->words.w1;
cmd->words.w1 = (uintptr_t)tex;
if (ourHash != -1)
if (ourHash != (uint64_t)-1)
ResourceMgr_RegisterResourcePatch(ourHash, cmd - dListStart, oldData);
cmd++;
@ -2648,7 +2650,7 @@ void gfx_init(struct GfxWindowManagerAPI *wapi, struct GfxRenderingAPI *rapi, co
game_framebuffer_msaa_resolved = gfx_rapi->create_framebuffer();
for (int i = 0; i < 16; i++)
segmentPointers[i] = NULL;
segmentPointers[i] = 0;
// Used in the 120 star TAS
static uint32_t precomp_shaders[] = {

View File

@ -4,12 +4,14 @@
#include <stdbool.h>
#include <stdint.h>
#include <unordered_map>
#include <list>
struct GfxRenderingAPI;
struct GfxWindowManagerAPI;
struct XYWidthHeight {
int16_t x, y, width, height;
int16_t x, y;
uint32_t width, height;
};
struct GfxDimensions {

View File

@ -1,6 +1,6 @@
#include <stdio.h>
#if !defined(__linux__) && defined(ENABLE_OPENGL)
#if defined(ENABLE_OPENGL)
#ifdef __MINGW32__
#define FOR_WINDOWS 1
@ -23,7 +23,9 @@
#include "gfx_window_manager_api.h"
#include "gfx_screen_config.h"
#ifdef _WIN32
#include <WTypesbase.h>
#endif
#include <time.h>
#define GFX_API_NAME "SDL2 - OpenGL"
@ -117,7 +119,9 @@ static void set_fullscreen(bool on, bool call_callback) {
}
static uint64_t previous_time;
#ifndef __linux__
static HANDLE timer;
#endif
static int frameDivisor = 1;
@ -131,7 +135,9 @@ static void gfx_sdl_init(const char *game_name, bool start_in_fullscreen) {
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
#ifndef __linux
timer = CreateWaitableTimer(nullptr, false, nullptr);
#endif
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
//SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);

View File

@ -86,14 +86,8 @@
#include <stdint.h>
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
#define unint uint32_t
#define INITIAL_CRC64 0xffffffffffffffffULL
extern uint64_t update_crc64(const void* buf, unint len, u64 crc);
extern u64 crc64(const void* buf, unint len);
extern u64 CRC64(const char* t);
extern uint64_t update_crc64(const void* buf, uint32_t len, uint64_t crc);
extern uint64_t crc64(const void* buf, uint32_t len);
extern uint64_t CRC64(const char* t);

View File

@ -47,7 +47,7 @@ protected:
formatted.push_back('\0');
const char *msg_output = formatted.data();
if (CVar_GetS32("gSinkEnabled", 0) && SohImGui::console->opened)
SohImGui::console->Append("SoH Logging", priority, msg_output);
SohImGui::console->Append("SoH Logging", priority, "%s", msg_output);
}
void flush_() override {}
@ -67,6 +67,8 @@ private:
return Priority::ERROR_LVL;
case spdlog::level::critical:
return Priority::ERROR_LVL;
default:
break;
}
return Priority::LOG_LVL;
}

View File

@ -39,7 +39,7 @@ namespace Ship
Vertex* vtxData = new Vertex[numVerts];
uint32_t* indicesData = new uint32_t[numPolys];
if (vertices != NULL)
if (vertices != 0)
{
reader->Seek(headerStart + vertices, SeekOffsetType::Start);
@ -47,7 +47,7 @@ namespace Ship
vtxData[i].pos = reader->ReadVec3f();
}
if (normals != NULL)
if (normals != 0)
{
reader->Seek(headerStart + normals, SeekOffsetType::Start);
@ -55,7 +55,7 @@ namespace Ship
vtxData[i].normal = reader->ReadVec3f();
}
if (vertexColors != NULL)
if (vertexColors != 0)
{
reader->Seek(headerStart + vertexColors, SeekOffsetType::Start);
@ -63,7 +63,7 @@ namespace Ship
vtxData[i].color = reader->ReadColor3b();
}
if (uvCoords != NULL)
if (uvCoords != 0)
{
reader->Seek(headerStart + uvCoords, SeekOffsetType::Start);
@ -71,7 +71,7 @@ namespace Ship
vtxData[i].uv = reader->ReadVec2f();
}
if (boneWeights != NULL)
if (boneWeights != 0)
{
reader->Seek(headerStart + boneWeights, SeekOffsetType::Start);
@ -81,7 +81,7 @@ namespace Ship
mdl->boneWeights[i] = reader->ReadVec2f();
}
if (faces != NULL)
if (faces != 0)
{
reader->Seek(headerStart + faces, SeekOffsetType::Start);
reader->Read((char*)indicesData, numPolys * sizeof(uint32_t));

View File

@ -0,0 +1,173 @@
#if defined(__linux__) || defined(__BSD__)
#include "PulseAudioPlayer.h"
#include <spdlog/spdlog.h>
namespace Ship
{
static void pas_context_state_cb(pa_context *c, void *userdata) {
switch (pa_context_get_state(c)) {
case PA_CONTEXT_READY:
case PA_CONTEXT_TERMINATED:
case PA_CONTEXT_FAILED:
*(bool*)userdata = true;
break;
default:
break;
}
}
static void pas_stream_state_cb(pa_stream *s, void *userdata) {
switch (pa_stream_get_state(s)) {
case PA_STREAM_READY:
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED:
*(bool*)userdata = true;
break;
default:
break;
}
}
static void pas_stream_write_cb(pa_stream* s, size_t length, void* userdata) {
}
static void pas_update_complete(pa_stream* stream, int success, void* userdata) {
*(bool*)userdata = true;
}
static void pas_write_complete(void* userdata) {
*(bool*)userdata = true;
}
bool PulseAudioPlayer::Init()
{
bool done = false;
const pa_buffer_attr* applied_attr = nullptr;
// Create mainloop
m_MainLoop = pa_mainloop_new();
if (m_MainLoop == NULL) {
return false;
}
// Create context and connect
m_Context = pa_context_new(pa_mainloop_get_api(m_MainLoop), "Ocarina of Time");
if (m_Context == NULL) {
goto fail;
}
pa_context_set_state_callback(m_Context, pas_context_state_cb, &done);
if (pa_context_connect(m_Context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) {
goto fail;
}
while (!done) {
pa_mainloop_iterate(m_MainLoop, true, NULL);
}
pa_context_set_state_callback(m_Context, NULL, NULL);
if (pa_context_get_state(m_Context) != PA_CONTEXT_READY) {
goto fail;
}
// Create stream
pa_sample_spec ss;
ss.format = PA_SAMPLE_S16LE;
ss.rate = 32000;
ss.channels = 2;
pa_buffer_attr attr;
attr.maxlength = (1600 + 544 + 528 + 1600) * 4;
attr.tlength = (528*2 + 544) * 4;
attr.prebuf = 1500 * 4;
attr.minreq = 161 * 4;
attr.fragsize = (uint32_t)-1;
m_Stream = pa_stream_new(m_Context, "zelda", &ss, NULL);
if (m_Stream == NULL) {
goto fail;
}
done = false;
pa_stream_set_state_callback(m_Stream, pas_stream_state_cb, &done);
pa_stream_set_write_callback(m_Stream, pas_stream_write_cb, NULL);
if (pa_stream_connect_playback(m_Stream, NULL, &attr, PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0) {
goto fail;
}
while (!done) {
pa_mainloop_iterate(m_MainLoop, true, NULL);
}
pa_stream_set_state_callback(m_Stream, NULL, NULL);
if (pa_stream_get_state(m_Stream) != PA_STREAM_READY) {
goto fail;
}
applied_attr = pa_stream_get_buffer_attr(m_Stream);
SPDLOG_TRACE("maxlength: {}\ntlength: {}\nprebuf: {}\nminreq: {}\nfragsize: {}\n",
applied_attr->maxlength, applied_attr->tlength, applied_attr->prebuf, applied_attr->minreq, applied_attr->fragsize);
m_Attr = *applied_attr;
return true;
fail:
if (m_Stream != NULL) {
pa_stream_unref(m_Stream);
m_Stream = NULL;
}
if (m_Context != NULL) {
pa_context_disconnect(m_Context);
pa_context_unref(m_Context);
m_Context = NULL;
}
if (m_MainLoop != NULL) {
pa_mainloop_free(m_MainLoop);
m_MainLoop = NULL;
}
return false;
}
int PulseAudioPlayer::Buffered()
{
if (m_Stream == NULL) {
return 0;
}
bool done = false;
pa_stream_update_timing_info(m_Stream, pas_update_complete, &done);
while (!done) {
pa_mainloop_iterate(m_MainLoop, true, NULL);
}
const pa_timing_info *info = pa_stream_get_timing_info(m_Stream);
if (info == NULL) {
SPDLOG_ERROR("pa_stream_get_timing_info failed, state is %d\n", pa_stream_get_state(m_Stream));
}
return (info->write_index - info->read_index) / 4;
}
int PulseAudioPlayer::GetDesiredBuffered()
{
// return 1100;
return 1680;
}
void PulseAudioPlayer::Play(const uint8_t* buff, uint32_t len)
{
size_t ws = m_Attr.maxlength - Buffered() * 4;
if (ws < len) {
len = ws;
}
if (pa_stream_write_ext_free(m_Stream, buff, len, pas_write_complete, &m_WriteComplete, 0LL, PA_SEEK_RELATIVE) < 0) {
SPDLOG_ERROR("pa_stream_write failed");
return;
}
while (!m_WriteComplete) {
pa_mainloop_iterate(m_MainLoop, true, NULL);
}
m_WriteComplete = false;
}
}
#endif

View File

@ -0,0 +1,26 @@
#pragma once
#if defined(__linux__) || defined(__BSD__)
#include "AudioPlayer.h"
#include <pulse/pulseaudio.h>
namespace Ship {
class PulseAudioPlayer : public AudioPlayer {
public:
PulseAudioPlayer() {}
bool Init() override;
int Buffered() override;
int GetDesiredBuffered() override;
void Play(const uint8_t* buff, uint32_t len) override;
private:
pa_context* m_Context = nullptr;
pa_stream* m_Stream = nullptr;
pa_mainloop* m_MainLoop = nullptr;
bool m_WriteComplete = false;
pa_buffer_attr m_Attr = {0};
};
}
#endif

View File

@ -2,8 +2,8 @@
#include "DisplayList.h"
#include "ResourceMgr.h"
#include "Utils/BinaryReader.h"
#include "lib/tinyxml2/tinyxml2.h"
#include "lib/Fast3D/U64/PR/ultra64/gbi.h"
#include "Lib/tinyxml2/tinyxml2.h"
#include "Lib/Fast3D/U64/PR/ultra64/gbi.h"
namespace Ship
{
@ -38,7 +38,7 @@ namespace Ship
free(cachedGameAsset);
cachedGameAsset = nullptr;
for (int i = 0; i < patches.size(); i++)
for (size_t i = 0; i < patches.size(); i++)
{
std::string hashStr = resMgr->HashToString(patches[i].crc);
auto resShared = resMgr->GetCachedFile(hashStr);

View File

@ -6,7 +6,7 @@
#include "GlobalCtx2.h"
#include "StrHash.h"
#include "File.h"
#include "lib/tinyxml2/tinyxml2.h"
#include "Lib/tinyxml2/tinyxml2.h"
namespace Ship
{
@ -101,10 +101,10 @@ namespace Ship
class ResourcePromise {
public:
std::shared_ptr<Resource> Resource;
std::shared_ptr<File> File;
std::condition_variable ResourceLoadNotifier;
std::mutex ResourceLoadMutex;
std::shared_ptr<Resource> resource;
std::shared_ptr<File> file;
std::condition_variable resourceLoadNotifier;
std::mutex resourceLoadMutex;
bool bHasResourceLoaded = false;
};
}

View File

@ -124,15 +124,15 @@ namespace Ship {
// Wait for the underlying File to complete loading
{
std::unique_lock<std::mutex> FileLock(ToLoad->File->FileLoadMutex);
while (!ToLoad->File->bIsLoaded && !ToLoad->File->bHasLoadError) {
ToLoad->File->FileLoadNotifier.wait(FileLock);
std::unique_lock<std::mutex> FileLock(ToLoad->file->FileLoadMutex);
while (!ToLoad->file->bIsLoaded && !ToLoad->file->bHasLoadError) {
ToLoad->file->FileLoadNotifier.wait(FileLock);
}
}
if (!ToLoad->File->bHasLoadError)
if (!ToLoad->file->bHasLoadError)
{
auto UnmanagedRes = ResourceLoader::LoadResource(ToLoad->File);
auto UnmanagedRes = ResourceLoader::LoadResource(ToLoad->file);
if (UnmanagedRes != nullptr)
{
@ -140,13 +140,13 @@ namespace Ship {
auto Res = std::shared_ptr<Resource>(UnmanagedRes);
if (Res != nullptr) {
std::unique_lock<std::mutex> Lock(ToLoad->ResourceLoadMutex);
std::unique_lock<std::mutex> Lock(ToLoad->resourceLoadMutex);
ToLoad->bHasResourceLoaded = true;
ToLoad->Resource = Res;
ToLoad->resource = Res;
ResourceCache[Res->file->path] = Res;
SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->File->path);
SPDLOG_DEBUG("Loaded Resource {} on ResourceMgr thread", ToLoad->file->path);
// Disabled for now because it can cause random crashes
//FileCache[Res->File->path] = nullptr;
@ -155,9 +155,9 @@ namespace Ship {
}
else {
ToLoad->bHasResourceLoaded = false;
ToLoad->Resource = nullptr;
ToLoad->resource = nullptr;
SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->File->path);
SPDLOG_ERROR("Resource load FAILED {} on ResourceMgr thread", ToLoad->file->path);
}
//ResLock.lock();
@ -167,10 +167,10 @@ namespace Ship {
else
{
ToLoad->bHasResourceLoaded = false;
ToLoad->Resource = nullptr;
ToLoad->resource = nullptr;
}
ToLoad->ResourceLoadNotifier.notify_all();
ToLoad->resourceLoadNotifier.notify_all();
}
SPDLOG_INFO("Resource Manager LoadResourceThread ended");
@ -232,17 +232,17 @@ namespace Ship {
if (!Promise->bHasResourceLoaded)
{
std::unique_lock<std::mutex> Lock(Promise->ResourceLoadMutex);
std::unique_lock<std::mutex> Lock(Promise->resourceLoadMutex);
while (!Promise->bHasResourceLoaded) {
Promise->ResourceLoadNotifier.wait(Lock);
Promise->resourceLoadNotifier.wait(Lock);
}
}
return Promise->Resource;
return Promise->resource;
}
std::shared_ptr<ResourcePromise> ResourceMgr::LoadResourceAsync(std::string FilePath) {
StringHelper::ReplaceOriginal(FilePath, "/", "\\");
StringHelper::ReplaceOriginal(FilePath, "\\", "/");
if (StringHelper::StartsWith(FilePath, "__OTR__"))
FilePath = StringHelper::Split(FilePath, "__OTR__")[1];
@ -257,9 +257,9 @@ namespace Ship {
}
std::shared_ptr<File> FileData = LoadFile(FilePath);
Promise->File = FileData;
Promise->file = FileData;
if (Promise->File->bHasLoadError)
if (Promise->file->bHasLoadError)
{
Promise->bHasResourceLoaded = true;
}
@ -271,7 +271,7 @@ namespace Ship {
}
} else {
Promise->bHasResourceLoaded = true;
Promise->Resource = resCacheFind->second;
Promise->resource = resCacheFind->second;
}
return Promise;
@ -295,15 +295,15 @@ namespace Ship {
auto PromiseList = CacheDirectoryAsync(SearchMask);
auto LoadedList = std::make_shared<std::vector<std::shared_ptr<Resource>>>();
for (int32_t i = 0; i < PromiseList->size(); i++) {
for (size_t i = 0; i < PromiseList->size(); i++) {
auto Promise = PromiseList->at(i);
std::unique_lock<std::mutex> Lock(Promise->ResourceLoadMutex);
std::unique_lock<std::mutex> Lock(Promise->resourceLoadMutex);
while (!Promise->bHasResourceLoaded) {
Promise->ResourceLoadNotifier.wait(Lock);
Promise->resourceLoadNotifier.wait(Lock);
}
LoadedList->push_back(Promise->Resource);
LoadedList->push_back(Promise->resource);
}
return LoadedList;
@ -314,18 +314,18 @@ namespace Ship {
auto PromiseList = CacheDirectoryAsync(SearchMask);
auto LoadedList = std::make_shared<std::vector<std::shared_ptr<Resource>>>();
for (int32_t i = 0; i < PromiseList->size(); i++) {
for (size_t i = 0; i < PromiseList->size(); i++) {
auto Promise = PromiseList->at(i);
std::unique_lock<std::mutex> Lock(Promise->ResourceLoadMutex);
std::unique_lock<std::mutex> Lock(Promise->resourceLoadMutex);
while (!Promise->bHasResourceLoaded) {
Promise->ResourceLoadNotifier.wait(Lock);
Promise->resourceLoadNotifier.wait(Lock);
}
if (Promise->Resource != nullptr)
Promise->Resource->isDirty = true;
if (Promise->resource != nullptr)
Promise->resource->isDirty = true;
LoadedList->push_back(Promise->Resource);
LoadedList->push_back(Promise->resource);
}
return LoadedList;

View File

@ -48,6 +48,7 @@ namespace Ship
private:
std::weak_ptr<GlobalCtx2> Context;
volatile bool bIsRunning;
std::map<std::string, std::shared_ptr<File>> FileCache;
std::map<std::string, std::shared_ptr<Resource>> ResourceCache;
std::queue<std::shared_ptr<File>> FileLoadQueue;
@ -59,7 +60,6 @@ namespace Ship
std::mutex ResourceLoadMutex;
std::condition_variable FileLoadNotifier;
std::condition_variable ResourceLoadNotifier;
volatile bool bIsRunning;
uint32_t gameVersion;
};
}

View File

@ -61,17 +61,17 @@ namespace Ship {
if (Conf[ConfSection]["GUID"].compare("") == 0 || Conf[ConfSection]["GUID"].compare(INVALID_SDL_CONTROLLER_GUID) == 0 || Conf[ConfSection]["GUID"].compare(NewGuid) == 0) {
auto NewCont = SDL_GameControllerOpen(i);
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO))
{
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
}
// We failed to load the controller. Go to next.
if (NewCont == nullptr) {
SPDLOG_ERROR("SDL Controller failed to open: ({})", SDL_GetError());
continue;
}
if (SDL_GameControllerHasSensor(NewCont, SDL_SENSOR_GYRO))
{
SDL_GameControllerSetSensorEnabled(NewCont, SDL_SENSOR_GYRO, SDL_TRUE);
}
guid = NewGuid;
Cont = NewCont;
@ -101,7 +101,7 @@ namespace Ship {
}
bool SDLController::Close() {
if (SDL_GameControllerHasRumble(Cont)) {
if (CanRumble()) {
SDL_GameControllerRumble(Cont, 0, 0, 0);
}
if (Cont != nullptr) {
@ -347,7 +347,7 @@ namespace Ship {
void SDLController::WriteToSource(ControllerCallback* controller)
{
if (SDL_GameControllerHasRumble(Cont)) {
if (CanRumble()) {
if (controller->rumble > 0) {
float rumble_strength = CVar_GetFloat(StringHelper::Sprintf("gCont%i_RumbleStrength", GetControllerNumber()).c_str(), 1.0f);
SDL_GameControllerRumble(Cont, 0xFFFF * rumble_strength, 0xFFFF * rumble_strength, 0);

View File

@ -13,7 +13,12 @@ namespace Ship {
void ReadFromSource();
void WriteToSource(ControllerCallback* controller);
bool Connected() const { return Cont != nullptr; }
bool CanRumble() const { return SDL_GameControllerHasRumble(Cont); }
bool CanRumble() const {
#if SDL_COMPILEDVERSION >= SDL_VERSIONNUM(2,0,18)
return SDL_GameControllerHasRumble(Cont);
#endif
return true;
}
std::string GetGuid() { return guid; };
@ -30,8 +35,8 @@ namespace Ship {
static bool IsGuidInUse(const std::string& guid);
private:
std::string guid;
SDL_GameController* Cont;
std::string guid;
std::map<int32_t, int16_t> ThresholdMapping;
void LoadAxisThresholds();

View File

@ -137,8 +137,8 @@ namespace Ship
y = 0;
z = 0;
unk_06 = 0;
opa;
xlu;
// opa;
// xlu;
}
SetMesh::SetMesh(BinaryReader* reader) : SceneCommand(reader)

View File

@ -15,7 +15,7 @@ namespace Ship
limb->skinVtxCnt = reader->ReadUInt16();
uint32_t skinCnt = reader->ReadUInt32();
for (int i = 0; i < skinCnt; i++)
for (size_t i = 0; i < skinCnt; i++)
{
Struct_800A598C struc;

View File

@ -16,7 +16,7 @@ std::map<ImGuiKey, std::string> BindingToggle;
static bool HelpCommand(const std::vector<std::string>&) {
INFO("SoH Commands:");
for(const auto& cmd : SohImGui::console->Commands) {
INFO((" - " + cmd.first).c_str());
INFO("%s", (" - " + cmd.first).c_str());
}
return CMD_SUCCESS;
}
@ -35,7 +35,7 @@ std::string toLowerCase(std::string in) {
static bool BindCommand(const std::vector<std::string>& args) {
if(args.size() > 2) {
const ImGuiIO* io = &ImGui::GetIO();;
for (int k = 0; k < std::size(io->KeysData); k++) {
for (size_t k = 0; k < std::size(io->KeysData); k++) {
std::string key(ImGui::GetKeyName(k));
if(toLowerCase(args[1]) == toLowerCase(key)) {
@ -55,7 +55,7 @@ static bool BindCommand(const std::vector<std::string>& args) {
static bool BindToggleCommand(const std::vector<std::string>& args) {
if (args.size() > 2) {
const ImGuiIO* io = &ImGui::GetIO();;
for (int k = 0; k < std::size(io->KeysData); k++) {
for (size_t k = 0; k < std::size(io->KeysData); k++) {
std::string key(ImGui::GetKeyName(k));
if (toLowerCase(args[1]) == toLowerCase(key)) {
@ -177,9 +177,11 @@ void Console::Draw() {
for (const auto& filter : priority_filters) {
const bool is_selected = (filter == std::string(this->level_filter));
if (ImGui::Selectable(filter.c_str(), is_selected))
{
this->level_filter = filter;
if (is_selected) ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
@ -194,7 +196,7 @@ void Console::Draw() {
if (ImGui::BeginTable("History", 1)) {
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)))
if (this->selectedId < this->Log.size() - 1) ++this->selectedId;
if (this->selectedId < (int)this->Log.size() - 1) ++this->selectedId;
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
if (this->selectedId > 0) --this->selectedId;
@ -317,7 +319,7 @@ int Console::CallbackStub(ImGuiInputTextCallbackData* data) {
return 0;
}
void Console::Append(const std::string& channel, Priority priority, const char* fmt, ...) IM_FMTARGS(4) {
void Console::Append(const std::string& channel, Priority priority, const char* fmt, ...) {
char buf[1024];
va_list args;
va_start(args, fmt);

View File

@ -7,10 +7,10 @@
#include "Lib/ImGui/imgui.h"
#define LOG(msg, ...) SohImGui::console->Append("Main", Priority::LOG_LVL, msg, __VA_ARGS__)
#define INFO(msg, ...) SohImGui::console->Append("Main", Priority::INFO_LVL, msg, __VA_ARGS__)
#define WARNING(msg, ...) SohImGui::console->Append("Main", Priority::WARNING_LVL, msg, __VA_ARGS__)
#define ERROR(msg, ...) SohImGui::console->Append("Main", Priority::ERROR_LVL, msg, __VA_ARGS__)
#define LOG(msg, ...) SohImGui::console->Append("Main", Priority::LOG_LVL, msg, ##__VA_ARGS__)
#define INFO(msg, ...) SohImGui::console->Append("Main", Priority::INFO_LVL, msg, ##__VA_ARGS__)
#define WARNING(msg, ...) SohImGui::console->Append("Main", Priority::WARNING_LVL, msg, ##__VA_ARGS__)
#define ERROR(msg, ...) SohImGui::console->Append("Main", Priority::ERROR_LVL, msg, ##__VA_ARGS__)
#define CMD_SUCCESS true
#define CMD_FAILED false
#define MAX_BUFFER_SIZE 255
@ -75,7 +75,7 @@ public:
void Init();
void Update();
void Draw();
void Append(const std::string& channel, Priority priority, const char* fmt, ...);
void Append(const std::string& channel, Priority priority, const char* fmt, ...) IM_FMTARGS(4);
void Dispatch(const std::string& line);
static int CallbackStub(ImGuiInputTextCallbackData* data);
};

View File

@ -24,7 +24,7 @@ namespace ModInternal {
bool handleHook(std::shared_ptr<HookCall> call) {
std::string hookName = std::string(call->name);
for (int l = 0; l < listeners[hookName].size(); l++) {
for (size_t l = 0; l < listeners[hookName].size(); l++) {
(listeners[hookName][l])(call);
}
return call->cancelled;

View File

@ -47,6 +47,7 @@ struct HookParameter {
#include <functional>
#include <string>
#include <map>
#include <memory>
struct HookCall {
std::string name;

View File

@ -92,9 +92,13 @@ namespace SohImGui {
case Backend::SDL:
ImGui_ImplSDL2_InitForOpenGL(static_cast<SDL_Window*>(impl.sdl.window), impl.sdl.context);
break;
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplWin32_Init(impl.dx11.window);
break;
#endif
default:
break;
}
// OTRTODO: This gameplay specific stuff should not be in libultraship. This needs to be moved to soh and use sTunicColors
@ -148,9 +152,14 @@ namespace SohImGui {
case Backend::SDL:
ImGui_ImplOpenGL3_Init("#version 120");
break;
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplDX11_Init(static_cast<ID3D11Device*>(impl.dx11.device), static_cast<ID3D11DeviceContext*>(impl.dx11.device_context));
break;
#endif
default:
break;
}
}
@ -159,9 +168,13 @@ namespace SohImGui {
case Backend::SDL:
ImGui_ImplSDL2_ProcessEvent(static_cast<const SDL_Event*>(event.sdl.event));
break;
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplWin32_WndProcHandler(static_cast<HWND>(event.win32.handle), event.win32.msg, event.win32.wparam, event.win32.lparam);
break;
#endif
default:
break;
}
}
@ -170,9 +183,13 @@ namespace SohImGui {
case Backend::SDL:
ImGui_ImplSDL2_NewFrame(static_cast<SDL_Window*>(impl.sdl.window));
break;
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplWin32_NewFrame();
break;
#endif
default:
break;
}
}
@ -181,9 +198,13 @@ namespace SohImGui {
case Backend::SDL:
ImGui_ImplOpenGL3_NewFrame();
break;
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplDX11_NewFrame();
break;
#endif
default:
break;
}
}
@ -192,9 +213,13 @@ namespace SohImGui {
case Backend::SDL:
ImGui_ImplOpenGL3_RenderDrawData(data);
break;
#if defined(ENABLE_DX11) || defined(ENABLE_DX12)
case Backend::DX11:
ImGui_ImplDX11_RenderDrawData(data);
break;
#endif
default:
break;
}
}
@ -202,11 +227,12 @@ namespace SohImGui {
switch (impl.backend) {
case Backend::DX11:
return true;
}
default:
return false;
}
}
void SohImGui::ShowCursor(bool hide, Dialogues d) {
void ShowCursor(bool hide, Dialogues d) {
if (d == Dialogues::dLoadSettings) {
GlobalCtx2::GetInstance()->GetWindow()->ShowCursor(hide);
return;
@ -724,7 +750,11 @@ namespace SohImGui {
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Begin("Debug Stats", nullptr, ImGuiWindowFlags_None);
#ifdef _WIN32
ImGui::Text("Platform: Windows");
#else
ImGui::Text("Platform: Linux");
#endif
ImGui::Text("Status: %.3f ms/frame (%.1f FPS)", 1000.0f / framerate, framerate);
ImGui::End();
ImGui::PopStyleColor();
@ -879,4 +909,16 @@ namespace SohImGui {
ImTextureID GetTextureByName(const std::string& name) {
return GetTextureByID(DefaultAssets[name]->textureId);
}
ImTextureID GetTextureByID(int id) {
#ifdef ENABLE_DX11
if (impl.backend == Backend::DX11)
{
ImTextureID gfx_d3d11_get_texture_by_id(int id);
return gfx_d3d11_get_texture_by_id(id);
}
#else
return reinterpret_cast<ImTextureID>(id);
#endif
}
}

View File

@ -1,9 +1,14 @@
#include "Utils.h"
#include <cstring>
#ifdef _MSC_VER
#define strdup _strdup
#endif
namespace Utils {
std::vector<std::string> SplitText(const std::string text, char separator = ' ', bool keep_quotes = false) {
std::vector<std::string> args;
char* input = _strdup(text.c_str());
char* input = strdup(text.c_str());
const size_t length = strlen(input);
bool inQuotes = false;

View File

@ -1,3 +1,4 @@
#ifdef _WIN32
#include "WasapiAudioPlayer.h"
#include "spdlog/spdlog.h"
@ -170,3 +171,4 @@ namespace Ship {
return S_OK;
}
}
#endif

View File

@ -1,4 +1,7 @@
#pragma once
#ifdef _WIN32
#include "AudioPlayer.h"
#include <wrl/client.h>
#include <mmdeviceapi.h>
@ -39,3 +42,4 @@ namespace Ship {
bool started;
};
}
#endif

View File

@ -12,6 +12,8 @@
#include "Matrix.h"
#include "AudioPlayer.h"
#include "WasapiAudioPlayer.h"
#include "PulseAudioPlayer.h"
#include "SDLAudioPlayer.h"
#include "Lib/Fast3D/gfx_pc.h"
#include "Lib/Fast3D/gfx_sdl.h"
#include "Lib/Fast3D/gfx_opengl.h"
@ -48,7 +50,7 @@ extern "C" {
}
// TODO: This for loop is debug. Burn it with fire.
for (size_t i = 0; i < SDL_NumJoysticks(); i++) {
for (int i = 0; i < SDL_NumJoysticks(); i++) {
if (SDL_IsGameController(i)) {
// Get the GUID from SDL
char buf[33];
@ -207,7 +209,7 @@ extern "C" {
return (char*)res->imageData;
}
void ResourceMgr_WriteTexS16ByName(char* texPath, int index, s16 value) {
void ResourceMgr_WriteTexS16ByName(char* texPath, size_t index, s16 value) {
const auto res = static_cast<Ship::Texture*>(Ship::GlobalCtx2::GetInstance()->GetResourceManager()->LoadResource(texPath).get());
if (res != nullptr)
@ -237,7 +239,7 @@ extern "C" {
}
}
extern "C" GfxWindowManagerAPI gfx_sdl;
extern GfxWindowManagerAPI gfx_sdl;
void SetWindowManager(GfxWindowManagerAPI** WmApi, GfxRenderingAPI** RenderingApi, const std::string& gfx_backend);
namespace Ship {
@ -397,6 +399,12 @@ namespace Ship {
}
void Window::SetAudioPlayer() {
#ifdef _WIN32
APlayer = std::make_shared<WasapiAudioPlayer>();
#elif defined(__linux)
APlayer = std::make_shared<PulseAudioPlayer>();
#else
APlayer = std::make_shared<SDLAudioPlayer>();
#endif
}
}

View File

@ -23,7 +23,9 @@ void SetWindowManager(struct GfxWindowManagerAPI** WmApi, struct GfxRenderingAPI
#ifdef ENABLE_OPENGL
*RenderingApi = &gfx_opengl_api;
#if defined(__linux__)
*WmApi = &gfx_glx;
// LINUX_TODO:
// *WmApi = &gfx_glx;
*WmApi = &gfx_sdl;
#else
*WmApi = &gfx_sdl;
#endif

View File

@ -449,7 +449,10 @@ void aFilterImpl(uint8_t flags, uint16_t count_or_buf, int16_t *state_or_filter)
int16_t *buf = BUF_S16(count_or_buf);
if (flags == A_INIT) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmemset-elt-size"
memset(tmp, 0, 8 * sizeof(int16_t));
#pragma GCC diagnostic pop
memset(tmp2, 0, 8 * sizeof(int16_t));
} else {
memcpy(tmp, state_or_filter, 8 * sizeof(int16_t));

View File

@ -1,3 +1,4 @@
#include <sstream>
#include "stox.h"
#include "spdlog/spdlog.h"

5
soh/.gitignore vendored
View File

@ -25,6 +25,10 @@ docs/doxygen/
*.map
*.dump
out.txt
shipofharkinian.ini
imgui.ini
oot.otr
oot_save.sav
# Tool artifacts
tools/mipspro7.2_compiler/
@ -397,6 +401,7 @@ ZAPDUtils/ZAPDUtils.a
build/
ZAPDUtils/build/
ZAPD/BuildInfo.h
cvars.cfg
DebugObj/*
ReleaseObj/*

158
soh/Makefile Normal file
View File

@ -0,0 +1,158 @@
CXX := g++
CC := gcc
LD := lld
AR := ar
FORMAT := clang-format-11
ZAPD := ../ZAPDTR/ZAPD.out
LIBULTRASHIP := ../libultraship/libultraship.a
ZAPDUTILS := ../ZAPDTR/ZAPDUtils/ZAPDUtils.a
ASAN ?= 0
DEBUG ?= 1
OPTFLAGS ?= -O0
LTO ?= 0
WARN := \
-Wno-return-type \
-funsigned-char \
-m32 -mhard-float -fno-stack-protector -fno-common -fno-zero-initialized-in-bss -fno-strict-aliasing -fno-inline-functions -fno-inline-small-functions -fno-toplevel-reorder -ffreestanding -fwrapv \
CXXFLAGS := $(WARN) -std=c++20 -D_GNU_SOURCE -fpermissive -no-pie -nostdlib -march=i386
CFLAGS := $(WARN) -std=c99 -D_GNU_SOURCE -no-pie -nostdlib -march=i386
LDFLAGS := -m32
CPPFLAGS := -MMD
ifneq ($(DEBUG),0)
CXXFLAGS += -g
CFLAGS += -g
endif
ifneq ($(ASAN),0)
CXXFLAGS += -fsanitize=address
LDFLAGS += -fsanitize=address
endif
ifneq ($(LTO),0)
CXXFLAGS += -flto
LDFLAGS += -flto
endif
TARGET := soh.elf
INC_DIRS := $(addprefix -I, \
. \
assets \
build \
include \
src \
../ZAPDTR/ZAPDUtils \
../libultraship/libultraship \
../libultraship/libultraship/Lib/spdlog/include \
../libultraship/libultraship/Lib/Fast3D/U64 \
../libultraship/libultraship/Lib/Fast3D/U64/PR \
)
LDDIRS := $(addprefix -L, \
../external \
../libultraship/ \
)
LDLIBS := \
$(ZAPDUTILS) \
$(addprefix -l, \
X11 \
dl \
bz2 \
z \
pthread \
atomic \
SDL2 \
GL \
GLEW \
storm \
pulse\
ultraship \
) \
ASSET_BIN_DIRS := $(shell find assets/* -type d -not -path "assets/xml*")
ASSET_FILES_XML := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.xml))
ASSET_FILES_BIN := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.bin))
ASSET_FILES_OUT := $(foreach f,$(ASSET_FILES_XML:.xml=.c),$f) \
$(foreach f,$(ASSET_FILES_BIN:.bin=.bin.inc.c),build/$f)
TEXTURE_FILES_PNG := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.png))
TEXTURE_FILES_JPG := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.jpg))
TEXTURE_FILES_OUT := $(foreach f,$(TEXTURE_FILES_PNG:.png=.inc.c),build/$f) \
$(foreach f,$(TEXTURE_FILES_JPG:.jpg=.jpg.inc.c),build/$f) \
CXX_FILES := \
$(shell find soh -type f -name *.cpp)
C_FILES := \
$(shell find soh -type f -name *.c) \
$(shell find src/boot -type f -name *.c) \
$(shell find src/buffers -type f -name *.c) \
$(shell find src/code -type f -name *.c) \
$(shell find src/overlays -type f -name *.c) \
src/libultra/gu/coss.c \
src/libultra/gu/guLookAt.c \
src/libultra/gu/guLookAtHilite.c \
src/libultra/gu/guPerspectiveF.c \
src/libultra/gu/guPosition.c \
src/libultra/gu/guS2DInitBg.c \
src/libultra/gu/ortho.c \
src/libultra/gu/rotate.c \
src/libultra/gu/sins.c \
src/libultra/gu/sintable.c \
src/libultra/libc/sprintf.c
O_FILES := \
$(C_FILES:%.c=build/%.o) \
$(CXX_FILES:%.cpp=build/%.o)
D_FILES := $(O_FILES:%.o=%.d)
# create build directory
SRC_DIRS := $(shell find . -type d -a -not -path "*build*")
$(shell mkdir -p $(SRC_DIRS:%=build/%))
all:
$(MAKE) -C ../libultraship
$(MAKE) $(TARGET)
setup:
cd ../OTRExporter && python3 extract_baserom.py
$(MAKE) mpq
mpq:
$(MAKE) -C ../libultraship
$(MAKE) -C ../OTRExporter/OTRExporter
$(MAKE) -C ../ZAPDTR
rm -rf ../OTRExporter/oot.otr
cd ../OTRExporter && python3 extract_assets.py
cp ../OTRExporter/oot.otr .
distclean: clean
$(RM) -r baserom/
$(MAKE) clean -C ../libultraship
$(MAKE) clean -C ../OTRExporter/OTRExporter
$(MAKE) clean -C ../ZAPDTR
clean:
rm -rf build $(TARGET)
.PHONY: all clean distclean setup mpq
build/%.o: %.cpp
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) $< -o $@
build/%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $(OPTFLAGS) $(INC_DIRS) $< -o $@
# make soh depend on libultraship
$(TARGET): $(LIBULTRASHIP)
$(TARGET): $(O_FILES)
$(CXX) $^ -o $@ $(LDFLAGS) -fuse-ld=$(LD) $(LDDIRS) $(LDLIBS)
-include $(D_FILES)

View File

@ -1,7 +1,7 @@
#ifndef ALLOCA_H
#define ALLOCA_H
void* alloca(u32);
// void* alloca(u32);
//#define alloca __builtin_alloca
#define alloca malloc

View File

@ -14,7 +14,7 @@ extern "C"
#if defined(INCLUDE_GAME_PRINTF) && !defined(NDEBUG)
#define osSyncPrintf(fmt, ...) lusprintf(__FILE__, __LINE__, 0, fmt, __VA_ARGS__)
#else
#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, __VA_ARGS__)
#define osSyncPrintf(fmt, ...) osSyncPrintfUnused(fmt, ##__VA_ARGS__)
#endif
f32 fabsf(f32 f);

View File

@ -4,8 +4,8 @@
#include "functions.h"
#include "variables.h"
#include "macros.h"
#include "soh\OTRGlobals.h"
#include "soh\Enhancements\gameconsole.h"
#include "soh/OTRGlobals.h"
#include "soh/Enhancements/gameconsole.h"
#include "Cvar.h"

View File

@ -205,6 +205,14 @@ extern GraphicsContext* __gfxCtx;
#define ALIGNED8
#endif
#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 0xF0000000)
#define SEG_ADDR(seg, addr) (addr | (seg << 24) | 1)
#ifdef _MSC_VER
#define BOMSWAP16 _byteswap_ushort
#define BOMSWAP32 _byteswap_ulong
#else
#define BOMSWAP16 __builtin_bswap16
#define BOMSWAP32 __builtin_bswap32
#endif
#endif

View File

@ -1,6 +1,9 @@
#ifndef ULTRA64_H
#define ULTRA64_H
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include "ultra64/types.h"
#include "unk.h"

View File

@ -278,6 +278,7 @@
<ClCompile Include="src\code\z_actor_dlftbls.c" />
<ClCompile Include="src\code\z_bgcheck.c" />
<ClCompile Include="src\code\z_camera.c" />
<ClCompile Include="src\code\z_cheap_proc.c" />
<ClCompile Include="src\code\z_collision_btltbls.c" />
<ClCompile Include="src\code\z_collision_check.c" />
<ClCompile Include="src\code\z_common_data.c" />

View File

@ -18,7 +18,7 @@ extern "C" {
extern GlobalContext* gGlobalCtx;
}
#include "cvar.h"
#include "Cvar.h"
#define CMD_REGISTER SohImGui::BindCmd

View File

@ -4,6 +4,7 @@
#include <vector>
#include <string>
#include <cmath>
extern "C" {
#include <z64.h>

View File

@ -3,7 +3,7 @@
#include <ultra64.h>
#include <z64.h>
#include "cvar.h"
#include "Cvar.h"
#define MAX_CVARS 2048

View File

@ -11,10 +11,14 @@
#include "Window.h"
#include "z64animation.h"
#include "z64bgcheck.h"
#include "../soh/enhancements/gameconsole.h"
#include "Enhancements/gameconsole.h"
#include <ultra64/gbi.h>
#include <Animation.h>
#ifdef _WIN32
#include <Windows.h>
#else
#include <time.h>
#endif
#include <Vertex.h>
#include <CollisionHeader.h>
#include <Array.h>
@ -22,10 +26,11 @@
#include <Texture.h>
#include "Lib/stb/stb_image.h"
#include "AudioPlayer.h"
#include "../soh/Enhancements/debugconsole.h"
#include "../soh/Enhancements/debugger/debugger.h"
#include "Enhancements/debugconsole.h"
#include "Enhancements/debugger/debugger.h"
#include "Utils/BitConverter.h"
#include "variables.h"
#include "macros.h"
#include <Utils/StringHelper.h>
OTRGlobals* OTRGlobals::Instance;
@ -72,6 +77,7 @@ extern "C" void InitOTR() {
Debug_Init();
}
#ifdef _WIN32
extern "C" uint64_t GetFrequency() {
LARGE_INTEGER nFreq;
@ -86,6 +92,21 @@ extern "C" uint64_t GetPerfCounter() {
return ticks.QuadPart;
}
#else
extern "C" uint64_t GetFrequency() {
return 1000; // sec -> ms
}
extern "C" uint64_t GetPerfCounter() {
struct timespec monotime;
clock_gettime(CLOCK_MONOTONIC, &monotime);
uint64_t remainingMs = (monotime.tv_nsec / 1000000);
// in milliseconds
return monotime.tv_sec * 1000 + remainingMs;
}
#endif
// C->C++ Bridge
extern "C" void Graph_ProcessFrame(void (*run_one_game_iter)(void)) {
@ -429,7 +450,7 @@ extern "C" int ResourceMgr_OTRSigCheck(char* imgData)
{
uintptr_t i = (uintptr_t)(imgData);
if (i == 0xD9000000 || i == 0xE7000000 || (i & 0xF0000000) == 0xF0000000)
if (i == 0xD9000000 || i == 0xE7000000 || (i & 1) == 1)
return 0;
if ((i & 0xFF000000) != 0xAB000000 && (i & 0xFF000000) != 0xCD000000 && i != 0) {
@ -823,24 +844,24 @@ extern "C" int16_t OTRGetRectDimensionFromRightEdge(float v) {
}
extern "C" void bswapSoundFontSound(SoundFontSound* swappable) {
swappable->sample = (SoundFontSample*)_byteswap_ulong((u32)swappable->sample);
swappable->tuningAsU32 = _byteswap_ulong((u32)swappable->tuningAsU32);
swappable->sample = (SoundFontSample*)BOMSWAP32((u32)swappable->sample);
swappable->tuningAsU32 = BOMSWAP32((u32)swappable->tuningAsU32);
}
extern "C" void bswapDrum(Drum* swappable) {
bswapSoundFontSound(&swappable->sound);
swappable->envelope = (AdsrEnvelope*)_byteswap_ulong((u32)swappable->envelope);
swappable->envelope = (AdsrEnvelope*)BOMSWAP32((u32)swappable->envelope);
}
extern "C" void bswapInstrument(Instrument* swappable) {
swappable->envelope = (AdsrEnvelope*)_byteswap_ulong((u32)swappable->envelope);
swappable->envelope = (AdsrEnvelope*)BOMSWAP32((u32)swappable->envelope);
bswapSoundFontSound(&swappable->lowNotesSound);
bswapSoundFontSound(&swappable->normalNotesSound);
bswapSoundFontSound(&swappable->highNotesSound);
}
extern "C" void bswapSoundFontSample(SoundFontSample* swappable) {
u32 origBitfield = _byteswap_ulong(swappable->asU32);
u32 origBitfield = BOMSWAP32(swappable->asU32);
swappable->codec = (origBitfield >> 28) & 0x0F;
swappable->medium = (origBitfield >> 24) & 0x03;
@ -848,29 +869,29 @@ extern "C" void bswapSoundFontSample(SoundFontSample* swappable) {
swappable->unk_bit25 = (origBitfield >> 21) & 0x01;
swappable->size = (origBitfield) & 0x00FFFFFF;
swappable->sampleAddr = (u8*)_byteswap_ulong((u32)swappable->sampleAddr);
swappable->loop = (AdpcmLoop*)_byteswap_ulong((u32)swappable->loop);
swappable->book = (AdpcmBook*)_byteswap_ulong((u32)swappable->book);
swappable->sampleAddr = (u8*)BOMSWAP32((u32)swappable->sampleAddr);
swappable->loop = (AdpcmLoop*)BOMSWAP32((u32)swappable->loop);
swappable->book = (AdpcmBook*)BOMSWAP32((u32)swappable->book);
}
extern "C" void bswapAdpcmLoop(AdpcmLoop* swappable) {
swappable->start = (u32)_byteswap_ulong((u32)swappable->start);
swappable->end = (u32)_byteswap_ulong((u32)swappable->end);
swappable->count = (u32)_byteswap_ulong((u32)swappable->count);
swappable->start = (u32)BOMSWAP32((u32)swappable->start);
swappable->end = (u32)BOMSWAP32((u32)swappable->end);
swappable->count = (u32)BOMSWAP32((u32)swappable->count);
if (swappable->count != 0) {
for (int i = 0; i < 16; i++) {
swappable->state[i] = (s16)_byteswap_ushort(swappable->state[i]);
swappable->state[i] = (s16)BOMSWAP16(swappable->state[i]);
}
}
}
extern "C" void bswapAdpcmBook(AdpcmBook* swappable) {
swappable->order = (u32)_byteswap_ulong((u32)swappable->order);
swappable->npredictors = (u32)_byteswap_ulong((u32)swappable->npredictors);
swappable->order = (u32)BOMSWAP32((u32)swappable->order);
swappable->npredictors = (u32)BOMSWAP32((u32)swappable->npredictors);
for (int i = 0; i < swappable->npredictors * swappable->order * sizeof(s16) * 4; i++)
swappable->book[i] = (s16)_byteswap_ushort(swappable->book[i]);
swappable->book[i] = (s16)BOMSWAP16(swappable->book[i]);
}
extern "C" bool AudioPlayer_Init(void) {

View File

@ -12,12 +12,12 @@ OSViMode osViModeNtscLan1;
OSViMode osViModeMpalLan1;
OSViMode osViModeFpalLan1;
OSViMode osViModePalLan1;
AudioContext gAudioContext;
unk_D_8016E750 D_8016E750[4];
// AudioContext gAudioContext;
// unk_D_8016E750 D_8016E750[4];
u8 gLetterTLUT[4][32];
u8 gFontFF[999];
DmaEntry gDmaDataTable[0x60C];
u8 D_80133418;
// u8 D_80133418;
u16 gAudioSEFlagSwapSource[64];
u16 gAudioSEFlagSwapTarget[64];
u8 gAudioSEFlagSwapMode[64];

View File

@ -28,7 +28,7 @@ extern "C" void OTRGameplay_SpawnScene(GlobalContext* globalCtx, s32 sceneNum, s
//osSyncPrintf("\nSCENE SIZE %fK\n", (scene->sceneFile.vromEnd - scene->sceneFile.vromStart) / 1024.0f);
std::string scenePath = StringHelper::Sprintf("scenes\\%s\\%s", scene->sceneFile.fileName, scene->sceneFile.fileName);
std::string scenePath = StringHelper::Sprintf("scenes/%s/%s", scene->sceneFile.fileName, scene->sceneFile.fileName);
globalCtx->sceneSegment = (Ship::Scene*)OTRGameplay_LoadFile(globalCtx, scenePath.c_str());

View File

@ -246,7 +246,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) {
retry:
case ADSR_STATE_LOOP:
adsr->delay = (s16)_byteswap_ushort(adsr->envelope[adsr->envIndex].delay);
adsr->delay = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].delay);
switch (adsr->delay) {
case ADSR_DISABLE:
adsr->action.s.state = ADSR_STATE_DISABLED;
@ -255,7 +255,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) {
adsr->action.s.state = ADSR_STATE_HANG;
break;
case ADSR_GOTO:
adsr->envIndex = (s16)_byteswap_ushort(adsr->envelope[adsr->envIndex].arg);
adsr->envIndex = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].arg);
goto retry;
case ADSR_RESTART:
adsr->action.s.state = ADSR_STATE_INITIAL;
@ -266,7 +266,7 @@ f32 Audio_AdsrUpdate(AdsrState* adsr) {
if (adsr->delay == 0) {
adsr->delay = 1;
}
adsr->target = (s16)_byteswap_ushort(adsr->envelope[adsr->envIndex].arg) / 32767.0f;
adsr->target = (s16)BOMSWAP16(adsr->envelope[adsr->envIndex].arg) / 32767.0f;
adsr->target = adsr->target * adsr->target;
adsr->velocity = (adsr->target - adsr->current) / adsr->delay;
adsr->action.s.state = ADSR_STATE_FADE;

View File

@ -1110,12 +1110,12 @@ void AudioLoad_InitSwapFont(void) {
numInstruments = font->numInstruments;
// drums
ptrs[0] = (void*)_byteswap_ulong((uintptr_t)ptrs[0]);
ptrs[0] = (void*)BOMSWAP32((uintptr_t)ptrs[0]);
if ((ptrs[0] != NULL) && (numDrums != 0)) {
drumList = (Drum**)BASE_ROM_OFFSET(ptrs[0]);
for (i = 0; i < numDrums; i++) {
drumList[i] = (Drum*)_byteswap_ulong((uintptr_t)drumList[i]);
drumList[i] = (Drum*)BOMSWAP32((uintptr_t)drumList[i]);
if (drumList[i] != NULL) {
drum = (Drum*)BASE_ROM_OFFSET(drumList[i]);
@ -1128,7 +1128,7 @@ void AudioLoad_InitSwapFont(void) {
}
// sfxs
ptrs[1] = (void*)_byteswap_ulong((u32)ptrs[1]);
ptrs[1] = (void*)BOMSWAP32((u32)ptrs[1]);
if ((ptrs[1] != NULL) && (numSfxs != 0)) {
sfxList = (SoundFontSound*)BASE_ROM_OFFSET(ptrs[1]);
@ -1151,7 +1151,7 @@ void AudioLoad_InitSwapFont(void) {
instList = (Instrument**)(&ptrs[2]);
for (i = 0; i < numInstruments; i++) {
instList[i] = (Instrument*)_byteswap_ulong((uintptr_t)instList[i]);
instList[i] = (Instrument*)BOMSWAP32((uintptr_t)instList[i]);
if (instList[i] != NULL) {
inst = BASE_ROM_OFFSET(instList[i]);

View File

@ -1323,14 +1323,14 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) {
case 0xB2:
offset = (u16)parameters[0];
// OTRTODO: Byteswap added for quick audio
channel->unk_22 = _byteswap_ushort(*(u16*)(seqPlayer->seqData + (uintptr_t)(offset + scriptState->value * 2)));
channel->unk_22 = BOMSWAP16(*(u16*)(seqPlayer->seqData + (uintptr_t)(offset + scriptState->value * 2)));
break;
case 0xB4:
channel->dynTable = (void*)&seqPlayer->seqData[channel->unk_22];
break;
case 0xB5:
// OTRTODO: Byteswap added for quick audio
channel->unk_22 = _byteswap_ushort(((u16*)(channel->dynTable))[scriptState->value]);
channel->unk_22 = BOMSWAP16(((u16*)(channel->dynTable))[scriptState->value]);
break;
case 0xB6:
scriptState->value = (*channel->dynTable)[0][scriptState->value];

View File

@ -1162,7 +1162,7 @@ Acmd* AudioSynth_LoadWaveSamples(Acmd* cmd, NoteSubEu* noteSubEu, NoteSynthesisS
if (temp_v0 < nSamplesToLoad) {
repeats = ((nSamplesToLoad - temp_v0 + 0x3F) / 0x40);
if (repeats != 0) {
aDuplicate(cmd++, repeats, DMEM_UNCOMPRESSED_NOTE, DMEM_UNCOMPRESSED_NOTE + 0x80, 0x80);
aDuplicate(cmd++, repeats, DMEM_UNCOMPRESSED_NOTE, DMEM_UNCOMPRESSED_NOTE + 0x80);
}
}
synthState->samplePosInt = samplePosInt;
@ -1225,6 +1225,6 @@ Acmd* AudioSynth_NoteApplyHeadsetPanEffects(Acmd* cmd, NoteSubEu* noteSubEu, Not
aSaveBuffer(cmd++, DMEM_NOTE_PAN_TEMP + bufLen, &synthState->synthesisBuffers->panResampleState[0x8],
ALIGN16(panShift));
}
aAddMixer(cmd++, ALIGN64(bufLen), DMEM_NOTE_PAN_TEMP, dest, 0x7FFF);
aAddMixer(cmd++, ALIGN64(bufLen), DMEM_NOTE_PAN_TEMP, dest);
return cmd;
}

View File

@ -3,7 +3,9 @@
//#include <string.h>
#ifdef _MSC_VER
extern void* __cdecl memset(_Out_writes_bytes_all_(_Size) void* _Dst, _In_ int _Val, _In_ size_t _Size);
#endif
s32 D_8012D280 = 1;

Some files were not shown because too many files have changed in this diff Show More