warband (account-wide)
This commit is contained in:
@@ -18280,45 +18280,10 @@ void Player::_LoadDeclinedNames(PreparedQueryResult result)
|
||||
SetUpdateFieldValue(declinedNames.ModifyValue(&UF::DeclinedNames::Name, i), (*result)[i].GetString());
|
||||
}
|
||||
|
||||
void Player::_LoadArenaTeamInfo(PreparedQueryResult result)
|
||||
{
|
||||
// arenateamid, played_week, played_season, personal_rating
|
||||
uint16 personalRatingCache[] = { 0, 0, 0 };
|
||||
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint32 arenaTeamId = fields[0].GetUInt32();
|
||||
|
||||
ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId);
|
||||
if (!arenaTeam)
|
||||
{
|
||||
TC_LOG_ERROR("entities.player.loading", "Player::_LoadArenaTeamInfo: couldn't load arenateam {}", arenaTeamId);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8 arenaSlot = arenaTeam->GetSlot();
|
||||
ASSERT(arenaSlot < 3);
|
||||
|
||||
personalRatingCache[arenaSlot] = fields[4].GetUInt16();
|
||||
|
||||
SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_ID, arenaTeamId);
|
||||
SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_TYPE, arenaTeam->GetType());
|
||||
SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_MEMBER, (arenaTeam->GetCaptain() == GetGUID()) ? 0 : 1);
|
||||
SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_GAMES_WEEK, uint32(fields[1].GetUInt16()));
|
||||
SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_GAMES_SEASON, uint32(fields[2].GetUInt16()));
|
||||
SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_WINS_SEASON, uint32(fields[3].GetUInt16()));
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
for (uint8 slot = 0; slot <= 2; ++slot)
|
||||
{
|
||||
SetArenaTeamInfoField(slot, ARENA_TEAM_PERSONAL_RATING, uint32(personalRatingCache[slot]));
|
||||
}
|
||||
}
|
||||
// Player::_LoadArenaTeamInfo was removed along with its login query (PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO): every
|
||||
// value it set went through SetArenaTeamInfoField, which is an intentional empty stub in this fork, so the loader
|
||||
// read the arena rows and wrote them nowhere. Per-player arena team state is derived from ArenaTeam membership at
|
||||
// runtime instead.
|
||||
|
||||
void Player::_LoadEquipmentSets(PreparedQueryResult result)
|
||||
{
|
||||
@@ -19283,6 +19248,18 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
|
||||
if (!m_taxi.LoadTaxiMask(fields.taximask)) // must be before InitTaxiNodesForLevel
|
||||
TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player ({}) has invalid taximask ({}) in DB. Forced partial load.", GetGUID().ToString(), fields.taximask);
|
||||
|
||||
//WowCommunity
|
||||
// Warband (account-wide) taxi: merge the account mask into this character's mask and keep the account copy
|
||||
// so newly learned nodes can be written back to warband_taxi_mask on save.
|
||||
if (PreparedQueryResult warbandTaxiResult = holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_WARBAND_TAXI_MASK))
|
||||
m_taxi.LoadAccountTaxiMask((*warbandTaxiResult)[0].GetString());
|
||||
|
||||
// Other max-level characters on this account (excluding self): KillRewarder grants +5% XP per alt, capped at
|
||||
// 25%.
|
||||
if (PreparedQueryResult maxLevelCharsResult = holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_WARBAND_MAX_LEVEL_COUNT))
|
||||
_warbandMaxLevelCharCount = uint8(std::min<uint64>((*maxLevelCharsResult)[0].GetUInt64(), 5));
|
||||
//WowCommunity
|
||||
|
||||
uint32 extraflags = fields.extra_flags;
|
||||
|
||||
_LoadPetStable(fields.summonedPetNumber, holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS));
|
||||
@@ -21801,6 +21778,16 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
|
||||
_SaveAccountBankTabSettings(trans);
|
||||
_SaveAccountBankItems(trans);
|
||||
_SaveAccountBankCoinage(trans);
|
||||
// Warband taxi: only rewrite warband_taxi_mask when this character learned a new account-wide node; the mask
|
||||
// loaded at login is already the account's, so an untouched session has nothing to write.
|
||||
if (m_taxi.IsAccountTaximaskDirty())
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_WARBAND_TAXI_MASK);
|
||||
stmt->setUInt32(0, GetSession()->GetBattlenetAccountId());
|
||||
stmt->setString(1, m_taxi.SaveAccountTaxiMaskToString());
|
||||
trans->Append(stmt);
|
||||
m_taxi.ClearAccountTaximaskDirty();
|
||||
}
|
||||
for (auto const& [type, garrison] : _garrisons)
|
||||
garrison->SaveToDB(trans);
|
||||
//WowCommunity
|
||||
|
||||
@@ -3607,7 +3607,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
|
||||
void _LoadStoredAuraTeleportLocations(PreparedQueryResult result);
|
||||
bool _LoadHomeBind(PreparedQueryResult result);
|
||||
void _LoadDeclinedNames(PreparedQueryResult result);
|
||||
void _LoadArenaTeamInfo(PreparedQueryResult result);
|
||||
// _LoadArenaTeamInfo removed: SetArenaTeamInfoField is an empty stub, so it persisted nothing (see Player.cpp).
|
||||
void _LoadEquipmentSets(PreparedQueryResult result);
|
||||
void _LoadTransmogCustomSets(PreparedQueryResult result);
|
||||
void _LoadTransmogOutfits(PreparedQueryResult setsResult, PreparedQueryResult situationsResult, PreparedQueryResult slotsResult,
|
||||
|
||||
@@ -300,3 +300,51 @@ void PlayerTaxi::MergeAccountTaxiMask(TaxiMask const& accountMask)
|
||||
m_taximask[field] |= submask;
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerTaxi::LoadAccountTaxiMask(std::string const& data)
|
||||
{
|
||||
m_accountTaximask = LoadTaxiMaskFromString(data);
|
||||
m_accountTaximaskDirty = false;
|
||||
MergeAccountTaxiMask(m_accountTaximask);
|
||||
|
||||
// Backfill: nodes this character knew before account-wide taxi existed (or before this character ever saved
|
||||
// with the account mask wired up) become part of the account mask; anything the account already had is a no-op.
|
||||
for (TaxiNodesEntry const* node : sTaxiNodesStore)
|
||||
{
|
||||
if (node->GetFlags().HasFlag(TaxiNodeFlags::NotAccountWide))
|
||||
continue;
|
||||
|
||||
uint32 field = uint32((node->ID - 1) / (sizeof(TaxiMask::value_type) * 8));
|
||||
TaxiMask::value_type submask = TaxiMask::value_type(1 << ((node->ID - 1) % (sizeof(TaxiMask::value_type) * 8)));
|
||||
|
||||
if ((m_taximask[field] & submask) && !(m_accountTaximask[field] & submask))
|
||||
{
|
||||
m_accountTaximask[field] |= submask;
|
||||
m_accountTaximaskDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PlayerTaxi::SetAccountTaximaskNode(uint32 nodeidx)
|
||||
{
|
||||
TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(nodeidx);
|
||||
if (!node || node->GetFlags().HasFlag(TaxiNodeFlags::NotAccountWide))
|
||||
return false;
|
||||
|
||||
uint32 field = uint32((nodeidx - 1) / (sizeof(TaxiMask::value_type) * 8));
|
||||
TaxiMask::value_type submask = TaxiMask::value_type(1 << ((nodeidx - 1) % (sizeof(TaxiMask::value_type) * 8)));
|
||||
if (m_accountTaximask[field] & submask)
|
||||
return false;
|
||||
|
||||
m_accountTaximask[field] |= submask;
|
||||
m_accountTaximaskDirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string PlayerTaxi::SaveAccountTaxiMaskToString() const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
for (std::size_t i = 0; i < m_accountTaximask.size(); ++i)
|
||||
ss << uint32(m_accountTaximask[i]) << ' ';
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
@@ -50,6 +50,12 @@ class TC_GAME_API PlayerTaxi
|
||||
//WowCommunity
|
||||
static TaxiMask LoadTaxiMaskFromString(std::string const& data);
|
||||
void MergeAccountTaxiMask(TaxiMask const& accountMask);
|
||||
void LoadAccountTaxiMask(std::string const& data);
|
||||
bool SetAccountTaximaskNode(uint32 nodeidx);
|
||||
TaxiMask const& GetAccountTaxiMask() const { return m_accountTaximask; }
|
||||
bool IsAccountTaximaskDirty() const { return m_accountTaximaskDirty; }
|
||||
void ClearAccountTaximaskDirty() { m_accountTaximaskDirty = false; }
|
||||
std::string SaveAccountTaxiMaskToString() const;
|
||||
//WowCommunity
|
||||
|
||||
bool IsTaximaskNodeKnown(uint32 nodeidx) const
|
||||
@@ -96,6 +102,10 @@ class TC_GAME_API PlayerTaxi
|
||||
friend std::ostringstream& operator<<(std::ostringstream& ss, PlayerTaxi const& taxi);
|
||||
private:
|
||||
TaxiMask m_taximask;
|
||||
//WowCommunity
|
||||
TaxiMask m_accountTaximask; // warband (account-wide) copy, persisted to warband_taxi_mask on save
|
||||
bool m_accountTaximaskDirty = false;
|
||||
//WowCommunity
|
||||
std::deque<uint32> m_TaxiDestinations;
|
||||
uint32 m_flightMasterFactionId = 0;
|
||||
};
|
||||
|
||||
@@ -136,6 +136,8 @@ bool WorldSession::SendLearnNewTaxiNode(Creature* unit)
|
||||
|
||||
if (GetPlayer()->m_taxi.SetTaximaskNode(curloc))
|
||||
{
|
||||
GetPlayer()->m_taxi.SetAccountTaximaskNode(curloc); // warband: learned paths are shared account-wide
|
||||
|
||||
SendPacket(WorldPackets::Taxi::NewTaxiPath(curloc).Write());
|
||||
|
||||
WorldPackets::Taxi::TaxiNodeStatus data;
|
||||
@@ -153,7 +155,10 @@ bool WorldSession::SendLearnNewTaxiNode(Creature* unit)
|
||||
void WorldSession::SendDiscoverNewTaxiNode(uint32 nodeid)
|
||||
{
|
||||
if (GetPlayer()->m_taxi.SetTaximaskNode(nodeid))
|
||||
{
|
||||
GetPlayer()->m_taxi.SetAccountTaximaskNode(nodeid); // warband: discovered paths are shared account-wide
|
||||
SendPacket(WorldPackets::Taxi::NewTaxiPath(nodeid).Write());
|
||||
}
|
||||
}
|
||||
|
||||
void WorldSession::HandleActivateTaxiOpcode(WorldPackets::Taxi::ActivateTaxi& activateTaxi)
|
||||
|
||||
@@ -41,6 +41,16 @@ void WorldSession::HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTick
|
||||
SendPacket(response.Write());
|
||||
}
|
||||
|
||||
void WorldSession::HandleGmTicketAcknowledgeSurvey(WorldPackets::Ticket::GMTicketAcknowledgeSurvey& packet)
|
||||
{
|
||||
// The client sends this after the player dismisses the post-resolution survey for a case shown in
|
||||
// SMSG_GM_TICKET_CASE_STATUS (CaseID = GMTICKET_CASE_ID_* base + ticket id, see SupportMgr.h). Cases are
|
||||
// derived from open tickets only, so by the time the survey appears the ticket is already closed and drops
|
||||
// out of the next case list on its own - the acknowledgement is purely a client-side UI dismissal and needs
|
||||
// no server state or response. Logged so the case id remains traceable if the flow is ever extended.
|
||||
TC_LOG_DEBUG("network", "WorldSession::HandleGmTicketAcknowledgeSurvey: {} acknowledged survey for case {}.", GetPlayerInfo(), packet.CaseID);
|
||||
}
|
||||
|
||||
void WorldSession::HandleSubmitUserFeedback(WorldPackets::Ticket::SubmitUserFeedback& userFeedback)
|
||||
{
|
||||
if (userFeedback.IsSuggestion)
|
||||
|
||||
@@ -151,7 +151,7 @@ void OpcodeTable::InitializeClientOpcodes()
|
||||
DEFINE_HANDLER(CMSG_ACCEPT_WARGAME_INVITE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAcceptWargameInvite);
|
||||
DEFINE_HANDLER(CMSG_ACCOUNT_BANK_DEPOSIT_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAccountBankDepositMoney);
|
||||
DEFINE_HANDLER(CMSG_ACCOUNT_BANK_WITHDRAW_MONEY, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleAccountBankWithdrawMoney);
|
||||
DEFINE_HANDLER(CMSG_ACCOUNT_NOTIFICATION_ACKNOWLEDGED, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_ACCOUNT_NOTIFICATION_ACKNOWLEDGED, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleAccountNotificationAcknowledged);
|
||||
DEFINE_HANDLER(CMSG_ACCOUNT_STORE_BEGIN_PURCHASE_OR_REFUND, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_ACTIVATE_SOULBIND, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleActivateSoulbind);
|
||||
DEFINE_HANDLER(CMSG_ACTIVATE_TAXI, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleActivateTaxiOpcode);
|
||||
@@ -509,12 +509,12 @@ void OpcodeTable::InitializeClientOpcodes()
|
||||
DEFINE_HANDLER(CMSG_GET_PVP_OPTIONS_ENABLED, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetPVPOptionsEnabled);
|
||||
DEFINE_HANDLER(CMSG_GET_RAF_ACCOUNT_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetRafAccountInfo);
|
||||
DEFINE_HANDLER(CMSG_GET_REGIONWIDE_CHARACTER_RESTRICTION_AND_MAIL_DATA, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGetRegionwideCharacterRestrictionAndMailData);
|
||||
DEFINE_HANDLER(CMSG_GET_REMAINING_GAME_TIME, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_GET_REMAINING_GAME_TIME, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetRemainingGameTime);
|
||||
DEFINE_HANDLER(CMSG_GET_TROPHY_LIST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGetTrophyList);
|
||||
DEFINE_HANDLER(CMSG_GET_UNDELETE_CHARACTER_COOLDOWN_STATUS, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleGetUndeleteCooldownStatus);
|
||||
DEFINE_HANDLER(CMSG_GET_VAS_ACCOUNT_CHARACTER_LIST, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleGetVasAccountCharacterList);
|
||||
DEFINE_HANDLER(CMSG_GET_VAS_TRANSFER_TARGET_REALM_LIST, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleGetVasTransferTargetRealmList);
|
||||
DEFINE_HANDLER(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
|
||||
DEFINE_HANDLER(CMSG_GM_TICKET_ACKNOWLEDGE_SURVEY, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGmTicketAcknowledgeSurvey);
|
||||
DEFINE_HANDLER(CMSG_GM_TICKET_GET_CASE_STATUS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGMTicketGetCaseStatusOpcode);
|
||||
DEFINE_HANDLER(CMSG_GM_TICKET_GET_SYSTEM_STATUS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleGMTicketSystemStatusOpcode);
|
||||
DEFINE_HANDLER(CMSG_GOSSIP_REFRESH_OPTIONS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleGossipRefreshOptions);
|
||||
|
||||
@@ -1198,6 +1198,7 @@ namespace WorldPackets
|
||||
class SupportTicketSubmitComplaint;
|
||||
class BugReport;
|
||||
class Complaint;
|
||||
class GMTicketAcknowledgeSurvey;
|
||||
}
|
||||
|
||||
namespace Token
|
||||
@@ -1822,6 +1823,7 @@ public:
|
||||
// GM Ticket opcodes
|
||||
void HandleGMTicketGetCaseStatusOpcode(WorldPackets::Ticket::GMTicketGetCaseStatus& packet);
|
||||
void HandleGMTicketSystemStatusOpcode(WorldPackets::Ticket::GMTicketGetSystemStatus& packet);
|
||||
void HandleGmTicketAcknowledgeSurvey(WorldPackets::Ticket::GMTicketAcknowledgeSurvey& packet);
|
||||
void HandleSubmitUserFeedback(WorldPackets::Ticket::SubmitUserFeedback& userFeedback);
|
||||
void HandleSupportTicketSubmitComplaint(WorldPackets::Ticket::SupportTicketSubmitComplaint& packet);
|
||||
void HandleBugReportOpcode(WorldPackets::Ticket::BugReport& bugReport);
|
||||
|
||||
Reference in New Issue
Block a user