Skip to content

Commit

Permalink
feat: serializing custom enchantments
Browse files Browse the repository at this point in the history
  • Loading branch information
RobbeBryssinck committed Feb 12, 2022
1 parent 57ed4f1 commit 0bc2e1b
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 15 deletions.
17 changes: 17 additions & 0 deletions Code/client/Games/Skyrim/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,23 @@ Container Actor::GetFullContainer() const noexcept
// TODO: enchantments seem to always be temporaries, keep this in mind when trying to apply container
// Get base form id of enchantment instead? Probably gonna have to serialize more data
modSystem.GetServerModId(pExtraEnchantment->pEnchantment->formID, innerEntry.ExtraEnchantId);
if (pExtraEnchantment->pEnchantment->formID & 0xFF000000)
{
for (EffectItem* pEffectItem : pExtraEnchantment->pEnchantment->listOfEffects)
{
// TODO: null checking and that
Container::EffectItem effect;
effect.Magnitude = pEffectItem->data.fMagnitude;
effect.Area = pEffectItem->data.iArea;
effect.Duration = pEffectItem->data.iDuration;
effect.RawCost = pEffectItem->fRawCost;
modSystem.GetServerModId(pEffectItem->pEffectSetting->formID, effect.EffectId);
innerEntry.EnchantData.Effects.push_back(effect);
}

uint32_t objectId = modSystem.GetGameId(innerEntry.BaseId);
innerEntry.EnchantData.IsWeapon = TESForm::GetById(objectId)->formType == FormType::Weapon;
}
innerEntry.ExtraEnchantCharge = pExtraEnchantment->usCharge;
innerEntry.ExtraEnchantRemoveUnequip = pExtraEnchantment->bRemoveOnUnequip;
}
Expand Down
12 changes: 12 additions & 0 deletions Code/client/Games/Skyrim/Forms/BGSListForm.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include "TESForm.h"

struct BGSListForm : TESForm
{
GameArray<TESForm*> ArrayOfForms{};
GameArray<uint32_t>* pScriptAddedTempFormA{};
uint32_t iScriptAddedFormCount{};
};

static_assert(sizeof(BGSListForm) == 0x48);
55 changes: 55 additions & 0 deletions Code/client/Games/Skyrim/Forms/EnchantmentItem.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,61 @@
#include "EnchantmentItem.h"

#include <Systems/ModSystem.h>
#include <Magic/EffectItem.h>
#include <World.h>

EnchantmentItem* EnchantmentItem::Create(const Container::EnchantmentData& aData) noexcept
{
TP_THIS_FUNCTION(TCreateNewEnchantment, EnchantmentItem*, GameArray<EffectItem*>, bool abIsWeapon);
POINTER_SKYRIMSE(TCreateNewEnchantment, createNewEnchantment, 0x1405C1290 - 0x140000000);

ModSystem& modSystem = World::Get().GetModSystem();

GameArray<EffectItem*> effects{};
for (Container::EffectItem effect : aData.Effects)
{
EffectItem* pEffectItem = new EffectItem;
pEffectItem->data.fMagnitude = effect.Magnitude;
pEffectItem->data.iArea = effect.Area;
pEffectItem->data.iDuration = effect.Duration;
pEffectItem->fRawCost = effect.RawCost;
pEffectItem->pEffectSetting =
RTTI_CAST(TESForm::GetById(modSystem.GetGameId(effect.EffectId)), TESForm, EffectSetting);
if (!pEffectItem->pEffectSetting)
spdlog::error("Effect setting not found: {:X}:{:X}", effect.EffectId.ModId, effect.EffectId.BaseId);
}

EnchantmentItem* pItem = ThisCall(createNewEnchantment, &effects, aData.IsWeapon);

for (EffectItem* pEffectItem : effects)
delete pEffectItem;

return pItem;
}

void EnchantmentItem::Init(const Container::EnchantmentData& aData)
{
/*
iCostOverride = aData.CostOverride;
iFlags = aData.Flags;
eCastingType = static_cast<MagicSystem::CastingType>(aData.CastingType);
iChargeOverride = aData.ChargeOverride;
eDelivery = static_cast<MagicSystem::Delivery>(aData.Delivery);
eSpellType = static_cast<MagicSystem::SpellType>(aData.SpellType);
fChargeTime = aData.ChargeTime;
ModSystem& modSystem = World::Get().GetModSystem();
TP_ASSERT(aData.BaseEnchantmentId.ModId != 0xFFFFFFFF, "Base enchantment is a temporary!");
uint32_t baseEnchantId = modSystem.GetGameId(aData.BaseEnchantmentId);
pBaseEnchantment = RTTI_CAST(TESForm::GetById(baseEnchantId), TESForm, EnchantmentItem);
if (!pBaseEnchantment)
spdlog::error("{}: base enchantment not found.", __FUNCTION__);
TP_ASSERT(aData.WornRestrictionsId.ModId != 0xFFFFFFFF, "Worn restrictions is a temporary!");
uint32_t restrictionsId = modSystem.GetGameId(aData.WornRestrictionsId);
pWornRestrictions = RTTI_CAST(TESForm::GetById(restrictionsId), TESForm, BGSListForm);
if (!pWornRestrictions)
spdlog::error("{}: worn restrictions not found.", __FUNCTION__);
*/
}
14 changes: 11 additions & 3 deletions Code/client/Games/Skyrim/Forms/EnchantmentItem.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
#pragma once

#include "TESForm.h"
#include "MagicItem.h"

#include <Structs/Container.h>
#include <Games/Magic/MagicSystem.h>
#include "BGSListForm.h"

