Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 242 additions & 3 deletions OpenKh.Research.Panacea/Panacea.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@
}
}

void GetTM2Offsets(void* addr, int baseoff, std::vector<int>& entries)
void GetTM2Offsets(void* addr, int baseoff, std::vector<int>& entries, int flags = 0x20000000)
{
if (*(int*)addr == '2MIT')
{
Expand All @@ -429,7 +429,7 @@
while (texcnt-- > 0)
{
int next = *(int*)off;
entries.push_back(*(short*)(off + 12) + baseoff + 0x20000000);
entries.push_back(*(short*)(off + 12) + baseoff + flags);
off += next;
baseoff += next;
}
Expand Down Expand Up @@ -722,6 +722,184 @@
}
}

void GetPMOOffsets(void* addr, int baseoff, std::vector<int>& entries)

Check failure on line 725 in OpenKh.Research.Panacea/Panacea.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this use of "void *" with a more meaningful type.

See more on https://sonarcloud.io/project/issues?id=OpenKH_OpenKh&issues=AaBOuwZykZtwr73qvO8d&open=AaBOuwZykZtwr73qvO8d&pullRequest=1285
{
if (*(int*)addr == '\0OMP')
{
int texCount = ((short*)addr)[4];
char* texOffset = (char*)addr + 0xA0;
for (int i = 0; i < texCount; i++)
{
int oTm2 = *(int*)(texOffset + (0x20 * i));
if (oTm2 != 0)
GetTM2Offsets((char*)addr + oTm2, baseoff + oTm2, entries, 0);
}
}
}

void GetPMPOffsets(void* addr, int baseoff, std::vector<int>& entries)

Check failure on line 740 in OpenKh.Research.Panacea/Panacea.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this use of "void *" with a more meaningful type.

See more on https://sonarcloud.io/project/issues?id=OpenKH_OpenKh&issues=AaBOuwZykZtwr73qvO8e&open=AaBOuwZykZtwr73qvO8e&pullRequest=1285
{
if (*(int*)addr == '\0PMP')
{
int texCount = ((short*)addr)[13];
int texOffset = ((int*)addr)[7];
char* pTex = ((char*)addr + texOffset);
for (int i = 0; i < texCount; i++)
{
int oTm2 = *(int*)(pTex + (0x20 * i));
if (oTm2 != 0)
GetTM2Offsets((char*)addr + oTm2, baseoff + oTm2, entries, 0);
}
}
}

void GetL2DOffsets(void* addr, int baseoff, std::vector<int>& entries)

Check failure on line 756 in OpenKh.Research.Panacea/Panacea.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this use of "void *" with a more meaningful type.

See more on https://sonarcloud.io/project/issues?id=OpenKH_OpenKh&issues=AaBOuwZykZtwr73qvO8f&open=AaBOuwZykZtwr73qvO8f&pullRequest=1285
{
if (*(int*)addr == '@D2L')
{
int sq2pCount = ((int*)addr)[8];
int oOffsets = ((int*)addr)[9];
int* offsets = (int*)((char*)addr + oOffsets);
for (int i = 0; i < sq2pCount; i++)
{
int oSQ2P = offsets[i];
char* pSQ2P = (char*)offsets + oSQ2P;
int oTM2 = ((int*)pSQ2P)[6];
char* pTM2 = pSQ2P + oTM2;
GetTM2Offsets(pTM2, baseoff + oOffsets + oSQ2P + oTM2, entries, 0);
}
}
}

void GetTXAOffsets(void* addr, int baseoff, std::vector<int>& entries)

Check failure on line 774 in OpenKh.Research.Panacea/Panacea.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this use of "void *" with a more meaningful type.

See more on https://sonarcloud.io/project/issues?id=OpenKH_OpenKh&issues=AaBOuwZykZtwr73qvO8g&open=AaBOuwZykZtwr73qvO8g&pullRequest=1285
{
// TODO: Recheck all the sizes and offsets here
if (*(int*)addr == '\0AXT')
{
// Animations can reuse frames. We only want each frame once.
std::set<int> frames = std::set<int>();
short tex0Count = ((short*)addr)[3];
int* pTex0 = (int*)((char*)addr + 0x10);
for (int i = 0; i < tex0Count; i++)
{
short tex1Count = ((short*)pTex0)[24];
int* pTex1 = (int*)((char*)addr + pTex0[13]);

for (int j = 0; j < tex1Count; j++)
{
short tex2Count = ((short*)pTex1)[9];
int* pTex2 = (int*)((char*)addr + pTex1[5]);

for (int k = 0; k < tex2Count; k++)

Check failure on line 793 in OpenKh.Research.Panacea/Panacea.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=OpenKH_OpenKh&issues=AaBOuwZykZtwr73qvO8b&open=AaBOuwZykZtwr73qvO8b&pullRequest=1285
{
int pframe = *pTex2;
if (pframe != 0)
frames.emplace(baseoff + pframe);
pTex2 += 3;
}

pTex1 += 6;
}

pTex0 += 14;
}
entries.insert(entries.end(), frames.begin(), frames.end());
}
}

