refactor(Core/ObjectMgr): Implement display probabilities. (#19068)

* Init.

Cherry-picked from TC commits 9d210476e5 and c488fb219a

Co-Authored-By: Traesh <9392905+traesh@users.noreply.github.com>
Co-Authored-By: Shauren <shauren.trinity@gmail.com>

* Add brute data.

Needs validation against what existed before, i.e. Classic change prevention.

* Add validation info for brute data.

* Remove incomplete data queries.

* Requested changes.

* Whitespace.

* Requested change.

Table name.

Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>

* Requested change.

Table name.

Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>

* Resolve the funny merge conflicts.

I wonder why git blame doesn't work on a file with 20k lines in it that's odd huh champ.

* Remove unused parameter.

* Remove uses of unused parameter.

* Use unused parameter.

Hopefully?

* I will cry.

* Sobbing endlessly.

* Remove comment.

* Adjust table structure query.

Remove length parameters and allow null for build value.

Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>

* Adjust column datatype and add check constraint.

---------

Co-authored-by: Traesh <9392905+traesh@users.noreply.github.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: Kitzunu <24550914+Kitzunu@users.noreply.github.com>
This commit is contained in:
Benjamin Jackson
2024-06-16 12:12:16 -04:00
committed by GitHub
parent 4e385304c0
commit d6d49a9e45
15 changed files with 423 additions and 300 deletions

View File

@@ -116,51 +116,104 @@ VendorItem const* VendorItemData::FindItemCostPair(uint32 item_id, uint32 extend
return nullptr;
}
uint32 CreatureTemplate::GetRandomValidModelId() const
CreatureModel const CreatureModel::DefaultInvisibleModel(11686, 1.0f, 1.0f);
CreatureModel const CreatureModel::DefaultVisibleModel(17519, 1.0f, 1.0f);
CreatureModel const* CreatureTemplate::GetModelByIdx(uint32 idx) const
{
uint8 c = 0;
uint32 modelIDs[4];
if (Modelid1) modelIDs[c++] = Modelid1;
if (Modelid2) modelIDs[c++] = Modelid2;
if (Modelid3) modelIDs[c++] = Modelid3;
if (Modelid4) modelIDs[c++] = Modelid4;
return ((c > 0) ? modelIDs[urand(0, c - 1)] : 0);
return idx < Models.size() ? &Models[idx] : nullptr;
}
uint32 CreatureTemplate::GetFirstValidModelId() const
CreatureModel const* CreatureTemplate::GetRandomValidModel() const
{
if (Modelid1) return Modelid1;
if (Modelid2) return Modelid2;
if (Modelid3) return Modelid3;
if (Modelid4) return Modelid4;
return 0;
if (!Models.size())
return nullptr;
// If only one element, ignore the Probability (even if 0)
if (Models.size() == 1)
return &Models[0];
auto selectedItr = Acore::Containers::SelectRandomWeightedContainerElement(Models, [](CreatureModel const& model)
{
return model.Probability;
});
return &(*selectedItr);
}
CreatureModel const* CreatureTemplate::GetFirstValidModel() const
{
for (CreatureModel const& model : Models)
if (model.CreatureDisplayID)
return &model;
return nullptr;
}
CreatureModel const* CreatureTemplate::GetModelWithDisplayId(uint32 displayId) const
{
for (CreatureModel const& model : Models)
if (displayId == model.CreatureDisplayID)
return &model;
return nullptr;
}
CreatureModel const* CreatureTemplate::GetFirstInvisibleModel() const
{
for (CreatureModel const& model : Models)
if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(model.CreatureDisplayID))
if (modelInfo && modelInfo->is_trigger)
return &model;
return &CreatureModel::DefaultInvisibleModel;
}
CreatureModel const* CreatureTemplate::GetFirstVisibleModel() const
{
for (CreatureModel const& model : Models)
if (CreatureModelInfo const* modelInfo = sObjectMgr->GetCreatureModelInfo(model.CreatureDisplayID))
if (modelInfo && !modelInfo->is_trigger)
return &model;
return &CreatureModel::DefaultVisibleModel;
}
void CreatureTemplate::InitializeQueryData()
{
queryData.Initialize(SMSG_CREATURE_QUERY_RESPONSE, 1);
queryData << uint32(Entry); // creature entry
queryData << uint32(Entry); // creature entry
queryData << Name;
queryData << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty
queryData << uint8(0) << uint8(0) << uint8(0); // name2, name3, name4, always empty
queryData << SubName;
queryData << IconName; // "Directions" for guard, string for Icons 2.3.0
queryData << uint32(type_flags); // flags
queryData << uint32(type); // CreatureType.dbc
queryData << uint32(family); // CreatureFamily.dbc
queryData << uint32(rank); // Creature Rank (elite, boss, etc)
queryData << uint32(KillCredit[0]); // new in 3.1, kill credit
queryData << uint32(KillCredit[1]); // new in 3.1, kill credit
queryData << uint32(Modelid1); // Modelid1
queryData << uint32(Modelid2); // Modelid2
queryData << uint32(Modelid3); // Modelid3
queryData << uint32(Modelid4); // Modelid4
queryData << float(ModHealth); // dmg/hp modifier
queryData << float(ModMana); // dmg/mana modifier
queryData << IconName; // "Directions" for guard, string for Icons 2.3.0
queryData << uint32(type_flags); // flags
queryData << uint32(type); // CreatureType.dbc
queryData << uint32(family); // CreatureFamily.dbc
queryData << uint32(rank); // Creature Rank (elite, boss, etc)
queryData << uint32(KillCredit[0]); // new in 3.1, kill credit
queryData << uint32(KillCredit[1]); // new in 3.1, kill credit
if (GetModelByIdx(0))
queryData << uint32(GetModelByIdx(0)->CreatureDisplayID); // Modelid1
else
queryData << uint32(0); // Modelid1
if (GetModelByIdx(1))
queryData << uint32(GetModelByIdx(1)->CreatureDisplayID); // Modelid2
else
queryData << uint32(0); // Modelid2
if (GetModelByIdx(2))
queryData << uint32(GetModelByIdx(2)->CreatureDisplayID); // Modelid3
else
queryData << uint32(0); // Modelid3
if (GetModelByIdx(3))
queryData << uint32(GetModelByIdx(3)->CreatureDisplayID); // Modelid4
else
queryData << uint32(0); // Modelid4
queryData << float(ModHealth); // dmg/hp modifier
queryData << float(ModMana); // dmg/mana modifier
queryData << uint8(RacialLeader);
queryData << uint32(movementId); // CreatureMovementInfo.dbc
queryData << uint32(movementId); // CreatureMovementInfo.dbc
}
bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
@@ -423,21 +476,22 @@ bool Creature::InitEntry(uint32 Entry, const CreatureData* data)
SetByteValue(UNIT_FIELD_BYTES_0, 1, uint8(cinfo->unit_class));
// Cancel load if no model defined
if (!(cinfo->GetFirstValidModelId()))
if (!(cinfo->GetFirstValidModel()))
{
LOG_ERROR("sql.sql", "Creature (Entry: {}) has no model defined in table `creature_template`, can't load. ", Entry);
LOG_ERROR("sql.sql", "Creature (Entry: {}) has no model defined in table `creature_template_model`, can't load. ", Entry);
return false;
}
uint32 displayID = ObjectMgr::ChooseDisplayId(GetCreatureTemplate(), data);
if (!sObjectMgr->GetCreatureModelRandomGender(&displayID)) // Cancel load if no model defined
CreatureModel model = *ObjectMgr::ChooseDisplayId(cinfo, data);
CreatureModelInfo const* mInfo = sObjectMgr->GetCreatureModelRandomGender(&model, cinfo);
if (!mInfo) // Cancel load if no model defined
{
LOG_ERROR("sql.sql", "Creature (Entry: {}) has no model defined in table `creature_template`, can't load. ", Entry);
LOG_ERROR("sql.sql", "Creature (Entry: {}) has no model {} defined in table `creature_template_model`, can't load. ", Entry, model.CreatureDisplayID);
return false;
}
SetDisplayId(displayID);
SetNativeDisplayId(displayID);
SetDisplayId(model.CreatureDisplayID, model.DisplayScale);
SetNativeDisplayId(model.CreatureDisplayID);
// Load creature equipment
if (!data)
@@ -1121,11 +1175,12 @@ bool Creature::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, u
break;
}
uint32 displayID = GetNativeDisplayId();
if (sObjectMgr->GetCreatureModelRandomGender(&displayID) && !IsTotem()) // Cancel load if no model defined or if totem
CreatureModel display(GetNativeDisplayId(), GetNativeObjectScale(), 1.0f);
CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&display, cinfo);
if (minfo && !IsTotem()) // Cancel load if no model defined or if totem
{
SetDisplayId(displayID);
SetNativeDisplayId(displayID);
SetDisplayId(display.CreatureDisplayID, display.DisplayScale);
SetNativeDisplayId(display.CreatureDisplayID);
}
LoadCreaturesAddon();
@@ -1360,9 +1415,9 @@ void Creature::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask)
CreatureTemplate const* cinfo = GetCreatureTemplate();
if (cinfo)
{
if (displayId == cinfo->Modelid1 || displayId == cinfo->Modelid2 ||
displayId == cinfo->Modelid3 || displayId == cinfo->Modelid4)
displayId = 0;
for (CreatureModel model : cinfo->Models)
if (displayId && displayId == model.CreatureDisplayID)
displayId = 0;
if (npcflag == cinfo->npcflag)
npcflag = 0;
@@ -2031,11 +2086,12 @@ void Creature::Respawn(bool force)
// Do not override transform auras
if (GetAuraEffectsByType(SPELL_AURA_TRANSFORM).empty())
{
uint32 displayID = GetNativeDisplayId();
if (sObjectMgr->GetCreatureModelRandomGender(&displayID)) // Cancel load if no model defined
CreatureModel display(GetNativeDisplayId(), GetNativeObjectScale(), 1.0f);
CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelRandomGender(&display, GetCreatureTemplate());
if (minfo) // Cancel load if no model defined
{
SetDisplayId(displayID);
SetNativeDisplayId(displayID);
SetDisplayId(display.CreatureDisplayID, display.DisplayScale);
SetNativeDisplayId(display.CreatureDisplayID);
}
}
@@ -3414,9 +3470,9 @@ void Creature::SetObjectScale(float scale)
SetFloatValue(UNIT_FIELD_COMBATREACH, combatReach * scale);
}
void Creature::SetDisplayId(uint32 modelId)
void Creature::SetDisplayId(uint32 modelId, float displayScale /*= 1.f*/)
{
Unit::SetDisplayId(modelId);
Unit::SetDisplayId(modelId, displayScale);
float combatReach = DEFAULT_WORLD_OBJECT_SIZE;
@@ -3430,9 +3486,17 @@ void Creature::SetDisplayId(uint32 modelId)
if (IsPet())
combatReach = DEFAULT_COMBAT_REACH;
SetObjectScale(displayScale);
SetFloatValue(UNIT_FIELD_COMBATREACH, combatReach * GetObjectScale());
}
void Creature::SetDisplayFromModel(uint32 modelIdx)
{
if (CreatureModel const* model = GetCreatureTemplate()->GetModelByIdx(modelIdx))
SetDisplayId(model->CreatureDisplayID, model->DisplayScale);
}
void Creature::SetTarget(ObjectGuid guid)
{
if (!_focusSpell)

View File

@@ -53,7 +53,8 @@ public:
float GetNativeObjectScale() const override;
void SetObjectScale(float scale) override;
void SetDisplayId(uint32 modelId) override;
void SetDisplayId(uint32 displayId, float displayScale = 1.f) override;
void SetDisplayFromModel(uint32 modelIdx);
void DisappearAndDie();

View File

@@ -171,16 +171,29 @@ struct CreatureMovementData
std::string ToString() const;
};
struct CreatureModel
{
static CreatureModel const DefaultInvisibleModel;
static CreatureModel const DefaultVisibleModel;
CreatureModel() :
CreatureDisplayID(0), DisplayScale(0.0f), Probability(0.0f) { }
CreatureModel(uint32 creatureDisplayID, float displayScale, float probability) :
CreatureDisplayID(creatureDisplayID), DisplayScale(displayScale), Probability(probability) { }
uint32 CreatureDisplayID;
float DisplayScale;
float Probability;
};
// from `creature_template` table
struct CreatureTemplate
{
uint32 Entry;
uint32 DifficultyEntry[MAX_DIFFICULTY - 1];
uint32 KillCredit[MAX_KILL_CREDIT];
uint32 Modelid1;
uint32 Modelid2;
uint32 Modelid3;
uint32 Modelid4;
std::vector<CreatureModel> Models;
std::string Name;
std::string SubName;
std::string IconName;
@@ -239,8 +252,12 @@ struct CreatureTemplate
uint32 flags_extra;
uint32 ScriptID;
WorldPacket queryData; // pussywizard
[[nodiscard]] uint32 GetRandomValidModelId() const;
[[nodiscard]] uint32 GetFirstValidModelId() const;
CreatureModel const* GetModelByIdx(uint32 idx) const;
CreatureModel const* GetRandomValidModel() const;
CreatureModel const* GetFirstValidModel() const;
CreatureModel const* GetModelWithDisplayId(uint32 displayId) const;
CreatureModel const* GetFirstInvisibleModel() const;
CreatureModel const* GetFirstVisibleModel() const;
// helpers
[[nodiscard]] SkillType GetRequiredLootSkill() const
@@ -389,6 +406,7 @@ struct CreatureModelInfo
float combat_reach;
uint8 gender;
uint32 modelid_other_gender;
float is_trigger;
};
// Benchmarked: Faster than std::map (insert/find)

