Core/Pooling: Quest pooling rewrite
Port From (https://github.com/TrinityCore/TrinityCore/commit/51fbda4223442635a35d3225c0797d0151ea7051)
This commit is contained in:
@@ -1734,6 +1734,7 @@ namespace Framework.Constants
|
|||||||
WardenNumMemChecks,
|
WardenNumMemChecks,
|
||||||
WardenNumOtherChecks,
|
WardenNumOtherChecks,
|
||||||
Weather,
|
Weather,
|
||||||
|
WeeklyQuestResetTimeWDay,
|
||||||
WintergraspBattletime,
|
WintergraspBattletime,
|
||||||
WintergraspEnable,
|
WintergraspEnable,
|
||||||
WintergraspNobattletime,
|
WintergraspNobattletime,
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ namespace Framework.Database
|
|||||||
"ig.gemItemId1, ig.gemBonuses1, ig.gemContext1, ig.gemScalingLevel1, ig.gemItemId2, ig.gemBonuses2, ig.gemContext2, ig.gemScalingLevel2, ig.gemItemId3, ig.gemBonuses3, ig.gemContext3, ig.gemScalingLevel3, " +
|
"ig.gemItemId1, ig.gemBonuses1, ig.gemContext1, ig.gemScalingLevel1, ig.gemItemId2, ig.gemBonuses2, ig.gemContext2, ig.gemScalingLevel2, ig.gemItemId3, ig.gemBonuses3, ig.gemContext3, ig.gemScalingLevel3, " +
|
||||||
"im.fixedScalingLevel, im.artifactKnowledgeLevel";
|
"im.fixedScalingLevel, im.artifactKnowledgeLevel";
|
||||||
|
|
||||||
PrepareStatement(CharStatements.DEL_QUEST_POOL_SAVE, "DELETE FROM pool_quest_save WHERE pool_id = ?");
|
PrepareStatement(CharStatements.DEL_POOL_QUEST_SAVE, "DELETE FROM pool_quest_save WHERE pool_id = ?");
|
||||||
PrepareStatement(CharStatements.INS_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)");
|
PrepareStatement(CharStatements.INS_POOL_QUEST_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)");
|
||||||
PrepareStatement(CharStatements.DEL_NONEXISTENT_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?");
|
PrepareStatement(CharStatements.DEL_NONEXISTENT_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?");
|
||||||
PrepareStatement(CharStatements.DEL_EXPIRED_BANS, "UPDATE character_banned SET active = 0 WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate");
|
PrepareStatement(CharStatements.DEL_EXPIRED_BANS, "UPDATE character_banned SET active = 0 WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate");
|
||||||
PrepareStatement(CharStatements.SEL_CHECK_NAME, "SELECT 1 FROM characters WHERE name = ?");
|
PrepareStatement(CharStatements.SEL_CHECK_NAME, "SELECT 1 FROM characters WHERE name = ?");
|
||||||
@@ -537,7 +537,6 @@ namespace Framework.Database
|
|||||||
PrepareStatement(CharStatements.SEL_PINFO_XP, "SELECT a.xp, b.guid FROM characters a LEFT JOIN guild_member b ON a.guid = b.guid WHERE a.guid = ?");
|
PrepareStatement(CharStatements.SEL_PINFO_XP, "SELECT a.xp, b.guid FROM characters a LEFT JOIN guild_member b ON a.guid = b.guid WHERE a.guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ, orientation FROM character_homebind WHERE guid = ?");
|
PrepareStatement(CharStatements.SEL_CHAR_HOMEBIND, "SELECT mapId, zoneId, posX, posY, posZ, orientation FROM character_homebind WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_GUID_NAME_BY_ACC, "SELECT guid, name, online FROM characters WHERE account = ?");
|
PrepareStatement(CharStatements.SEL_CHAR_GUID_NAME_BY_ACC, "SELECT guid, name, online FROM characters WHERE account = ?");
|
||||||
PrepareStatement(CharStatements.SEL_POOL_QUEST_SAVE, "SELECT quest_id FROM pool_quest_save WHERE pool_id = ?");
|
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_CUSTOMIZE_INFO, "SELECT name, race, class, gender, at_login FROM characters WHERE guid = ?");
|
PrepareStatement(CharStatements.SEL_CHAR_CUSTOMIZE_INFO, "SELECT name, race, class, gender, at_login FROM characters WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS, "SELECT at_login, knownTitles FROM characters WHERE guid = ?");
|
PrepareStatement(CharStatements.SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS, "SELECT at_login, knownTitles FROM characters WHERE guid = ?");
|
||||||
PrepareStatement(CharStatements.SEL_INSTANCE, "SELECT data, completedEncounters, entranceId FROM instance WHERE map = ? AND id = ?");
|
PrepareStatement(CharStatements.SEL_INSTANCE, "SELECT data, completedEncounters, entranceId FROM instance WHERE map = ? AND id = ?");
|
||||||
@@ -791,8 +790,8 @@ namespace Framework.Database
|
|||||||
|
|
||||||
public enum CharStatements
|
public enum CharStatements
|
||||||
{
|
{
|
||||||
DEL_QUEST_POOL_SAVE,
|
DEL_POOL_QUEST_SAVE,
|
||||||
INS_QUEST_POOL_SAVE,
|
INS_POOL_QUEST_SAVE,
|
||||||
DEL_NONEXISTENT_GUILD_BANK_ITEM,
|
DEL_NONEXISTENT_GUILD_BANK_ITEM,
|
||||||
DEL_EXPIRED_BANS,
|
DEL_EXPIRED_BANS,
|
||||||
SEL_CHECK_NAME,
|
SEL_CHECK_NAME,
|
||||||
@@ -1199,7 +1198,6 @@ namespace Framework.Database
|
|||||||
SEL_PINFO_BANS,
|
SEL_PINFO_BANS,
|
||||||
SEL_CHAR_HOMEBIND,
|
SEL_CHAR_HOMEBIND,
|
||||||
SEL_CHAR_GUID_NAME_BY_ACC,
|
SEL_CHAR_GUID_NAME_BY_ACC,
|
||||||
SEL_POOL_QUEST_SAVE,
|
|
||||||
SEL_CHAR_CUSTOMIZE_INFO,
|
SEL_CHAR_CUSTOMIZE_INFO,
|
||||||
SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS,
|
SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS,
|
||||||
SEL_INSTANCE,
|
SEL_INSTANCE,
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ namespace Framework.Database
|
|||||||
{
|
{
|
||||||
public override void PreparedStatements()
|
public override void PreparedStatements()
|
||||||
{
|
{
|
||||||
PrepareStatement(WorldStatements.SEL_QUEST_POOLS, "SELECT entry, pool_entry FROM pool_quest");
|
|
||||||
PrepareStatement(WorldStatements.DEL_LINKED_RESPAWN, "DELETE FROM linked_respawn WHERE guid = ? AND linkType = ?");
|
PrepareStatement(WorldStatements.DEL_LINKED_RESPAWN, "DELETE FROM linked_respawn WHERE guid = ? AND linkType = ?");
|
||||||
PrepareStatement(WorldStatements.DEL_LINKED_RESPAWN_MASTER, "DELETE FROM linked_respawn WHERE linkedGuid = ? AND linkType = ?");
|
PrepareStatement(WorldStatements.DEL_LINKED_RESPAWN_MASTER, "DELETE FROM linked_respawn WHERE linkedGuid = ? AND linkType = ?");
|
||||||
PrepareStatement(WorldStatements.REP_LINKED_RESPAWN, "REPLACE INTO linked_respawn (guid, linkedGuid, linkType) VALUES (?, ?, ?)");
|
PrepareStatement(WorldStatements.REP_LINKED_RESPAWN, "REPLACE INTO linked_respawn (guid, linkedGuid, linkType) VALUES (?, ?, ?)");
|
||||||
@@ -98,7 +97,6 @@ namespace Framework.Database
|
|||||||
|
|
||||||
public enum WorldStatements
|
public enum WorldStatements
|
||||||
{
|
{
|
||||||
SEL_QUEST_POOLS,
|
|
||||||
DEL_LINKED_RESPAWN,
|
DEL_LINKED_RESPAWN,
|
||||||
DEL_LINKED_RESPAWN_MASTER,
|
DEL_LINKED_RESPAWN_MASTER,
|
||||||
REP_LINKED_RESPAWN,
|
REP_LINKED_RESPAWN,
|
||||||
|
|||||||
@@ -537,7 +537,7 @@ namespace Game.Entities
|
|||||||
if (_spellFocusInfo.delay <= diff)
|
if (_spellFocusInfo.delay <= diff)
|
||||||
ReacquireSpellFocusTarget();
|
ReacquireSpellFocusTarget();
|
||||||
else
|
else
|
||||||
_spellFocusInfo.delay -= 0;
|
_spellFocusInfo.delay -= diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// periodic check to see if the creature has passed an evade boundary
|
// periodic check to see if the creature has passed an evade boundary
|
||||||
@@ -1588,26 +1588,14 @@ namespace Game.Entities
|
|||||||
SetControlled(true, UnitState.Root);
|
SetControlled(true, UnitState.Root);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HasQuest(uint quest_id)
|
public override bool HasQuest(uint questId)
|
||||||
{
|
{
|
||||||
var qr = Global.ObjectMgr.GetCreatureQuestRelationBounds(GetEntry());
|
return Global.ObjectMgr.GetCreatureQuestRelations(GetEntry()).HasQuest(questId);
|
||||||
foreach (var id in qr)
|
|
||||||
{
|
|
||||||
if (id == quest_id)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HasInvolvedQuest(uint quest_id)
|
public override bool HasInvolvedQuest(uint questId)
|
||||||
{
|
{
|
||||||
var qir = Global.ObjectMgr.GetCreatureQuestInvolvedRelationBounds(GetEntry());
|
return Global.ObjectMgr.GetCreatureQuestInvolvedRelations(GetEntry()).HasQuest(questId);
|
||||||
foreach (var id in qir)
|
|
||||||
{
|
|
||||||
if (id == quest_id)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool DeleteFromDB(ulong spawnId)
|
public static bool DeleteFromDB(ulong spawnId)
|
||||||
|
|||||||
@@ -1210,27 +1210,14 @@ namespace Game.Entities
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HasQuest(uint quest_id)
|
public override bool HasQuest(uint questId)
|
||||||
{
|
{
|
||||||
|
return Global.ObjectMgr.GetGOQuestRelations(GetEntry()).HasQuest(questId);
|
||||||
var qr = Global.ObjectMgr.GetGOQuestRelationBounds(GetEntry());
|
|
||||||
foreach (var id in qr)
|
|
||||||
{
|
|
||||||
if (id == quest_id)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool HasInvolvedQuest(uint quest_id)
|
public override bool HasInvolvedQuest(uint questId)
|
||||||
{
|
{
|
||||||
var qir = Global.ObjectMgr.GetGOQuestInvolvedRelationBounds(GetEntry());
|
return Global.ObjectMgr.GetGOQuestInvolvedRelations(GetEntry()).HasQuest(questId);
|
||||||
foreach (var id in qir)
|
|
||||||
{
|
|
||||||
if (id == quest_id)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsTransport()
|
public bool IsTransport()
|
||||||
|
|||||||
@@ -260,15 +260,15 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public void PrepareQuestMenu(ObjectGuid guid)
|
public void PrepareQuestMenu(ObjectGuid guid)
|
||||||
{
|
{
|
||||||
List<uint> objectQR;
|
QuestRelationResult questRelations;
|
||||||
List<uint> objectQIR;
|
QuestRelationResult questInvolvedRelations;
|
||||||
|
|
||||||
// pets also can have quests
|
// pets also can have quests
|
||||||
Creature creature = ObjectAccessor.GetCreatureOrPetOrVehicle(this, guid);
|
Creature creature = ObjectAccessor.GetCreatureOrPetOrVehicle(this, guid);
|
||||||
if (creature != null)
|
if (creature != null)
|
||||||
{
|
{
|
||||||
objectQR = Global.ObjectMgr.GetCreatureQuestRelationBounds(creature.GetEntry());
|
questRelations = Global.ObjectMgr.GetCreatureQuestRelations(creature.GetEntry());
|
||||||
objectQIR = Global.ObjectMgr.GetCreatureQuestInvolvedRelationBounds(creature.GetEntry());
|
questInvolvedRelations = Global.ObjectMgr.GetCreatureQuestInvolvedRelations(creature.GetEntry());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -279,8 +279,8 @@ namespace Game.Entities
|
|||||||
GameObject gameObject = _map.GetGameObject(guid);
|
GameObject gameObject = _map.GetGameObject(guid);
|
||||||
if (gameObject != null)
|
if (gameObject != null)
|
||||||
{
|
{
|
||||||
objectQR = Global.ObjectMgr.GetGOQuestRelationBounds(gameObject.GetEntry());
|
questRelations = Global.ObjectMgr.GetGOQuestRelations(gameObject.GetEntry());
|
||||||
objectQIR = Global.ObjectMgr.GetGOQuestInvolvedRelationBounds(gameObject.GetEntry());
|
questInvolvedRelations = Global.ObjectMgr.GetGOQuestInvolvedRelations(gameObject.GetEntry());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
@@ -289,18 +289,18 @@ namespace Game.Entities
|
|||||||
QuestMenu qm = PlayerTalkClass.GetQuestMenu();
|
QuestMenu qm = PlayerTalkClass.GetQuestMenu();
|
||||||
qm.ClearMenu();
|
qm.ClearMenu();
|
||||||
|
|
||||||
foreach (var quest_id in objectQIR)
|
foreach (var questId in questInvolvedRelations)
|
||||||
{
|
{
|
||||||
QuestStatus status = GetQuestStatus(quest_id);
|
QuestStatus status = GetQuestStatus(questId);
|
||||||
if (status == QuestStatus.Complete)
|
if (status == QuestStatus.Complete)
|
||||||
qm.AddMenuItem(quest_id, 4);
|
qm.AddMenuItem(questId, 4);
|
||||||
else if (status == QuestStatus.Incomplete)
|
else if (status == QuestStatus.Incomplete)
|
||||||
qm.AddMenuItem(quest_id, 4);
|
qm.AddMenuItem(questId, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var quest_id in objectQR)
|
foreach (var questId in questRelations)
|
||||||
{
|
{
|
||||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(quest_id);
|
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
|
||||||
if (quest == null)
|
if (quest == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -308,11 +308,11 @@ namespace Game.Entities
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (quest.IsAutoComplete() && (!quest.IsRepeatable() || quest.IsDaily() || quest.IsWeekly() || quest.IsMonthly()))
|
if (quest.IsAutoComplete() && (!quest.IsRepeatable() || quest.IsDaily() || quest.IsWeekly() || quest.IsMonthly()))
|
||||||
qm.AddMenuItem(quest_id, 0);
|
qm.AddMenuItem(questId, 0);
|
||||||
else if (quest.IsAutoComplete())
|
else if (quest.IsAutoComplete())
|
||||||
qm.AddMenuItem(quest_id, 4);
|
qm.AddMenuItem(questId, 4);
|
||||||
else if (GetQuestStatus(quest_id) == QuestStatus.None)
|
else if (GetQuestStatus(questId) == QuestStatus.None)
|
||||||
qm.AddMenuItem(quest_id, 2);
|
qm.AddMenuItem(questId, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,7 +365,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public Quest GetNextQuest(ObjectGuid guid, Quest quest)
|
public Quest GetNextQuest(ObjectGuid guid, Quest quest)
|
||||||
{
|
{
|
||||||
List<uint> objectQR;
|
QuestRelationResult quests;
|
||||||
uint nextQuestID = quest.NextQuestInChain;
|
uint nextQuestID = quest.NextQuestInChain;
|
||||||
|
|
||||||
switch (guid.GetHigh())
|
switch (guid.GetHigh())
|
||||||
@@ -379,7 +379,7 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
Creature creature = ObjectAccessor.GetCreatureOrPetOrVehicle(this, guid);
|
Creature creature = ObjectAccessor.GetCreatureOrPetOrVehicle(this, guid);
|
||||||
if (creature != null)
|
if (creature != null)
|
||||||
objectQR = Global.ObjectMgr.GetCreatureQuestRelationBounds(creature.GetEntry());
|
quests = Global.ObjectMgr.GetCreatureQuestRelations(creature.GetEntry());
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
break;
|
break;
|
||||||
@@ -392,7 +392,7 @@ namespace Game.Entities
|
|||||||
Cypher.Assert(_map != null);
|
Cypher.Assert(_map != null);
|
||||||
GameObject gameObject = _map.GetGameObject(guid);
|
GameObject gameObject = _map.GetGameObject(guid);
|
||||||
if (gameObject != null)
|
if (gameObject != null)
|
||||||
objectQR = Global.ObjectMgr.GetGOQuestRelationBounds(gameObject.GetEntry());
|
quests = Global.ObjectMgr.GetGOQuestRelations(gameObject.GetEntry());
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
break;
|
break;
|
||||||
@@ -401,12 +401,9 @@ namespace Game.Entities
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for unit and go state
|
if (nextQuestID != 0)
|
||||||
foreach (var id in objectQR)
|
if (quests.HasQuest(nextQuestID))
|
||||||
{
|
|
||||||
if (id == nextQuestID)
|
|
||||||
return Global.ObjectMgr.GetQuestTemplate(nextQuestID);
|
return Global.ObjectMgr.GetQuestTemplate(nextQuestID);
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1898,8 +1895,8 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public QuestGiverStatus GetQuestDialogStatus(WorldObject questgiver)
|
public QuestGiverStatus GetQuestDialogStatus(WorldObject questgiver)
|
||||||
{
|
{
|
||||||
List<uint> qr;
|
QuestRelationResult questRelations;
|
||||||
List<uint> qir;
|
QuestRelationResult questInvolvedRelations;
|
||||||
|
|
||||||
switch (questgiver.GetTypeId())
|
switch (questgiver.GetTypeId())
|
||||||
{
|
{
|
||||||
@@ -1913,8 +1910,8 @@ namespace Game.Entities
|
|||||||
return questStatus.Value;
|
return questStatus.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
qr = Global.ObjectMgr.GetGOQuestRelationBounds(questgiver.GetEntry());
|
questRelations = Global.ObjectMgr.GetGOQuestRelations(questgiver.GetEntry());
|
||||||
qir = Global.ObjectMgr.GetGOQuestInvolvedRelationBounds(questgiver.GetEntry());
|
questInvolvedRelations = Global.ObjectMgr.GetGOQuestInvolvedRelations(questgiver.GetEntry());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TypeId.Unit:
|
case TypeId.Unit:
|
||||||
@@ -1927,8 +1924,8 @@ namespace Game.Entities
|
|||||||
return questStatus.Value;
|
return questStatus.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
qr = Global.ObjectMgr.GetCreatureQuestRelationBounds(questgiver.GetEntry());
|
questRelations = Global.ObjectMgr.GetCreatureQuestRelations(questgiver.GetEntry());
|
||||||
qir = Global.ObjectMgr.GetCreatureQuestInvolvedRelationBounds(questgiver.GetEntry());
|
questInvolvedRelations = Global.ObjectMgr.GetCreatureQuestInvolvedRelations(questgiver.GetEntry());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -1939,7 +1936,7 @@ namespace Game.Entities
|
|||||||
|
|
||||||
QuestGiverStatus result = QuestGiverStatus.None;
|
QuestGiverStatus result = QuestGiverStatus.None;
|
||||||
|
|
||||||
foreach (var questId in qir)
|
foreach (var questId in questInvolvedRelations)
|
||||||
{
|
{
|
||||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
|
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
|
||||||
if (quest == null)
|
if (quest == null)
|
||||||
@@ -1974,7 +1971,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var questId in qr)
|
foreach (var questId in questRelations)
|
||||||
{
|
{
|
||||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
|
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
|
||||||
if (quest == null)
|
if (quest == null)
|
||||||
|
|||||||
@@ -1428,7 +1428,7 @@ namespace Game
|
|||||||
{
|
{
|
||||||
foreach (var pair in mGameEventCreatureQuests[eventId])
|
foreach (var pair in mGameEventCreatureQuests[eventId])
|
||||||
{
|
{
|
||||||
var CreatureQuestMap = Global.ObjectMgr.GetCreatureQuestRelationMap();
|
var CreatureQuestMap = Global.ObjectMgr.GetCreatureQuestRelationMapHACK();
|
||||||
if (activate) // Add the pair(id, quest) to the multimap
|
if (activate) // Add the pair(id, quest) to the multimap
|
||||||
CreatureQuestMap.Add(pair.Item1, pair.Item2);
|
CreatureQuestMap.Add(pair.Item1, pair.Item2);
|
||||||
else
|
else
|
||||||
@@ -1442,7 +1442,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
foreach (var pair in mGameEventGameObjectQuests[eventId])
|
foreach (var pair in mGameEventGameObjectQuests[eventId])
|
||||||
{
|
{
|
||||||
var GameObjectQuestMap = Global.ObjectMgr.GetGOQuestRelationMap();
|
var GameObjectQuestMap = Global.ObjectMgr.GetGOQuestRelationMapHACK();
|
||||||
if (activate) // Add the pair(id, quest) to the multimap
|
if (activate) // Add the pair(id, quest) to the multimap
|
||||||
GameObjectQuestMap.Add(pair.Item1, pair.Item2);
|
GameObjectQuestMap.Add(pair.Item1, pair.Item2);
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ public static class Global
|
|||||||
public static DB2Manager DB2Mgr { get { return DB2Manager.Instance; } }
|
public static DB2Manager DB2Mgr { get { return DB2Manager.Instance; } }
|
||||||
public static DisableManager DisableMgr { get { return DisableManager.Instance; } }
|
public static DisableManager DisableMgr { get { return DisableManager.Instance; } }
|
||||||
public static PoolManager PoolMgr { get { return PoolManager.Instance; } }
|
public static PoolManager PoolMgr { get { return PoolManager.Instance; } }
|
||||||
|
public static QuestPoolManager QuestPoolMgr { get { return QuestPoolManager.Instance; } }
|
||||||
public static WeatherManager WeatherMgr { get { return WeatherManager.Instance; } }
|
public static WeatherManager WeatherMgr { get { return WeatherManager.Instance; } }
|
||||||
|
|
||||||
public static GameEventManager GameEventMgr { get { return GameEventManager.Instance; } }
|
public static GameEventManager GameEventMgr { get { return GameEventManager.Instance; } }
|
||||||
|
|||||||
@@ -7751,7 +7751,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
public void LoadGameobjectQuestStarters()
|
public void LoadGameobjectQuestStarters()
|
||||||
{
|
{
|
||||||
LoadQuestRelationsHelper(_goQuestRelations, null, "gameobject_queststarter", true, true);
|
LoadQuestRelationsHelper(_goQuestRelations, null, "gameobject_queststarter");
|
||||||
|
|
||||||
foreach (var pair in _goQuestRelations)
|
foreach (var pair in _goQuestRelations)
|
||||||
{
|
{
|
||||||
@@ -7764,7 +7764,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
public void LoadGameobjectQuestEnders()
|
public void LoadGameobjectQuestEnders()
|
||||||
{
|
{
|
||||||
LoadQuestRelationsHelper(_goQuestInvolvedRelations, _goQuestInvolvedRelationsReverse, "gameobject_questender", false, true);
|
LoadQuestRelationsHelper(_goQuestInvolvedRelations, _goQuestInvolvedRelationsReverse, "gameobject_questender");
|
||||||
|
|
||||||
foreach (var pair in _goQuestInvolvedRelations)
|
foreach (var pair in _goQuestInvolvedRelations)
|
||||||
{
|
{
|
||||||
@@ -7777,7 +7777,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
public void LoadCreatureQuestStarters()
|
public void LoadCreatureQuestStarters()
|
||||||
{
|
{
|
||||||
LoadQuestRelationsHelper(_creatureQuestRelations, null, "creature_queststarter", true, false);
|
LoadQuestRelationsHelper(_creatureQuestRelations, null, "creature_queststarter");
|
||||||
|
|
||||||
foreach (var pair in _creatureQuestRelations)
|
foreach (var pair in _creatureQuestRelations)
|
||||||
{
|
{
|
||||||
@@ -7790,7 +7790,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
public void LoadCreatureQuestEnders()
|
public void LoadCreatureQuestEnders()
|
||||||
{
|
{
|
||||||
LoadQuestRelationsHelper(_creatureQuestInvolvedRelations, _creatureQuestInvolvedRelationsReverse, "creature_questender", false, false);
|
LoadQuestRelationsHelper(_creatureQuestInvolvedRelations, _creatureQuestInvolvedRelationsReverse, "creature_questender");
|
||||||
|
|
||||||
foreach (var pair in _creatureQuestInvolvedRelations)
|
foreach (var pair in _creatureQuestInvolvedRelations)
|
||||||
{
|
{
|
||||||
@@ -7801,7 +7801,7 @@ namespace Game
|
|||||||
Log.outError(LogFilter.Sql, "Table `creature_questender` has creature entry ({0}) for quest {1}, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", pair.Key, pair.Value);
|
Log.outError(LogFilter.Sql, "Table `creature_questender` has creature entry ({0}) for quest {1}, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER", pair.Key, pair.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void LoadQuestRelationsHelper(MultiMap<uint, uint> map, MultiMap<uint, uint> reverseMap, string table, bool starter, bool go)
|
void LoadQuestRelationsHelper(MultiMap<uint, uint> map, MultiMap<uint, uint> reverseMap, string table)
|
||||||
{
|
{
|
||||||
uint oldMSTime = Time.GetMSTime();
|
uint oldMSTime = Time.GetMSTime();
|
||||||
|
|
||||||
@@ -7809,7 +7809,7 @@ namespace Game
|
|||||||
|
|
||||||
uint count = 0;
|
uint count = 0;
|
||||||
|
|
||||||
SQLResult result = DB.World.Query("SELECT id, quest, pool_entry FROM {0} qr LEFT JOIN pool_quest pq ON qr.quest = pq.entry", table);
|
SQLResult result = DB.World.Query($"SELECT id, quest FROM {table} qr LEFT JOIN pool_quest pq ON qr.quest = pq.entry");
|
||||||
|
|
||||||
if (result.IsEmpty())
|
if (result.IsEmpty())
|
||||||
{
|
{
|
||||||
@@ -7817,15 +7817,10 @@ namespace Game
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var poolRelationMap = go ? Global.PoolMgr.mQuestGORelation : Global.PoolMgr.mQuestCreatureRelation;
|
|
||||||
if (starter)
|
|
||||||
poolRelationMap.Clear();
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
uint id = result.Read<uint>(0);
|
uint id = result.Read<uint>(0);
|
||||||
uint quest = result.Read<uint>(1);
|
uint quest = result.Read<uint>(1);
|
||||||
uint poolId = result.Read<uint>(2);
|
|
||||||
|
|
||||||
if (!_questTemplates.ContainsKey(quest))
|
if (!_questTemplates.ContainsKey(quest))
|
||||||
{
|
{
|
||||||
@@ -7833,14 +7828,9 @@ namespace Game
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (poolId == 0 || !starter)
|
map.Add(id, quest);
|
||||||
{
|
if (reverseMap != null)
|
||||||
map.Add(id, quest);
|
reverseMap.Add(quest, id);
|
||||||
if (reverseMap != null)
|
|
||||||
reverseMap.Add(quest, id);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
poolRelationMap.Add(quest, id);
|
|
||||||
|
|
||||||
++count;
|
++count;
|
||||||
} while (result.NextRow());
|
} while (result.NextRow());
|
||||||
@@ -8050,38 +8040,14 @@ namespace Game
|
|||||||
{
|
{
|
||||||
return _questTemplatesAutoPush;
|
return _questTemplatesAutoPush;
|
||||||
}
|
}
|
||||||
public MultiMap<uint, uint> GetGOQuestRelationMap()
|
public MultiMap<uint, uint> GetGOQuestRelationMapHACK() { return _goQuestRelations; }
|
||||||
{
|
public QuestRelationResult GetGOQuestRelations(uint entry) { return GetQuestRelationsFrom(_goQuestRelations, entry, true); }
|
||||||
return _goQuestRelations;
|
public QuestRelationResult GetGOQuestInvolvedRelations(uint entry) { return GetQuestRelationsFrom(_goQuestInvolvedRelations, entry, false);}
|
||||||
}
|
public List<uint> GetGOQuestInvolvedRelationReverseBounds(uint questId) { return _goQuestInvolvedRelationsReverse.LookupByKey(questId); }
|
||||||
public List<uint> GetGOQuestRelationBounds(uint go_entry)
|
public MultiMap<uint, uint> GetCreatureQuestRelationMapHACK() { return _creatureQuestRelations; }
|
||||||
{
|
public QuestRelationResult GetCreatureQuestRelations(uint entry) { return GetQuestRelationsFrom(_creatureQuestRelations, entry, true); }
|
||||||
return _goQuestRelations.LookupByKey(go_entry);
|
public QuestRelationResult GetCreatureQuestInvolvedRelations(uint entry) { return GetQuestRelationsFrom(_creatureQuestInvolvedRelations, entry, false); }
|
||||||
}
|
public List<uint> GetCreatureQuestInvolvedRelationReverseBounds(uint questId) { return _creatureQuestInvolvedRelationsReverse.LookupByKey(questId); }
|
||||||
public List<uint> GetGOQuestInvolvedRelationBounds(uint go_entry)
|
|
||||||
{
|
|
||||||
return _goQuestInvolvedRelations.LookupByKey(go_entry);
|
|
||||||
}
|
|
||||||
public List<uint> GetGOQuestInvolvedRelationReverseBounds(uint questId)
|
|
||||||
{
|
|
||||||
return _goQuestInvolvedRelationsReverse.LookupByKey(questId);
|
|
||||||
}
|
|
||||||
public MultiMap<uint, uint> GetCreatureQuestRelationMap()
|
|
||||||
{
|
|
||||||
return _creatureQuestRelations;
|
|
||||||
}
|
|
||||||
public List<uint> GetCreatureQuestRelationBounds(uint creature_entry)
|
|
||||||
{
|
|
||||||
return _creatureQuestRelations.LookupByKey(creature_entry);
|
|
||||||
}
|
|
||||||
public List<uint> GetCreatureQuestInvolvedRelationBounds(uint creature_entry)
|
|
||||||
{
|
|
||||||
return _creatureQuestInvolvedRelations.LookupByKey(creature_entry);
|
|
||||||
}
|
|
||||||
public List<uint> GetCreatureQuestInvolvedRelationReverseBounds(uint questId)
|
|
||||||
{
|
|
||||||
return _creatureQuestInvolvedRelationsReverse.LookupByKey(questId);
|
|
||||||
}
|
|
||||||
public QuestPOIData GetQuestPOIData(uint questId)
|
public QuestPOIData GetQuestPOIData(uint questId)
|
||||||
{
|
{
|
||||||
return _questPOIStorage.LookupByKey(questId);
|
return _questPOIStorage.LookupByKey(questId);
|
||||||
@@ -8122,7 +8088,8 @@ namespace Game
|
|||||||
{
|
{
|
||||||
return _exclusiveQuestGroups.LookupByKey(exclusiveGroupId);
|
return _exclusiveQuestGroups.LookupByKey(exclusiveGroupId);
|
||||||
}
|
}
|
||||||
|
QuestRelationResult GetQuestRelationsFrom(MultiMap<uint, uint> map, uint key, bool onlyActive) { return new QuestRelationResult(map.LookupByKey(key), onlyActive);}
|
||||||
|
|
||||||
//Spells /Skills / Phases
|
//Spells /Skills / Phases
|
||||||
public void LoadPhases()
|
public void LoadPhases()
|
||||||
{
|
{
|
||||||
@@ -10423,7 +10390,7 @@ namespace Game
|
|||||||
{
|
{
|
||||||
return _phaseNameStorage.TryGetValue(phaseId, out string value) ? value : "Unknown Name";
|
return _phaseNameStorage.TryGetValue(phaseId, out string value) ? value : "Unknown Name";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Vehicles
|
//Vehicles
|
||||||
public void LoadVehicleTemplate()
|
public void LoadVehicleTemplate()
|
||||||
{
|
{
|
||||||
@@ -11706,4 +11673,21 @@ namespace Game
|
|||||||
public byte Expansion;
|
public byte Expansion;
|
||||||
public uint AchievementId;
|
public uint AchievementId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class QuestRelationResult : List<uint>
|
||||||
|
{
|
||||||
|
bool _onlyActive;
|
||||||
|
|
||||||
|
public QuestRelationResult() { }
|
||||||
|
|
||||||
|
public QuestRelationResult(List<uint> range, bool onlyActive) : base(range)
|
||||||
|
{
|
||||||
|
_onlyActive = onlyActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasQuest(uint questId)
|
||||||
|
{
|
||||||
|
return Contains(questId) && (!_onlyActive || Quest.IsTakingQuestEnabled(questId));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -292,12 +292,10 @@ namespace Game
|
|||||||
|
|
||||||
questCompletionNPC.QuestID = questID;
|
questCompletionNPC.QuestID = questID;
|
||||||
|
|
||||||
var creatures = Global.ObjectMgr.GetCreatureQuestInvolvedRelationReverseBounds(questID);
|
foreach (var id in Global.ObjectMgr.GetCreatureQuestInvolvedRelationReverseBounds(questID))
|
||||||
foreach (var id in creatures)
|
|
||||||
questCompletionNPC.NPCs.Add(id);
|
questCompletionNPC.NPCs.Add(id);
|
||||||
|
|
||||||
var gos = Global.ObjectMgr.GetGOQuestInvolvedRelationReverseBounds(questID);
|
foreach (var id in Global.ObjectMgr.GetGOQuestInvolvedRelationReverseBounds(questID))
|
||||||
foreach (var id in gos)
|
|
||||||
questCompletionNPC.NPCs.Add(id | 0x80000000); // GO mask
|
questCompletionNPC.NPCs.Add(id | 0x80000000); // GO mask
|
||||||
|
|
||||||
response.QuestCompletionNPCs.Add(questCompletionNPC);
|
response.QuestCompletionNPCs.Add(questCompletionNPC);
|
||||||
|
|||||||
@@ -605,7 +605,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
|
|
||||||
// in pool and not currently available (wintergrasp weekly, dalaran weekly) - can't share
|
// in pool and not currently available (wintergrasp weekly, dalaran weekly) - can't share
|
||||||
if (Global.PoolMgr.IsPartOfAPool<Quest>(packet.QuestID) != 0 && !Global.PoolMgr.IsSpawnedObject<Quest>(packet.QuestID))
|
if (Global.QuestPoolMgr.IsQuestActive(packet.QuestID))
|
||||||
{
|
{
|
||||||
sender.SendPushToPartyResponse(sender, QuestPushReason.NotDaily);
|
sender.SendPushToPartyResponse(sender, QuestPushReason.NotDaily);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ namespace Game
|
|||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
mQuestSearchMap.Clear();
|
|
||||||
mGameobjectSearchMap.Clear();
|
mGameobjectSearchMap.Clear();
|
||||||
mCreatureSearchMap.Clear();
|
mCreatureSearchMap.Clear();
|
||||||
}
|
}
|
||||||
@@ -253,91 +252,6 @@ namespace Game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Loading Quest Pooling Data...");
|
|
||||||
{
|
|
||||||
uint oldMSTime = Time.GetMSTime();
|
|
||||||
|
|
||||||
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.SEL_QUEST_POOLS);
|
|
||||||
SQLResult result = DB.World.Query(stmt);
|
|
||||||
|
|
||||||
if (result.IsEmpty())
|
|
||||||
{
|
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 quests in pools");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
List<uint> creBounds;
|
|
||||||
List<uint> goBounds;
|
|
||||||
|
|
||||||
Dictionary<uint, QuestTypes> poolTypeMap = new();
|
|
||||||
uint count = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint entry = result.Read<uint>(0);
|
|
||||||
uint pool_id = result.Read<uint>(1);
|
|
||||||
|
|
||||||
if (!poolTypeMap.ContainsKey(pool_id))
|
|
||||||
poolTypeMap[pool_id] = 0;
|
|
||||||
|
|
||||||
Quest quest = Global.ObjectMgr.GetQuestTemplate(entry);
|
|
||||||
if (quest == null)
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Sql, "`pool_quest` has a non existing quest template (Entry: {0}) defined for pool id ({1}), skipped.", entry, pool_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mPoolTemplate.ContainsKey(pool_id))
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Sql, "`pool_quest` pool id ({0}) is not in `pool_template`, skipped.", pool_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!quest.IsDailyOrWeekly())
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Sql, "`pool_quest` has an quest ({0}) which is not daily or weekly in pool id ({1}), use ExclusiveGroup instead, skipped.", entry, pool_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (poolTypeMap[pool_id] == QuestTypes.None)
|
|
||||||
poolTypeMap[pool_id] = quest.IsDaily() ? QuestTypes.Daily : QuestTypes.Weekly;
|
|
||||||
|
|
||||||
QuestTypes currType = quest.IsDaily() ? QuestTypes.Daily : QuestTypes.Weekly;
|
|
||||||
|
|
||||||
if (poolTypeMap[pool_id] != currType)
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Sql, "`pool_quest` quest {0} is {1} but pool ({2}) is specified for {3}, mixing not allowed, skipped.",
|
|
||||||
entry, currType, pool_id, poolTypeMap[pool_id]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
creBounds = mQuestCreatureRelation.LookupByKey(entry);
|
|
||||||
goBounds = mQuestGORelation.LookupByKey(entry);
|
|
||||||
|
|
||||||
if (creBounds.Empty() && goBounds.Empty())
|
|
||||||
{
|
|
||||||
Log.outError(LogFilter.Sql, "`pool_quest` lists entry ({0}) as member of pool ({1}) but is not started anywhere, skipped.", entry, pool_id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
PoolTemplateData pPoolTemplate = mPoolTemplate[pool_id];
|
|
||||||
PoolObject plObject = new(entry, 0.0f);
|
|
||||||
|
|
||||||
if (!mPoolQuestGroups.ContainsKey(pool_id))
|
|
||||||
mPoolQuestGroups[pool_id] = new PoolGroup<Quest>();
|
|
||||||
|
|
||||||
PoolGroup<Quest> questgroup = mPoolQuestGroups[pool_id];
|
|
||||||
questgroup.SetPoolId(pool_id);
|
|
||||||
questgroup.AddEntry(plObject, pPoolTemplate.MaxLimit);
|
|
||||||
|
|
||||||
mQuestSearchMap.Add(entry, pool_id);
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
while (result.NextRow());
|
|
||||||
|
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Loaded {0} quests in pools in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The initialize method will spawn all pools not in an event and not in another pool, this is why there is 2 left joins with 2 null checks
|
// The initialize method will spawn all pools not in an event and not in another pool, this is why there is 2 left joins with 2 null checks
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Starting objects pooling system...");
|
Log.outInfo(LogFilter.ServerLoading, "Starting objects pooling system...");
|
||||||
{
|
{
|
||||||
@@ -385,67 +299,6 @@ namespace Game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveQuestsToDB()
|
|
||||||
{
|
|
||||||
SQLTransaction trans = new();
|
|
||||||
|
|
||||||
foreach (var questPoolGroup in mPoolQuestGroups.Values)
|
|
||||||
{
|
|
||||||
if (questPoolGroup.IsEmpty())
|
|
||||||
continue;
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_QUEST_POOL_SAVE);
|
|
||||||
stmt.AddValue(0, questPoolGroup.GetPoolId());
|
|
||||||
trans.Append(stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var pair in mQuestSearchMap)
|
|
||||||
{
|
|
||||||
if (IsSpawnedObject<Quest>(pair.Key))
|
|
||||||
{
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_QUEST_POOL_SAVE);
|
|
||||||
stmt.AddValue(0, pair.Value);
|
|
||||||
stmt.AddValue(1, pair.Key);
|
|
||||||
trans.Append(stmt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DB.Characters.CommitTransaction(trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ChangeDailyQuests()
|
|
||||||
{
|
|
||||||
foreach (var questPoolGroup in mPoolQuestGroups.Values)
|
|
||||||
{
|
|
||||||
Quest quest = Global.ObjectMgr.GetQuestTemplate((uint)questPoolGroup.GetFirstEqualChancedObjectId());
|
|
||||||
if (quest != null)
|
|
||||||
{
|
|
||||||
if (quest.IsWeekly())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
UpdatePool<Quest>(questPoolGroup.GetPoolId(), 1); // anything non-zero means don't load from db
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveQuestsToDB();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ChangeWeeklyQuests()
|
|
||||||
{
|
|
||||||
foreach (var questPoolGroup in mPoolQuestGroups.Values)
|
|
||||||
{
|
|
||||||
Quest quest = Global.ObjectMgr.GetQuestTemplate((uint)questPoolGroup.GetFirstEqualChancedObjectId());
|
|
||||||
if (quest != null)
|
|
||||||
{
|
|
||||||
if (quest.IsDaily())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
UpdatePool<Quest>(questPoolGroup.GetPoolId(), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveQuestsToDB();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpawnPool<T>(uint pool_id, ulong db_guid)
|
void SpawnPool<T>(uint pool_id, ulong db_guid)
|
||||||
{
|
{
|
||||||
switch (typeof(T).Name)
|
switch (typeof(T).Name)
|
||||||
@@ -462,10 +315,6 @@ namespace Game
|
|||||||
if (mPoolPoolGroups.ContainsKey(pool_id) && !mPoolPoolGroups[pool_id].IsEmpty())
|
if (mPoolPoolGroups.ContainsKey(pool_id) && !mPoolPoolGroups[pool_id].IsEmpty())
|
||||||
mPoolPoolGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid);
|
mPoolPoolGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid);
|
||||||
break;
|
break;
|
||||||
case "Quest":
|
|
||||||
if (mPoolQuestGroups.ContainsKey(pool_id) && !mPoolQuestGroups[pool_id].IsEmpty())
|
|
||||||
mPoolQuestGroups[pool_id].SpawnObject(mSpawnedData, mPoolTemplate[pool_id].MaxLimit, db_guid);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +323,6 @@ namespace Game
|
|||||||
SpawnPool<Pool>(pool_id, 0);
|
SpawnPool<Pool>(pool_id, 0);
|
||||||
SpawnPool<GameObject>(pool_id, 0);
|
SpawnPool<GameObject>(pool_id, 0);
|
||||||
SpawnPool<Creature>(pool_id, 0);
|
SpawnPool<Creature>(pool_id, 0);
|
||||||
SpawnPool<Quest>(pool_id, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DespawnPool(uint pool_id)
|
public void DespawnPool(uint pool_id)
|
||||||
@@ -487,9 +335,6 @@ namespace Game
|
|||||||
|
|
||||||
if (mPoolPoolGroups.ContainsKey(pool_id) && !mPoolPoolGroups[pool_id].IsEmpty())
|
if (mPoolPoolGroups.ContainsKey(pool_id) && !mPoolPoolGroups[pool_id].IsEmpty())
|
||||||
mPoolPoolGroups[pool_id].DespawnObject(mSpawnedData);
|
mPoolPoolGroups[pool_id].DespawnObject(mSpawnedData);
|
||||||
|
|
||||||
if (mPoolQuestGroups.ContainsKey(pool_id) && !mPoolQuestGroups[pool_id].IsEmpty())
|
|
||||||
mPoolQuestGroups[pool_id].DespawnObject(mSpawnedData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CheckPool(uint pool_id)
|
public bool CheckPool(uint pool_id)
|
||||||
@@ -503,9 +348,6 @@ namespace Game
|
|||||||
if (mPoolPoolGroups.ContainsKey(pool_id) && !mPoolPoolGroups[pool_id].CheckPool())
|
if (mPoolPoolGroups.ContainsKey(pool_id) && !mPoolPoolGroups[pool_id].CheckPool())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (mPoolQuestGroups.ContainsKey(pool_id) && !mPoolQuestGroups[pool_id].CheckPool())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,8 +370,6 @@ namespace Game
|
|||||||
return mGameobjectSearchMap.LookupByKey(db_guid);
|
return mGameobjectSearchMap.LookupByKey(db_guid);
|
||||||
case "Pool":
|
case "Pool":
|
||||||
return mPoolSearchMap.LookupByKey(db_guid);
|
return mPoolSearchMap.LookupByKey(db_guid);
|
||||||
case "Quest":
|
|
||||||
return mQuestSearchMap.LookupByKey(db_guid);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -566,11 +406,9 @@ namespace Game
|
|||||||
Dictionary<uint, PoolGroup<Creature>> mPoolCreatureGroups = new();
|
Dictionary<uint, PoolGroup<Creature>> mPoolCreatureGroups = new();
|
||||||
Dictionary<uint, PoolGroup<GameObject>> mPoolGameobjectGroups = new();
|
Dictionary<uint, PoolGroup<GameObject>> mPoolGameobjectGroups = new();
|
||||||
Dictionary<uint, PoolGroup<Pool>> mPoolPoolGroups = new();
|
Dictionary<uint, PoolGroup<Pool>> mPoolPoolGroups = new();
|
||||||
Dictionary<uint, PoolGroup<Quest>> mPoolQuestGroups = new();
|
|
||||||
Dictionary<ulong, uint> mCreatureSearchMap = new();
|
Dictionary<ulong, uint> mCreatureSearchMap = new();
|
||||||
Dictionary<ulong, uint> mGameobjectSearchMap = new();
|
Dictionary<ulong, uint> mGameobjectSearchMap = new();
|
||||||
Dictionary<ulong, uint> mPoolSearchMap = new();
|
Dictionary<ulong, uint> mPoolSearchMap = new();
|
||||||
Dictionary<ulong, uint> mQuestSearchMap = new();
|
|
||||||
|
|
||||||
// dynamic data
|
// dynamic data
|
||||||
ActivePoolData mSpawnedData = new();
|
ActivePoolData mSpawnedData = new();
|
||||||
@@ -684,37 +522,6 @@ namespace Game
|
|||||||
case "Pool":
|
case "Pool":
|
||||||
Global.PoolMgr.DespawnPool((uint)guid);
|
Global.PoolMgr.DespawnPool((uint)guid);
|
||||||
break;
|
break;
|
||||||
case "Quest":
|
|
||||||
// Creatures
|
|
||||||
var questMap = Global.ObjectMgr.GetCreatureQuestRelationMap();
|
|
||||||
var qr = Global.PoolMgr.mQuestCreatureRelation.LookupByKey(guid);
|
|
||||||
foreach (var creature in qr)
|
|
||||||
{
|
|
||||||
if (!questMap.ContainsKey(creature))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var quest in questMap[creature].ToList())
|
|
||||||
{
|
|
||||||
if (quest == guid)
|
|
||||||
questMap.Remove(creature, quest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gameobjects
|
|
||||||
questMap = Global.ObjectMgr.GetGOQuestRelationMap();
|
|
||||||
qr = Global.PoolMgr.mQuestGORelation.LookupByKey(guid);
|
|
||||||
foreach (var go in qr)
|
|
||||||
{
|
|
||||||
if (!questMap.ContainsKey(go))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var quest in questMap[go])
|
|
||||||
{
|
|
||||||
if (quest == guid)
|
|
||||||
questMap.Remove(go, quest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,12 +550,6 @@ namespace Game
|
|||||||
|
|
||||||
public void SpawnObject(ActivePoolData spawns, uint limit, ulong triggerFrom)
|
public void SpawnObject(ActivePoolData spawns, uint limit, ulong triggerFrom)
|
||||||
{
|
{
|
||||||
if (typeof(T).Name == "Quest")
|
|
||||||
{
|
|
||||||
SpawnQuestObject(spawns, limit, triggerFrom);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = (int)(limit - spawns.GetActiveObjectCount(poolId));
|
int count = (int)(limit - spawns.GetActiveObjectCount(poolId));
|
||||||
|
|
||||||
// If triggered from some object respawn this object is still marked as spawned
|
// If triggered from some object respawn this object is still marked as spawned
|
||||||
@@ -807,71 +608,6 @@ namespace Game
|
|||||||
DespawnObject(spawns, triggerFrom);
|
DespawnObject(spawns, triggerFrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpawnQuestObject(ActivePoolData spawns, uint limit, ulong triggerFrom)
|
|
||||||
{
|
|
||||||
Log.outDebug(LogFilter.Pool, "PoolGroup<Quest>: Spawning pool {0}", poolId);
|
|
||||||
// load state from db
|
|
||||||
if (triggerFrom == 0)
|
|
||||||
{
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_POOL_QUEST_SAVE);
|
|
||||||
stmt.AddValue(0, poolId);
|
|
||||||
SQLResult result = DB.Characters.Query(stmt);
|
|
||||||
|
|
||||||
if (!result.IsEmpty())
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint questId = result.Read<uint>(0);
|
|
||||||
spawns.ActivateObject<Quest>(questId, poolId);
|
|
||||||
PoolObject tempObj = new(questId, 0.0f);
|
|
||||||
Spawn1Object(tempObj);
|
|
||||||
--limit;
|
|
||||||
} while (result.NextRow() && limit != 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ulong> currentQuests = spawns.GetActiveQuests();
|
|
||||||
List<ulong> newQuests = new();
|
|
||||||
|
|
||||||
// always try to select different quests
|
|
||||||
foreach (var poolObject in EqualChanced)
|
|
||||||
{
|
|
||||||
if (spawns.IsActiveObject<Quest>(poolObject.guid))
|
|
||||||
continue;
|
|
||||||
newQuests.Add(poolObject.guid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear the pool
|
|
||||||
DespawnObject(spawns);
|
|
||||||
|
|
||||||
// recycle minimal amount of quests if possible count is lower than limit
|
|
||||||
while (limit > newQuests.Count && !currentQuests.Empty())
|
|
||||||
{
|
|
||||||
ulong questId = currentQuests.SelectRandom();
|
|
||||||
newQuests.Add(questId);
|
|
||||||
currentQuests.Remove(questId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newQuests.Empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// activate <limit> random quests
|
|
||||||
do
|
|
||||||
{
|
|
||||||
ulong questId = newQuests.SelectRandom();
|
|
||||||
spawns.ActivateObject<Quest>(questId, poolId);
|
|
||||||
PoolObject tempObj = new(questId, 0.0f);
|
|
||||||
Spawn1Object(tempObj);
|
|
||||||
newQuests.Remove(questId);
|
|
||||||
--limit;
|
|
||||||
} while (limit != 0 && !newQuests.Empty());
|
|
||||||
|
|
||||||
// if we are here it means the pool is initialized at startup and did not have previous saved state
|
|
||||||
if (triggerFrom == 0)
|
|
||||||
Global.PoolMgr.SaveQuestsToDB();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Spawn1Object(PoolObject obj)
|
void Spawn1Object(PoolObject obj)
|
||||||
{
|
{
|
||||||
switch (typeof(T).Name)
|
switch (typeof(T).Name)
|
||||||
@@ -916,25 +652,6 @@ namespace Game
|
|||||||
case "Pool":
|
case "Pool":
|
||||||
Global.PoolMgr.SpawnPool((uint)obj.guid);
|
Global.PoolMgr.SpawnPool((uint)obj.guid);
|
||||||
break;
|
break;
|
||||||
case "Quest":
|
|
||||||
// Creatures
|
|
||||||
var questMap = Global.ObjectMgr.GetCreatureQuestRelationMap();
|
|
||||||
var qr = Global.PoolMgr.mQuestCreatureRelation.LookupByKey(obj.guid);
|
|
||||||
foreach (var creature in qr)
|
|
||||||
{
|
|
||||||
Log.outDebug(LogFilter.Pool, "PoolGroup<Quest>: Adding quest {0} to creature {1}", obj.guid, creature);
|
|
||||||
questMap.Add(creature, (uint)obj.guid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gameobjects
|
|
||||||
questMap = Global.ObjectMgr.GetGOQuestRelationMap();
|
|
||||||
qr = Global.PoolMgr.mQuestGORelation.LookupByKey(obj.guid);
|
|
||||||
foreach (var go in qr)
|
|
||||||
{
|
|
||||||
Log.outDebug(LogFilter.Pool, "PoolGroup<Quest>: Adding quest {0} to GO {1}", obj.guid, go);
|
|
||||||
questMap.Add(go, (uint)obj.guid);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -977,8 +694,6 @@ namespace Game
|
|||||||
return mSpawnedGameobjects.Contains(db_guid);
|
return mSpawnedGameobjects.Contains(db_guid);
|
||||||
case "Pool":
|
case "Pool":
|
||||||
return mSpawnedPools.ContainsKey(db_guid);
|
return mSpawnedPools.ContainsKey(db_guid);
|
||||||
case "Quest":
|
|
||||||
return mActiveQuests.Contains(db_guid);
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -997,9 +712,6 @@ namespace Game
|
|||||||
case "Pool":
|
case "Pool":
|
||||||
mSpawnedPools[db_guid] = 0;
|
mSpawnedPools[db_guid] = 0;
|
||||||
break;
|
break;
|
||||||
case "Quest":
|
|
||||||
mActiveQuests.Add(db_guid);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1022,9 +734,6 @@ namespace Game
|
|||||||
case "Pool":
|
case "Pool":
|
||||||
mSpawnedPools.Remove(db_guid);
|
mSpawnedPools.Remove(db_guid);
|
||||||
break;
|
break;
|
||||||
case "Quest":
|
|
||||||
mActiveQuests.Remove(db_guid);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1033,11 +742,8 @@ namespace Game
|
|||||||
--mSpawnedPools[pool_id];
|
--mSpawnedPools[pool_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ulong> GetActiveQuests() { return mActiveQuests; } // a copy of the set
|
|
||||||
|
|
||||||
List<ulong> mSpawnedCreatures = new();
|
List<ulong> mSpawnedCreatures = new();
|
||||||
List<ulong> mSpawnedGameobjects = new();
|
List<ulong> mSpawnedGameobjects = new();
|
||||||
List<ulong> mActiveQuests = new();
|
|
||||||
Dictionary<ulong, uint> mSpawnedPools = new();
|
Dictionary<ulong, uint> mSpawnedPools = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,315 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
using Framework.Constants;
|
||||||
|
using Framework.Database;
|
||||||
|
using Game.Entities;
|
||||||
|
using Game.Maps;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Game
|
||||||
|
{
|
||||||
|
public class QuestPoolManager : Singleton<QuestPoolManager>
|
||||||
|
{
|
||||||
|
List<QuestPool> _dailyPools = new();
|
||||||
|
List<QuestPool> _weeklyPools = new();
|
||||||
|
List<QuestPool> _monthlyPools = new();
|
||||||
|
Dictionary<uint, QuestPool> _poolLookup = new(); // questId -> pool
|
||||||
|
|
||||||
|
QuestPoolManager() { }
|
||||||
|
|
||||||
|
public static void RegeneratePool(QuestPool pool)
|
||||||
|
{
|
||||||
|
Cypher.Assert(!pool.members.Empty(), $"Quest pool {pool.poolId} is empty");
|
||||||
|
Cypher.Assert(pool.numActive <= pool.members.Count, $"Quest Pool {pool.poolId} requests {pool.numActive} spawns, but has only {pool.members.Count} members.");
|
||||||
|
|
||||||
|
int n = pool.members.Count - 1;
|
||||||
|
pool.activeQuests.Clear();
|
||||||
|
for (uint i = 0; i < pool.numActive; ++i)
|
||||||
|
{
|
||||||
|
uint j = RandomHelper.URand(i, n);
|
||||||
|
if (i != j)
|
||||||
|
{
|
||||||
|
var leftList = pool.members[i];
|
||||||
|
pool.members[i] = pool.members[j];
|
||||||
|
pool.members[j] = leftList;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (uint quest in pool.members[i])
|
||||||
|
pool.activeQuests.Add(quest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SaveToDB(QuestPool pool, SQLTransaction trans)
|
||||||
|
{
|
||||||
|
PreparedStatement delStmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_POOL_QUEST_SAVE);
|
||||||
|
delStmt.AddValue(0, pool.poolId);
|
||||||
|
trans.Append(delStmt);
|
||||||
|
|
||||||
|
foreach (uint questId in pool.activeQuests)
|
||||||
|
{
|
||||||
|
PreparedStatement insStmt = DB.Characters.GetPreparedStatement(CharStatements.INS_POOL_QUEST_SAVE);
|
||||||
|
insStmt.AddValue(0, pool.poolId);
|
||||||
|
insStmt.AddValue(1, questId);
|
||||||
|
trans.Append(insStmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadFromDB()
|
||||||
|
{
|
||||||
|
uint oldMSTime = Time.GetMSTime();
|
||||||
|
Dictionary<uint, Tuple<List<QuestPool>, int>> lookup = new(); // poolId -> (list, index)
|
||||||
|
|
||||||
|
_poolLookup.Clear();
|
||||||
|
_dailyPools.Clear();
|
||||||
|
_weeklyPools.Clear();
|
||||||
|
_monthlyPools.Clear();
|
||||||
|
|
||||||
|
// load template data from world DB
|
||||||
|
{
|
||||||
|
SQLResult result = DB.World.Query("SELECT qpm.questId, qpm.poolId, qpm.poolIndex, qpt.numActive FROM quest_pool_members qpm LEFT JOIN quest_pool_template qpt ON qpm.poolId = qpt.poolId");
|
||||||
|
if (result.IsEmpty())
|
||||||
|
{
|
||||||
|
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 quest pools. DB table `quest_pool_members` is empty.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (result.IsNull(2))
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, $"Table `quest_pool_members` contains reference to non-existing pool {result.Read<uint>(1)}. Skipped.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint questId = result.Read<uint>(0);
|
||||||
|
uint poolId = result.Read<uint>(1);
|
||||||
|
uint poolIndex = result.Read<uint>(2);
|
||||||
|
uint numActive = result.Read<uint>(3);
|
||||||
|
|
||||||
|
Quest quest = Global.ObjectMgr.GetQuestTemplate(questId);
|
||||||
|
if (quest == null)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, "Table `quest_pool_members` contains reference to non-existing quest %u. Skipped.", questId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!quest.IsDailyOrWeekly() && !quest.IsMonthly())
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, "Table `quest_pool_members` contains reference to quest %u, which is neither daily, weekly nor monthly. Skipped.", questId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!lookup.ContainsKey(poolId))
|
||||||
|
{
|
||||||
|
var poolList = quest.IsDaily() ? _dailyPools : quest.IsWeekly() ? _weeklyPools : _monthlyPools;
|
||||||
|
poolList.Add(new QuestPool() { poolId = poolId, numActive = numActive });
|
||||||
|
|
||||||
|
lookup.Add(poolId, new Tuple<List<QuestPool>, int>(poolList, poolList.Count - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
var pair = lookup[poolId];
|
||||||
|
|
||||||
|
var members = pair.Item1[pair.Item2].members;
|
||||||
|
members.Add(poolIndex, questId);
|
||||||
|
} while (result.NextRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
// load saved spawns from character DB
|
||||||
|
{
|
||||||
|
SQLResult result = DB.Characters.Query("SELECT pool_id, quest_id FROM pool_quest_save");
|
||||||
|
if (!result.IsEmpty())
|
||||||
|
{
|
||||||
|
List<uint> unknownPoolIds = new();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
uint poolId = result.Read<uint>(0);
|
||||||
|
uint questId = result.Read<uint>(1);
|
||||||
|
|
||||||
|
var it = lookup.LookupByKey(poolId);
|
||||||
|
if (it == null || it.Item1 == null)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, "Table `pool_quest_save` contains reference to non-existant quest pool %u. Deleted.", poolId);
|
||||||
|
unknownPoolIds.Add(poolId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Item1[it.Item2].activeQuests.Add(questId);
|
||||||
|
} while (result.NextRow());
|
||||||
|
|
||||||
|
SQLTransaction trans0 = new SQLTransaction();
|
||||||
|
foreach (uint poolId in unknownPoolIds)
|
||||||
|
{
|
||||||
|
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_POOL_QUEST_SAVE);
|
||||||
|
stmt.AddValue(0, poolId);
|
||||||
|
trans0.Append(stmt);
|
||||||
|
}
|
||||||
|
DB.Characters.CommitTransaction(trans0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// post-processing and sanity checks
|
||||||
|
SQLTransaction trans = new SQLTransaction();
|
||||||
|
foreach (var pair in lookup)
|
||||||
|
{
|
||||||
|
if (pair.Value.Item1 == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
QuestPool pool = pair.Value.Item1[pair.Value.Item2];
|
||||||
|
if (pool.members.Count < pool.numActive)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, $"Table `quest_pool_template` contains quest pool {pool.poolId} requesting {pool.numActive} spawns, but only has {pool.members.Count} members. Requested spawns reduced.");
|
||||||
|
pool.numActive = (uint)pool.members.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doRegenerate = pool.activeQuests.Empty();
|
||||||
|
if (!doRegenerate)
|
||||||
|
{
|
||||||
|
List<uint> accountedFor = new();
|
||||||
|
uint activeCount = 0;
|
||||||
|
for (uint i = (uint)pool.members.Count; (i--) != 0;)
|
||||||
|
{
|
||||||
|
var member = pool.members[i];
|
||||||
|
if (member.Empty())
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, $"Table `quest_pool_members` contains no entries at index {i} for quest pool {pool.poolId}. Index removed.");
|
||||||
|
pool.members.Remove(i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the first member is active
|
||||||
|
bool status = pool.activeQuests.Contains(member[0]);
|
||||||
|
// temporarily remove any spawns that are accounted for
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
accountedFor.Add(member[0]);
|
||||||
|
pool.activeQuests.Remove(member[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now check if all other members also have the same status, and warn if not
|
||||||
|
foreach (var id in member)
|
||||||
|
{
|
||||||
|
bool otherStatus = pool.activeQuests.Contains(id);
|
||||||
|
if (status != otherStatus)
|
||||||
|
Log.outWarn(LogFilter.Sql, $"Table `pool_quest_save` {(status ? "does not have" : "has")} quest {id} (in pool {pool.poolId}, index {i}) saved, but its index is{(status ? "" : " not")} " +
|
||||||
|
$"active (because quest {member[0]} is{(status ? "" : " not")} in the table). Set quest {id} to {(status ? "" : "in")}active.");
|
||||||
|
if (otherStatus)
|
||||||
|
pool.activeQuests.Remove(id);
|
||||||
|
if (status)
|
||||||
|
accountedFor.Add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
++activeCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// warn for any remaining active spawns (not part of the pool)
|
||||||
|
foreach (uint quest in pool.activeQuests)
|
||||||
|
Log.outWarn(LogFilter.Sql, $"Table `pool_quest_save` has saved quest {quest} for pool {pool.poolId}, but that quest is not part of the pool. Skipped.");
|
||||||
|
|
||||||
|
// only the previously-found spawns should actually be active
|
||||||
|
pool.activeQuests = accountedFor;
|
||||||
|
|
||||||
|
if (activeCount != pool.numActive)
|
||||||
|
{
|
||||||
|
doRegenerate = true;
|
||||||
|
Log.outError(LogFilter.Sql, "Table `pool_quest_save` has %u active members saved for pool %u, which requests %u active members. Pool spawns re-generated.", activeCount, pool.poolId, pool.numActive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doRegenerate)
|
||||||
|
{
|
||||||
|
RegeneratePool(pool);
|
||||||
|
SaveToDB(pool, trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var memberKey in pool.members.Keys)
|
||||||
|
{
|
||||||
|
foreach (uint quest in pool.members[memberKey])
|
||||||
|
{
|
||||||
|
QuestPool refe = _poolLookup[quest];
|
||||||
|
if (refe != null)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Sql, "Table `quest_pool_members` lists quest %u as member of pool %u, but it is already a member of pool %u. Skipped.", quest, pool.poolId, refe.poolId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
refe = pool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DB.Characters.CommitTransaction(trans);
|
||||||
|
|
||||||
|
Log.outInfo(LogFilter.ServerLoading, $"Loaded {_dailyPools.Count} daily, {_weeklyPools.Count} weekly and {_monthlyPools.Count} monthly quest pools in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Regenerate(List<QuestPool> pools)
|
||||||
|
{
|
||||||
|
SQLTransaction trans = new SQLTransaction();
|
||||||
|
foreach (QuestPool pool in pools)
|
||||||
|
{
|
||||||
|
RegeneratePool(pool);
|
||||||
|
SaveToDB(pool, trans);
|
||||||
|
}
|
||||||
|
DB.Characters.CommitTransaction(trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
// the storage structure ends up making this kind of inefficient
|
||||||
|
// we don't use it in practice (only in debug commands), so that's fine
|
||||||
|
public QuestPool FindQuestPool(uint poolId)
|
||||||
|
{
|
||||||
|
bool lambda(QuestPool p) { return p.poolId == poolId; };
|
||||||
|
|
||||||
|
var questPool = _dailyPools.Find(lambda);
|
||||||
|
if (questPool != null)
|
||||||
|
return questPool;
|
||||||
|
|
||||||
|
questPool = _weeklyPools.Find(lambda);
|
||||||
|
if (questPool != null)
|
||||||
|
return questPool;
|
||||||
|
|
||||||
|
questPool = _monthlyPools.Find(lambda);
|
||||||
|
if (questPool != null)
|
||||||
|
return questPool;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsQuestActive(uint questId)
|
||||||
|
{
|
||||||
|
var it = _poolLookup.LookupByKey(questId);
|
||||||
|
if (it == null) // not pooled
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return it.activeQuests.Contains(questId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ChangeDailyQuests() { Regenerate(_dailyPools); }
|
||||||
|
public void ChangeWeeklyQuests() { Regenerate(_weeklyPools); }
|
||||||
|
public void ChangeMonthlyQuests() { Regenerate(_monthlyPools); }
|
||||||
|
|
||||||
|
public bool IsQuestPooled(uint questId) { return _poolLookup.ContainsKey(questId); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QuestPool
|
||||||
|
{
|
||||||
|
public uint poolId;
|
||||||
|
public uint numActive;
|
||||||
|
public MultiMap<uint, uint> members = new();
|
||||||
|
public List<uint> activeQuests = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -312,6 +312,14 @@ namespace Game
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsTakingQuestEnabled(uint questId)
|
||||||
|
{
|
||||||
|
if (!Global.QuestPoolMgr.IsQuestActive(questId))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public uint MoneyValue(Player player)
|
public uint MoneyValue(Player player)
|
||||||
{
|
{
|
||||||
QuestMoneyRewardRecord money = CliDB.QuestMoneyRewardStorage.LookupByKey(player.GetQuestLevel(this));
|
QuestMoneyRewardRecord money = CliDB.QuestMoneyRewardStorage.LookupByKey(player.GetQuestLevel(this));
|
||||||
|
|||||||
@@ -542,6 +542,18 @@ namespace Game
|
|||||||
Values[WorldCfg.InstanceResetTimeHour] = GetDefaultValue("Instance.ResetTimeHour", 4);
|
Values[WorldCfg.InstanceResetTimeHour] = GetDefaultValue("Instance.ResetTimeHour", 4);
|
||||||
Values[WorldCfg.InstanceUnloadDelay] = GetDefaultValue("Instance.UnloadDelay", 30 * Time.Minute * Time.InMilliseconds);
|
Values[WorldCfg.InstanceUnloadDelay] = GetDefaultValue("Instance.UnloadDelay", 30 * Time.Minute * Time.InMilliseconds);
|
||||||
Values[WorldCfg.DailyQuestResetTimeHour] = GetDefaultValue("Quests.DailyResetTime", 3);
|
Values[WorldCfg.DailyQuestResetTimeHour] = GetDefaultValue("Quests.DailyResetTime", 3);
|
||||||
|
if ((int)Values[WorldCfg.DailyQuestResetTimeHour] < 0 || (int)Values[WorldCfg.DailyQuestResetTimeHour] > 23)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.ServerLoading, $"Quests.DailyResetTime ({Values[WorldCfg.DailyQuestResetTimeHour]}) must be in range 0..23. Set to 3.");
|
||||||
|
Values[WorldCfg.DailyQuestResetTimeHour] = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
Values[WorldCfg.WeeklyQuestResetTimeWDay] = GetDefaultValue("Quests.WeeklyResetWDay", 3);
|
||||||
|
if ((int)Values[WorldCfg.WeeklyQuestResetTimeWDay] < 0 || (int)Values[WorldCfg.WeeklyQuestResetTimeWDay] > 6)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.ServerLoading, $"Quests.WeeklyResetDay ({Values[WorldCfg.WeeklyQuestResetTimeWDay]}) must be in range 0..6. Set to 3 (Wednesday).");
|
||||||
|
Values[WorldCfg.WeeklyQuestResetTimeWDay] = 3;
|
||||||
|
}
|
||||||
|
|
||||||
Values[WorldCfg.MaxPrimaryTradeSkill] = GetDefaultValue("MaxPrimaryTradeSkill", 2);
|
Values[WorldCfg.MaxPrimaryTradeSkill] = GetDefaultValue("MaxPrimaryTradeSkill", 2);
|
||||||
Values[WorldCfg.MinPetitionSigns] = GetDefaultValue("MinPetitionSigns", 4);
|
Values[WorldCfg.MinPetitionSigns] = GetDefaultValue("MinPetitionSigns", 4);
|
||||||
|
|||||||
+123
-114
@@ -688,6 +688,9 @@ namespace Game
|
|||||||
Log.outInfo(LogFilter.ServerLoading, "Loading Objects Pooling Data...");
|
Log.outInfo(LogFilter.ServerLoading, "Loading Objects Pooling Data...");
|
||||||
Global.PoolMgr.LoadFromDB();
|
Global.PoolMgr.LoadFromDB();
|
||||||
|
|
||||||
|
Log.outInfo(LogFilter.ServerLoading, "Loading Quest Pooling Data...");
|
||||||
|
Global.QuestPoolMgr.LoadFromDB(); // must be after quest templates
|
||||||
|
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Loading Game Event Data..."); // must be after loading pools fully
|
Log.outInfo(LogFilter.ServerLoading, "Loading Game Event Data..."); // must be after loading pools fully
|
||||||
Global.GameEventMgr.LoadFromDB();
|
Global.GameEventMgr.LoadFromDB();
|
||||||
|
|
||||||
@@ -1065,14 +1068,9 @@ namespace Game
|
|||||||
Log.outInfo(LogFilter.ServerLoading, "Deleting expired bans...");
|
Log.outInfo(LogFilter.ServerLoading, "Deleting expired bans...");
|
||||||
DB.Login.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); // One-time query
|
DB.Login.Execute("DELETE FROM ip_banned WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate<>bandate"); // One-time query
|
||||||
|
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Calculate next daily quest reset time...");
|
Log.outInfo(LogFilter.ServerLoading, "Initializing quest reset times...");
|
||||||
InitDailyQuestResetTime();
|
InitQuestResetTimes();
|
||||||
|
CheckScheduledResetTimes();
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Calculate next weekly quest reset time...");
|
|
||||||
InitWeeklyQuestResetTime();
|
|
||||||
|
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Calculate next monthly quest reset time...");
|
|
||||||
InitMonthlyQuestResetTime();
|
|
||||||
|
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Calculate random Battlegroundreset time...");
|
Log.outInfo(LogFilter.ServerLoading, "Calculate random Battlegroundreset time...");
|
||||||
InitRandomBGResetTime();
|
InitRandomBGResetTime();
|
||||||
@@ -1307,20 +1305,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle daily quests reset time
|
CheckScheduledResetTimes();
|
||||||
if (currentGameTime > m_NextDailyQuestReset)
|
|
||||||
{
|
|
||||||
DailyReset();
|
|
||||||
InitDailyQuestResetTime(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle weekly quests reset time
|
|
||||||
if (currentGameTime > m_NextWeeklyQuestReset)
|
|
||||||
ResetWeeklyQuests();
|
|
||||||
|
|
||||||
// Handle monthly quests reset time
|
|
||||||
if (currentGameTime > m_NextMonthlyQuestReset)
|
|
||||||
ResetMonthlyQuests();
|
|
||||||
|
|
||||||
if (currentGameTime > m_NextRandomBGReset)
|
if (currentGameTime > m_NextRandomBGReset)
|
||||||
ResetRandomBG();
|
ResetRandomBG();
|
||||||
@@ -1979,50 +1964,136 @@ namespace Game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitWeeklyQuestResetTime()
|
void InitQuestResetTimes()
|
||||||
{
|
{
|
||||||
long wstime = GetWorldState(WorldStates.WeeklyQuestResetTime);
|
m_NextDailyQuestReset = GetWorldState(WorldStates.DailyQuestResetTime);
|
||||||
long curtime = GameTime.GetGameTime();
|
m_NextWeeklyQuestReset = GetWorldState(WorldStates.WeeklyQuestResetTime);
|
||||||
m_NextWeeklyQuestReset = wstime < curtime ? curtime : wstime;
|
m_NextMonthlyQuestReset = GetWorldState(WorldStates.MonthlyQuestResetTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitDailyQuestResetTime(bool loading = true)
|
static long GetNextDailyResetTime(long t)
|
||||||
{
|
{
|
||||||
long mostRecentQuestTime = 0;
|
return Time.GetLocalHourTimestamp(t, WorldConfig.GetUIntValue(WorldCfg.DailyQuestResetTimeHour), true);
|
||||||
|
}
|
||||||
|
|
||||||
if (loading)
|
void DailyReset()
|
||||||
|
{
|
||||||
|
// reset all saved quest status
|
||||||
|
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_DAILY);
|
||||||
|
DB.Characters.Execute(stmt);
|
||||||
|
|
||||||
|
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS);
|
||||||
|
stmt.AddValue(0, 1);
|
||||||
|
DB.Characters.Execute(stmt);
|
||||||
|
|
||||||
|
// reset all quest status in memory
|
||||||
|
foreach (var itr in m_sessions)
|
||||||
{
|
{
|
||||||
SQLResult result = DB.Characters.Query("SELECT MAX(time) FROM character_queststatus_daily");
|
Player player = itr.Value.GetPlayer();
|
||||||
if (!result.IsEmpty())
|
if (player != null)
|
||||||
{
|
player.DailyReset();
|
||||||
mostRecentQuestTime = result.Read<uint>(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reselect pools
|
||||||
|
Global.QuestPoolMgr.ChangeDailyQuests();
|
||||||
|
|
||||||
// FIX ME: client not show day start time
|
// store next reset time
|
||||||
long curTime = GameTime.GetGameTime();
|
long now = GameTime.GetGameTime();
|
||||||
|
long next = GetNextDailyResetTime(now);
|
||||||
|
Cypher.Assert(now < next);
|
||||||
|
|
||||||
// current day reset time
|
m_NextDailyQuestReset = next;
|
||||||
long curDayResetTime = Time.GetNextResetUnixTime(WorldConfig.GetIntValue(WorldCfg.DailyQuestResetTimeHour));
|
SetWorldState(WorldStates.DailyQuestResetTime, (ulong)next);
|
||||||
|
|
||||||
// last reset time before current moment
|
Log.outInfo(LogFilter.Misc, "Daily quests for all characters have been reset.");
|
||||||
long resetTime = (curTime < curDayResetTime) ? curDayResetTime - Time.Day : curDayResetTime;
|
|
||||||
|
|
||||||
// need reset (if we have quest time before last reset time (not processed by some reason)
|
|
||||||
if (mostRecentQuestTime != 0 && mostRecentQuestTime <= resetTime)
|
|
||||||
m_NextDailyQuestReset = mostRecentQuestTime;
|
|
||||||
else // plan next reset time
|
|
||||||
m_NextDailyQuestReset = (curTime >= curDayResetTime) ? curDayResetTime + Time.Day : curDayResetTime;
|
|
||||||
|
|
||||||
SetWorldState(WorldStates.DailyQuestResetTime, (ulong)m_NextDailyQuestReset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitMonthlyQuestResetTime()
|
static long GetNextWeeklyResetTime(long t)
|
||||||
{
|
{
|
||||||
long wstime = GetWorldState(WorldStates.MonthlyQuestResetTime);
|
t = GetNextDailyResetTime(t);
|
||||||
long curtime = GameTime.GetGameTime();
|
DateTime time = Time.UnixTimeToDateTime(t);
|
||||||
m_NextMonthlyQuestReset = wstime < curtime ? curtime : wstime;
|
int wday = (int)time.DayOfWeek;
|
||||||
|
int target = WorldConfig.GetIntValue(WorldCfg.WeeklyQuestResetTimeWDay);
|
||||||
|
if (target < wday)
|
||||||
|
wday -= 7;
|
||||||
|
t += (Time.Day * (target - wday));
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetWeeklyQuests()
|
||||||
|
{
|
||||||
|
// reset all saved quest status
|
||||||
|
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY);
|
||||||
|
DB.Characters.Execute(stmt);
|
||||||
|
// reset all quest status in memory
|
||||||
|
foreach (var itr in m_sessions)
|
||||||
|
{
|
||||||
|
Player player = itr.Value.GetPlayer();
|
||||||
|
if (player != null)
|
||||||
|
player.ResetWeeklyQuestStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// reselect pools
|
||||||
|
Global.QuestPoolMgr.ChangeWeeklyQuests();
|
||||||
|
|
||||||
|
// store next reset time
|
||||||
|
long now = GameTime.GetGameTime();
|
||||||
|
long next = GetNextWeeklyResetTime(now);
|
||||||
|
Cypher.Assert(now < next);
|
||||||
|
|
||||||
|
m_NextWeeklyQuestReset = next;
|
||||||
|
SetWorldState(WorldStates.WeeklyQuestResetTime, (ulong)next);
|
||||||
|
|
||||||
|
Log.outInfo(LogFilter.Misc, "Weekly quests for all characters have been reset.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static long GetNextMonthlyResetTime(long t)
|
||||||
|
{
|
||||||
|
t = GetNextDailyResetTime(t);
|
||||||
|
DateTime time = Time.UnixTimeToDateTime(t);
|
||||||
|
if (time.Day == 1)
|
||||||
|
return t;
|
||||||
|
|
||||||
|
var newDate = new DateTime(time.Year, time.Month + 1, 1, 0, 0, 0, time.Kind);
|
||||||
|
return Time.DateTimeToUnixTime(newDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetMonthlyQuests()
|
||||||
|
{
|
||||||
|
// reset all saved quest status
|
||||||
|
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY);
|
||||||
|
DB.Characters.Execute(stmt);
|
||||||
|
// reset all quest status in memory
|
||||||
|
foreach (var itr in m_sessions)
|
||||||
|
{
|
||||||
|
Player player = itr.Value.GetPlayer();
|
||||||
|
if (player != null)
|
||||||
|
player.ResetMonthlyQuestStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// reselect pools
|
||||||
|
Global.QuestPoolMgr.ChangeMonthlyQuests();
|
||||||
|
|
||||||
|
// store next reset time
|
||||||
|
long now = GameTime.GetGameTime();
|
||||||
|
long next = GetNextMonthlyResetTime(now);
|
||||||
|
Cypher.Assert(now < next);
|
||||||
|
|
||||||
|
m_NextMonthlyQuestReset = next;
|
||||||
|
SetWorldState(WorldStates.MonthlyQuestResetTime, (ulong)next);
|
||||||
|
|
||||||
|
Log.outInfo(LogFilter.Misc, "Monthly quests for all characters have been reset.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckScheduledResetTimes()
|
||||||
|
{
|
||||||
|
long now = GameTime.GetGameTime();
|
||||||
|
if (m_NextDailyQuestReset <= now)
|
||||||
|
DailyReset();
|
||||||
|
if (m_NextWeeklyQuestReset <= now)
|
||||||
|
ResetWeeklyQuests();
|
||||||
|
if (m_NextMonthlyQuestReset <= now)
|
||||||
|
ResetMonthlyQuests();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitRandomBGResetTime()
|
void InitRandomBGResetTime()
|
||||||
@@ -2089,25 +2160,6 @@ namespace Game
|
|||||||
SetWorldState(WorldStates.CurrencyResetTime, (ulong)m_NextCurrencyReset);
|
SetWorldState(WorldStates.CurrencyResetTime, (ulong)m_NextCurrencyReset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DailyReset()
|
|
||||||
{
|
|
||||||
Log.outInfo(LogFilter.Server, "Daily quests reset for all characters.");
|
|
||||||
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_DAILY);
|
|
||||||
DB.Characters.Execute(stmt);
|
|
||||||
|
|
||||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_CHARACTER_GARRISON_FOLLOWER_ACTIVATIONS);
|
|
||||||
stmt.AddValue(0, 1);
|
|
||||||
DB.Characters.Execute(stmt);
|
|
||||||
|
|
||||||
foreach (var session in m_sessions.Values)
|
|
||||||
if (session.GetPlayer() != null)
|
|
||||||
session.GetPlayer().DailyReset();
|
|
||||||
|
|
||||||
// change available dailies
|
|
||||||
Global.PoolMgr.ChangeDailyQuests();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResetCurrencyWeekCap()
|
void ResetCurrencyWeekCap()
|
||||||
{
|
{
|
||||||
DB.Characters.Execute("UPDATE `character_currency` SET `WeeklyQuantity` = 0");
|
DB.Characters.Execute("UPDATE `character_currency` SET `WeeklyQuantity` = 0");
|
||||||
@@ -2120,49 +2172,6 @@ namespace Game
|
|||||||
SetWorldState(WorldStates.CurrencyResetTime, (ulong)m_NextCurrencyReset);
|
SetWorldState(WorldStates.CurrencyResetTime, (ulong)m_NextCurrencyReset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetWeeklyQuests()
|
|
||||||
{
|
|
||||||
Log.outInfo(LogFilter.Server, "Weekly quests reset for all characters.");
|
|
||||||
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY);
|
|
||||||
DB.Characters.Execute(stmt);
|
|
||||||
|
|
||||||
foreach (var session in m_sessions.Values)
|
|
||||||
if (session.GetPlayer() != null)
|
|
||||||
session.GetPlayer().ResetWeeklyQuestStatus();
|
|
||||||
|
|
||||||
m_NextWeeklyQuestReset += Time.Week;
|
|
||||||
SetWorldState(WorldStates.WeeklyQuestResetTime, (ulong)m_NextWeeklyQuestReset);
|
|
||||||
|
|
||||||
// change available weeklies
|
|
||||||
Global.PoolMgr.ChangeWeeklyQuests();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ResetMonthlyQuests()
|
|
||||||
{
|
|
||||||
Log.outInfo(LogFilter.Server, "Monthly quests reset for all characters.");
|
|
||||||
|
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY);
|
|
||||||
DB.Characters.Execute(stmt);
|
|
||||||
|
|
||||||
foreach (var session in m_sessions.Values)
|
|
||||||
if (session.GetPlayer() != null)
|
|
||||||
session.GetPlayer().ResetMonthlyQuestStatus();
|
|
||||||
|
|
||||||
long curTime = GameTime.GetGameTime();
|
|
||||||
|
|
||||||
// current day reset time
|
|
||||||
long curDayResetTime = Time.GetNextResetUnixTime(30, 1, 0);
|
|
||||||
|
|
||||||
// last reset time before current moment
|
|
||||||
long nextMonthResetTime = (curTime < curDayResetTime) ? curDayResetTime - Time.Day : curDayResetTime;
|
|
||||||
|
|
||||||
// plan next reset time
|
|
||||||
m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + Time.Month : nextMonthResetTime;
|
|
||||||
|
|
||||||
SetWorldState(WorldStates.MonthlyQuestResetTime, (ulong)m_NextMonthlyQuestReset);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetEventSeasonalQuests(ushort event_id)
|
public void ResetEventSeasonalQuests(ushort event_id)
|
||||||
{
|
{
|
||||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT);
|
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT);
|
||||||
|
|||||||
@@ -1025,6 +1025,15 @@ Quests.IgnoreAutoComplete = 0
|
|||||||
|
|
||||||
Quests.DailyResetTime = 3
|
Quests.DailyResetTime = 3
|
||||||
|
|
||||||
|
#
|
||||||
|
# Quests.WeeklyResetWDay
|
||||||
|
# Description: Day of the week when weekly quest reset occurs.
|
||||||
|
# Range: 0 (Sunday) to 6 (Saturday)
|
||||||
|
# Default: 3 - (Wednesday)
|
||||||
|
#
|
||||||
|
|
||||||
|
Quests.WeeklyResetWDay = 3
|
||||||
|
|
||||||
#
|
#
|
||||||
# Guild.EventLogRecordsCount
|
# Guild.EventLogRecordsCount
|
||||||
# Description: Number of log entries for guild events that are stored per guild. Old entries
|
# Description: Number of log entries for guild events that are stored per guild. Old entries
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
-- quest pools no longer support nesting, but they also don't need it
|
||||||
|
DROP TABLE IF EXISTS `quest_pool_members`;
|
||||||
|
CREATE TABLE `quest_pool_members` (
|
||||||
|
`questId` int(10) unsigned not null,
|
||||||
|
`poolId` int(10) unsigned not null,
|
||||||
|
`poolIndex` tinyint(2) unsigned not null COMMENT 'Multiple quests with the same index will always spawn together!',
|
||||||
|
`description` varchar(255) default null,
|
||||||
|
PRIMARY KEY (`questId`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE `_temp_pool_quests` (
|
||||||
|
`sortIndex` int auto_increment not null,
|
||||||
|
`questId` int(10) unsigned not null,
|
||||||
|
`subPool` int(10) unsigned,
|
||||||
|
`topPool` int(10) unsigned not null,
|
||||||
|
`description` varchar(255) default null,
|
||||||
|
PRIMARY KEY (`sortIndex`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
-- build a lookup table of questid <-> nested pool <-> toplevel pool
|
||||||
|
INSERT INTO `_temp_pool_quests` (`questId`,`subPool`,`topPool`,`description`)
|
||||||
|
SELECT pq.`entry` as `questId`, IF(pp.`poolSpawnId` is null, null, pq.`pool_entry`) as `subPool`, IFNULL(pp.`poolSpawnId`,pq.`pool_entry`) AS `topPool`, pq.`description`
|
||||||
|
FROM `pool_quest` as pq LEFT JOIN `pool_members` pp ON (pp.`type`=2) and (pp.`spawnId` = pq.`pool_entry`)
|
||||||
|
ORDER BY `topPool` ASC, `subPool` ASC;
|
||||||
|
|
||||||
|
-- delete any nested pools whose members we'll remove
|
||||||
|
DELETE FROM `pool_template` WHERE `entry` IN (SELECT DISTINCT `subPool` FROM `_temp_pool_quests` WHERE `subPool` is not null);
|
||||||
|
DELETE FROM `pool_members` WHERE `type`=2 AND `spawnId` IN (SELECT DISTINCT `subPool` FROM `_temp_pool_quests` WHERE `subPool` is not null);
|
||||||
|
|
||||||
|
-- ensure quests without a subPool have different subPool values
|
||||||
|
UPDATE `_temp_pool_quests` SET `subPool`=`sortIndex` WHERE `subPool` is null;
|
||||||
|
|
||||||
|
SET @pool_index = 0;
|
||||||
|
SET @last_pool = 0;
|
||||||
|
SET @last_subpool = 0;
|
||||||
|
|
||||||
|
-- poolIndex is chosen as follows:
|
||||||
|
-- *) if we're starting a new pool, the index is 0
|
||||||
|
-- *) if the preceding element had the same subpool, the index remains the same
|
||||||
|
-- *) if the preceding element had a different subpool, the index increases by 1
|
||||||
|
INSERT INTO `quest_pool_members` (`questId`, `poolId`, `poolIndex`, `description`)
|
||||||
|
SELECT
|
||||||
|
`questId`,
|
||||||
|
`topPool` as `poolId`,
|
||||||
|
(CASE WHEN @last_subpool = `subPool` THEN @pool_index ELSE (@pool_index := (((@last_subpool := `subPool`) and 0) + (CASE WHEN @last_pool = `topPool` THEN @pool_index+1 ELSE ((@last_pool := `topPool`) and 0) END))) END) as `poolIndex`,
|
||||||
|
`description`
|
||||||
|
FROM `_temp_pool_quests`;
|
||||||
|
|
||||||
|
-- drop the old table
|
||||||
|
DROP TABLE `pool_quest`;
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `quest_pool_template`;
|
||||||
|
CREATE TABLE `quest_pool_template` (
|
||||||
|
`poolId` mediumint(8) unsigned not null,
|
||||||
|
`numActive` int(10) unsigned not null COMMENT 'Number of indices to have active at any time',
|
||||||
|
`description` varchar(255) default null,
|
||||||
|
PRIMARY KEY (`poolId`)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
-- copy any quest pool templates over
|
||||||
|
INSERT INTO `quest_pool_template` (`poolId`, `numActive`, `description`)
|
||||||
|
SELECT DISTINCT pt.`entry`,pt.`max_limit`,pt.`description` FROM `quest_pool_members` qpm LEFT JOIN `pool_template` pt ON (qpm.`poolId` = pt.`entry`);
|
||||||
|
|
||||||
|
-- and delete them from the original table
|
||||||
|
DELETE pt FROM `pool_template` pt LEFT JOIN `quest_pool_template` qpt ON qpt.`poolId`=pt.`entry` WHERE qpt.`poolId` is not null;
|
||||||
Reference in New Issue
Block a user