Correct Player Data Def class limit & migration!
This commit is contained in:
parent
704a125223
commit
21d5b05554
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
namespace Components
|
namespace Components
|
||||||
{
|
{
|
||||||
|
constexpr auto BASE_PLAYERSTATS_VERSION = 155;
|
||||||
|
|
||||||
Utils::Memory::Allocator StructuredData::MemAllocator;
|
Utils::Memory::Allocator StructuredData::MemAllocator;
|
||||||
|
|
||||||
const char* StructuredData::EnumTranslation[COUNT] =
|
const char* StructuredData::EnumTranslation[COUNT] =
|
||||||
@ -26,6 +28,11 @@ namespace Components
|
|||||||
{
|
{
|
||||||
if (!data || type >= StructuredData::PlayerDataType::COUNT) return;
|
if (!data || type >= StructuredData::PlayerDataType::COUNT) return;
|
||||||
|
|
||||||
|
// Reallocate them before patching
|
||||||
|
Game::StructuredDataEnum* newEnums = MemAllocator.allocateArray<Game::StructuredDataEnum>(data->enumCount);
|
||||||
|
std::memcpy(newEnums, data->enums, sizeof(Game::StructuredDataEnum) * data->enumCount);
|
||||||
|
data->enums = newEnums;
|
||||||
|
|
||||||
Game::StructuredDataEnum* dataEnum = &data->enums[type];
|
Game::StructuredDataEnum* dataEnum = &data->enums[type];
|
||||||
|
|
||||||
// Build index-sorted data vector
|
// Build index-sorted data vector
|
||||||
@ -86,24 +93,53 @@ namespace Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
void StructuredData::PatchCustomClassLimit(Game::StructuredDataDef* data, int count)
|
void StructuredData::PatchCustomClassLimit(Game::StructuredDataDef* data, int count)
|
||||||
|
{
|
||||||
|
constexpr auto CLASS_ARRAY = 5;
|
||||||
|
const auto originalClassCount = data->indexedArrays[CLASS_ARRAY].arraySize;
|
||||||
|
|
||||||
|
if (count != originalClassCount)
|
||||||
{
|
{
|
||||||
const int customClassSize = 64;
|
const int customClassSize = 64;
|
||||||
|
|
||||||
for (int i = 0; i < data->structs[0].propertyCount; ++i)
|
// We need to recreate the struct list cause it's used in order definitions
|
||||||
|
auto newStructs = StructuredData::MemAllocator.allocateArray<Game::StructuredDataStruct>(data->structCount);
|
||||||
|
std::memcpy(newStructs, data->structs, data->structCount * sizeof(Game::StructuredDataStruct));
|
||||||
|
data->structs = newStructs;
|
||||||
|
|
||||||
|
constexpr auto structIndex = 0;
|
||||||
{
|
{
|
||||||
// 3003 is the offset of the customClasses structure
|
auto strct = &data->structs[structIndex];
|
||||||
if (data->structs[0].properties[i].offset >= 3643)
|
|
||||||
|
auto newProperties = StructuredData::MemAllocator.allocateArray<Game::StructuredDataStructProperty>(strct->propertyCount);
|
||||||
|
std::memcpy(newProperties, strct->properties, strct->propertyCount * sizeof(Game::StructuredDataStructProperty));
|
||||||
|
strct->properties = newProperties;
|
||||||
|
|
||||||
|
for (int propertyIndex = 0; propertyIndex < strct->propertyCount; ++propertyIndex)
|
||||||
|
{
|
||||||
|
// 3643 is the offset of the customClasses structure
|
||||||
|
if (strct->properties[propertyIndex].offset >= 3643)
|
||||||
{
|
{
|
||||||
// -10 because 10 is the default amount of custom classes.
|
// -10 because 10 is the default amount of custom classes.
|
||||||
data->structs[0].properties[i].offset += ((count - 10) * customClassSize);
|
strct->properties[propertyIndex].offset += ((count - originalClassCount) * customClassSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update structure size
|
// update structure size
|
||||||
data->size += ((count - 10) * customClassSize);
|
data->size += ((count - originalClassCount) * customClassSize);
|
||||||
|
|
||||||
// Update amount of custom classes
|
// Update amount of custom classes
|
||||||
data->indexedArrays[5].arraySize = count;
|
if (data->indexedArrays[CLASS_ARRAY].arraySize != count)
|
||||||
|
{
|
||||||
|
// We need to recreate the whole array - this reference could be reused accross definitions
|
||||||
|
auto newIndexedArray = StructuredData::MemAllocator.allocateArray<Game::StructuredDataIndexedArray>(data->indexedArrayCount);
|
||||||
|
std::memcpy(newIndexedArray, data->indexedArrays, data->indexedArrayCount * sizeof(Game::StructuredDataIndexedArray));
|
||||||
|
data->indexedArrays = newIndexedArray;
|
||||||
|
|
||||||
|
// Add classes
|
||||||
|
data->indexedArrays[CLASS_ARRAY].arraySize = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructuredData::PatchAdditionalData(Game::StructuredDataDef* data, std::unordered_map<std::string, std::string>& patches)
|
void StructuredData::PatchAdditionalData(Game::StructuredDataDef* data, std::unordered_map<std::string, std::string>& patches)
|
||||||
@ -119,27 +155,45 @@ namespace Components
|
|||||||
|
|
||||||
bool StructuredData::UpdateVersionOffsets(Game::StructuredDataDefSet* set, Game::StructuredDataBuffer* buffer, Game::StructuredDataDef* whatever)
|
bool StructuredData::UpdateVersionOffsets(Game::StructuredDataDefSet* set, Game::StructuredDataBuffer* buffer, Game::StructuredDataDef* whatever)
|
||||||
{
|
{
|
||||||
Game::StructuredDataDef* newDef = &set->defs[0];
|
if (set->defCount > 1)
|
||||||
Game::StructuredDataDef* oldDef = &set->defs[0];
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < set->defCount; ++i)
|
|
||||||
{
|
{
|
||||||
if (newDef->version < set->defs[i].version)
|
int bufferVersion = *reinterpret_cast<int*>(buffer->data);
|
||||||
{
|
|
||||||
newDef = &set->defs[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (set->defs[i].version == *reinterpret_cast<int*>(buffer->data))
|
for (size_t i = 0; i < set->defCount; i++)
|
||||||
{
|
{
|
||||||
oldDef = &set->defs[i];
|
if (set->defs[i].version == bufferVersion)
|
||||||
}
|
{
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
// No update to conduct
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Game::StructuredDataDef* newDef = &set->defs[i - 1];
|
||||||
|
Game::StructuredDataDef* oldDef = &set->defs[i];
|
||||||
|
|
||||||
if (newDef->version >= 159 && oldDef->version <= 158)
|
if (newDef->version == 159 && oldDef->version <= 158)
|
||||||
{
|
{
|
||||||
// this should move the data 320 bytes infront
|
// this should move the data 320 bytes infront
|
||||||
std::memmove(&buffer->data[3963], &buffer->data[3643], oldDef->size - 3643);
|
std::memmove(&buffer->data[3963], &buffer->data[3643], oldDef->size - 3643);
|
||||||
}
|
}
|
||||||
|
else if (newDef->version > 159 && false)
|
||||||
|
{
|
||||||
|
// 159 cannot be translated upwards and it's hard to say why
|
||||||
|
// Reading it fails in various ways
|
||||||
|
// might be the funky class bump...?
|
||||||
|
|
||||||
|
Command::Execute("setPlayerData prestige 10");
|
||||||
|
Command::Execute("setPlayerData experience 2516000");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils::Hook::Call<bool(void*, void*, void*)>(0x456830)(set, buffer, whatever);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils::Hook::Call<bool(void*, void*, void*)>(0x456830)(set, buffer, whatever);
|
||||||
|
}
|
||||||
|
|
||||||
// StructuredData_UpdateVersion
|
// StructuredData_UpdateVersion
|
||||||
return Utils::Hook::Call<bool(void*, void*, void*)>(0x456830)(set, buffer, whatever);
|
return Utils::Hook::Call<bool(void*, void*, void*)>(0x456830)(set, buffer, whatever);
|
||||||
@ -182,7 +236,7 @@ namespace Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->defs[0].version != 155)
|
if (data->defs[0].version != BASE_PLAYERSTATS_VERSION)
|
||||||
{
|
{
|
||||||
Logger::Error(Game::ERR_FATAL, "Initial PlayerDataDef is not version 155, patching not possible!");
|
Logger::Error(Game::ERR_FATAL, "Initial PlayerDataDef is not version 155, patching not possible!");
|
||||||
return;
|
return;
|
||||||
@ -262,16 +316,10 @@ namespace Components
|
|||||||
auto* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->defCount + patchDefinitions.size());
|
auto* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->defCount + patchDefinitions.size());
|
||||||
std::memcpy(&newData[patchDefinitions.size()], data->defs, sizeof Game::StructuredDataDef * data->defCount);
|
std::memcpy(&newData[patchDefinitions.size()], data->defs, sizeof Game::StructuredDataDef * data->defCount);
|
||||||
|
|
||||||
// Prepare the buffers
|
// Set the versions
|
||||||
for (unsigned int i = 0; i < patchDefinitions.size(); ++i)
|
for (unsigned int i = 0; i < patchDefinitions.size(); ++i)
|
||||||
{
|
{
|
||||||
std::memcpy(&newData[i], data->defs, sizeof Game::StructuredDataDef);
|
newData[i].version = (patchDefinitions.size() - i) + BASE_PLAYERSTATS_VERSION;
|
||||||
newData[i].version = (patchDefinitions.size() - i) + 155;
|
|
||||||
|
|
||||||
// Reallocate the enum array
|
|
||||||
auto* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(data->defs->enumCount);
|
|
||||||
std::memcpy(newEnums, data->defs->enums, sizeof Game::StructuredDataEnum * data->defs->enumCount);
|
|
||||||
newData[i].enums = newEnums;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply new data
|
// Apply new data
|
||||||
@ -279,10 +327,18 @@ namespace Components
|
|||||||
data->defCount += patchDefinitions.size();
|
data->defCount += patchDefinitions.size();
|
||||||
|
|
||||||
// Patch the definition
|
// Patch the definition
|
||||||
for (unsigned int i = 0; i < data->defCount; ++i)
|
for (int i = data->defCount - 1; i >= 0; --i)
|
||||||
{
|
{
|
||||||
// No need to patch version 155
|
// No need to patch version 155
|
||||||
if (newData[i].version == 155) continue;
|
if (newData[i].version == BASE_PLAYERSTATS_VERSION)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We start from the previous one
|
||||||
|
const auto version = newData[i].version;
|
||||||
|
data->defs[i] = data->defs[i + 1];
|
||||||
|
newData[i].version = version;
|
||||||
|
|
||||||
if (patchDefinitions.contains(newData[i].version))
|
if (patchDefinitions.contains(newData[i].version))
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user