mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-03-01 06:55:59 +00:00
Merge branch 'master' into Playerbot
# Conflicts: # src/server/game/Entities/Unit/Unit.cpp
This commit is contained in:
@@ -62,6 +62,7 @@ DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
|
||||
DBCStorage <CinematicCameraEntry> sCinematicCameraStore(CinematicCameraEntryfmt);
|
||||
DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt);
|
||||
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
|
||||
DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt);
|
||||
DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore(CreatureFamilyfmt);
|
||||
DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore(CreatureModelDatafmt);
|
||||
DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore(CreatureSpellDatafmt);
|
||||
@@ -290,6 +291,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
LOAD_DBC(sCinematicCameraStore, "CinematicCamera.dbc", "cinematiccamera_dbc");
|
||||
LOAD_DBC(sCinematicSequencesStore, "CinematicSequences.dbc", "cinematicsequences_dbc");
|
||||
LOAD_DBC(sCreatureDisplayInfoStore, "CreatureDisplayInfo.dbc", "creaturedisplayinfo_dbc");
|
||||
LOAD_DBC(sCreatureDisplayInfoExtraStore, "CreatureDisplayInfoExtra.dbc", "creaturedisplayinfoextra_dbc");
|
||||
LOAD_DBC(sCreatureFamilyStore, "CreatureFamily.dbc", "creaturefamily_dbc");
|
||||
LOAD_DBC(sCreatureModelDataStore, "CreatureModelData.dbc", "creaturemodeldata_dbc");
|
||||
LOAD_DBC(sCreatureSpellDataStore, "CreatureSpellData.dbc", "creaturespelldata_dbc");
|
||||
|
||||
@@ -95,6 +95,7 @@ extern DBCStorage <ChrRacesEntry> sChrRacesStore;
|
||||
extern DBCStorage <CinematicCameraEntry> sCinematicCameraStore;
|
||||
extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore;
|
||||
extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
|
||||
extern DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore;
|
||||
extern DBCStorage <CreatureFamilyEntry> sCreatureFamilyStore;
|
||||
extern DBCStorage <CreatureModelDataEntry> sCreatureModelDataStore;
|
||||
extern DBCStorage <CreatureSpellDataEntry> sCreatureSpellDataStore;
|
||||
|
||||
@@ -329,7 +329,31 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
|
||||
|
||||
// GAMEOBJECT_BYTES_1, index at 0, 1, 2 and 3
|
||||
SetGoType(GameobjectTypes(goinfo->type));
|
||||
SetGoState(go_state);
|
||||
|
||||
if (IsInstanceGameobject())
|
||||
{
|
||||
switch (GetStateSavedOnInstance())
|
||||
{
|
||||
case 0:
|
||||
SetGoState(GO_STATE_READY);
|
||||
SwitchDoorOrButton(true);
|
||||
break;
|
||||
case 1:
|
||||
SetGoState(GO_STATE_READY);
|
||||
break;
|
||||
case 2:
|
||||
SetGoState(GO_STATE_ACTIVE_ALTERNATIVE);
|
||||
break;
|
||||
default:
|
||||
SetGoState(go_state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetGoState(go_state);
|
||||
}
|
||||
|
||||
SetGoArtKit(artKit);
|
||||
|
||||
SetDisplayId(goinfo->displayId);
|
||||
@@ -2432,6 +2456,146 @@ void GameObject::SetGoState(GOState state)
|
||||
else if (state == GO_STATE_READY)
|
||||
EnableCollision(!startOpen);*/
|
||||
}
|
||||
/* Whenever a gameobject inside an instance changes
|
||||
* save it's state on the database to be loaded properly
|
||||
* on server restart or crash.
|
||||
*/
|
||||
if (IsInstanceGameobject() && IsAbleToSaveOnDb())
|
||||
{
|
||||
// Save the gameobject state on the Database
|
||||
if (!FindStateSavedOnInstance())
|
||||
{
|
||||
SaveInstanceData(GameobjectStateToInt(&state));
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateInstanceData(GameobjectStateToInt(&state));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GameObject::IsInstanceGameobject()
|
||||
{
|
||||
// Avoid checking for unecessary gameobjects whose
|
||||
// states don't matter for the dungeon progression
|
||||
if (!ValidateGameobjectType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (auto* map = FindMap())
|
||||
{
|
||||
if (map->IsDungeon() || map->IsRaid())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GameObject::ValidateGameobjectType()
|
||||
{
|
||||
switch (m_goInfo->type)
|
||||
{
|
||||
case GAMEOBJECT_TYPE_DOOR:
|
||||
case GAMEOBJECT_TYPE_BUTTON:
|
||||
case GAMEOBJECT_TYPE_TRAP:
|
||||
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
|
||||
case GAMEOBJECT_TYPE_TRAPDOOR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 GameObject::GameobjectStateToInt(GOState* state)
|
||||
{
|
||||
uint8 m_state = 3;
|
||||
|
||||
if (state)
|
||||
{
|
||||
switch (*state)
|
||||
{
|
||||
case GO_STATE_ACTIVE:
|
||||
m_state = 0;
|
||||
return m_state;
|
||||
case GO_STATE_READY:
|
||||
m_state = 1;
|
||||
return m_state;
|
||||
case GO_STATE_ACTIVE_ALTERNATIVE:
|
||||
m_state = 2;
|
||||
return m_state;
|
||||
}
|
||||
}
|
||||
|
||||
// Returning any value that is not one of the specified ones
|
||||
// Which will default into the invalid part of the switch
|
||||
return m_state;
|
||||
}
|
||||
|
||||
bool GameObject::IsAbleToSaveOnDb()
|
||||
{
|
||||
return m_saveStateOnDb;
|
||||
}
|
||||
|
||||
void GameObject::UpdateSaveToDb(bool enable)
|
||||
{
|
||||
m_saveStateOnDb = enable;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
SavingStateOnDB();
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::SavingStateOnDB()
|
||||
{
|
||||
if (IsInstanceGameobject())
|
||||
{
|
||||
GOState param = GetGoState();
|
||||
if (!FindStateSavedOnInstance())
|
||||
{
|
||||
SaveInstanceData(GameobjectStateToInt(¶m));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::SaveInstanceData(uint8 state)
|
||||
{
|
||||
uint32 id = GetInstanceId();
|
||||
uint32 guid = GetSpawnId();
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INSERT_INSTANCE_SAVED_DATA);
|
||||
stmt->SetData(0, id);
|
||||
stmt->SetData(1, guid);
|
||||
stmt->SetData(2, state);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
sObjectMgr->NewInstanceSavedGameobjectState(id, guid, state);
|
||||
}
|
||||
|
||||
void GameObject::UpdateInstanceData(uint8 state)
|
||||
{
|
||||
uint32 id = GetInstanceId();
|
||||
uint32 guid = GetSpawnId();
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPDATE_INSTANCE_SAVED_DATA);
|
||||
stmt->SetData(0, state);
|
||||
stmt->SetData(1, guid);
|
||||
stmt->SetData(2, id);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
|
||||
sObjectMgr->SetInstanceSavedGameobjectState(id, guid, state);
|
||||
}
|
||||
|
||||
uint8 GameObject::GetStateSavedOnInstance()
|
||||
{
|
||||
return sObjectMgr->GetInstanceSavedGameobjectState(GetInstanceId(), GetSpawnId());
|
||||
}
|
||||
|
||||
bool GameObject::FindStateSavedOnInstance()
|
||||
{
|
||||
return sObjectMgr->FindInstanceSavedGameobjectState(GetInstanceId(), GetSpawnId());
|
||||
}
|
||||
|
||||
void GameObject::SetDisplayId(uint32 displayid)
|
||||
|
||||
@@ -1011,6 +1011,25 @@ public:
|
||||
|
||||
static std::unordered_map<int, goEventFlag> gameObjectToEventFlag; // Gameobject -> event flag
|
||||
|
||||
void SaveInstanceData(uint8 state);
|
||||
void UpdateInstanceData(uint8 state);
|
||||
bool FindStateSavedOnInstance();
|
||||
bool ValidateGameobjectType();
|
||||
uint8 GetStateSavedOnInstance();
|
||||
bool IsInstanceGameobject();
|
||||
uint8 GameobjectStateToInt(GOState* state);
|
||||
|
||||
/* A check to verify if this object is available to be saved on the DB when
|
||||
* a state change occurs
|
||||
*/
|
||||
bool IsAbleToSaveOnDb();
|
||||
|
||||
/* Enable or Disable the ability to save on the database this gameobject's state
|
||||
* whenever it changes
|
||||
*/
|
||||
void UpdateSaveToDb(bool enable);
|
||||
|
||||
void SavingStateOnDB();
|
||||
protected:
|
||||
bool AIM_Initialize();
|
||||
GameObjectModel* CreateModel();
|
||||
@@ -1067,5 +1086,7 @@ private:
|
||||
return IsInRange(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), dist2compare);
|
||||
}
|
||||
GameObjectAI* m_AI;
|
||||
|
||||
bool m_saveStateOnDb = false;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -181,6 +181,16 @@ void Player::SendResetFailedNotify(uint32 mapid)
|
||||
GetSession()->SendPacket(&data);
|
||||
}
|
||||
|
||||
void DeleteInstanceSavedData(uint32 instanceId)
|
||||
{
|
||||
if (instanceId)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DELETE_INSTANCE_SAVED_DATA);
|
||||
stmt->SetData(0, instanceId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset all solo instances and optionally send a message on success for each
|
||||
void Player::ResetInstances(ObjectGuid guid, uint8 method, bool isRaid)
|
||||
{
|
||||
@@ -198,7 +208,9 @@ void Player::ResetInstances(ObjectGuid guid, uint8 method, bool isRaid)
|
||||
InstanceSave* instanceSave = itr->second.save;
|
||||
MapEntry const* entry = sMapStore.LookupEntry(itr->first);
|
||||
if (!entry || entry->IsRaid() || !instanceSave->CanReset())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Map* map = sMapMgr->FindMap(instanceSave->GetMapId(), instanceSave->GetInstanceId());
|
||||
if (!map || map->ToInstanceMap()->Reset(method))
|
||||
@@ -207,10 +219,16 @@ void Player::ResetInstances(ObjectGuid guid, uint8 method, bool isRaid)
|
||||
toUnbind.push_back(instanceSave);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
}
|
||||
|
||||
DeleteInstanceSavedData(instanceSave->GetInstanceId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
{
|
||||
sInstanceSaveMgr->UnbindAllFor(*itr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case INSTANCE_RESET_CHANGE_DIFFICULTY:
|
||||
@@ -225,7 +243,9 @@ void Player::ResetInstances(ObjectGuid guid, uint8 method, bool isRaid)
|
||||
InstanceSave* instanceSave = itr->second.save;
|
||||
MapEntry const* entry = sMapStore.LookupEntry(itr->first);
|
||||
if (!entry || entry->IsRaid() != isRaid || !instanceSave->CanReset())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Map* map = sMapMgr->FindMap(instanceSave->GetMapId(), instanceSave->GetInstanceId());
|
||||
if (!map || map->ToInstanceMap()->Reset(method))
|
||||
@@ -234,7 +254,11 @@ void Player::ResetInstances(ObjectGuid guid, uint8 method, bool isRaid)
|
||||
toUnbind.push_back(instanceSave);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
}
|
||||
|
||||
DeleteInstanceSavedData(instanceSave->GetInstanceId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
sInstanceSaveMgr->UnbindAllFor(*itr);
|
||||
@@ -262,6 +286,8 @@ void Player::ResetInstances(ObjectGuid guid, uint8 method, bool isRaid)
|
||||
}
|
||||
//else
|
||||
// p->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
|
||||
DeleteInstanceSavedData(instanceSave->GetInstanceId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
sInstanceSaveMgr->PlayerUnbindInstance(p->GetGUID(), (*itr)->GetMapId(), (*itr)->GetDifficulty(), true, p);
|
||||
|
||||
@@ -20713,3 +20713,58 @@ bool Unit::SetCannotReachTarget(bool cannotReach, bool /*isChase = true*/)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Unit::IsInDisallowedMountForm() const
|
||||
{
|
||||
if (SpellInfo const* transformSpellInfo = sSpellMgr->GetSpellInfo(getTransForm()))
|
||||
{
|
||||
if (transformSpellInfo->HasAttribute(SPELL_ATTR0_ALLOW_WHILE_MOUNTED))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ShapeshiftForm form = GetShapeshiftForm())
|
||||
{
|
||||
SpellShapeshiftEntry const* shapeshift = sSpellShapeshiftStore.LookupEntry(form);
|
||||
if (!shapeshift)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(shapeshift->flags1 & 0x1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetDisplayId() == GetNativeDisplayId())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CreatureDisplayInfoEntry const* display = sCreatureDisplayInfoStore.LookupEntry(GetDisplayId());
|
||||
if (!display)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureDisplayInfoExtraEntry const* displayExtra = sCreatureDisplayInfoExtraStore.LookupEntry(display->ExtendedDisplayInfoID);
|
||||
if (!displayExtra)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
CreatureModelDataEntry const* model = sCreatureModelDataStore.LookupEntry(display->ModelId);
|
||||
ChrRacesEntry const* race = sChrRacesStore.LookupEntry(displayExtra->DisplayRaceID);
|
||||
|
||||
if (model && !(model->HasFlag(CREATURE_MODEL_DATA_FLAGS_CAN_MOUNT)))
|
||||
{
|
||||
if (race && !(race->HasFlag(CHRRACES_FLAGS_CAN_MOUNT)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2036,18 +2036,13 @@ public:
|
||||
SetByteValue(UNIT_FIELD_BYTES_2, 3, form);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IsInFeralForm() const
|
||||
[[nodiscard]] bool IsInFeralForm() const
|
||||
{
|
||||
ShapeshiftForm form = GetShapeshiftForm();
|
||||
return form == FORM_CAT || form == FORM_BEAR || form == FORM_DIREBEAR || form == FORM_GHOSTWOLF; // Xinef: added shamans Ghost Wolf, should behave exactly like druid forms
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool IsInDisallowedMountForm() const
|
||||
{
|
||||
ShapeshiftForm form = GetShapeshiftForm();
|
||||
return form != FORM_NONE && form != FORM_BATTLESTANCE && form != FORM_BERSERKERSTANCE && form != FORM_DEFENSIVESTANCE &&
|
||||
form != FORM_SHADOW && form != FORM_STEALTH && form != FORM_UNDEAD;
|
||||
}
|
||||
[[nodiscard]] bool IsInDisallowedMountForm() const;
|
||||
|
||||
float m_modMeleeHitChance;
|
||||
float m_modRangedHitChance;
|
||||
@@ -2129,7 +2124,7 @@ public:
|
||||
void AddInterruptMask(uint32 mask) { m_interruptMask |= mask; }
|
||||
void UpdateInterruptMask();
|
||||
|
||||
uint32 GetDisplayId() { return GetUInt32Value(UNIT_FIELD_DISPLAYID); }
|
||||
[[nodiscard]] uint32 GetDisplayId() const { return GetUInt32Value(UNIT_FIELD_DISPLAYID); }
|
||||
virtual void SetDisplayId(uint32 modelId);
|
||||
[[nodiscard]] uint32 GetNativeDisplayId() const { return GetUInt32Value(UNIT_FIELD_NATIVEDISPLAYID); }
|
||||
void RestoreDisplayId();
|
||||
|
||||
@@ -9762,6 +9762,72 @@ uint32 ObjectMgr::GetQuestMoneyReward(uint8 level, uint32 questMoneyDifficulty)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadInstanceSavedGameobjectStateData()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SELECT_INSTANCE_SAVED_DATA);
|
||||
PreparedQueryResult result = CharacterDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
// There's no gameobject with this GUID saved on the DB
|
||||
LOG_INFO("sql.sql", ">> Loaded 0 Instance saved gameobject state data. DB table `instance_saved_go_state_data` is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
Field* fields;
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
fields = result->Fetch();
|
||||
GameobjectInstanceSavedStateList.push_back({ fields[0].Get<uint32>(), fields[1].Get<uint32>(), fields[2].Get<unsigned short>() });
|
||||
count++;
|
||||
} while (result->NextRow());
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded {} instance saved gameobject state data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
uint8 ObjectMgr::GetInstanceSavedGameobjectState(uint32 id, uint32 guid)
|
||||
{
|
||||
for (auto it = GameobjectInstanceSavedStateList.begin(); it != GameobjectInstanceSavedStateList.end(); it++)
|
||||
{
|
||||
if (it->m_guid == guid && it->m_instance == id)
|
||||
{
|
||||
return it->m_state;
|
||||
}
|
||||
}
|
||||
return 3; // Any state higher than 2 to get the default state
|
||||
}
|
||||
|
||||
bool ObjectMgr::FindInstanceSavedGameobjectState(uint32 id, uint32 guid)
|
||||
{
|
||||
for (auto it = GameobjectInstanceSavedStateList.begin(); it != GameobjectInstanceSavedStateList.end(); it++)
|
||||
{
|
||||
if (it->m_guid == guid && it->m_instance == id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ObjectMgr::SetInstanceSavedGameobjectState(uint32 id, uint32 guid, uint8 state)
|
||||
{
|
||||
for (auto it = GameobjectInstanceSavedStateList.begin(); it != GameobjectInstanceSavedStateList.end(); it++)
|
||||
{
|
||||
if (it->m_guid == guid && it->m_instance == id)
|
||||
{
|
||||
it->m_state = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ObjectMgr::NewInstanceSavedGameobjectState(uint32 id, uint32 guid, uint8 state)
|
||||
{
|
||||
GameobjectInstanceSavedStateList.push_back({ id, guid, state });
|
||||
}
|
||||
|
||||
void ObjectMgr::SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint32 reqPlayTime, uint32 rewardMoneyA, uint32 rewardMoneyH, uint32 rewardItemA, uint32 rewardItemCountA, uint32 rewardItemH, uint32 rewardItemCountH, std::string subject, std::string body, uint8 active) const
|
||||
{
|
||||
if (active)
|
||||
|
||||
@@ -1411,6 +1411,11 @@ public:
|
||||
[[nodiscard]] uint32 GetQuestMoneyReward(uint8 level, uint32 questMoneyDifficulty) const;
|
||||
void SendServerMail(Player* player, uint32 id, uint32 reqLevel, uint32 reqPlayTime, uint32 rewardMoneyA, uint32 rewardMoneyH, uint32 rewardItemA, uint32 rewardItemCountA, uint32 rewardItemH, uint32 rewardItemCountH, std::string subject, std::string body, uint8 active) const;
|
||||
|
||||
void LoadInstanceSavedGameobjectStateData();
|
||||
bool FindInstanceSavedGameobjectState(uint32 id, uint32 guid);
|
||||
uint8 GetInstanceSavedGameobjectState(uint32 id, uint32 guid);
|
||||
void SetInstanceSavedGameobjectState(uint32 id, uint32 guid, uint8 state);
|
||||
void NewInstanceSavedGameobjectState(uint32 id, uint32 guid, uint8 state);
|
||||
private:
|
||||
// first free id for selected id type
|
||||
uint32 _auctionId; // pussywizard: accessed by a single thread
|
||||
@@ -1580,6 +1585,14 @@ private:
|
||||
std::set<uint32> _transportMaps; // Helper container storing map ids that are for transports only, loaded from gameobject_template
|
||||
|
||||
QuestMoneyRewardStore _questMoneyRewards;
|
||||
|
||||
struct GameobjectInstanceSavedState
|
||||
{
|
||||
uint32 m_instance;
|
||||
uint32 m_guid;
|
||||
unsigned short m_state;
|
||||
};
|
||||
std::vector<GameobjectInstanceSavedState> GameobjectInstanceSavedStateList;
|
||||
};
|
||||
|
||||
#define sObjectMgr ObjectMgr::instance()
|
||||
|
||||
@@ -744,6 +744,8 @@ void Group::Disband(bool hideDestroy /* = false */)
|
||||
sScriptMgr->OnGroupDisband(this);
|
||||
|
||||
Player* player;
|
||||
uint32 instanceId = 0;
|
||||
|
||||
for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
|
||||
{
|
||||
if (!isBGGroup() && !isBFGroup())
|
||||
@@ -753,6 +755,11 @@ void Group::Disband(bool hideDestroy /* = false */)
|
||||
|
||||
player = ObjectAccessor::FindConnectedPlayer(citr->guid);
|
||||
|
||||
if (player && !instanceId && !isBGGroup() && !isBFGroup())
|
||||
{
|
||||
instanceId = player->GetInstanceId();
|
||||
}
|
||||
|
||||
_homebindIfInstance(player);
|
||||
if (!isBGGroup() && !isBFGroup())
|
||||
Player::ResetInstances(citr->guid, INSTANCE_RESET_GROUP_LEAVE, false);
|
||||
@@ -821,6 +828,14 @@ void Group::Disband(bool hideDestroy /* = false */)
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
// Cleaning up instance saved data for gameobjects when a group is disbanded
|
||||
if (instanceId)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DELETE_INSTANCE_SAVED_DATA);
|
||||
stmt->SetData(0, instanceId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
sGroupMgr->RemoveGroup(this);
|
||||
delete this;
|
||||
}
|
||||
@@ -2022,6 +2037,16 @@ void Group::SetRaidDifficulty(Difficulty difficulty)
|
||||
}
|
||||
}
|
||||
|
||||
void Group::ResetInstanceSavedGameobjects(uint32 instanceId)
|
||||
{
|
||||
if (instanceId)
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DELETE_INSTANCE_SAVED_DATA);
|
||||
stmt->SetData(0, instanceId);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
void Group::ResetInstances(uint8 method, bool isRaid, Player* leader)
|
||||
{
|
||||
if (isBGGroup() || isBFGroup() || isLFGGroup())
|
||||
@@ -2049,7 +2074,11 @@ void Group::ResetInstances(uint8 method, bool isRaid, Player* leader)
|
||||
toUnbind.push_back(instanceSave);
|
||||
}
|
||||
else
|
||||
{
|
||||
leader->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
}
|
||||
|
||||
ResetInstanceSavedGameobjects(instanceSave->GetInstanceId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
sInstanceSaveMgr->UnbindAllFor(*itr);
|
||||
@@ -2073,7 +2102,11 @@ void Group::ResetInstances(uint8 method, bool isRaid, Player* leader)
|
||||
toUnbind.push_back(instanceSave);
|
||||
}
|
||||
else
|
||||
{
|
||||
leader->SendResetInstanceFailed(0, instanceSave->GetMapId());
|
||||
}
|
||||
|
||||
ResetInstanceSavedGameobjects(instanceSave->GetInstanceId());
|
||||
}
|
||||
for (std::vector<InstanceSave*>::const_iterator itr = toUnbind.begin(); itr != toUnbind.end(); ++itr)
|
||||
sInstanceSaveMgr->UnbindAllFor(*itr);
|
||||
|
||||
@@ -318,9 +318,10 @@ public:
|
||||
uint32 GetDifficultyChangePreventionTime() const;
|
||||
DifficultyPreventionChangeType GetDifficultyChangePreventionReason() const { return _difficultyChangePreventionType; }
|
||||
void SetDifficultyChangePrevention(DifficultyPreventionChangeType type);
|
||||
|
||||
void DoForAllMembers(std::function<void(Player*)> const& worker);
|
||||
|
||||
// Reset Instance Gameobjects
|
||||
void ResetInstanceSavedGameobjects(uint32 instanceId);
|
||||
protected:
|
||||
void _homebindIfInstance(Player* player);
|
||||
void _cancelHomebindIfInstance(Player* player);
|
||||
|
||||
@@ -238,6 +238,12 @@ bool InstanceSave::RemovePlayer(ObjectGuid guid, InstanceSaveMgr* ism)
|
||||
return deleteSave;
|
||||
}
|
||||
|
||||
void InstanceSaveMgr::SanitizeInstanceSavedData()
|
||||
{
|
||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SANITIZE_INSTANCE_SAVED_DATA);
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void InstanceSaveMgr::LoadInstances()
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
@@ -270,6 +276,9 @@ void InstanceSaveMgr::LoadInstances()
|
||||
LoadInstanceSaves();
|
||||
LoadCharacterBinds();
|
||||
|
||||
// Sanitize pending rows on Instance_saved_data for data that wasn't deleted properly
|
||||
SanitizeInstanceSavedData();
|
||||
|
||||
LOG_INFO("server.loading", ">> Loaded instances and binds in {} ms", GetMSTimeDiffToNow(oldMSTime));
|
||||
LOG_INFO("server.loading", " ");
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ public:
|
||||
void CopyBinds(ObjectGuid from, ObjectGuid to, Player* toPlr = nullptr);
|
||||
void UnbindAllFor(InstanceSave* save);
|
||||
|
||||
void SanitizeInstanceSavedData();
|
||||
protected:
|
||||
static uint16 ResetTimeDelay[];
|
||||
static PlayerBindStorage playerBindStorage;
|
||||
|
||||
@@ -1200,13 +1200,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY);
|
||||
});
|
||||
|
||||
// Shadow Weaving
|
||||
ApplySpellFix({ 15257, 15331, 15332 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
|
||||
spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_PROC_TRIGGER_SPELL;
|
||||
});
|
||||
|
||||
// Hymn of Hope
|
||||
ApplySpellFix({ 64904 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
|
||||
@@ -1588,6 +1588,9 @@ void World::SetInitialWorldSettings()
|
||||
LOG_INFO("server.loading", "Loading Instance Template...");
|
||||
sObjectMgr->LoadInstanceTemplate();
|
||||
|
||||
LOG_INFO("server.loading", "Loading Instance Saved Gameobject State Data...");
|
||||
sObjectMgr->LoadInstanceSavedGameobjectStateData();
|
||||
|
||||
LOG_INFO("server.loading", "Load Character Cache...");
|
||||
sCharacterCache->LoadCharacterCacheStorage();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user