Skip to content
This repository was archived by the owner on Sep 2, 2022. It is now read-only.
Open
Show file tree
Hide file tree
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
161 changes: 93 additions & 68 deletions api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,26 +21,26 @@ std::unordered_map<uint32_t, std::string> channelNames =

std::vector<std::string> dataNames =
{
"Detail Diffuse Transform",
"Detail Normal Transform",
"\"detail_diffuse_transform\"",
"\"detail_normal_transform\"",
"\"spec_aa_transform\"",
"Primary Color",
"\"primary_albedo_tint\"",
"\"primary_emissive_tint_color_and_intensity_bias\"",
"\"primary_material_params\"",
"\"primary_material_advanced_params\"",
"Primary Roughness Remap",
"Primary Wear Color",
"Primary Wear Remap",
"Primary Worn Roughness Remap",
"\"primary_roughness_remap\"",
"\"primary_worn_albedo_tint\"",
"\"primary_wear_remap\"",
"\"primary_worn_roughness_remap\"",
"\"primary_worn_material_parameters\"",
"Secondary Color",
"\"secondary_albedo_tint\"",
"\"secondary_emissive_tint_color_and_intensity_bias\"",
"\"secondary_material_params\"",
"\"secondary_material_advanced_params\"",
"Secondary Roughness Remap",
"Secondary Wear Color",
"Secondary Wear Remap",
"Secondary Worn Roughness Remap",
"\"secondary_roughness_remap\"",
"\"secondary_worn_albedo_tint\"",
"\"secondary_wear_remap\"",
"\"secondary_worn_roughness_remap\"",
"\"secondary_worn_material_parameters\"",
};

Expand Down Expand Up @@ -113,7 +113,7 @@ uint32_t getArtArrangementHash(uint32_t apiHash, std::string packagesPath)
}


