* Even more restructuring of the game library.

--HG--
branch : trunk
This commit is contained in:
XTZGZoReX
2010-06-06 22:55:56 +02:00
parent 840d4ab99d
commit 62200e8d02
169 changed files with 0 additions and 0 deletions
-243
View File
@@ -1,243 +0,0 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Corpse.h"
#include "Player.h"
#include "UpdateMask.h"
#include "ObjectAccessor.h"
#include "Database/DatabaseEnv.h"
#include "Opcodes.h"
#include "GossipDef.h"
#include "World.h"
Corpse::Corpse(CorpseType type) : WorldObject()
, m_type(type)
{
m_objectType |= TYPEMASK_CORPSE;
m_objectTypeId = TYPEID_CORPSE;
m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION);
m_valuesCount = CORPSE_END;
m_time = time(NULL);
lootForBody = false;
if (type != CORPSE_BONES)
m_isWorldObject = true;
}
Corpse::~Corpse()
{
}
void Corpse::AddToWorld()
{
///- Register the corpse for guid lookup
if (!IsInWorld())
ObjectAccessor::Instance().AddObject(this);
Object::AddToWorld();
}
void Corpse::RemoveFromWorld()
{
///- Remove the corpse from the accessor
if (IsInWorld())
ObjectAccessor::Instance().RemoveObject(this);
Object::RemoveFromWorld();
}
bool Corpse::Create(uint32 guidlow, Map *map)
{
SetMap(map);
Object::_Create(guidlow, 0, HIGHGUID_CORPSE);
return true;
}
bool Corpse::Create(uint32 guidlow, Player *owner)
{
ASSERT(owner);
Relocate(owner->GetPositionX(), owner->GetPositionY(), owner->GetPositionZ(), owner->GetOrientation());
if (!IsPositionValid())
{
sLog.outError("Corpse (guidlow %d, owner %s) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
guidlow, owner->GetName(), owner->GetPositionX(), owner->GetPositionY());
return false;
}
//we need to assign owner's map for corpse
//in other way we will get a crash in Corpse::SaveToDB()
SetMap(owner->GetMap());
WorldObject::_Create(guidlow, HIGHGUID_CORPSE, owner->GetPhaseMask());
SetFloatValue(OBJECT_FIELD_SCALE_X, 1);
SetUInt64Value(CORPSE_FIELD_OWNER, owner->GetGUID());
m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY());
return true;
}
void Corpse::SaveToDB()
{
// prevent DB data inconsistence problems and duplicates
CharacterDatabase.BeginTransaction();
DeleteFromDB();
std::ostringstream ss;
ss << "INSERT INTO corpse (guid,player,position_x,position_y,position_z,orientation,zone,map,data,time,corpse_type,instance,phaseMask) VALUES ("
<< GetGUIDLow() << ", "
<< GUID_LOPART(GetOwnerGUID()) << ", "
<< GetPositionX() << ", "
<< GetPositionY() << ", "
<< GetPositionZ() << ", "
<< GetOrientation() << ", "
<< GetZoneId() << ", "
<< GetMapId() << ", '";
for (uint16 i = 0; i < m_valuesCount; ++i)
ss << GetUInt32Value(i) << " ";
ss << "',"
<< uint64(m_time) <<", "
<< uint32(GetType()) << ", "
<< int(GetInstanceId()) << ", "
<< uint16(GetPhaseMask()) << ")"; // prevent out of range error
CharacterDatabase.Execute(ss.str().c_str());
CharacterDatabase.CommitTransaction();
}
void Corpse::DeleteBonesFromWorld()
{
assert(GetType() == CORPSE_BONES);
Corpse* corpse = ObjectAccessor::GetCorpse(*this, GetGUID());
if (!corpse)
{
sLog.outError("Bones %u not found in world.", GetGUIDLow());
return;
}
AddObjectToRemoveList();
}
void Corpse::DeleteFromDB()
{
if (GetType() == CORPSE_BONES)
// only specific bones
CharacterDatabase.PExecute("DELETE FROM corpse WHERE guid = '%d'", GetGUIDLow());
else
// all corpses (not bones)
CharacterDatabase.PExecute("DELETE FROM corpse WHERE player = '%d' AND corpse_type <> '0'", GUID_LOPART(GetOwnerGUID()));
}
/*
bool Corpse::LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId)
{
bool external = (result != NULL);
if (!external)
// 0 1 2 3 4 5 6 7 8 9
result = CharacterDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map,data,time,corpse_type,instance,phaseMask FROM corpse WHERE guid = '%u'",guid);
if (!result)
{
sLog.outError("Corpse (GUID: %u) not found in table `corpse`, can't load. ",guid);
return false;
}
Field *fields = result->Fetch();
if (!LoadFromDB(guid, fields))
{
if (!external)
delete result;
return false;
}
if (!external)
delete result;
return true;
}*/
bool Corpse::LoadFromDB(uint32 guid, Field *fields)
{
float positionX = fields[0].GetFloat();
float positionY = fields[1].GetFloat();
float positionZ = fields[2].GetFloat();
float ort = fields[3].GetFloat();
uint32 mapid = fields[4].GetUInt32();
Object::_Create(guid, 0, HIGHGUID_CORPSE);
if (!LoadValues(fields[5].GetString()))
{
sLog.outError("Corpse #%d have broken data in `data` field. Can't be loaded.",guid);
return false;
}
m_time = time_t(fields[6].GetUInt64());
m_type = CorpseType(fields[7].GetUInt32());
if (m_type >= MAX_CORPSE_TYPE)
{
sLog.outError("Corpse (guidlow %d, owner %d) have wrong corpse type, not load.",GetGUIDLow(),GUID_LOPART(GetOwnerGUID()));
return false;
}
if (m_type != CORPSE_BONES)
m_isWorldObject = true;
uint32 instanceid = fields[8].GetUInt32();
uint32 phaseMask = fields[9].GetUInt32();
// overwrite possible wrong/corrupted guid
SetUInt64Value(OBJECT_FIELD_GUID, MAKE_NEW_GUID(guid, 0, HIGHGUID_CORPSE));
// place
SetLocationInstanceId(instanceid);
SetLocationMapId(mapid);
SetPhaseMask(phaseMask, false);
Relocate(positionX, positionY, positionZ, ort);
if (!IsPositionValid())
{
sLog.outError("Corpse (guidlow %d, owner %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",
GetGUIDLow(), GUID_LOPART(GetOwnerGUID()), GetPositionX(), GetPositionY());
return false;
}
m_grid = Trinity::ComputeGridPair(GetPositionX(), GetPositionY());
return true;
}
bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const
{
return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u->m_seer, World::GetMaxVisibleDistanceForObject() + (inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false);
}
-97
View File
@@ -1,97 +0,0 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYCORE_CORPSE_H
#define TRINITYCORE_CORPSE_H
#include "Object.h"
#include "Database/DatabaseEnv.h"
#include "GridDefines.h"
#include "LootMgr.h"
enum CorpseType
{
CORPSE_BONES = 0,
CORPSE_RESURRECTABLE_PVE = 1,
CORPSE_RESURRECTABLE_PVP = 2
};
#define MAX_CORPSE_TYPE 3
// Value equal client resurrection dialog show radius.
#define CORPSE_RECLAIM_RADIUS 39
enum CorpseFlags
{
CORPSE_FLAG_NONE = 0x00,
CORPSE_FLAG_BONES = 0x01,
CORPSE_FLAG_UNK1 = 0x02,
CORPSE_FLAG_UNK2 = 0x04,
CORPSE_FLAG_HIDE_HELM = 0x08,
CORPSE_FLAG_HIDE_CLOAK = 0x10,
CORPSE_FLAG_LOOTABLE = 0x20
};
class Corpse : public WorldObject, public GridObject<Corpse>
{
public:
explicit Corpse(CorpseType type = CORPSE_BONES);
~Corpse();
void AddToWorld();
void RemoveFromWorld();
bool Create(uint32 guidlow, Map *map);
bool Create(uint32 guidlow, Player *owner);
void SaveToDB();
//bool LoadFromDB(uint32 guid, QueryResult *result, uint32 InstanceId);
bool LoadFromDB(uint32 guid, Field *fields);
void DeleteBonesFromWorld();
void DeleteFromDB();
uint64 const& GetOwnerGUID() const { return GetUInt64Value(CORPSE_FIELD_OWNER); }
time_t const& GetGhostTime() const { return m_time; }
void ResetGhostTime() { m_time = time(NULL); }
CorpseType GetType() const { return m_type; }
GridPair const& GetGrid() const { return m_grid; }
void SetGrid(GridPair const& grid) { m_grid = grid; }
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
Loot loot; // remove insignia ONLY at BG
Player* lootRecipient;
bool lootForBody;
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
private:
CorpseType m_type;
time_t m_time;
GridPair m_grid; // gride for corpse position for fast search
};
#endif
@@ -1,189 +0,0 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "UpdateMask.h"
#include "Opcodes.h"
#include "World.h"
#include "ObjectAccessor.h"
#include "Database/DatabaseEnv.h"
#include "GridNotifiers.h"
#include "CellImpl.h"
#include "GridNotifiersImpl.h"
DynamicObject::DynamicObject() : WorldObject()
{
m_objectType |= TYPEMASK_DYNAMICOBJECT;
m_objectTypeId = TYPEID_DYNAMICOBJECT;
m_updateFlag = (UPDATEFLAG_HIGHGUID | UPDATEFLAG_HAS_POSITION | UPDATEFLAG_POSITION);
m_valuesCount = DYNAMICOBJECT_END;
m_aura = 0;
m_duration = 0;
}
void DynamicObject::AddToWorld()
{
///- Register the dynamicObject for guid lookup
if (!IsInWorld())
{
ObjectAccessor::Instance().AddObject(this);
WorldObject::AddToWorld();
}
}
void DynamicObject::RemoveFromWorld()
{
///- Remove the dynamicObject from the accessor
if (IsInWorld())
{
if (m_isWorldObject)
{
if (Unit *caster = GetCaster())
{
if (caster->GetTypeId() == TYPEID_PLAYER)
caster->ToPlayer()->SetViewpoint(this, false);
}
else
{
sLog.outCrash("DynamicObject::RemoveFromWorld cannot find viewpoint owner");
}
}
WorldObject::RemoveFromWorld();
ObjectAccessor::Instance().RemoveObject(this);
}
}
bool DynamicObject::Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active)
{
SetMap(caster->GetMap());
Relocate(pos);
if (!IsPositionValid())
{
sLog.outError("DynamicObject (spell %u) not created. Suggested coordinates isn't valid (X: %f Y: %f)",spellId,GetPositionX(),GetPositionY());
return false;
}
WorldObject::_Create(guidlow, HIGHGUID_DYNAMICOBJECT, caster->GetPhaseMask());
SetEntry(spellId);
SetFloatValue(OBJECT_FIELD_SCALE_X, 1);
SetUInt64Value(DYNAMICOBJECT_CASTER, caster->GetGUID());
// The lower word of DYNAMICOBJECT_BYTES must be 0x0001. This value means that the visual radius will be overriden
// by client for most of the "ground patch" visual effect spells and a few "skyfall" ones like Hurricane.
// If any other value is used, the client will _always_ use the radius provided in DYNAMICOBJECT_RADIUS, but
// precompensation is necessary (eg radius *= 2) for many spells. Anyway, blizz sends 0x0001 for all the spells
// I saw sniffed...
SetUInt32Value(DYNAMICOBJECT_BYTES, 0x00000001);
SetUInt32Value(DYNAMICOBJECT_SPELLID, spellId);
SetFloatValue(DYNAMICOBJECT_RADIUS, radius);
SetUInt32Value(DYNAMICOBJECT_CASTTIME, getMSTime());
m_isWorldObject = active;
return true;
}
Unit* DynamicObject::GetCaster() const
{
// can be not found in some cases
return ObjectAccessor::GetUnit(*this, GetCasterGUID());
}
void DynamicObject::Update(uint32 p_time)
{
// caster can be not in world at time dynamic object update, but dynamic object not yet deleted in Unit destructor
Unit* caster = GetCaster();
if (!caster)
{
Delete();
return;
}
bool expired = false;
if (m_aura)
{
if (!m_aura->IsRemoved())
m_aura->UpdateOwner(p_time, this);
// m_aura may be set to null in Unit::RemoveGameObject call
if (m_aura && (m_aura->IsRemoved() || m_aura->IsExpired()))
expired = true;
}
else
{
if (GetDuration() > int32(p_time))
m_duration -= p_time;
else
expired = true;
}
if (expired)
{
caster->RemoveDynObjectWithGUID(GetGUID());
Delete();
}
}
void DynamicObject::Delete()
{
if (m_aura)
{
// dynObj may be removed in Aura::Remove - we cannot delete there
// so recheck aura here
if (!m_aura->IsRemoved())
m_aura->_Remove(AURA_REMOVE_BY_DEFAULT);
delete m_aura;
m_aura = NULL;
}
SendObjectDeSpawnAnim(GetGUID());
RemoveFromWorld();
AddObjectToRemoveList();
}
int32 DynamicObject::GetDuration() const
{
if (!m_aura)
return m_duration;
else
return m_aura->GetDuration();
}
void DynamicObject::SetDuration(int32 newDuration)
{
if (!m_aura)
m_duration = newDuration;
else
m_aura->SetDuration(newDuration);
}
void DynamicObject::Delay(int32 delaytime)
{
SetDuration(GetDuration() - delaytime);
}
bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const
{
return IsInWorld() && u->IsInWorld()
&& (IsWithinDistInMap(u->m_seer,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f), false));
}
@@ -1,61 +0,0 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYCORE_DYNAMICOBJECT_H
#define TRINITYCORE_DYNAMICOBJECT_H
#include "Object.h"
class Unit;
class Aura;
struct SpellEntry;
class DynamicObject : public WorldObject, public GridObject<DynamicObject>
{
public:
explicit DynamicObject();
void AddToWorld();
void RemoveFromWorld();
bool Create(uint32 guidlow, Unit *caster, uint32 spellId, const Position &pos, float radius, bool active);
void Update(uint32 p_time);
void Delete();
void SetDuration(int32 newDuration);
int32 GetDuration() const;
void SetAura(Aura * aura) {assert (!m_aura && aura); m_aura = aura;}
void Delay(int32 delaytime);
uint32 GetSpellId() const { return GetUInt32Value(DYNAMICOBJECT_SPELLID); }
uint64 GetCasterGUID() const { return GetUInt64Value(DYNAMICOBJECT_CASTER); }
float GetRadius() const { return GetFloatValue(DYNAMICOBJECT_RADIUS); }
Unit* GetCaster() const;
bool isVisibleForInState(Player const* u, bool inVisibleList) const;
void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId,language,TargetGuid); }
void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId,language,TargetGuid); }
void TextEmote(int32 textId, uint64 TargetGuid) { MonsterTextEmote(textId,TargetGuid); }
void Whisper(int32 textId,uint64 receiver) { MonsterWhisper(textId,receiver); }
void YellToZone(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYellToZone(textId,language,TargetGuid); }
protected:
int32 m_duration; // for non-aura dynobjects
Aura * m_aura;
};
#endif
@@ -1,375 +0,0 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Policies/SingletonImp.h"
#include "Player.h"
#include "Creature.h"
#include "GameObject.h"
#include "DynamicObject.h"
#include "Vehicle.h"
#include "WorldPacket.h"
#include "Item.h"
#include "Corpse.h"
#include "GridNotifiers.h"
#include "MapManager.h"
#include "Map.h"
#include "CellImpl.h"
#include "GridNotifiersImpl.h"
#include "Opcodes.h"
#include "ObjectDefines.h"
#include "MapInstanced.h"
#include "World.h"
#include <cmath>
#define CLASS_LOCK Trinity::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex>
INSTANTIATE_SINGLETON_2(ObjectAccessor, CLASS_LOCK);
INSTANTIATE_CLASS_MUTEX(ObjectAccessor, ACE_Thread_Mutex);
ObjectAccessor::ObjectAccessor()
{
}
ObjectAccessor::~ObjectAccessor()
{
for (Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr)
{
itr->second->RemoveFromWorld();
delete itr->second;
}
}
Creature* ObjectAccessor::GetCreatureOrPetOrVehicle(WorldObject const& u, uint64 guid)
{
if (IS_PLAYER_GUID(guid))
return NULL;
if (IS_PET_GUID(guid))
return GetPet(guid);
return u.IsInWorld() ? u.GetMap()->GetCreature(guid) : NULL;
}
Corpse* ObjectAccessor::GetCorpse(WorldObject const& u, uint64 guid)
{
Corpse* ret = GetObjectInWorld(guid, (Corpse*)NULL);
if (!ret)
return NULL;
if (ret->GetMapId() != u.GetMapId())
return NULL;
if (ret->GetInstanceId() != u.GetInstanceId())
return NULL;
return ret;
}
WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, uint64 guid)
{
switch (GUID_HIPART(guid))
{
case HIGHGUID_PLAYER: return FindPlayer(guid);
case HIGHGUID_GAMEOBJECT: return p.GetMap()->GetGameObject(guid);
case HIGHGUID_VEHICLE:
case HIGHGUID_UNIT: return p.GetMap()->GetCreature(guid);
case HIGHGUID_PET: return GetPet(guid);
case HIGHGUID_DYNAMICOBJECT: return p.GetMap()->GetDynamicObject(guid);
case HIGHGUID_TRANSPORT: return NULL;
case HIGHGUID_CORPSE: return GetCorpse(p,guid);
case HIGHGUID_MO_TRANSPORT: return NULL;
default: return NULL;
}
}
Object* ObjectAccessor::GetObjectByTypeMask(WorldObject const& p, uint64 guid, uint32 typemask)
{
switch (GUID_HIPART(guid))
{
case HIGHGUID_ITEM:
if (typemask & TYPEMASK_ITEM && p.GetTypeId() == TYPEID_PLAYER)
return ((Player const&)p).GetItemByGuid(guid);
break;
case HIGHGUID_PLAYER:
if (typemask & TYPEMASK_PLAYER)
return FindPlayer(guid);
break;
case HIGHGUID_GAMEOBJECT:
if (typemask & TYPEMASK_GAMEOBJECT)
return p.GetMap()->GetGameObject(guid);
break;
case HIGHGUID_UNIT:
case HIGHGUID_VEHICLE:
if (typemask & TYPEMASK_UNIT)
return p.GetMap()->GetCreature(guid);
break;
case HIGHGUID_PET:
if (typemask & TYPEMASK_UNIT)
return GetPet(guid);
break;
case HIGHGUID_DYNAMICOBJECT:
if (typemask & TYPEMASK_DYNAMICOBJECT)
return p.GetMap()->GetDynamicObject(guid);
break;
case HIGHGUID_TRANSPORT:
case HIGHGUID_CORPSE:
case HIGHGUID_MO_TRANSPORT:
break;
}
return NULL;
}
Player* ObjectAccessor::FindPlayer(uint64 guid)
{
Player* plr = GetObjectInWorld(guid, (Player*)NULL);
if (!plr || !plr->IsInWorld())
return NULL;
return plr;
}
Player* ObjectAccessor::FindPlayerByName(const char* name)
{
Guard guard(*HashMapHolder<Player>::GetLock());
HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
for (HashMapHolder<Player>::MapType::iterator iter = m.begin(); iter != m.end(); ++iter)
if (iter->second->IsInWorld() && strcmp(name, iter->second->GetName()) == 0)
return iter->second;
return NULL;
}
void ObjectAccessor::SaveAllPlayers()
{
Guard guard(*HashMapHolder<Player>::GetLock());
HashMapHolder<Player>::MapType& m = HashMapHolder<Player>::GetContainer();
for (HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
itr->second->SaveToDB();
}
Pet* ObjectAccessor::GetPet(uint64 guid)
{
return GetObjectInWorld(guid, (Pet*)NULL);
}
Corpse* ObjectAccessor::GetCorpseForPlayerGUID(uint64 guid)
{
Guard guard(i_corpseGuard);
Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid);
if (iter == i_player2corpse.end())
return NULL;
assert(iter->second->GetType() != CORPSE_BONES);
return iter->second;
}
void ObjectAccessor::RemoveCorpse(Corpse* corpse)
{
assert(corpse && corpse->GetType() != CORPSE_BONES);
if (corpse->FindMap())
corpse->FindMap()->Remove(corpse, false);
else
corpse->RemoveFromWorld();
// Critical section
{
Guard guard(i_corpseGuard);
Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID());
if (iter == i_player2corpse.end()) // TODO: Fix this
return;
// build mapid*cellid -> guid_set map
CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
objmgr.DeleteCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID());
i_player2corpse.erase(iter);
}
}
void ObjectAccessor::AddCorpse(Corpse* corpse)
{
assert(corpse && corpse->GetType() != CORPSE_BONES);
// Critical section
{
Guard guard(i_corpseGuard);
assert(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end());
i_player2corpse[corpse->GetOwnerGUID()] = corpse;
// build mapid*cellid -> guid_set map
CellPair cell_pair = Trinity::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());
uint32 cell_id = (cell_pair.y_coord * TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
objmgr.AddCorpseCellData(corpse->GetMapId(), cell_id, corpse->GetOwnerGUID(), corpse->GetInstanceId());
}
}
void ObjectAccessor::AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map)
{
Guard guard(i_corpseGuard);
for (Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter)
{
if (iter->second->GetGrid() == gridpair)
{
// verify, if the corpse in our instance (add only corpses which are)
if (map->Instanceable())
{
if (iter->second->GetInstanceId() == map->GetInstanceId())
grid.AddWorldObject(iter->second);
}
else
grid.AddWorldObject(iter->second);
}
}
}
Corpse* ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid, bool /*insignia*/)
{
Corpse* corpse = GetCorpseForPlayerGUID(player_guid);
if (!corpse)
{
//in fact this function is called from several places
//even when player doesn't have a corpse, not an error
// TODO: really, now...
//sLog.outError("Try remove corpse that not in map for GUID %ul", player_guid);
return NULL;
}
DEBUG_LOG("Deleting Corpse and spawned bones.");
//Map* map = corpse->FindMap();
// remove corpse from player_guid -> corpse map
RemoveCorpse(corpse);
// done in removecorpse
// remove resurrectable corpse from grid object registry (loaded state checked into call)
// do not load the map if it's not loaded
//Map *map = MapManager::Instance().FindMap(corpse->GetMapId(), corpse->GetInstanceId());
//if (map)
// map->Remove(corpse, false);
// remove corpse from DB
corpse->DeleteFromDB();
// we don't want bones to save some cpu.. :)
delete corpse;
return NULL;
/*
Corpse* bones = NULL;
// create the bones only if the map and the grid is loaded at the corpse's location
// ignore bones creating option in case insignia
if (map && (insignia ||
(map->IsBattleGroundOrArena() ? sWorld.getConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld.getConfig(CONFIG_DEATH_BONES_WORLD))) &&
!map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
{
// Create bones, don't change Corpse
bones = new Corpse;
bones->Create(corpse->GetGUIDLow(), map);
for (int i = 3; i < CORPSE_END; ++i) // don't overwrite guid and object type
bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
bones->SetGrid(corpse->GetGrid());
// bones->m_time = m_time; // don't overwrite time
// bones->m_inWorld = m_inWorld; // don't overwrite in-world state
// bones->m_type = m_type; // don't overwrite type
bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
bones->SetPhaseMask(corpse->GetPhaseMask(), false);
bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
bones->SetUInt64Value(CORPSE_FIELD_OWNER, 0);
for (int i = 0; i < EQUIPMENT_SLOT_END; ++i)
{
if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
}
// add bones in grid store if grid loaded where corpse placed
map->Add(bones);
}
// all references to the corpse should be removed at this point
delete corpse;
return bones;
*/
}
void ObjectAccessor::Update(uint32 /*diff*/)
{
UpdateDataMapType update_players;
// Critical section
{
Guard guard(i_updateGuard);
while (!i_objects.empty())
{
Object* obj = *i_objects.begin();
assert(obj && obj->IsInWorld());
i_objects.erase(i_objects.begin());
obj->BuildUpdate(update_players);
}
}
WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
{
iter->second.BuildPacket(&packet);
iter->first->GetSession()->SendPacket(&packet);
packet.clear(); // clean the string
}
}
/// Define the static members of HashMapHolder
template <class T> UNORDERED_MAP< uint64, T* > HashMapHolder<T>::m_objectMap;
template <class T> ACE_Thread_Mutex HashMapHolder<T>::i_lock;
/// Global definitions for the hashmap storage
template class HashMapHolder<Player>;
template class HashMapHolder<Pet>;
template class HashMapHolder<GameObject>;
template class HashMapHolder<DynamicObject>;
template class HashMapHolder<Creature>;
template class HashMapHolder<Corpse>;
template Player* ObjectAccessor::GetObjectInWorld<Player>(uint32 mapid, float x, float y, uint64 guid, Player* /*fake*/);
template Pet* ObjectAccessor::GetObjectInWorld<Pet>(uint32 mapid, float x, float y, uint64 guid, Pet* /*fake*/);
template Creature* ObjectAccessor::GetObjectInWorld<Creature>(uint32 mapid, float x, float y, uint64 guid, Creature* /*fake*/);
template Corpse* ObjectAccessor::GetObjectInWorld<Corpse>(uint32 mapid, float x, float y, uint64 guid, Corpse* /*fake*/);
template GameObject* ObjectAccessor::GetObjectInWorld<GameObject>(uint32 mapid, float x, float y, uint64 guid, GameObject* /*fake*/);
template DynamicObject* ObjectAccessor::GetObjectInWorld<DynamicObject>(uint32 mapid, float x, float y, uint64 guid, DynamicObject* /*fake*/);
@@ -1,257 +0,0 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* Copyright (C) 2008-2010 Trinity <http://www.trinitycore.org/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITY_OBJECTACCESSOR_H
#define TRINITY_OBJECTACCESSOR_H
#include "Platform/Define.h"
#include "Policies/Singleton.h"
#include <ace/Thread_Mutex.h>
#include "Utilities/UnorderedMap.h"
#include "Policies/ThreadingModel.h"
#include "UpdateData.h"
#include "GridDefines.h"
#include "Object.h"
#include "Player.h"
#include <set>
class Creature;
class Corpse;
class Unit;
class GameObject;
class DynamicObject;
class WorldObject;
class Map;
template <class T>
class HashMapHolder
{
public:
typedef UNORDERED_MAP<uint64, T*> MapType;
typedef ACE_Thread_Mutex LockType;
typedef Trinity::GeneralLock<LockType> Guard;
static void Insert(T* o)
{
Guard guard(i_lock);
m_objectMap[o->GetGUID()] = o;
}
static void Remove(T* o)
{
Guard guard(i_lock);
m_objectMap.erase(o->GetGUID());
}
static T* Find(uint64 guid)
{
Guard guard(i_lock);
typename MapType::iterator itr = m_objectMap.find(guid);
return (itr != m_objectMap.end()) ? itr->second : NULL;
}
static MapType& GetContainer() { return m_objectMap; }
static LockType* GetLock() { return &i_lock; }
private:
//Non instanceable only static
HashMapHolder() {}
static LockType i_lock;
static MapType m_objectMap;
};
class ObjectAccessor : public Trinity::Singleton<ObjectAccessor, Trinity::ClassLevelLockable<ObjectAccessor, ACE_Thread_Mutex> >
{
friend class Trinity::OperatorNew<ObjectAccessor>;
ObjectAccessor();
~ObjectAccessor();
ObjectAccessor(const ObjectAccessor&);
ObjectAccessor& operator=(const ObjectAccessor&);
public:
typedef UNORDERED_MAP<uint64, Corpse*> Player2CorpsesMapType;
typedef UNORDERED_MAP<Player*, UpdateData>::value_type UpdateDataValueType;
template<class T> static T* GetObjectInWorld(uint64 guid, T* /*fake*/)
{
return HashMapHolder<T>::Find(guid);
}
static Unit* GetObjectInWorld(uint64 guid, Unit* /*fake*/)
{
if (!guid)
return NULL;
if (IS_PLAYER_GUID(guid))
{
Unit* u = (Unit*)HashMapHolder<Player>::Find(guid);
if (!u || !u->IsInWorld())
return NULL;
return u;
}
if (IS_PET_GUID(guid))
return (Unit*)HashMapHolder<Pet>::Find(guid);
return (Unit*)HashMapHolder<Creature>::Find(guid);
}
static Unit* GetUnitInOrOutOfWorld(uint64 guid, Unit* /*fake*/)
{
if (!guid)
return NULL;
if (IS_PLAYER_GUID(guid))
{
Unit* u = (Unit*)HashMapHolder<Player>::Find(guid);
if (!u)
return NULL;
return u;
}
// Other object types than player are unloaded while out of world
return GetObjectInWorld(guid, (Unit*)NULL);
}
template<class T> static T* GetObjectInWorld(uint32 mapid, float x, float y, uint64 guid, T* /*fake*/)
{
T* obj = HashMapHolder<T>::Find(guid);
if (!obj || obj->GetMapId() != mapid)
return NULL;
CellPair p = Trinity::ComputeCellPair(x, y);
if (p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
{
sLog.outError("ObjectAccessor::GetObjectInWorld: invalid coordinates supplied X:%f Y:%f grid cell [%u:%u]", x, y, p.x_coord, p.y_coord);
return NULL;
}
CellPair q = Trinity::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
if (q.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || q.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
{
sLog.outError("ObjectAccessor::GetObjecInWorld: object (GUID: %u TypeId: %u) has invalid coordinates X:%f Y:%f grid cell [%u:%u]", obj->GetGUIDLow(), obj->GetTypeId(), obj->GetPositionX(), obj->GetPositionY(), q.x_coord, q.y_coord);
return NULL;
}
int32 dx = int32(p.x_coord) - int32(q.x_coord);
int32 dy = int32(p.y_coord) - int32(q.y_coord);
if (dx > -2 && dx < 2 && dy > -2 && dy < 2)
return obj;
else
return NULL;
}
static WorldObject* GetWorldObject(WorldObject const&, uint64);
static Object* GetObjectByTypeMask(WorldObject const&, uint64, uint32 typemask);
static Creature* GetCreatureOrPetOrVehicle(WorldObject const&, uint64);
static Unit* GetUnit(WorldObject const&, uint64 guid) { return GetObjectInWorld(guid, (Unit*)NULL); }
static Unit* GetUnitInOrOutOfWorld(WorldObject const&, uint64 guid) { return GetUnitInOrOutOfWorld(guid, (Unit*)NULL); }
static Pet* GetPet(Unit const&, uint64 guid) { return GetPet(guid); }
static Player* GetPlayer(Unit const&, uint64 guid) { return FindPlayer(guid); }
static Corpse* GetCorpse(WorldObject const& u, uint64 guid);
static Pet* GetPet(uint64 guid);
static Player* FindPlayer(uint64);
Player* FindPlayerByName(const char* name) ;
// when using this, you must use the hashmapholder's lock
HashMapHolder<Player>::MapType& GetPlayers()
{
return HashMapHolder<Player>::GetContainer();
}
// when using this, you must use the hashmapholder's lock
HashMapHolder<Creature>::MapType& GetCreatures()
{
return HashMapHolder<Creature>::GetContainer();
}
// when using this, you must use the hashmapholder's lock
HashMapHolder<GameObject>::MapType& GetGameObjects()
{
return HashMapHolder<GameObject>::GetContainer();
}
template<class T> void AddObject(T* object)
{
HashMapHolder<T>::Insert(object);
}
template<class T> void RemoveObject(T* object)
{
HashMapHolder<T>::Remove(object);
}
void RemoveObject(Player* pl)
{
HashMapHolder<Player>::Remove(pl);
RemoveUpdateObject((Object*)pl);
}
void SaveAllPlayers();
void AddUpdateObject(Object* obj)
{
Guard guard(i_updateGuard);
i_objects.insert(obj);
}
void RemoveUpdateObject(Object* obj)
{
Guard guard(i_updateGuard);
i_objects.erase(obj);
}
void Update(uint32 diff);
Corpse* GetCorpseForPlayerGUID(uint64 guid);
void RemoveCorpse(Corpse* corpse);
void AddCorpse(Corpse* corpse);
void AddCorpsesToGrid(GridPair const& gridpair, GridType& grid, Map* map);
Corpse* ConvertCorpseForPlayer(uint64 player_guid, bool insignia = false);
typedef ACE_Thread_Mutex LockType;
typedef Trinity::GeneralLock<LockType> Guard;
private:
Player2CorpsesMapType i_player2corpse;
static void _buildChangeObjectForPlayer(WorldObject*, UpdateDataMapType&);
static void _buildPacket(Player*, Object*, UpdateDataMapType&);
void _update();
std::set<Object*> i_objects;
LockType i_updateGuard;
LockType i_corpseGuard;
};
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,157 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "ObjectPosSelector.h"
ObjectPosSelector::ObjectPosSelector(float x,float y,float size,float dist)
: m_center_x(x),m_center_y(y),m_size(size),m_dist(dist)
{
m_anglestep = acos(m_dist/(m_dist+2*m_size));
m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].end();
m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].end();
m_smallStepAngle[USED_POS_PLUS] = 0;
m_smallStepAngle[USED_POS_MINUS] = 0;
m_smallStepOk[USED_POS_PLUS] = false;
m_smallStepOk[USED_POS_MINUS] = false;
m_smallStepNextUsedPos[USED_POS_PLUS] = NULL;
m_smallStepNextUsedPos[USED_POS_MINUS] = NULL;
}
ObjectPosSelector::UsedPosList::value_type const* ObjectPosSelector::nextUsedPos(UsedPosType uptype)
{
UsedPosList::const_iterator itr = m_nextUsedPos[uptype];
if(itr!=m_UsedPosLists[uptype].end())
++itr;
if(itr==m_UsedPosLists[uptype].end())
{
if(!m_UsedPosLists[~uptype].empty())
return &*m_UsedPosLists[~uptype].rbegin();
else
return NULL;
}
else
return &*itr;
}
void ObjectPosSelector::AddUsedPos(float size,float angle,float dist)
{
if(angle>=0)
m_UsedPosLists[USED_POS_PLUS].insert(UsedPosList::value_type(angle,UsedPos(1.0,size,dist)));
else
m_UsedPosLists[USED_POS_MINUS].insert(UsedPosList::value_type(-angle,UsedPos(-1.0,size,dist)));
}
void ObjectPosSelector::InitializeAngle()
{
m_nextUsedPos[USED_POS_PLUS] = m_UsedPosLists[USED_POS_PLUS].begin();
m_nextUsedPos[USED_POS_MINUS] = m_UsedPosLists[USED_POS_MINUS].begin();
m_smallStepAngle[USED_POS_PLUS] = 0;
m_smallStepAngle[USED_POS_MINUS] = 0;
m_smallStepOk[USED_POS_PLUS] = true;
m_smallStepOk[USED_POS_MINUS] = true;
}
bool ObjectPosSelector::FirstAngle(float& angle)
{
if(m_UsedPosLists[USED_POS_PLUS].empty() && !m_UsedPosLists[USED_POS_MINUS].empty() )
return NextAngleFor(*m_UsedPosLists[USED_POS_MINUS].begin(),1.0,USED_POS_PLUS,angle);
else if(m_UsedPosLists[USED_POS_MINUS].empty() && !m_UsedPosLists[USED_POS_PLUS].empty() )
return NextAngleFor(*m_UsedPosLists[USED_POS_PLUS].begin(),-1.0,USED_POS_MINUS,angle);
return false;
}
bool ObjectPosSelector::NextAngle(float& angle)
{
while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() ||
m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() ||
m_smallStepOk[USED_POS_PLUS] || m_smallStepOk[USED_POS_MINUS] )
{
// calculate next possible angle
if(NextPosibleAngle(angle))
return true;
}
return false;
}
bool ObjectPosSelector::NextUsedAngle(float& angle)
{
while(m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() ||
m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end() )
{
// calculate next possible angle
if(!NextPosibleAngle(angle))
return true;
}
return false;
}
bool ObjectPosSelector::NextPosibleAngle( float& angle )
{
// ++ direction less updated
if( m_nextUsedPos[USED_POS_PLUS]!=m_UsedPosLists[USED_POS_PLUS].end() &&
(m_nextUsedPos[USED_POS_MINUS]==m_UsedPosLists[USED_POS_MINUS].end() || m_nextUsedPos[USED_POS_PLUS]->first <= m_nextUsedPos[USED_POS_MINUS]->first) )
{
bool ok;
if(m_smallStepOk[USED_POS_PLUS])
ok = NextSmallStepAngle(1.0,USED_POS_PLUS,angle);
else
ok = NextAngleFor(*m_nextUsedPos[USED_POS_PLUS],1.0,USED_POS_PLUS,angle);
if(!ok)
++m_nextUsedPos[USED_POS_PLUS]; // increase. only at fail (original or checked)
return ok;
}
// -- direction less updated
else if( m_nextUsedPos[USED_POS_MINUS]!=m_UsedPosLists[USED_POS_MINUS].end())
{
bool ok;
if(m_smallStepOk[USED_POS_MINUS])
ok = NextSmallStepAngle(-1.0,USED_POS_MINUS,angle);
else
ok = NextAngleFor(*m_nextUsedPos[USED_POS_MINUS],-1.0,USED_POS_MINUS,angle);
if(!ok)
++m_nextUsedPos[USED_POS_MINUS];
return ok;
}
else // both list empty
{
if( m_smallStepOk[USED_POS_PLUS] && (!m_smallStepOk[USED_POS_MINUS] || m_smallStepAngle[USED_POS_PLUS] <= m_smallStepAngle[USED_POS_MINUS]) )
{
return NextSmallStepAngle(1.0,USED_POS_PLUS,angle);
}
// -- direction less updated
else if( m_smallStepOk[USED_POS_MINUS] )
{
return NextSmallStepAngle(-1.0,USED_POS_MINUS,angle);
}
}
// no angles
return false;
}
@@ -0,0 +1,155 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _OBJECT_POS_SELECTOR_H
#define _OBJECT_POS_SELECTOR_H
#include<Common.h>
#include<map>
enum UsedPosType { USED_POS_PLUS, USED_POS_MINUS };
inline UsedPosType operator ~(UsedPosType uptype)
{
return uptype==USED_POS_PLUS ? USED_POS_MINUS : USED_POS_PLUS;
}
struct ObjectPosSelector
{
struct UsedPos
{
UsedPos(float sign_, float size_,float dist_) : sign(sign_), size(size_),dist(dist_) {}
float sign;
float size; // size of point
float dist; // dist to central point (including central point size)
};
typedef std::multimap<float,UsedPos> UsedPosList; // abs(angle)->Node
ObjectPosSelector(float x,float y,float size,float dist);
void AddUsedPos(float size,float angle,float dist);
void InitializeAngle();
bool FirstAngle(float& angle);
bool NextAngle(float& angle);
bool NextUsedAngle(float& angle);
bool NextPosibleAngle( float& angle );
bool CheckAngle(UsedPosList::value_type const& nextUsedPos, float sign, float angle ) const
{
float angle_step2 = GetAngle(nextUsedPos.second);
float next_angle = nextUsedPos.first;
if(nextUsedPos.second.sign * sign < 0) // last node from diff. list (-pi+alpha)
next_angle = 2*M_PI-next_angle; // move to positive
return fabs(angle)+angle_step2 <= next_angle;
}
bool CheckOriginal() const
{
return (m_UsedPosLists[USED_POS_PLUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_PLUS].begin(),1.0,0)) &&
(m_UsedPosLists[USED_POS_MINUS].empty() || CheckAngle( *m_UsedPosLists[USED_POS_MINUS].begin(),-1.0,0));
}
bool IsNonBalanced() const { return m_UsedPosLists[USED_POS_PLUS].empty() != m_UsedPosLists[USED_POS_MINUS].empty(); }
bool NextAngleFor( UsedPosList::value_type const& usedPos, float sign, UsedPosType uptype, float &angle )
{
float angle_step = GetAngle(usedPos.second);
// next possible angle
angle = usedPos.first * usedPos.second.sign + angle_step * sign;
UsedPosList::value_type const* nextNode = nextUsedPos(uptype);
if(nextNode)
{
// if next node permit use selected angle, then do it
if(!CheckAngle(*nextNode, sign, angle))
{
m_smallStepOk[uptype] = false;
return false;
}
}
// possible more points
m_smallStepOk[uptype] = true;
m_smallStepAngle[uptype] = angle;
m_smallStepNextUsedPos[uptype] = nextNode;
return true;
}
bool NextSmallStepAngle( float sign, UsedPosType uptype, float &angle )
{
// next possible angle
angle = m_smallStepAngle[uptype] + m_anglestep * sign;
if(fabs(angle) > M_PI)
{
m_smallStepOk[uptype] = false;
return false;
}
if(m_smallStepNextUsedPos[uptype])
{
if(fabs(angle) >= m_smallStepNextUsedPos[uptype]->first)
{
m_smallStepOk[uptype] = false;
return false;
}
// if next node permit use selected angle, then do it
if(!CheckAngle(*m_smallStepNextUsedPos[uptype], sign, angle))
{
m_smallStepOk[uptype] = false;
return false;
}
}
// possible more points
m_smallStepAngle[uptype] = angle;
return true;
}
// next used post for m_nextUsedPos[uptype]
UsedPosList::value_type const* nextUsedPos(UsedPosType uptype);
// angle from used pos to next possible free pos
float GetAngle(UsedPos const& usedPos) const { return acos(m_dist/(usedPos.dist+usedPos.size+m_size)); }
float m_center_x;
float m_center_y;
float m_size; // size of object in center
float m_dist; // distance for searching pos (including central object size)
float m_anglestep;
UsedPosList m_UsedPosLists[2];
UsedPosList::const_iterator m_nextUsedPos[2];
// field for small step from first after next used pos until next pos
float m_smallStepAngle[2];
bool m_smallStepOk[2];
UsedPosList::value_type const* m_smallStepNextUsedPos[2];
};
#endif