Legends-of-Azeroth-Pandaria-5.4.8
332 строки · 9.7 Кб
1/*
2* This file is part of the Pandaria 5.4.8 Project. See THANKS file for Copyright information
3*
4* This program is free software; you can redistribute it and/or modify it
5* under the terms of the GNU General Public License as published by the
6* Free Software Foundation; either version 2 of the License, or (at your
7* option) any later version.
8*
9* This program is distributed in the hope that it will be useful, but WITHOUT
10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12* more details.
13*
14* You should have received a copy of the GNU General Public License along
15* with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include "DynamicTree.h"19#include "BoundingIntervalHierarchyWrapper.h"20#include "GameObjectModel.h"21#include "Log.h"22#include "MapTree.h"23#include "ModelIgnoreFlags.h"24#include "ModelInstance.h"25#include "RegularGrid.h"26#include "Timer.h"27#include "VMapFactory.h"28#include "VMapManager2.h"29#include "WorldModel.h"30#include <G3D/AABox.h>31#include <G3D/Ray.h>32#include <G3D/Vector3.h>33
34#include <G3D/AABox.h>35#include <G3D/Ray.h>36#include <G3D/Vector3.h>37
38using VMAP::ModelInstance;39
40namespace {41
42int CHECK_TREE_PERIOD = 200;43
44} // namespace45
46template<> struct HashTrait< GameObjectModel>{47static size_t hashCode(const GameObjectModel& g) { return (size_t)(void*)&g; }48};49
50template<> struct PositionTrait< GameObjectModel> {51static void getPosition(const GameObjectModel& g, G3D::Vector3& p) { p = g.getPosition(); }52};53
54template<> struct BoundsTrait< GameObjectModel> {55static void getBounds(const GameObjectModel& g, G3D::AABox& out) { out = g.getBounds();}56static void getBounds2(const GameObjectModel* g, G3D::AABox& out) { out = g->getBounds();}57};58
59/*
60static bool operator == (const GameObjectModel& mdl, const GameObjectModel& mdl2){
61return &mdl == &mdl2;
62}
63*/
64
65typedef RegularGrid2D<GameObjectModel, BIHWrap<GameObjectModel> > ParentTree;66
67struct DynTreeImpl : public ParentTree/*, public Intersectable*/68{
69typedef GameObjectModel Model;70typedef ParentTree base;71
72DynTreeImpl() :73rebalance_timer(CHECK_TREE_PERIOD),74unbalanced_times(0)75{76}77
78void insert(const Model& mdl)79{80base::insert(mdl);81++unbalanced_times;82}83
84void remove(const Model& mdl)85{86base::remove(mdl);87++unbalanced_times;88}89
90void balance()91{92base::balance();93unbalanced_times = 0;94}95
96void update(uint32 difftime)97{98if (empty())99return;100
101rebalance_timer.Update(difftime);102if (rebalance_timer.Passed())103{104rebalance_timer.Reset(CHECK_TREE_PERIOD);105if (unbalanced_times > 0)106balance();107}108}109
110TimeTrackerSmall rebalance_timer;111int unbalanced_times;112};113
114DynamicMapTree::DynamicMapTree() : impl(new DynTreeImpl()) { }115
116DynamicMapTree::~DynamicMapTree()117{
118delete impl;119}
120
121void DynamicMapTree::insert(const GameObjectModel& mdl)122{
123impl->insert(mdl);124}
125
126void DynamicMapTree::remove(const GameObjectModel& mdl)127{
128impl->remove(mdl);129}
130
131bool DynamicMapTree::contains(const GameObjectModel& mdl) const132{
133return impl->contains(mdl);134}
135
136void DynamicMapTree::balance()137{
138impl->balance();139}
140
141void DynamicMapTree::update(uint32 t_diff)142{
143impl->update(t_diff);144}
145
146struct DynamicTreeIntersectionCallback147{
148bool did_hit;149uint32 phase_mask;150DynamicTreeIntersectionCallback(uint32 phasemask) : did_hit(false), phase_mask(phasemask) { }151bool operator()(const G3D::Ray& r, const GameObjectModel& obj, float& distance)152{153did_hit = obj.intersectRay(r, distance, true, phase_mask, VMAP::ModelIgnoreFlags::Nothing);154return did_hit;155}156bool didHit() const { return did_hit;}157};158
159struct DynamicTreeIntersectionCallback_WithLogger160{
161bool did_hit;162uint32 phase_mask;163DynamicTreeIntersectionCallback_WithLogger(uint32 phasemask) : did_hit(false), phase_mask(phasemask)164{165TC_LOG_DEBUG("maps", "Dynamic Intersection log");166}167bool operator()(const G3D::Ray& r, const GameObjectModel& obj, float& distance)168{169TC_LOG_DEBUG("maps", "testing intersection with %s", obj.name.c_str());170bool hit = obj.intersectRay(r, distance, true, phase_mask, VMAP::ModelIgnoreFlags::Nothing);171if (hit)172{173did_hit = true;174TC_LOG_DEBUG("maps", "result: intersects");175}176return hit;177}178bool didHit() const { return did_hit;}179};180
181struct DynamicTreeAreaInfoCallback182{
183DynamicTreeAreaInfoCallback(uint32 phaseMask) : _phaseMask(phaseMask) {}184
185void operator()(G3D::Vector3 const& p, GameObjectModel const& obj)186{187obj.intersectPoint(p, _areaInfo, _phaseMask);188}189
190VMAP::AreaInfo const& GetAreaInfo() const { return _areaInfo; }191
192private:193uint32 _phaseMask;194VMAP::AreaInfo _areaInfo;195};196
197struct DynamicTreeLocationInfoCallback198{
199DynamicTreeLocationInfoCallback(uint32 phaseMask) : _phaseMask(phaseMask), _hitModel(nullptr) {}200
201void operator()(G3D::Vector3 const& p, GameObjectModel const& obj)202{203if (obj.GetLocationInfo(p, _locationInfo, _phaseMask))204_hitModel = &obj;205}206
207VMAP::LocationInfo& GetLocationInfo() { return _locationInfo; }208GameObjectModel const* GetHitModel() const { return _hitModel; }209
210private:211uint32 _phaseMask;212VMAP::LocationInfo _locationInfo;213GameObjectModel const* _hitModel;214};215
216bool DynamicMapTree::getIntersectionTime(const uint32 phasemask, const G3D::Ray& ray,217const G3D::Vector3& endPos, float& maxDist) const218{
219float distance = maxDist;220DynamicTreeIntersectionCallback callback(phasemask);221impl->intersectRay(ray, callback, distance, endPos);222if (callback.didHit())223maxDist = distance;224return callback.didHit();225}
226
227bool DynamicMapTree::getObjectHitPos(const uint32 phasemask, const G3D::Vector3& startPos,228const G3D::Vector3& endPos, G3D::Vector3& resultHit,229float modifyDist) const230{
231bool result = false;232float maxDist = (endPos - startPos).magnitude();233// valid map coords should *never ever* produce float overflow, but this would produce NaNs too234ASSERT(maxDist < std::numeric_limits<float>::max());235// prevent NaN values which can cause BIH intersection to enter infinite loop236if (maxDist < 1e-10f)237{238resultHit = endPos;239return false;240}241G3D::Vector3 dir = (endPos - startPos)/maxDist; // direction with length of 1242G3D::Ray ray(startPos, dir);243float dist = maxDist;244if (getIntersectionTime(phasemask, ray, endPos, dist))245{246resultHit = startPos + dir * dist;247if (modifyDist < 0)248{249if ((resultHit - startPos).magnitude() > -modifyDist)250resultHit = resultHit + dir*modifyDist;251else252resultHit = startPos;253}254else255resultHit = resultHit + dir*modifyDist;256
257result = true;258}259else260{261resultHit = endPos;262result = false;263}264return result;265}
266
267bool DynamicMapTree::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const268{
269G3D::Vector3 v1(x1, y1, z1), v2(x2, y2, z2);270
271float maxDist = (v2 - v1).magnitude();272
273if (!G3D::fuzzyGt(maxDist, 0) )274return true;275
276G3D::Ray r(v1, (v2-v1) / maxDist);277DynamicTreeIntersectionCallback callback(phasemask);278impl->intersectRay(r, callback, maxDist, v2);279
280return !callback.did_hit;281}
282
283float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const284{
285G3D::Vector3 v(x, y, z);286G3D::Ray r(v, G3D::Vector3(0, 0, -1));287DynamicTreeIntersectionCallback callback(phasemask);288impl->intersectZAllignedRay(r, callback, maxSearchDist);289
290if (callback.didHit())291return v.z - maxSearchDist;292else293return -G3D::finf();294}
295
296bool DynamicMapTree::getAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const297{
298G3D::Vector3 v(x, y, z + 0.5f);299DynamicTreeAreaInfoCallback intersectionCallBack(phasemask);300impl->intersectPoint(v, intersectionCallBack);301if (intersectionCallBack.GetAreaInfo().result)302{303flags = intersectionCallBack.GetAreaInfo().flags;304adtId = intersectionCallBack.GetAreaInfo().adtId;305rootId = intersectionCallBack.GetAreaInfo().rootId;306groupId = intersectionCallBack.GetAreaInfo().groupId;307z = intersectionCallBack.GetAreaInfo().ground_Z;308return true;309}310return false;311}
312
313void DynamicMapTree::getAreaAndLiquidData(float x, float y, float z, uint32 phasemask, uint8 reqLiquidType, VMAP::AreaAndLiquidData& data) const314{
315G3D::Vector3 v(x, y, z + 0.5f);316DynamicTreeLocationInfoCallback intersectionCallBack(phasemask);317impl->intersectPoint(v, intersectionCallBack);318if (intersectionCallBack.GetLocationInfo().hitModel)319{320data.floorZ = intersectionCallBack.GetLocationInfo().ground_Z;321uint32 liquidType = intersectionCallBack.GetLocationInfo().hitModel->GetLiquidType();322float liquidLevel;323if (!reqLiquidType || VMAP::VMapFactory::createOrGetVMapManager()->GetLiquidFlagsPtr(liquidType) & reqLiquidType)324if (intersectionCallBack.GetHitModel()->GetLiquidLevel(v, intersectionCallBack.GetLocationInfo(), liquidLevel))325data.liquidInfo.emplace(liquidType, liquidLevel);326
327data.areaInfo.emplace(0,328intersectionCallBack.GetLocationInfo().rootId,329intersectionCallBack.GetLocationInfo().hitModel->GetWmoID(),330intersectionCallBack.GetLocationInfo().hitModel->GetMogpFlags());331}332}
333