void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packagesPath, std::unordered_map<uint64_t, uint32_t> hash64Table)
void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packagesPath, std::unordered_map<uint64_t, uint32_t> hash64Table, std::uint32_t dyeManifestHashes[], std::uint32_t dyeManHashesSize)
{
File* dataTable = new File("26FCDD80", packagesPath);
dataTable->getData();
Expand All @@ -125,49 +125,60 @@ void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packages
std::unordered_map<uint16_t, uint16_t> defaultChannelDyeMap;
std::unordered_map<uint16_t, uint16_t> customChannelDyeMap;
memcpy((char*)&tableCount, dataTable->data + 8, 4);
for (int i = tableOffset; i < tableOffset + tableCount * 0x20; i += 0x20)
if (!dyeManHashesSize > 0)
{
memcpy((char*)&val, dataTable->data + i, 4);
if (val == apiHash)
for (int i = tableOffset; i < tableOffset + tableCount * 0x20; i += 0x20)
{
memcpy((char*)&val, dataTable->data + i + 0x10, 4);
File dataFile = File(uint32ToHexStr(val), packagesPath);
dataFile.getData();
memcpy((char*)&val, dataFile.data + 0x88, 4);
val += 0x88;
memcpy((char*)&val2, dataFile.data + val - 4, 4);
if (val2 != 2155901815)
{
printf("Given shader is not valid!\n");
return;
}
uint32_t defaultDyeTableCount;
uint32_t defaultDyeTableOffset;
uint32_t customDyeTableCount;
uint32_t customDyeTableOffset;
memcpy((char*)&defaultDyeTableCount, dataFile.data + val + 0x28, 4);
memcpy((char*)&defaultDyeTableOffset, dataFile.data + val + 0x30, 4);
defaultDyeTableOffset += 0x10 + val + 0x30;
memcpy((char*)&customDyeTableCount, dataFile.data + val + 0x38, 4);
memcpy((char*)&customDyeTableOffset, dataFile.data + val + 0x40, 4);
customDyeTableOffset += 0x10 + val + 0x40;
uint16_t channelIndex;
uint16_t dyeIndex;
for (int j = defaultDyeTableOffset; j < defaultDyeTableOffset + defaultDyeTableCount * 4; j += 4)
{
memcpy((char*)&channelIndex, dataFile.data + j, 2);
memcpy((char*)&dyeIndex, dataFile.data + j + 2, 2);
defaultChannelDyeMap[channelIndex] = dyeIndex;
}
for (int j = customDyeTableOffset; j < customDyeTableOffset + customDyeTableCount * 4; j += 4)
memcpy((char*)&val, dataTable->data + i, 4);
if (val == apiHash)
{
memcpy((char*)&channelIndex, dataFile.data + j, 2);
memcpy((char*)&dyeIndex, dataFile.data + j + 2, 2);
customChannelDyeMap[channelIndex] = dyeIndex;
memcpy((char*)&val, dataTable->data + i + 0x10, 4);
File dataFile = File(uint32ToHexStr(val), packagesPath);
dataFile.getData();
memcpy((char*)&val, dataFile.data + 0x88, 4);
val += 0x88;
memcpy((char*)&val2, dataFile.data + val - 4, 4);
if (val2 != 2155901815)
{
printf("Given shader is not valid!\n");
return;
}
uint32_t defaultDyeTableCount;
uint32_t defaultDyeTableOffset;
uint32_t customDyeTableCount;
uint32_t customDyeTableOffset;
memcpy((char*)&defaultDyeTableCount, dataFile.data + val + 0x28, 4);
memcpy((char*)&defaultDyeTableOffset, dataFile.data + val + 0x30, 4);
defaultDyeTableOffset += 0x10 + val + 0x30;
memcpy((char*)&customDyeTableCount, dataFile.data + val + 0x38, 4);
memcpy((char*)&customDyeTableOffset, dataFile.data + val + 0x40, 4);
customDyeTableOffset += 0x10 + val + 0x40;
uint16_t channelIndex;
uint16_t dyeIndex;
for (int j = defaultDyeTableOffset; j < defaultDyeTableOffset + defaultDyeTableCount * 4; j += 4)
{
memcpy((char*)&channelIndex, dataFile.data + j, 2);
memcpy((char*)&dyeIndex, dataFile.data + j + 2, 2);
defaultChannelDyeMap[channelIndex] = dyeIndex;
}
for (int j = customDyeTableOffset; j < customDyeTableOffset + customDyeTableCount * 4; j += 4)
{
memcpy((char*)&channelIndex, dataFile.data + j, 2);
memcpy((char*)&dyeIndex, dataFile.data + j + 2, 2);
customChannelDyeMap[channelIndex] = dyeIndex;
printf(std::to_string(channelIndex).c_str());
printf("\n");
}
}
}
if (defaultChannelDyeMap.size() == 0) return;
}
else
{
customChannelDyeMap[0] = 0;
customChannelDyeMap[1] = 1;
customChannelDyeMap[2] = 2;
}
if (defaultChannelDyeMap.size() == 0) return;

File* channelTable = new File("C92FCF80", packagesPath);
channelTable->getData();
Expand All @@ -180,6 +191,7 @@ void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packages
std::string dyeFileHash;
File* finalDyeFile = nullptr;
std::string channelName;
std::string channelNameHash;
// For each pair, find the channel hash to pair it with a name + find the dye file

std::unordered_map<std::string, std::unordered_map<std::string, std::vector<float>>> defaultDyes;
Expand All @@ -200,9 +212,13 @@ void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packages
// Get channel name
memcpy((char*)&channelHash, channelTable->data + 0x30 + 4 * it.first, 4);
channelName = channelNames[channelHash];
channelNameHash = std::to_string(channelHash);

// Get dye file
memcpy((char*)&dyeManifestHash, dyeManifestTable->data + 0x30 + 8 * it.second + 4, 4);
if (!dyeManHashesSize > 0)
memcpy((char*)&dyeManifestHash, dyeManifestTable->data + 0x30 + 8 * it.second + 4, 4);
else
dyeManifestHash = dyeManifestHashes[it.second];
tableOffset = 0x40;
memcpy((char*)&tableCount, dyeFileTable->data + 8, 4);
for (int i = tableOffset; i < tableOffset + tableCount * 0x18; i += 0x18)
Expand Down Expand Up @@ -292,17 +308,17 @@ void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packages

if (q == 0)
{
defaultDyes[channelName] = dyeData;
defaultDyes[channelNameHash] = dyeData;
texData["Diffuse"] = diffuseName;
texData["Normal"] = normalName;
defaultTextures[channelName] = texData;
defaultTextures[channelNameHash] = texData;
}
else
{
customDyes[channelName] = dyeData;
customDyes[channelNameHash] = dyeData;
texData["Diffuse"] = diffuseName;
texData["Normal"] = normalName;
customTextures[channelName] = texData;
customTextures[channelNameHash] = texData;
}
}
}
Expand All @@ -316,29 +332,38 @@ void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packages

