4
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

346 lines
9.0 KiB

#pragma once
namespace RE
{
// 18
template <class T, int nGrow = 10, int nShrink = 10>
class tArray
{
public:
T* entries; // 00
uint32_t capacity; // 08
uint32_t pad0C; // 0C
uint32_t count; // 10
uint32_t pad14; // 14
tArray() :
entries(NULL), capacity(0), count(0), pad0C(0), pad14(0) {}
T& operator[](uint64_t index)
{
return entries[index];
}
RE::MemoryManager* Heap()
{
return RE::MemoryManager::GetSingleton();
}
void Clear()
{
Heap()->Deallocate(entries, false);
entries = NULL;
capacity = 0;
count = 0;
}
bool Allocate(uint32_t numEntries)
{
entries = (T*)Heap()->Allocate(sizeof(T) * numEntries, 0, false);
if (!entries)
return false;
for (uint32_t i = 0; i < numEntries; i++)
new (&entries[i]) T;
capacity = numEntries;
count = numEntries;
return true;
}
bool CopyFrom(const tArray<T>* rhs)
{
if (rhs->count == 0)
return false;
if (!rhs->entries)
return false;
if (entries)
Clear();
if (!Allocate(rhs->count))
return false;
memcpy(entries, rhs->entries, sizeof(T) * count);
return true;
}
bool Resize(uint32_t numEntries)
{
if (numEntries == capacity)
return false;
if (!entries) {
Allocate(numEntries);
return true;
}
if (numEntries < capacity) {
// Delete the truncated entries
for (uint32_t i = numEntries; i < capacity; i++)
delete &entries[i];
}
T* newBlock = (T*)Heap()->Allocate(sizeof(T) * numEntries, 0, false); // Create a new block
memmove_s(newBlock, sizeof(T) * numEntries, entries, sizeof(T) * numEntries); // Move the old memory to the new block
if (numEntries > capacity) { // Fill in new remaining entries
for (uint32_t i = capacity; i < numEntries; i++)
new (&entries[i]) T;
}
Heap()->Deallocate(entries, false); // Free the old block
entries = newBlock; // Assign the new block
capacity = numEntries; // Capacity is now the number of total entries in the block
count = std::min(capacity, count); // Count stays the same, or is truncated to capacity
return true;
}
bool Push(const T& entry)
{
if (!entries || count + 1 > capacity) {
if (!Grow(nGrow))
return false;
}
new (&entries[count]) T(entry);
count++;
return true;
};
bool Insert(uint32_t index, const T& entry)
{
if (!entries || index < count)
return false;
entries[index] = entry;
return true;
};
bool Remove(uint32_t index)
{
if (!entries || index >= count)
return false;
// This might not be right for pointer types...
(&entries[index])->~T();
if (index + 1 < count) {
uint32_t remaining = count - index;
memmove_s(&entries[index + 1], sizeof(T) * remaining, &entries[index], sizeof(T) * remaining); // Move the rest up
}
count--;
if (capacity > count + nShrink)
Shrink();
return true;
}
bool Shrink()
{
if (!entries || count == capacity)
return false;
try {
uint32_t newSize = count;
T* oldArray = entries;
T* newArray = (T*)Heap()->Allocate(sizeof(T) * newSize, 0, false); // Allocate new block
memmove_s(newArray, sizeof(T) * newSize, entries, sizeof(T) * newSize); // Move the old block
entries = newArray;
capacity = count;
Heap()->Deallocate(oldArray, false); // Free the old block
return true;
} catch (...) {
return false;
}
return false;
}
bool Grow(uint32_t numEntries)
{
if (!entries) {
entries = (T*)Heap()->Allocate(sizeof(T) * numEntries, 0, false);
count = 0;
capacity = numEntries;
return true;
}
try {
uint32_t oldSize = capacity;
uint32_t newSize = oldSize + numEntries;
T* oldArray = entries;
T* newArray = (T*)Heap()->Allocate(sizeof(T) * newSize, 0, false); // Allocate new block
if (oldArray)
memmove_s(newArray, sizeof(T) * newSize, entries, sizeof(T) * capacity); // Move the old block
entries = newArray;
capacity = newSize;
if (oldArray)
Heap()->Deallocate(oldArray, false); // Free the old block
for (uint32_t i = oldSize; i < newSize; i++) // Allocate the rest of the free blocks
new (&entries[i]) T;
return true;
} catch (...) {
return false;
}
return false;
}
bool GetNthItem(uint64_t index, T& pT) const
{
if (index < count) {
pT = entries[index];
return true;
}
return false;
}
int64_t GetItemIndex(T& pFind) const
{
for (uint64_t n = 0; n < count; n++) {
T& pT = entries[n];
if (pT == pFind)
return n;
}
return -1;
}
};
typedef tArray<uint64_t> UnkArray;
typedef tArray<TESForm*> UnkFormArray;
// D0
class PersistentFormManager
{
public:
// 10
struct EnchantData
{
EnchantmentItem* enchantment; // 00
volatile long refCount; // 08
uint32_t pad; // 0C
};
uint64_t unk00; // 00
tArray<EnchantData> weaponEnchants; // 08
tArray<EnchantData> armorEnchants; // 20
uint64_t unk38; // 38
uint32_t unk40; // 40
uint32_t unk44; // 44
uint32_t unk48; // 48
uint32_t unk4C; // 4C
// 30
struct Data
{
void* unk00; // 00
uint64_t unk08; // 08
void* unk10; // 10
uint64_t unk18; // 18
uint32_t unk20; // 20
uint32_t unk24; // 24
uint32_t unk28; // 28
uint32_t unk2C; // 2C
};
Data unk50; // 50
Data unk80; // 80
void* unkB0; // B0
uint64_t unkB8; // B8
uint64_t unkC0; // C0
uint64_t unkC8; // C8
//RelocPtr<RE::PersistentFormManager*> g_persistentFormManager(0x01EBEAE8); // SE
//RelocPtr<RE::PersistentFormManager*> g_persistentFormManager(0x01F5A468); // AE
[[nodiscard]] static PersistentFormManager* GetSingleton()
{
REL::Relocation<PersistentFormManager**> singleton{ RELOCATION_ID(514172, 400320) };
return *singleton;
}
void IncRefEnchantment(EnchantmentItem* enchantment)
{
if (enchantment && enchantment->formID >= 0xFF000000) {
for (uint32_t i = 0; i < weaponEnchants.count; i++) {
EnchantData foundData;
weaponEnchants.GetNthItem(i, foundData);
if (foundData.enchantment == enchantment) {
InterlockedIncrement(&weaponEnchants[i].refCount);
break;
}
}
for (uint32_t i = 0; i < armorEnchants.count; i++) {
EnchantData foundData;
armorEnchants.GetNthItem(i, foundData);
if (foundData.enchantment == enchantment) {
InterlockedIncrement(&armorEnchants[i].refCount);
break;
}
}
}
}
// The game doesn't bother to dec ref or even delete custom enchants
// when they are no longer used, maybe we can fix this?
void DecRefEnchantment(EnchantmentItem* enchantment)
{
if (enchantment && enchantment->formID >= 0xFF000000) {
for (uint32_t i = 0; i < weaponEnchants.count; i++) {
EnchantData foundData;
weaponEnchants.GetNthItem(i, foundData);
if (foundData.enchantment == enchantment) {
if (!InterlockedDecrement(&weaponEnchants[i].refCount))
ScheduleForDeletion(enchantment);
break;
}
}
for (uint32_t i = 0; i < armorEnchants.count; i++) {
EnchantData foundData;
armorEnchants.GetNthItem(i, foundData);
if (foundData.enchantment == enchantment) {
if (!InterlockedDecrement(&armorEnchants[i].refCount))
ScheduleForDeletion(enchantment);
break;
}
}
}
}
//MEMBER_FN_PREFIX(PersistentFormManager);
// SE
/*
DEFINE_MEMBER_FN(CreateOffensiveEnchantment, EnchantmentItem*, 0x0059F0F0, tArray<Effect::EffectItem>* effectArray);
DEFINE_MEMBER_FN(CreateDefensiveEnchantment, EnchantmentItem*, 0x0059F190, tArray<Effect::EffectItem>* effectArray);
DEFINE_MEMBER_FN(CreatePoison, void, 0x0059F2E0, tArray<Effect::EffectItem>* effectArray, AlchemyItem** poison);
DEFINE_MEMBER_FN(CreatePotion, void, 0x0059F230, AlchemyItem** potion, tArray<Effect::EffectItem>* effectArray);
DEFINE_MEMBER_FN(ScheduleForDeletion, void, 0x0059F6E0, TESForm*);
*/
// AE
/*
DEFINE_MEMBER_FN(CreateOffensiveEnchantment, EnchantmentItem*, 0x005C1350, tArray<Effect::EffectItem>* effectArray);
DEFINE_MEMBER_FN(CreateDefensiveEnchantment, EnchantmentItem*, 0x005C13F0, tArray<Effect::EffectItem>* effectArray);
DEFINE_MEMBER_FN(CreatePoison, void, 0x005C1540, tArray<Effect::EffectItem>* effectArray, AlchemyItem** poison);
DEFINE_MEMBER_FN(CreatePotion, void, 0x005C1490, AlchemyItem** potion, tArray<Effect>* effectArray);
DEFINE_MEMBER_FN(ScheduleForDeletion, void, 0x005C1870, TESForm*);
*/
void CreatePotion(AlchemyItem** potion, tArray<Effect>* effectArray)
{
using func_t = decltype(&PersistentFormManager::CreatePotion);
REL::Relocation<func_t> func{ RELOCATION_ID(35265, 36167) };
return func(this, potion, effectArray);
}
void ScheduleForDeletion(TESForm* form)
{
using func_t = decltype(&PersistentFormManager::ScheduleForDeletion);
REL::Relocation<func_t> func{ RELOCATION_ID(35269, 36171) };
return func(this, form);
}
};
//STATIC_ASSERT(sizeof(PersistentFormManager) == 0xD0);
}