void GetFEPOffsets(void* addr, int baseoff, std::vector<int>& entries)

Check failure on line 810 in OpenKh.Research.Panacea/Panacea.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this use of "void *" with a more meaningful type.

See more on https://sonarcloud.io/project/issues?id=OpenKH_OpenKh&issues=AaBOuwZykZtwr73qvO8h&open=AaBOuwZykZtwr73qvO8h&pullRequest=1285
{
if ((*(int*)addr & 0x00FFFFFF) == '\0PEF')
{
std::set<int> frames = std::set<int>();
unsigned short tex_c = ((unsigned short*)addr)[16];
int* pTexResArr = (int*)((char*)addr + ((int*)addr)[12]);
for (int i = 0; i < tex_c; i++)
{
char* pTexRes = (char*)addr + pTexResArr[i];
int texSize = ((int*)pTexRes)[2];
if (texSize > 0)
{
int oTex = ((int*)pTexRes)[3];
int* pTex = (int*)((char*)addr + oTex);
int oPixels = pTex[9];
frames.emplace(baseoff + oTex + oPixels);
}
}

entries.insert(entries.end(), frames.begin(), frames.end());
}

return;
}

void GetARCOffsets(void* addr, int baseoff, std::vector<int>& entries)

Check failure on line 836 in OpenKh.Research.Panacea/Panacea.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this use of "void *" with a more meaningful type.

See more on https://sonarcloud.io/project/issues?id=OpenKH_OpenKh&issues=AaBOuwZykZtwr73qvO8i&open=AaBOuwZykZtwr73qvO8i&pullRequest=1285
{
if (*(int*)addr == '\0CRA')
{
short count = ((short*)addr)[3];
char* pEntry = (char*)addr + 0x10;
char nameBuf[17] = { 0 };
std::unordered_map<std::string, std::vector<int>> fileMap{};
std::vector<std::pair<std::string, std::vector<int>>> fileList{};
for (int i = 0; i < count; i++)
{
std::vector<int> currOffs{};

int offset = ((int*)pEntry)[1];
char* pName = pEntry + 0x10;
strncpy_s(nameBuf, 17, pName, 16);
char* ext = PathFindExtensionA(nameBuf);
if (!_stricmp(ext, ".pmo"))
{
GetPMOOffsets((char*)addr + offset, baseoff + offset, currOffs);
}
else if (!_stricmp(ext, ".pmp"))
{
GetPMPOffsets((char*)addr + offset, baseoff + offset, currOffs);
}
else if (!_stricmp(ext, ".tm2"))
{
GetTM2Offsets((char*)addr + offset, baseoff + offset, currOffs, 0);
}
else if (!_stricmp(ext, ".l2d"))
{
GetL2DOffsets((char*)addr + offset, baseoff + offset, currOffs);
}
else if (!_stricmp(ext, ".txa"))
{
GetTXAOffsets((char*)addr + offset, baseoff + offset, currOffs);
}
else if (!_stricmp(ext, ".fep"))
{
GetFEPOffsets((char*)addr + offset, baseoff + offset, currOffs);
}
pEntry += 0x20;
auto name = std::string(nameBuf);
fileMap.emplace(name, currOffs);
fileList.emplace_back(name, currOffs);
}

// TXA files immediatly preceed the file they're attatched to. Everything else shows up in order.
for (auto& pair : fileList)
{
auto path = PathFindExtensionA(pair.first.c_str());
if (!_stricmp(path, ".txa")) continue;
if (!_stricmp(path, ".pmo") || !_stricmp(path, ".pmp"))
{
std::string name2 = pair.first.substr(0, pair.first.length() - 4) + ".txa";
auto itr = fileMap.find(name2);
if (itr != fileMap.end())

Check failure on line 892 in OpenKh.Research.Panacea/Panacea.cpp

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this code to not nest more than 3 if|for|do|while|switch statements.

See more on https://sonarcloud.io/project/issues?id=OpenKH_OpenKh&issues=AaBOuwZykZtwr73qvO8c&open=AaBOuwZykZtwr73qvO8c&pullRequest=1285
{
entries.insert(entries.end(), itr->second.begin(), itr->second.end());
}
}
entries.insert(entries.end(), pair.second.begin(), pair.second.end());
}

}
}

