получение instance id для encounter journal

This commit is contained in:
2026-06-13 15:09:04 +04:00
parent 60bf86a9f7
commit ddee7e14ac
4 changed files with 151 additions and 51 deletions
@@ -9,8 +9,11 @@
#include "../IndividualProgression.h"
#include "Config.h"
#include "DatabaseEnv.h"
#include "Field.h"
#include "Log.h"
#include "Player.h"
#include "QueryResult.h"
#include "QuestDef.h"
#include <algorithm>
@@ -202,6 +205,45 @@ namespace MoonWell::PlayerGuide
// characters. We leave room for the framing header.
if (_chunkSize < 64) _chunkSize = 64;
if (_chunkSize > 240) _chunkSize = 240;
ReloadEncounterJournalCache();
}
void Mgr::ReloadEncounterJournalCache()
{
_ejByMapId.clear();
// mod-encounter-journal may be disabled or its table absent.
// The query then yields no result and we keep an empty cache;
// recommendations that would have used EJ ids are skipped.
QueryResult result = WorldDatabase.Query(
"SELECT `id`, `map_id`, `name` "
"FROM `custom_ej_instance`");
if (!result)
{
LOG_INFO("server.loading",
">> PlayerGuide: no custom_ej_instance rows found. "
"Recommendations will be empty.");
return;
}
do
{
Field* f = result->Fetch();
EjInstanceRef ref;
ref.ejId = f[0].Get<uint32>();
uint32 mapId = f[1].Get<uint32>();
ref.name = f[2].Get<std::string>();
// First entry wins. If the EJ has duplicates for the same
// map (e.g. heroic variants) the lowest id is taken via the
// INSERT order; we don't reorder.
_ejByMapId.emplace(mapId, std::move(ref));
} while (result->NextRow());
LOG_INFO("server.loading",
">> PlayerGuide: cached {} EJ instance entries by mapId.",
_ejByMapId.size());
}
std::string Mgr::StageName(uint32 stage) const
@@ -258,14 +300,19 @@ namespace MoonWell::PlayerGuide
std::string const& title,
uint32 order) const
{
auto it = _ejByMapId.find(mapId);
if (it == _ejByMapId.end())
return; // no EJ entry -> skip rather than emit a stub.
Objective o;
o.id = order;
o.type = "dungeon";
o.title = title;
o.required = 1;
o.targetId = mapId;
o.instanceId = mapId;
o.order = order;
o.id = order;
o.type = "dungeon";
o.title = it->second.name.empty() ? title : it->second.name;
o.required = 1;
o.targetId = it->second.ejId; // primary id for click
o.ejInstanceId = it->second.ejId; // JOURNALINSTANCE key
o.mapId = mapId; // WoW map id (auxiliary)
o.order = order;
out.objectives.push_back(std::move(o));
}
@@ -273,14 +320,19 @@ namespace MoonWell::PlayerGuide
std::string const& title,
uint32 order) const
{
auto it = _ejByMapId.find(mapId);
if (it == _ejByMapId.end())
return;
Objective o;
o.id = order;
o.type = "raid";
o.title = title;
o.required = 1;
o.targetId = mapId;
o.instanceId = mapId;
o.order = order;
o.id = order;
o.type = "raid";
o.title = it->second.name.empty() ? title : it->second.name;
o.required = 1;
o.targetId = it->second.ejId;
o.ejInstanceId = it->second.ejId;
o.mapId = mapId;
o.order = order;
out.objectives.push_back(std::move(o));
}
@@ -298,18 +350,29 @@ namespace MoonWell::PlayerGuide
continue;
if (level + 2 < d.minLevel || level > d.maxLevel + 1)
continue;
if (!seen.insert(d.mapId).second)
// Resolve EJ id from custom_ej_instance. If the EJ does
// not know about this map, we cannot link to a card, so
// we skip the recommendation entirely. This keeps the
// contract that recommendations.instanceID is always a
// valid EJ id.
auto it = _ejByMapId.find(d.mapId);
if (it == _ejByMapId.end())
continue;
if (!seen.insert(it->second.ejId).second)
continue;
Recommendation r;
r.id = recId++;
r.type = "dungeon";
r.title = d.title;
r.instanceId = d.mapId;
r.priority = 100 -
r.id = recId++;
r.type = "dungeon";
r.title = it->second.name.empty() ? d.title
: it->second.name;
r.ejInstanceId = it->second.ejId; // JOURNALINSTANCE key
r.mapId = d.mapId; // WoW map id (auxiliary)
r.priority = 100 -
static_cast<uint32>(std::abs(int32(level) -
int32((d.minLevel + d.maxLevel) / 2)));
r.description = "Подходит для вашего текущего этапа.";
r.description = "Подходит для вашего текущего этапа.";
out.recommendations.push_back(std::move(r));
if (out.recommendations.size() >= 6)
@@ -496,15 +559,16 @@ namespace MoonWell::PlayerGuide
WriteUInt(s, "targetID", o.targetId, first);
WriteUInt(s, "order", o.order, first);
WriteOptUInt(s, "questID", o.questId, first);
WriteOptUInt(s, "questChainID", o.questChainId, first);
WriteOptUInt(s, "instanceID", o.instanceId, first);
WriteOptUInt(s, "encounterID", o.encounterId, first);
WriteOptUInt(s, "achievementID", o.achievementId, first);
WriteOptUInt(s, "factionID", o.factionId, first);
WriteOptUInt(s, "professionID", o.professionId, first);
WriteOptUInt(s, "itemID", o.itemId, first);
WriteOptUInt(s, "currencyID", o.currencyId, first);
WriteOptUInt(s, "questID", o.questId, first);
WriteOptUInt(s, "questChainID", o.questChainId, first);
WriteOptUInt(s, "ej_instanceID", o.ejInstanceId, first);
WriteOptUInt(s, "mapID", o.mapId, first);
WriteOptUInt(s, "encounterID", o.encounterId, first);
WriteOptUInt(s, "achievementID", o.achievementId, first);
WriteOptUInt(s, "factionID", o.factionId, first);
WriteOptUInt(s, "professionID", o.professionId, first);
WriteOptUInt(s, "itemID", o.itemId, first);
WriteOptUInt(s, "currencyID", o.currencyId, first);
s << '}';
return s.str();
}
@@ -551,10 +615,11 @@ namespace MoonWell::PlayerGuide
WriteString(s, "title", r.title, f);
if (!r.description.empty())
WriteString(s, "description", r.description, f);
WriteOptUInt(s, "instanceID", r.instanceId, f);
WriteOptUInt(s, "encounterID", r.encounterId, f);
WriteOptUInt(s, "questID", r.questId, f);
WriteOptUInt(s, "itemID", r.itemId, f);
WriteOptUInt(s, "ej_instanceID", r.ejInstanceId, f);
WriteOptUInt(s, "mapID", r.mapId, f);
WriteOptUInt(s, "encounterID", r.encounterId, f);
WriteOptUInt(s, "questID", r.questId, f);
WriteOptUInt(s, "itemID", r.itemId, f);
WriteUInt(s, "priority", r.priority, f);
s << '}';
firstRec = false;