Core/Misc: Implemented spawn tracking

Port From (https://github.com/TrinityCore/TrinityCore/commit/c9099c87567ead635811ef71b990ae7f19103509)
This commit is contained in:
Hondacrx
2025-05-25 20:13:24 -04:00
parent 84642c2ccf
commit 2043ac37f9
17 changed files with 953 additions and 44 deletions
+65 -1
View File
@@ -821,9 +821,11 @@ namespace Game.Entities
uint questID = result.Read<uint>(0);
Quest quest = Global.ObjectMgr.GetQuestTemplate(questID);
if (quest == null)
continue;
var questStatusData = m_QuestStatus.LookupByKey(questID);
if (questStatusData != null && questStatusData.Slot < SharedConst.MaxQuestLogSize && quest != null)
if (questStatusData != null && questStatusData.Slot < SharedConst.MaxQuestLogSize)
{
byte storageIndex = result.Read<byte>(1);
@@ -845,6 +847,42 @@ namespace Game.Entities
while (result.NextRow());
}
}
void _LoadQuestStatusObjectiveSpawnTrackings(SQLResult result)
{
if (!result.IsEmpty())
{
do
{
uint questID = result.Read<uint>(0);
Quest quest = Global.ObjectMgr.GetQuestTemplate(questID);
if (quest == null)
continue;
var itr = m_QuestStatus.LookupByKey(questID);
if (itr != null && itr.Slot < SharedConst.MaxQuestLogSize)
{
QuestStatusData questStatusData = itr;
sbyte storageIndex = result.Read<sbyte>(1);
var objectiveItr = quest.Objectives.Find(objective => objective.StorageIndex == storageIndex);
if (objectiveItr != null)
{
uint spawnTrackingId = result.Read<uint>(2);
if (Global.ObjectMgr.IsQuestObjectiveForSpawnTracking(spawnTrackingId, objectiveItr.Id))
questStatusData.SpawnTrackingList.Add((storageIndex, spawnTrackingId));
else
Log.outError(LogFilter.Player, $"Player::_LoadQuestStatusObjectiveSpawnTrackings: Player '{GetName()}' ({GetGUID()}) has objective {objectiveItr.Id} (quest {questID}) with unrelated spawn tracking {spawnTrackingId}.");
}
else
Log.outError(LogFilter.Player, $"Player::_LoadQuestStatusObjectiveSpawnTrackings: Player '{GetName()}' ({GetGUID()}) has quest {questID} out of range objective index {storageIndex}.");
}
else
Log.outError(LogFilter.Player, $"Player::_LoadQuestStatusObjectiveSpawnTrackings: Player {GetName()} ({GetGUID()}) does not have quest {questID} but has objective spawn trackings for it.");
} while (result.NextRow());
}
}
void _LoadQuestStatusRewarded(SQLResult result)
{
if (!result.IsEmpty())
@@ -2189,6 +2227,22 @@ namespace Game.Entities
stmt.AddValue(3, GetQuestSlotObjectiveData(data.Slot, obj));
trans.Append(stmt);
}
// Save spawn trackings
stmt = CharacterDatabase.GetPreparedStatement( CharStatements.DEL_CHAR_QUESTSTATUS_OBJECTIVES_SPAWN_TRACKING_BY_QUEST);
stmt.AddValue(0, GetGUID().GetCounter());
stmt.AddValue(1, save.Key);
trans.Append(stmt);
foreach (var (questObjectiveStorageIndex, spawnTrackingId) in data.SpawnTrackingList)
{
stmt = CharacterDatabase.GetPreparedStatement(CharStatements.REP_CHAR_QUESTSTATUS_OBJECTIVES_SPAWN_TRACKING);
stmt.AddValue(0, GetGUID().GetCounter());
stmt.AddValue(1, save.Key);
stmt.AddValue(2, questObjectiveStorageIndex);
stmt.AddValue(3, spawnTrackingId);
trans.Append(stmt);
}
}
}
else
@@ -2203,6 +2257,11 @@ namespace Game.Entities
stmt.AddValue(0, GetGUID().GetCounter());
stmt.AddValue(1, save.Key);
trans.Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CharStatements.DEL_CHAR_QUESTSTATUS_OBJECTIVES_SPAWN_TRACKING_BY_QUEST);
stmt.AddValue(0, GetGUID().GetCounter());
stmt.AddValue(1, save.Key);
trans.Append(stmt);
}
}
@@ -3427,6 +3486,7 @@ namespace Game.Entities
// after spell load, learn rewarded spell if need also
_LoadQuestStatus(holder.GetResult(PlayerLoginQueryLoad.QuestStatus));
_LoadQuestStatusObjectives(holder.GetResult(PlayerLoginQueryLoad.QuestStatusObjectives));
_LoadQuestStatusObjectiveSpawnTrackings(holder.GetResult(PlayerLoginQueryLoad.QuestStatusSpawnTracking));
_LoadQuestStatusRewarded(holder.GetResult(PlayerLoginQueryLoad.QuestStatusRew));
_LoadDailyQuestStatus(holder.GetResult(PlayerLoginQueryLoad.DailyQuestStatus));
_LoadWeeklyQuestStatus(holder.GetResult(PlayerLoginQueryLoad.WeeklyQuestStatus));
@@ -4407,6 +4467,10 @@ namespace Game.Entities
stmt.AddValue(0, guid);
trans.Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CharStatements.DEL_CHAR_QUESTSTATUS_OBJECTIVES_SPAWN_TRACKING);
stmt.AddValue(0, guid);
trans.Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CharStatements.DEL_CHAR_QUESTSTATUS_REWARDED);
stmt.AddValue(0, guid);
trans.Append(stmt);
+133 -2
View File
@@ -753,6 +753,8 @@ namespace Game.Entities
QuestStatusData questStatusData = m_QuestStatus.LookupByKey(questId);
QuestStatus oldStatus = questStatusData.Status;
SendForceSpawnTrackingUpdate(questId);
// check for repeatable quests status reset
SetQuestSlot(logSlot, questId);
questStatusData.Slot = logSlot;
@@ -836,6 +838,8 @@ namespace Game.Entities
{
if (quest_id != 0)
{
SendForceSpawnTrackingUpdate(quest_id);
SetQuestStatus(quest_id, QuestStatus.Complete);
QuestStatusData questStatus = m_QuestStatus.LookupByKey(quest_id);
@@ -2610,6 +2614,32 @@ namespace Game.Entities
bool updatePhaseShift = false;
bool updateZoneAuras = false;
bool anyObjectiveChangedSpawnTrackingState = false;
bool isObjectiveTypeForSpawnTracking = false;
if (objectiveType == QuestObjectiveType.Monster ||
objectiveType == QuestObjectiveType.GameObject ||
objectiveType == QuestObjectiveType.TalkTo ||
objectiveType == QuestObjectiveType.WinPetBattleAgainstNpc)
isObjectiveTypeForSpawnTracking = true;
SpawnMetadata data = null;
if (isObjectiveTypeForSpawnTracking)
{
if (victimGuid.IsGameObject())
{
GameObject gameObject = ObjectAccessor.GetGameObject(this, victimGuid);
if (gameObject != null)
data = Global.ObjectMgr.GetSpawnMetadata(SpawnObjectType.GameObject, gameObject.GetSpawnId());
}
else if (victimGuid.IsCreatureOrVehicle())
{
Creature creature = ObjectAccessor.GetCreatureOrPetOrVehicle(this, victimGuid);
if (creature != null)
data = Global.ObjectMgr.GetSpawnMetadata(SpawnObjectType.Creature, creature.GetSpawnId());
}
}
foreach (var objectiveStatusData in m_questObjectiveStatus.LookupByKey((objectiveType, objectId)))
{
uint questId = objectiveStatusData.QuestStatusPair.QuestID;
@@ -2719,6 +2749,41 @@ namespace Game.Entities
}
}
if (data != null && data.spawnTrackingQuestObjectiveId != 0 && data.spawnTrackingData != null)
{
if (objective.Id == data.spawnTrackingQuestObjectiveId)
{
// Store spawn tracking to return correct state in Player::GetSpawnTrackingStateByObjective
QuestStatusData questStatus = objectiveStatusData.QuestStatusPair.Status;
questStatus.SpawnTrackingList.Add((objective.StorageIndex, data.spawnTrackingData.SpawnTrackingId));
// Send QuestPOIUpdateResponse for every spawn linked to same SpawnTrackingId
foreach (var spawnMetaData in Global.ObjectMgr.GetSpawnMetadataForSpawnTracking(data.spawnTrackingData.SpawnTrackingId))
{
SpawnData spawnData = spawnMetaData.ToSpawnData();
if (spawnData == null)
continue;
QuestPOIUpdateResponse response = new();
SpawnTrackingResponseInfo responseInfo = new();
responseInfo.SpawnTrackingID = data.spawnTrackingData.SpawnTrackingId;
responseInfo.ObjectID = (int)spawnData.Id;
responseInfo.PhaseID = (int)spawnData.PhaseId;
responseInfo.PhaseGroupID = (int)spawnData.PhaseGroup;
responseInfo.PhaseUseFlags = (int)spawnData.PhaseUseFlags;
SpawnTrackingState state = GetSpawnTrackingStateByObjective(data.spawnTrackingData.SpawnTrackingId, objective.Id);
responseInfo.Visible = data.spawnTrackingStates[(int)state].Visible;
response.SpawnTrackingResponses.Add(responseInfo);
SendPacket(response);
}
anyObjectiveChangedSpawnTrackingState = true;
}
}
if (objectiveWasComplete != objectiveIsNowComplete)
anyObjectiveChangedCompletionState = true;
@@ -2752,7 +2817,7 @@ namespace Game.Entities
}
if (anyObjectiveChangedCompletionState)
if (anyObjectiveChangedCompletionState || anyObjectiveChangedSpawnTrackingState)
UpdateVisibleObjectInteractions(true, false, false, true);
if (updatePhaseShift)
@@ -3138,6 +3203,8 @@ namespace Game.Entities
moneyReward = (uint)(GetQuestMoneyReward(quest) + (int)(quest.GetRewMoneyMaxLevel() * WorldConfig.GetFloatValue(WorldCfg.RateDropMoney)));
}
SendForceSpawnTrackingUpdate(questId);
if (quest.HasFlag(QuestFlags.TrackingEvent))
return;
@@ -3348,6 +3415,51 @@ namespace Game.Entities
return false;
}
public void SendForceSpawnTrackingUpdate(uint questId)
{
if (questId != 0)
{
ForceSpawnTrackingUpdate data = new();
data.QuestID = questId;
SendPacket(data);
}
}
public QuestObjective GetActiveQuestObjectiveForForSpawnTracking(uint spawnTrackingId)
{
var questObjectiveList = Global.ObjectMgr.GetSpawnTrackingQuestObjectiveList(spawnTrackingId);
if (questObjectiveList != null)
foreach (QuestObjective questObjective in questObjectiveList)
if (FindQuestSlot(questObjective.QuestID) < SharedConst.MaxQuestLogSize)
return questObjective;
return null;
}
public SpawnTrackingState GetSpawnTrackingStateByObjective(uint spawnTrackingId, uint questObjectiveId)
{
if (spawnTrackingId != 0 && questObjectiveId != 0 && Global.ObjectMgr.IsQuestObjectiveForSpawnTracking(spawnTrackingId, questObjectiveId))
{
QuestObjective questObjective = Global.ObjectMgr.GetQuestObjective(questObjectiveId);
if (questObjective != null)
{
if (IsQuestRewarded(questObjective.QuestID) || IsQuestObjectiveComplete(questObjective.QuestID, questObjective.Id))
return SpawnTrackingState.Complete;
else if (GetQuestStatus(questObjective.QuestID) != QuestStatus.None)
{
var itr = m_QuestStatus.LookupByKey(questObjective.QuestID);
if (itr != null && itr.Slot < SharedConst.MaxQuestLogSize)
if (itr.SpawnTrackingList.Contains((questObjective.StorageIndex, spawnTrackingId)))
return SpawnTrackingState.Complete;
return SpawnTrackingState.Active;
}
}
}
return SpawnTrackingState.None;
}
public bool HasQuestForGO(int GOId)
{
foreach (var objectiveStatusData in m_questObjectiveStatus.LookupByKey((QuestObjectiveType.GameObject, GOId)))
@@ -3389,7 +3501,16 @@ namespace Game.Entities
ObjectFieldData objMask = new();
GameObjectFieldData goMask = new();
if (m_questObjectiveStatus.ContainsKey((QuestObjectiveType.GameObject, (int)gameObject.GetEntry())) || gameObject.GetGoInfo().GetConditionID1() != 0)
SpawnMetadata data = Global.ObjectMgr.GetSpawnMetadata(SpawnObjectType.GameObject, gameObject.GetSpawnId());
if (data != null && data.spawnTrackingQuestObjectiveId != 0 && data.spawnTrackingData != null)
{
objMask.MarkChanged(m_objectData.DynamicFlags);
goMask.MarkChanged(gameObject.m_gameObjectData.StateWorldEffectIDs);
goMask.MarkChanged(gameObject.m_gameObjectData.StateSpellVisualID);
goMask.MarkChanged(gameObject.m_gameObjectData.SpawnTrackingStateAnimID);
goMask.MarkChanged(gameObject.m_gameObjectData.SpawnTrackingStateAnimKitID);
}
else if (m_questObjectiveStatus.ContainsKey((QuestObjectiveType.GameObject, (int)gameObject.GetEntry())) || gameObject.GetGoInfo().GetConditionID1() != 0)
objMask.MarkChanged(gameObject.m_objectData.DynamicFlags);
else
{
@@ -3430,6 +3551,16 @@ namespace Game.Entities
if (creature.m_unitData.NpcFlags2 != 0)
unitMask.MarkChanged(m_unitData.NpcFlags2);
SpawnMetadata data = Global.ObjectMgr.GetSpawnMetadata(SpawnObjectType.Creature, creature.GetSpawnId());
if (data != null && data.spawnTrackingQuestObjectiveId != 0 && data.spawnTrackingData != null)
{
objMask.MarkChanged(objMask.DynamicFlags);
unitMask.MarkChanged(unitMask.StateWorldEffectIDs);
unitMask.MarkChanged(unitMask.StateSpellVisualID);
unitMask.MarkChanged(unitMask.StateAnimID);
unitMask.MarkChanged(unitMask.StateAnimKitID);
}
if (objMask.GetUpdateMask().IsAnySet() || unitMask.GetUpdateMask().IsAnySet())
creature.BuildValuesUpdateForPlayerWithMask(udata, objMask.GetUpdateMask(), unitMask.GetUpdateMask(), this);
-1
View File
@@ -5524,7 +5524,6 @@ namespace Game.Entities
}
SetDisplayId(model.DisplayID, true);
SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.StateAnimID), DB2Mgr.GetEmptyAnimStateID());
}
//Creature