/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* 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 2 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 .
*/
#include "SceneObject.h"
#include "GameTime.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "PhasingHandler.h"
#include "Player.h"
#include "SpellAuras.h"
#include "UpdateData.h"
#include "Util.h"
SceneObject::SceneObject() : WorldObject(false)
{
m_objectType |= TYPEMASK_SCENEOBJECT;
m_objectTypeId = TYPEID_SCENEOBJECT;
m_updateFlag.Stationary = true;
m_updateFlag.SceneObject = true;
m_entityFragments.Add(WowCS::EntityFragment::Tag_SceneObject, false);
}
SceneObject::~SceneObject() = default;
void SceneObject::AddToWorld()
{
if (!IsInWorld())
{
GetMap()->GetObjectsStore().Insert(this);
WorldObject::AddToWorld();
}
}
void SceneObject::RemoveFromWorld()
{
if (IsInWorld())
{
WorldObject::RemoveFromWorld();
GetMap()->GetObjectsStore().Remove(this);
}
}
void SceneObject::Update(uint32 diff)
{
WorldObject::Update(diff);
if (ShouldBeRemoved())
Remove();
}
void SceneObject::Remove()
{
if (IsInWorld())
AddObjectToRemoveList();
}
bool SceneObject::ShouldBeRemoved() const
{
Unit* creator = ObjectAccessor::GetUnit(*this, GetOwnerGUID());
if (!creator)
return true;
if (!_createdBySpellCast.IsEmpty())
{
// search for a dummy aura on creator
Aura const* linkedAura = creator->GetAura(_createdBySpellCast.GetEntry(), [this](Aura const* aura)
{
return aura->GetCastId() == _createdBySpellCast;
});
if (!linkedAura)
return true;
}
return false;
}
SceneObject* SceneObject::CreateSceneObject(uint32 sceneId, Unit* creator, Position const& pos, ObjectGuid privateObjectOwner)
{
SceneTemplate const* sceneTemplate = sObjectMgr->GetSceneTemplate(sceneId);
if (!sceneTemplate)
return nullptr;
ObjectGuid::LowType lowGuid = creator->GetMap()->GenerateLowGuid();
SceneObject* sceneObject = new SceneObject();
if (!sceneObject->Create(lowGuid, SceneType::Normal, sceneId, sceneTemplate ? sceneTemplate->ScenePackageId : 0, creator->GetMap(), creator, pos, privateObjectOwner))
{
delete sceneObject;
return nullptr;
}
return sceneObject;
}
bool SceneObject::Create(ObjectGuid::LowType lowGuid, SceneType type, uint32 sceneId, uint32 scriptPackageId, Map* map, Unit* creator,
Position const& pos, ObjectGuid privateObjectOwner)
{
SetMap(map);
Relocate(pos);
RelocateStationaryPosition(pos);
SetPrivateObjectOwner(privateObjectOwner);
Object::_Create(ObjectGuid::Create(GetMapId(), sceneId, lowGuid));
PhasingHandler::InheritPhaseShift(this, creator);
UpdatePositionData();
SetZoneScript();
SetEntry(scriptPackageId);
SetObjectScale(1.0f);
SetUpdateFieldValue(m_values.ModifyValue(&SceneObject::m_sceneObjectData).ModifyValue(&UF::SceneObjectData::ScriptPackageID), scriptPackageId);
SetUpdateFieldValue(m_values.ModifyValue(&SceneObject::m_sceneObjectData).ModifyValue(&UF::SceneObjectData::RndSeedVal), GameTime::GetGameTimeMS());
SetUpdateFieldValue(m_values.ModifyValue(&SceneObject::m_sceneObjectData).ModifyValue(&UF::SceneObjectData::CreatedBy), creator->GetGUID());
SetUpdateFieldValue(m_values.ModifyValue(&SceneObject::m_sceneObjectData).ModifyValue(&UF::SceneObjectData::SceneType), AsUnderlyingType(type));
if (!GetMap()->AddToMap(this))
return false;
return true;
}
void SceneObject::BuildValuesCreate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const
{
m_objectData->WriteCreate(*data, flags, this, target);
m_sceneObjectData->WriteCreate(*data, flags, this, target);
}
void SceneObject::BuildValuesUpdate(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const
{
*data << uint32(m_values.GetChangedObjectTypeMask());
if (m_values.HasChanged(TYPEID_OBJECT))
m_objectData->WriteUpdate(*data, flags, this, target);
if (m_values.HasChanged(TYPEID_SCENEOBJECT))
m_sceneObjectData->WriteUpdate(*data, flags, this, target);
}
void SceneObject::BuildValuesUpdateForPlayerWithMask(UpdateData* data, UF::ObjectData::Mask const& requestedObjectMask,
UF::SceneObjectData::Mask const& requestedSceneObjectMask, Player const* target) const
{
UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target);
UpdateMask valuesMask;
if (requestedObjectMask.IsAnySet())
valuesMask.Set(TYPEID_OBJECT);
if (requestedSceneObjectMask.IsAnySet())
valuesMask.Set(TYPEID_SCENEOBJECT);
ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
std::size_t sizePos = buffer.wpos();
buffer << uint32(0);
BuildEntityFragmentsForValuesUpdateForPlayerWithMask(&buffer, flags);
buffer << uint32(valuesMask.GetBlock(0));
if (valuesMask[TYPEID_OBJECT])
m_objectData->WriteUpdate(buffer, requestedObjectMask, true, this, target);
if (valuesMask[TYPEID_SCENEOBJECT])
m_sceneObjectData->WriteUpdate(buffer, requestedSceneObjectMask, true, this, target);
buffer.put(sizePos, buffer.wpos() - sizePos - 4);
data->AddUpdateBlock();
}
void SceneObject::ValuesUpdateForPlayerWithMaskSender::operator()(Player const* player) const
{
UpdateData udata(Owner->GetMapId());
WorldPacket packet;
Owner->BuildValuesUpdateForPlayerWithMask(&udata, ObjectMask.GetChangesMask(), SceneObjectMask.GetChangesMask(), player);
udata.BuildPacket(&packet);
player->SendDirectMessage(&packet);
}
void SceneObject::ClearUpdateMask(bool remove)
{
m_values.ClearChangesMask(&SceneObject::m_sceneObjectData);
Object::ClearUpdateMask(remove);
}