void ScanFolder(const std::wstring& folder, std::vector<Axa::RemasteredEntry>& files)
{
std::queue<std::wstring> folq;
Expand Down Expand Up @@ -806,8 +984,42 @@
return false;
}

bool sortRemasteredFiles_LexBBS(const Axa::RemasteredEntry& a, const Axa::RemasteredEntry& b)
{
std::string na = std::string(a.name);
std::string nb = std::string(b.name);
return na < nb;
}

bool sortRemasteredFiles_NumBBS(const Axa::RemasteredEntry& a, const Axa::RemasteredEntry& b)
{
// this doesn't work, we need to start at the end and walk back until we find a digit (.dds), then until we find not a digit.
/*const char* pa = a.name;
while (*pa != '\0' && !isdigit(*pa)) pa++;
const char* pb = b.name;
while (*pb != '\0' && !isdigit(*pb)) pb++;
if (*pa == '\0' || *pb == '\0') return false;
int ia = atoi(pa);
int ib = atoi(pb);
return ia < ib;*/

char* pa = PathFindExtensionA(a.name) - 1;
while (isdigit(*(pa - 1)) && pa > a.name) pa--;

char* pb = PathFindExtensionA(b.name) - 1;
while (isdigit(*(pb - 1)) && pb > b.name) pb--;

int ia = atoi(pa);
int ib = atoi(pb);
return ia < ib;
}

void ScanRemasteredFolder(const wchar_t* path, void* addr, const wchar_t* remasteredFolder, std::vector<Axa::RemasteredEntry>& entries)
{
// BBS wants it's files as 0, 1, 10, 11, 12, 2, 3..., so we need to sort them numerically to work with them then sort them lexically to send to the game.
if (OpenKH::m_GameID == OpenKH::GameId::KingdomHeartsBbs)
std::stable_sort(entries.begin(), entries.end(), sortRemasteredFiles_NumBBS);

std::vector<int> assetoffs{};
const wchar_t* ext = PathFindExtensionW(path);
switch (OpenKH::m_GameID)
Expand Down Expand Up @@ -845,6 +1057,27 @@
for (int i = 0; i < entries.size(); ++i)
assetoffs.push_back(entries[i].origOffset);
break;
case OpenKH::GameId::KingdomHeartsBbs:
if (!_wcsicmp(ext, L".arc"))
GetARCOffsets(addr, 0, assetoffs);
else if (!_wcsicmp(ext, L".pmo"))
GetPMOOffsets(addr, 0, assetoffs);
else if (!_wcsicmp(ext, L".pmp"))
GetPMPOffsets(addr, 0, assetoffs);
else if (!_wcsicmp(ext, L".tm2"))
GetTM2Offsets(addr, 0, assetoffs, 0);
else if (!_wcsicmp(ext, L".l2d"))
GetL2DOffsets(addr, 0, assetoffs);
else if (!_wcsicmp(ext, L".txa"))
GetTXAOffsets(addr, 0, assetoffs);
else if (!_wcsicmp(ext, L".fep"))
GetFEPOffsets(addr, 0, assetoffs);
// TODO: .frr
// TODO: Font support: CLU COD INF MTX
else // unknown file type
for (int i = 0; i < entries.size(); ++i)
assetoffs.push_back(entries[i].origOffset);
break;
default:
for (int i = 0; i < entries.size(); ++i)
assetoffs.push_back(entries[i].origOffset);
Expand All @@ -854,7 +1087,10 @@
ScanFolder(remasteredFolder, modfiles);
if (modfiles.size() >= assetoffs.size())
{
std::stable_sort(modfiles.begin(), modfiles.end(), sortRemasteredFiles);
if (OpenKH::m_GameID == OpenKH::GameId::KingdomHeartsBbs)
std::stable_sort(modfiles.begin(), modfiles.end(), sortRemasteredFiles_NumBBS);
else
std::stable_sort(modfiles.begin(), modfiles.end(), sortRemasteredFiles);
entries = modfiles;
entries.resize(assetoffs.size());
for (int i = 0; i < entries.size(); ++i)
Expand Down Expand Up @@ -883,6 +1119,9 @@
}
}
}

if (OpenKH::m_GameID == OpenKH::GameId::KingdomHeartsBbs)
std::stable_sort(entries.begin(), entries.end(), sortRemasteredFiles_LexBBS);
}

void GetRemasteredFiles(Axa::PackageFile* fileinfo, const wchar_t* path, void* addr)
Expand Down
Loading