View File

@@ -2418,9 +2418,9 @@ void Pet::SynchronizeLevelWithOwner()
}
}
void Pet::SetDisplayId(uint32 modelId)
void Pet::SetDisplayId(uint32 modelId, float displayScale /*= 1.f*/)
{
Guardian::SetDisplayId(modelId);
Guardian::SetDisplayId(modelId, displayScale);
if (!isControlled())
return;

View File

@@ -46,7 +46,7 @@ public:
void RemoveFromWorld() override;
float GetNativeObjectScale() const override;
void SetDisplayId(uint32 modelId) override;
void SetDisplayId(uint32 modelId, float displayScale = 1.f) override;
PetType getPetType() const { return m_petType; }
void setPetType(PetType type) { m_petType = type; }

View File

@@ -17034,13 +17034,16 @@ void Unit::RecalculateObjectScale()
SetObjectScale(std::max(scale, scaleMin));
}
void Unit::SetDisplayId(uint32 modelId)
void Unit::SetDisplayId(uint32 modelId, float displayScale /*=1.f*/)
{
SetUInt32Value(UNIT_FIELD_DISPLAYID, modelId);
// Set Gender by modelId
if (CreatureModelInfo const* minfo = sObjectMgr->GetCreatureModelInfo(modelId))
SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);
SetObjectScale(displayScale);
sScriptMgr->OnDisplayIdChange(this, modelId);
}
@@ -21233,17 +21236,11 @@ void Unit::PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPoi
{
if (target->IsGameMaster() && target->GetSession()->IsGMAccount())
{
if (cinfo->Modelid1)
displayId = cinfo->Modelid1; // Modelid1 is a visible model for gms
else
displayId = 17519; // world visible trigger's model
displayId = cinfo->GetFirstVisibleModel()->CreatureDisplayID;
}
else
{
if (cinfo->Modelid2)
displayId = cinfo->Modelid2; // Modelid2 is an invisible model for players
else
displayId = 11686; // world invisible trigger's model
displayId = cinfo->GetFirstInvisibleModel()->CreatureDisplayID;
}
}
}

View File

@@ -2261,10 +2261,10 @@ public:
virtual float GetNativeObjectScale() const { return 1.0f; }
virtual void RecalculateObjectScale();
[[nodiscard]] uint32 GetDisplayId() const { return GetUInt32Value(UNIT_FIELD_DISPLAYID); }
virtual void SetDisplayId(uint32 modelId);
virtual void SetDisplayId(uint32 modelId, float displayScale = 1.f);
[[nodiscard]] uint32 GetNativeDisplayId() const { return GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID); }
void RestoreDisplayId();
void SetNativeDisplayId(uint32 modelId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, modelId); }
void SetNativeDisplayId(uint32 displayId) { SetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID, displayId); }
void setTransForm(uint32 spellid) { m_transform = spellid;}
[[nodiscard]] uint32 getTransForm() const { return m_transform;}