Merge branch 'master' into Playerbot

# Conflicts:
#	src/server/game/Entities/Unit/Unit.cpp
This commit is contained in:
郑佩茹
2022-05-25 08:51:01 -06:00
33 changed files with 656 additions and 28 deletions

View File

@@ -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(&param));
}
}
}
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)

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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();