struct EnchantmentItem : TESForm
struct EnchantmentItem : MagicItem
{
static EnchantmentItem* Create(const Container::EnchantmentData& aData) noexcept;

void Init(const Container::EnchantmentData& aData);

int32_t iCostOverride;
int32_t iFlags;
MagicSystem::CastingType eCastingType;
int32_t iChargeOverride;
MagicSystem::Delivery eDelivery;
MagicSystem::SpellType eSpellType;
float fChargeTime;
EnchantmentItem* pBaseEnchantment;
void* pWornRestrictions;
// TODO: use BGSListForm::SaveGame() and BGSListForm::LoadGame()?
BGSListForm* pWornRestrictions;
};

static_assert(sizeof(EnchantmentItem) == 0xC0);
6 changes: 4 additions & 2 deletions Code/client/Games/Skyrim/Forms/MagicItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ struct MagicItem : TESBoundObject
GameArray<EffectItem*> listOfEffects;
int32_t iHostileCount;
EffectSetting* pAVEffectSetting;
uint32_t unk48;
uint32_t unk4C;
uint32_t uiPreloadCount;
void* pPreloadItem;
};

static_assert(sizeof(MagicItem) == 0x90);
1 change: 1 addition & 0 deletions Code/client/Games/Skyrim/Forms/TESForm.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ enum class FormType : uint8_t
Book = 27,
Container = 28,
Door = 29,
Weapon = 41,
Ammo = 42,
Npc = 43,
LeveledCharacter = 44,
Expand Down
26 changes: 17 additions & 9 deletions Code/client/Games/Skyrim/TESObjectREFR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <ExtraData/ExtraTextDisplayData.h>
#include <ExtraData/ExtraWorn.h>
#include <ExtraData/ExtraWornLeft.h>
#include <Forms/EnchantmentItem.h>

TP_THIS_FUNCTION(TActivate, void, TESObjectREFR, TESObjectREFR* apActivator, uint8_t aUnk1, TESBoundObject* apObjectToGet, int32_t aCount, char aDefaultProcessing);
TP_THIS_FUNCTION(TAddInventoryItem, void*, TESObjectREFR, TESBoundObject* apItem, BSExtraDataList* apExtraData, uint32_t aCount, TESObjectREFR* apOldOwner);
Expand Down Expand Up @@ -183,18 +184,25 @@ void TESObjectREFR::AddItem(const Container::Entry& arEntry) noexcept
// TODO: deal with temp forms for enchanted items
if (arEntry.ExtraEnchantId != 0)
{
TP_ASSERT(arEntry.ExtraEnchantId.ModId != 0xFFFFFFFF, "Enchantment is sent as temp!");
//TP_ASSERT(arEntry.ExtraEnchantId.ModId != 0xFFFFFFFF, "Enchantment is sent as temp!");

uint32_t enchantId = modSystem.GetGameId(arEntry.ExtraEnchantId);
if (EnchantmentItem* pEnchantment = RTTI_CAST(TESForm::GetById(enchantId), TESForm, EnchantmentItem))
EnchantmentItem* pEnchantment = nullptr;
if (arEntry.ExtraEnchantId.ModId == 0xFFFFFFFF)
{
ExtraEnchantment* pExtraEnchantment = Memory::Allocate<ExtraEnchantment>();
*((uint64_t*)pExtraEnchantment) = 0x141623E70;
pExtraEnchantment->next = nullptr;
pExtraEnchantment->pEnchantment = pEnchantment;
pExtraEnchantment->usCharge = arEntry.ExtraEnchantCharge;
pExtraEnchantment->bRemoveOnUnequip = arEntry.ExtraEnchantRemoveUnequip;
pEnchantment = EnchantmentItem::Create(arEntry.EnchantData);
}
else
{
uint32_t enchantId = modSystem.GetGameId(arEntry.ExtraEnchantId);
pEnchantment = RTTI_CAST(TESForm::GetById(enchantId), TESForm, EnchantmentItem);
}

ExtraEnchantment* pExtraEnchantment = Memory::Allocate<ExtraEnchantment>();
*((uint64_t*)pExtraEnchantment) = 0x141623E70;
pExtraEnchantment->next = nullptr;
pExtraEnchantment->pEnchantment = pEnchantment;
pExtraEnchantment->usCharge = arEntry.ExtraEnchantCharge;
pExtraEnchantment->bRemoveOnUnequip = arEntry.ExtraEnchantRemoveUnequip;
}

if (arEntry.ExtraHealth > 0.f)
Expand Down
29 changes: 28 additions & 1 deletion Code/encoding/Structs/Container.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,35 @@ using TiltedPhoques::Vector;

struct Container
{
struct EffectItem
{
float Magnitude{};
int32_t Area{};
int32_t Duration{};
float RawCost{};
GameId EffectId{};
};

struct EnchantmentData
{
GameId EnchantmentId{};
bool IsWeapon{};
Vector<EffectItem> Effects{};

/*
int32_t CostOverride{};
int32_t Flags{};
int32_t CastingType{};
int32_t ChargeOverride{};
int32_t Delivery{};
int32_t SpellType{};
float ChargeTime{};
// TODO: try with IDs for base and worn restrictions first
// place asserts to see if these are ever temporary
// should probably support it anyway though
GameId BaseEnchantmentId{};
GameId WornRestrictionsId{};
//Vector<GameId> WornRestrictions{};
*/
};

struct Entry
Expand All @@ -26,6 +52,7 @@ struct Container
GameId ExtraEnchantId{};
uint16_t ExtraEnchantCharge{};
bool ExtraEnchantRemoveUnequip{};
EnchantmentData EnchantData{};

float ExtraHealth{};

Expand Down

0 comments on commit 0bc2e1b

Please sign in to comment.