void writeShader(std::unordered_map<std::string, std::unordered_map<std::string, std::vector<float>>> dyes, std::unordered_map<std::string, std::unordered_map<std::string, std::string>> textures, bool bCustom, std::string outputPath)
{
std::string stringFactoryShader = "";
if (!bCustom) stringFactoryShader += "Default dyes:\n";
else stringFactoryShader += "Custom dyes:\n";
std::string stringFactoryShader = "{\n";
if (!bCustom) stringFactoryShader += " \"custom_dyes\": [],\n \"locked_dyes\": [],\n \"default_dyes\": [\n";
else stringFactoryShader += " \"default_dyes\": [],\n \"locked_dyes\": [],\n \"custom_dyes\": [\n";
std::string propertiesString = "";
for (auto& it : dyes)
{
stringFactoryShader += " " + it.first + ":\n";
if (it.first.find("Cloth", 0) != std::string::npos) stringFactoryShader += " Is cloth: True\n";
else stringFactoryShader += " Is cloth: False\n";
stringFactoryShader += " Properties:\n";
//propertiesString += " " + it.first + ":\n";
propertiesString += " {\n";
propertiesString += " \"investment_hash\": " + it.first + ",\n";
if (it.first.find("Cloth", 0) != std::string::npos) propertiesString += " \"cloth\": true,\n";
else propertiesString += " \"cloth\": false,\n";
propertiesString += " \"material_properties\": {\n";
std::string valuesString = "";
for (auto& it2 : it.second)
{
if (it.first.find("Diffuse", 0) != std::string::npos) break;
if (it.first.find("diffuse", 0) != std::string::npos) break;
std::string floatString = "[";
for (auto& flt : it2.second) floatString += std::to_string(flt) + ", ";
stringFactoryShader += " " + it2.first + ": " + floatString.substr(0, floatString.size()-2) + "]\n";
//stringFactoryShader += " " + it2.first + ": " + floatString.substr(0, floatString.size()-2) + "],\n";
valuesString += " " + it2.first + ": " + floatString.substr(0, floatString.size()-2) + "],\n";
}
stringFactoryShader += " Diffuse: " + textures[it.first]["Diffuse"] + "\n";
stringFactoryShader += " Normal: " + textures[it.first]["Normal"] + "\n";
propertiesString += valuesString.substr(0, valuesString.size()-2) + "\n },\n";
propertiesString += " \"textures\": {\n";
propertiesString += " \"diffuse\": {\n \"name\": \"" + textures[it.first]["Diffuse"] + "\"\n },\n";
propertiesString += " \"normal\": {\n \"name\": \"" + textures[it.first]["Normal"] + "\"\n }\n";
propertiesString += " }\n },\n";
}
stringFactoryShader += "\n";
stringFactoryShader += propertiesString.substr(0, propertiesString.size()-2) + "\n ]\n}";
//stringFactoryShader += "\n";

FILE* shaderFile;
std::string path = outputPath + "/shader.txt";
std::string path = outputPath + "/shader.json";
fopen_s(&shaderFile, path.c_str(), "w");
fwrite(stringFactoryShader.c_str(), stringFactoryShader.size(), 1, shaderFile);
fclose(shaderFile);
Expand Down
2 changes: 1 addition & 1 deletion api.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ std::vector<std::string> getAPISingleHashes(uint32_t mHash, uint32_t fHash, std:
std::vector<std::string> getAPIMultiHashes(uint32_t tableOffset, File* modelTable, std::string packagesPath, std::unordered_map<uint64_t, uint32_t> hash64Table);
std::vector<std::string> getHashesFromH64s(std::vector<std::string> h64Files, std::string packagesPath, std::unordered_map<uint64_t, uint32_t> hash64Table);
uint32_t getArtArrangementHash(uint32_t apiHash, std::string packagesPath);
void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packagesPath, std::unordered_map<uint64_t, uint32_t> hash64Table);
void getAPIShader(uint32_t apiHash, std::string outputPath, std::string packagesPath, std::unordered_map<uint64_t, uint32_t> hash64Table, std::uint32_t dyeManifestHashes[], std::uint32_t dyeManHashesSize);
void writeShader(std::unordered_map<std::string, std::unordered_map<std::string, std::vector<float>>> dyes, std::unordered_map<std::string, std::unordered_map<std::string, std::string>> textures, bool bCustom, std::string outputPath);
25 changes: 23 additions & 2 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ int main(int argc, char** argv)
sarge.setArgument("s", "skeloverride", "skeleton override", true);
sarge.setArgument("c", "cbuffer", "enable cbuffer extraction", false);
sarge.setArgument("h", "shader", "shader hash", true);
sarge.setArgument("d", "dyemanifesthashes", "shader by individual dyes", true);
sarge.setDescription("Destiny 2 dynamic model extractor by Monteven.");
sarge.setUsage("MontevenDynamicExtractor");

Expand All @@ -51,19 +52,36 @@ int main(int argc, char** argv)
std::string batchPkg;
std::string apiHashStr = "";
std::string shaderHashStr = "";
std::string dyeHashesStr = "";
uint32_t apiHash = 0;
uint32_t shaderHash = 0;
uint32_t dyeHashes[3] = {};
sarge.getFlag("pkgspath", pkgsPath);
sarge.getFlag("outputpath", outputPath);
sarge.getFlag("filename", fileName);
sarge.getFlag("inputhash", modelHash);
sarge.getFlag("api", apiHashStr);
sarge.getFlag("shader", shaderHashStr);
sarge.getFlag("dyemanifesthashes", dyeHashesStr);
sarge.getFlag("skeloverride", skeletonOverrideStr);

if (skeletonOverrideStr != "") skeletonOverride = std::stol(skeletonOverrideStr);
if (apiHashStr != "") apiHash = std::stoul(apiHashStr);
if (shaderHashStr != "") shaderHash = std::stoul(shaderHashStr);
if (dyeHashesStr != "")
{
shaderHash = 1;
size_t pos = 0;
std::string token;
std::int8_t index = 0;
std::string delimiter = " ";
dyeHashesStr += " ";
while ((pos = dyeHashesStr.find(delimiter)) != std::string::npos) {
dyeHashes[index] = stoul(dyeHashesStr.substr(0, pos));
dyeHashesStr.erase(0, pos + delimiter.length());
index++;
}
}
bTextures = sarge.exists("textures");
bCBuffer = sarge.exists("cbuffer");
sarge.getFlag("batch", batchPkg);
Expand Down Expand Up @@ -119,9 +137,12 @@ int main(int argc, char** argv)
if (shaderHash != 0)
{
printf("Shader flag found, getting shader data...\n");
std::string savePath = outputPath + "/" + std::to_string(shaderHash);
std::string savePath = outputPath + "/" + fileName;//std::to_string(shaderHash);
std::filesystem::create_directories(savePath);
getAPIShader(shaderHash, savePath, pkgsPath, hash64Table);
if (shaderHash != 1)
getAPIShader(shaderHash, savePath, pkgsPath, hash64Table, new std::uint32_t[0]{}, 0);
else
getAPIShader(shaderHash, savePath, pkgsPath, hash64Table, dyeHashes, sizeof(dyeHashes));

printf("Shader rip done!");
return 0;
Expand Down