Jump to content

MMaps Redux


Guest auntieMangos

Recommended Posts

          • I am starting a new mmaps thread because the previous one was getting long, the first 5 pages did not use Recast/Detour, and it was difficult to cleanly define goals and report progress.
            If you would like to see the history of this MoveMaps project, read
this thread, starting at post 142.
I will attempt to keep this post updated. See the bottom for update info.
Purpose:
NavMesh generation using Recast, and efficient NavMesh management in MaNGOS.
Efficient pathfinding system using Detour, allowing obstacle avoidance and terrain following.
In simple terms, monsters shouldn't walk through:


    • [li]walls[/li]
      [li]mid air[/li]
      [li]ground[/li]
    Remaining Work:

These items are not being worked on, are open to dev discussion, or are just items to be aware of in the future.

Red items need community support.

(If you're colorblind, I apologize)



    • [li]offmesh connections
      Some collision meshes are poorly made, and there are small gaps or holes which prevent generating a contiguous navmesh.
      Offmesh connections fix this by linking two arbitrary navmesh locations to each other.
      They need to be created manually, and any contributions by the community are welcome. Also, currently they are only added to the navmesh through the generator - a way to add/remove them at server runtime would be nice.[/li]
      [li]Miscellaneous places that may need pathfinding:

      • [li]Creature::IsOutOfThreatArea (debatable, see Aggro point)[/li]
        [li]Unit::isInAccessiblePlaceFor (debatable, see Aggro point)[/li]
        [li]AssistDelayEvent::Execute (to generate one path for a group of creatures at aggro)[/li]
      [/l][/li]


  • [li]Aggro system integration
    It has been heavily discussed whether monsters should be able to target only creatures that they can reach.
    Current implementation is a 'lazy' one - it generates only one path to one creature in aggro list per update cycle.
    Also, when targets are unreachable they are dropped from the threat list... most likely need an explicit RemoveFromThreatList function for this, current implementation is a bit 'hacky'.
    [/li]
    [li]Evade timer implementation
    Currently, evasion happens immediately. Retail testing shows that there should be a delay of 26 seconds before evasion.[/li]
    [li]modify navmesh at runtime
    Game objects that appear/disappear or move need to be handled somehow. Currently, only way is to disable pathfinding on affected maps or npcs.
    Most likely dependent on unimplemented features in other core subsystems (vmaps)[/li]

See it in action:

From an early revision, this is video shows that the basics are possible.

Try it for yourself:

This is a development-oriented thread, not a how-to. If all you want is to try it out, and the directions below aren't working for you, please don't make 'how do I make it work?' posts.

The code is only available from GitHub, read a git tutorial if you don't know how to use git.



    • [li]
mangos master[/li]
[li]mangos one[/li]
[li]mangos zero[/li]
A short tutorial:



    • [li]build contrib/extractor from source (my repo does not include a compatible binary!)[/li]
    run it in your client directory to extract new .map files

put the new maps in your mangos data directory


  • [li]create a mmaps directory in your mangos data directory[/li]
    [li]build contrib/mmap, run it in your mangos data directory[/li]

read contrib/mmap/readme for advanced usage instructions

Some ways to test your new movemaps



    • [li]use a ranged attack on something[/li]
      [li]admin command .mmap (security level 2 required)[/li]
    If you find problems, please report them.

We need a general description of the problem (like 'mob evades immediately after aggro') and a location (mapID x y z).

Thanks

Mikko - creator and maintainer of recast navigation (http://code.google.com/p/recastnavigation/)

Gotisch - getting the ball rolling with recast navigation

Lynx3d - vmap_rewrite simplified this project immensely

qsa - majority of core implementation

Everybody who participated by testing and providing feedback, helping others, or providing retail data

If you would like to contribute (testing counts!), please let us know

Link to comment
Share on other sites

  • Replies 1.2k
  • Created
  • Last Reply

Top Posters In This Topic

I post here since it could help other testing :

First you have to build the vmaps used in vmaps_rewrite since mmaps are based on those. On this thread you should be able to do so. once you have extract map & dbc (with ad.exe) & vmaps you can compile mmaps extractor from this folder.

Then you have to copy paste it where the vmaps folder is and create a mmaps folder. Then use a commande line bash, go to the directorie and use

movemapgen

according to the readme file you can find in the src/mmap folder.

Link to comment
Share on other sites

No I am not able to do that either. I would appreciate to compile the Linux generator. Any advice on how to compile the Linux generator?

I'm a newb when it comes to linux build chain. Have been begging for help with that for over a month!

Skirnir started to do it in this post. He hadn't gotten it working yet, and I've added stuff since then. But it's a start.

Link to comment
Share on other sites

faramir118

I think that you forget update VC90 build files for MoveMapGen...

Maybe I'm wrong...

* VC90 update will be here in the next couple days, just need to get my work computer up to date.

You don't need to re-extract maps. Liquids work now, but because of #3 above they don't work in all cases.

think he is working on it but isn't finished with it yet :)

Link to comment
Share on other sites

TOM_RUS : perfect answer ! Thank you very much. Did a try on HomeMovement generator and it worked nicely. Which means the code in Unit::SendMonsterMoveByPath() is outdated.

Schmoozerd: thanks dude.

faramir118: Sorry, that Recast.h thing is a relic. Not needed anymore.

"those intervals are so inefficient" : the interval themselves are configurable, and they aren't that bad - the generation is not very efficient at the moment :) But that's better than nothing.

Link to comment
Share on other sites

This happens when some enemy creatures can't reach you for attack - they running all around and can't find a path to come closer, but if you come closer to their attack range - they will start attack through walls or another textures and climb up to you through walls or any objects, console error happens in this moment.

...

when creature walk through wall this error appears

That is the bug that i tried to show you before.

And another thing - if creature can't reach you then he should go into evade after few seconds, but on mangos with mmaps they doesn't evade, they just waiting a moment to walk through wall or other object.

Firstly, thanks for testing and input. The more people get involved, the faster and better this will advance.

Secondly : As Faramir mentioned, it is our temporary "solution" to lack of avoidance when target is not reachable. Something better will have to be made eventually.

About the console error, I have pretty good idea where it comes from. Pretty sure it is due to given end position not being "close" to last polygon on our poly-path. Happens every time when A* cannot give you full path, it gives you best effort/closest poly. Then we still use expected end point as its final destination, thus making point-path functions to error.

I'm working on solution which hopefully will solve it, but it isn't ready yet.

Basically I want to distinguish between end position and actual reachable end position. They are not always the same. On the way, solving all the related cases, like flying, vmap ground level vs mmap mesh differences, etc. Then we'll be able to easily implement avoidance on nonreachability.

faramir118:

Please push my patch, so we wont have differences in work-base like we did last time.

Take care.

Link to comment
Share on other sites

I think we should handle the evading and similar stuff in SelectHostileTarget.

We can do:

* Skip not-reachable enemies as tanks

* control an evade timer

* add a param to not evade by default (ie for a boss like gothik where the encounter starts the first few minutes without any enemy in accessible place

an idea about something that is handled similar: (also would be easy to extend to the above points)

http://getmangos.eu/community/viewtopic.php?id=15188

Link to comment
Share on other sites

Lynx3d is right, its 2GB VAS reserved for the OSfor itself. I dealt with this back when the generator was still under heavy development, and I loaded the entire map geometry into memory at once.

For pysical memory there are other limits; see this post.

Long story short, for mangos in general:

If its a small server, and you have grid unload on, use whatever OS and architecture is convenient for you.

Otherwise use x64.

Link to comment
Share on other sites

Ok, as you probably are aware vmaps v3 backport was accepted for one, and Vladimir went further and backported it to zero.

The only other major merge conflict is Ambal's not-backported [10727] map system re-engineering and all dependencies. While not necessary, backporting it will make maintaining separate branches much easier. (I touched some of this, but it was too much to include all of it in the vmap v3 backport)

My plan is to backport the mmap extractor, then [10727] et al, followed by mmaps core implementation. It will probably be slow since I have a backlog of real-life work. :(

Link to comment
Share on other sites

I finally crawl from under the rock I was stuck for a while and had the time to play around with things.

What came out of it, was the ability of create off mesh connection. In other words, the ability to patch

mmaps generated by the extractor.

When I tried to fix that issue, i got crash

#0  0x0000000000a7817a in dtNavMeshQuery::closestPointOnPolyInTile (
   this=0x846b69120, tile=0x858a1e400, poly=0x85cd609e0, pos=0x7ffffedf7590,
   closest=0x7ffffedf6a20)
   at DetourNavMeshQuery.cpp
       k = 0
       t = (
   const unsigned char *) 0x86acd4c9c <Error reading address 0x86acd4c9c: Некорректный адрес>
       v = {0x7ffffedf6980, 0xa6ce84, 0x85cd1dfd0}
       pt = {2.93873448e-39, 0, nan(0x7fffff)}
       d = 3.24456323e-07
       j = 0
       ip = 7204
       pd = (const dtPolyDetail *) 0x85cde3f70
       closestDistSqr = 3.40282347e+38
#1  0x0000000000a78526 in dtNavMeshQuery::closestPointOnPoly (
   this=0x846b69120, ref=4503599627377700, pos=0x7ffffedf7590,
   closest=0x7ffffedf6a20)
   at /DetourNavMeshQuery.cpp
       tile = (const dtMeshTile *) 0x858a1e400
       poly = (const dtPoly *) 0x85cd609e0
       __func__ = "closestPointOnPoly"
#2  0x0000000000811bbf in PathInfo::getPathPolyByPosition (this=0x82e5bfe80,
   polyPath=0x8358dc280, polyPathSize=3, point=0x7ffffedf7590,
   distance=0x7ffffedf75b8)
   at PathFinder.cpp
       closestPoint = {265.174316, 11.998889, 6244.83008}
       d = 64.2281036
       i = 1
       nearestPoly = 4503599627375809
       minDist2d = 64.2281036
       minDist3d = 64.8027649
#3  0x0000000000811ce1 in PathInfo::getPolyByLocation (this=0x82e5bfe80,
   point=0x7ffffedf7590, distance=0x7ffffedf75b8)
   at PathFinder.cpp
       polyRef = 4503599627375809
       extents = {-1.484889e+38, 4.59163468e-41, -1.48488819e+38}
       filter = {m_areaCost = {0, 4.7019774e-38, inf, inf, 85847.9375,
   1.12103877e-44, -1.48499447e+38, 4.59163468e-41, -1.48486547e+38,
   4.59163468e-41, 2.0178384e-38, 0, 1.40129846e-45, inf, -1.48488291e+38,
   4.59163468e-41, -1.48487358e+38, 4.59163468e-41, 85847.5, 1.12103877e-44,
   1.7998807e+09, 1.12103877e-44, 1.80617216e+09, 1.12103877e-44,
   -1.4848672e+38, 4.59163468e-41, -1.48487358e+38, 4.59163468e-41,
   -1.48488981e+38, 4.59163468e-41, 2.01861556e-38, 0, -1.48500988e+38,
   4.59163468e-41, 2.05193816e-38, 1.40129846e-45, -46.0220261, 25.8849583,
   9.66707611, 4.59163468e-41, -1.48489508e+38, 4.59163468e-41,
   -1.48499447e+38, 4.59163468e-41, -1.4850115e+38, 4.59163468e-41, 85847.5,
   1.12103877e-44, -46.0220261, 25.8849583, 9.66707611, -0, 0, -1, -inf, inf,
   -1, 1.821688e-44, -nan(0x400000), -nan(0x400000), -inf, -0, 0, inf},
 m_includeFlags = 0, m_excludeFlags = 65472}
       closestPoint = {-46.0220261, 25.8849583, 85848.125}
       result = DT_FAILURE
#4  0x0000000000811f3f in PathInfo::BuildPolyPath (this=0x82e5bfe80, startPos=
     {x = 6239.68018, y = 265.149872, z = 11.5367823}, endPos=
     {x = 6249.86133, y = 271.412476, z = 11.2408276})
   at PathFinder.cpp
       distToStartPoly = 0
       distToEndPoly = 0
       startPoint = {265.149872, 11.5367823, 6239.68018}
       endPoint = {271.412476, 11.2408276, 6249.86133}
       startPoly = 4503599627375809
       endPoly = 4692750813042601992
       farFromPoly = false
       startPolyFound = false
       endPolyFound = 64
       pathStartIndex = 1
       pathEndIndex = 1177092920
#5  0x0000000000812bab in PathInfo::Update (this=0x82e5bfe80,
   destX=6249.86133, destY=271.412476, destZ=11.2408276,
   useStraightPath=false)
   at PathFinder.cpp
       newDest = {x = 6249.86133, y = 271.412476, z = 11.2408276}
       oldDest = {x = 6246.91992, y = 270.063599, z = 11.7686615}
       x = 6239.68018
       y = 265.149872
       z = 11.5367823
       newStart = {x = 6239.68018, y = 265.149872, z = 11.5367823}
       oldStart = {x = 6234.30859, y = 262.476501, z = 11.932827}
       dist = 1.5
       oldDestInRange = false

offmeshes:

562 31,20 (6234.545898 256.902100 11.075373) (6230.961914 252.127274 11.180979) 8 // Blade's Edge Arena
562 31,20 (6243.081543 266.918854 11.059557) (6246.507324 271.623505 11.230524) 8 // Blade's Edge Arena

Link to comment
Share on other sites

Can you please try the following :

diff --git a/dep/recastnavigation/Detour/Source/DetourNode.cpp b/dep/recastnavigation/Detour/Source/DetourNode.cpp
index 0d1af83..52e55a7 100644
--- a/dep/recastnavigation/Detour/Source/DetourNode.cpp
+++ b/dep/recastnavigation/Detour/Source/DetourNode.cpp
@@ -88,14 +88,16 @@ dtNode* dtNodePool::getNode(dtPolyRef id)
    unsigned int bucket = dtHashRef(id) & (m_hashSize-1);
    unsigned short i = m_first[bucket];
    dtNode* node = 0;
-    while (i != DT_NULL_IDX)
+    int counter = 0;
+    while (i != DT_NULL_IDX && counter < m_maxNodes)
    {
        if (m_nodes[i].id == id)
            return &m_nodes[i];
        i = m_next[i];
+        counter++;
    }

-    if (m_nodeCount >= m_maxNodes)
+    if (m_nodeCount >= m_maxNodes - 1)
        return 0;

    i = (unsigned short)m_nodeCount;

Ugly hack, but I want to see it is in the right direction. Since I cannot reproduce it on local. Thanks in advance.

PS: how often it happens? since from what I see, you got it only on map 33, shadowfang.

Tried it, and it works lovely for me.

...

When I tried to fix that issue, i got crash

....

There's indeed a problem there. I can't get it to crash, but for some reason, while having pet on follow, if will get call location update every cycle, even tho it is at the right position.

I will debug it once I get some more time. Thanks for the report.

Can you please check if you get same problem in other places in world when using off mesh connections?

Anyway to reproduce it? doe's it always happen, or just sometimes?

Cheers

Link to comment
Share on other sites

1- Does exist a way to detect boat, zepplin and other transports ?

Transports aren't supported at all in mmaps. At best, you can disable pathfinding to players where Player::GetTransport() != NULL

2- Does exist a way to fall down from unaccessible plateform if path doesn't exist ?

Try offmesh connections, read post #891.

I have a question, where I can put a, for example, IsWorldBoss() check to disable mmaps for bosses? With mmaps, several bosses went bugged (is not mmaps problem, I know, but I need time to fix they one by one and workarround like this could do the trick temporaly). In SendMonsterMoveByPath() may be?

Unit::addUnitState(UNIT_STAT_IGNORE_PATHFINDING)

You can do this from wherever it is appropriate, most likely in the boss's script.

Link to comment
Share on other sites

I found a very strange situation in Stormwind City and Stranglethorn Vale. Pets can not follow master but just run along the riverbank or cliff and disappear after long distance when hunter pass the bridge/ hanging bridge. This can happen when the bridge/ hanging bridge is very long and narrow which means hunter can easily stand on the edge or side.

Another case is an old fallen tree as a bridge between two hills on the northest map of Stranglethorn Vale. Pets just can not follow hunter to pass the tree but run along the cliff no matter where hunter stand on( edge/middle).

Hunter will be in danger if aggo mobs/PVP on the bridge/hanging bridge without pets help.

Regards,

AMING51

I think that's exactly the kind of case why qsa worked on this : http://getmangos.eu/community/post/131450/#p131450

Link to comment
Share on other sites

  • 40 years later...
here the source from the extractor:

That link is for the non-recast generator. Thyros, could you edit your post and remove it, just so people don't get confused?

The one modified by Gotisch is here: http://rs806.rapidshare.com/files/368138336/recastmmaps.tar.gz

I will try to add it to my mmaps branch. Gotisch was using linux, so I'll have to make his changes work in visual studio.

Link to comment
Share on other sites

they work right off except that it's missing GridMapManager.h/cpp so you can't compile it. I happened to find them though lol.

GridMapManager.cpp

#include "GridMapManager.h"


namespace VMAP
{

   GridMap::GridMap()
   {
       m_flags = 0;
       // Area data
       m_gridArea = 0;
       m_area_map = NULL;
       // Height level data
       m_gridHeight = -100000.0f;
       m_gridGetHeight = &GridMap::getHeightFromFlat;
       m_V9 = NULL;
       m_V8 = NULL;
       // Liquid data
       m_liquidType    = 0;
       m_liquid_offX   = 0;
       m_liquid_offY   = 0;
       m_liquid_width  = 0;
       m_liquid_height = 0;
       m_liquidLevel = -100000.0f;
       m_liquid_type = NULL;
       m_liquid_map  = NULL;
   }

   GridMap::~GridMap()
   {
       unloadData();
   }

   bool GridMap::loadAreaData(FILE *in, uint32 offset, uint32 /*size*/)
   {
       map_areaHeader header;
       fseek(in, offset, SEEK_SET);
       fread(&header, sizeof(header), 1, in);
       if (header.fourcc != *((uint32 const*)(MAP_AREA_MAGIC)))
           return false;

       m_gridArea = header.gridArea;
       if (!(header.flags & MAP_AREA_NO_AREA))
       {
           m_area_map = new uint16 [16*16];
           fread(m_area_map, sizeof(uint16), 16*16, in);
       }
       return true;
   }

   bool  GridMap::loadHeightData(FILE *in, uint32 offset, uint32 /*size*/)
   {
       map_heightHeader header;
       fseek(in, offset, SEEK_SET);
       fread(&header, sizeof(header), 1, in);
       if (header.fourcc != *((uint32 const*)(MAP_HEIGHT_MAGIC)))
           return false;

       m_gridHeight = header.gridHeight;
       if (!(header.flags & MAP_HEIGHT_NO_HEIGHT))
       {
           if ((header.flags & MAP_HEIGHT_AS_INT16))
           {
               m_uint16_V9 = new uint16 [129*129];
               m_uint16_V8 = new uint16 [128*128];
               fread(m_uint16_V9, sizeof(uint16), 129*129, in);
               fread(m_uint16_V8, sizeof(uint16), 128*128, in);
               m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535;
               m_gridGetHeight = &GridMap::getHeightFromUint16;
           }
           else if ((header.flags & MAP_HEIGHT_AS_INT8))
           {
               m_uint8_V9 = new uint8 [129*129];
               m_uint8_V8 = new uint8 [128*128];
               fread(m_uint8_V9, sizeof(uint8), 129*129, in);
               fread(m_uint8_V8, sizeof(uint8), 128*128, in);
               m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255;
               m_gridGetHeight = &GridMap::getHeightFromUint8;
           }
           else
           {
               m_V9 = new float [129*129];
               m_V8 = new float [128*128];
               fread(m_V9, sizeof(float), 129*129, in);
               fread(m_V8, sizeof(float), 128*128, in);
               m_gridGetHeight = &GridMap::getHeightFromFloat;
           }
       }
       else
           m_gridGetHeight = &GridMap::getHeightFromFlat;
       return true;
   }

   bool  GridMap::loadLiquidData(FILE *in, uint32 offset, uint32 /*size*/)
   {
       map_liquidHeader header;
       fseek(in, offset, SEEK_SET);
       fread(&header, sizeof(header), 1, in);
       if (header.fourcc != *((uint32 const*)(MAP_LIQUID_MAGIC)))
           return false;

       m_liquidType   = header.liquidType;
       m_liquid_offX  = header.offsetX;
       m_liquid_offY  = header.offsetY;
       m_liquid_width = header.width;
       m_liquid_height= header.height;
       m_liquidLevel  = header.liquidLevel;

       if (!(header.flags & MAP_LIQUID_NO_TYPE))
       {
           m_liquid_type = new uint8 [16*16];
           fread(m_liquid_type, sizeof(uint8), 16*16, in);
       }
       if (!(header.flags & MAP_LIQUID_NO_HEIGHT))
       {
           m_liquid_map = new float [m_liquid_width*m_liquid_height];
           fread(m_liquid_map, sizeof(float), m_liquid_width*m_liquid_height, in);
       }
       return true;
   }

   float  GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const
   {
       return m_gridHeight;
   }

   float  GridMap::getHeightFromFloat(float x, float y) const
   {
       if (!m_V8 || !m_V9)
           return m_gridHeight;

       x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
       y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);

       int x_int = (int)x;
       int y_int = (int)y;
       x -= x_int;
       y -= y_int;
       x_int&=(MAP_RESOLUTION - 1);
       y_int&=(MAP_RESOLUTION - 1);

       // Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
       // +--------------> X
       // | h1-------h2     Coordinates is:
       // | | \\  1  / |     h1 0,0
       // | |  \\   /  |     h2 0,1
       // | | 2  h5 3 |     h3 1,0
       // | |  /   \\  |     h4 1,1
       // | | /  4  \\ |     h5 1/2,1/2
       // | h3-------h4
       // V Y
       // For find height need
       // 1 - detect triangle
       // 2 - solve linear equation from triangle points
       // Calculate coefficients for solve h = a*x + b*y + c

       float a,b,c;
       // Select triangle:
       if (x+y < 1)
       {
           if (x > y)
           {
               // 1 triangle (h1, h2, h5 points)
               float h1 = m_V9[(x_int  )*129 + y_int];
               float h2 = m_V9[(x_int+1)*129 + y_int];
               float h5 = 2 * m_V8[x_int*128 + y_int];
               a = h2-h1;
               b = h5-h1-h2;
               c = h1;
           }
           else
           {
               // 2 triangle (h1, h3, h5 points)
               float h1 = m_V9[x_int*129 + y_int  ];
               float h3 = m_V9[x_int*129 + y_int+1];
               float h5 = 2 * m_V8[x_int*128 + y_int];
               a = h5 - h1 - h3;
               b = h3 - h1;
               c = h1;
           }
       }
       else
       {
           if (x > y)
           {
               // 3 triangle (h2, h4, h5 points)
               float h2 = m_V9[(x_int+1)*129 + y_int  ];
               float h4 = m_V9[(x_int+1)*129 + y_int+1];
               float h5 = 2 * m_V8[x_int*128 + y_int];
               a = h2 + h4 - h5;
               b = h4 - h2;
               c = h5 - h4;
           }
           else
           {
               // 4 triangle (h3, h4, h5 points)
               float h3 = m_V9[(x_int  )*129 + y_int+1];
               float h4 = m_V9[(x_int+1)*129 + y_int+1];
               float h5 = 2 * m_V8[x_int*128 + y_int];
               a = h4 - h3;
               b = h3 + h4 - h5;
               c = h5 - h4;
           }
       }
       // Calculate height
       return a * x + b * y + c;
   }

   float  GridMap::getHeightFromUint8(float x, float y) const
   {
       if (!m_uint8_V8 || !m_uint8_V9)
           return m_gridHeight;

       x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
       y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);

       int x_int = (int)x;
       int y_int = (int)y;
       x -= x_int;
       y -= y_int;
       x_int&=(MAP_RESOLUTION - 1);
       y_int&=(MAP_RESOLUTION - 1);

       int32 a, b, c;
       uint8 *V9_h1_ptr = &m_uint8_V9[x_int*128 + x_int + y_int];
       if (x+y < 1)
       {
           if (x > y)
           {
               // 1 triangle (h1, h2, h5 points)
               int32 h1 = V9_h1_ptr[  0];
               int32 h2 = V9_h1_ptr[129];
               int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
               a = h2-h1;
               b = h5-h1-h2;
               c = h1;
           }
           else
           {
               // 2 triangle (h1, h3, h5 points)
               int32 h1 = V9_h1_ptr[0];
               int32 h3 = V9_h1_ptr[1];
               int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
               a = h5 - h1 - h3;
               b = h3 - h1;
               c = h1;
           }
       }
       else
       {
           if (x > y)
           {
               // 3 triangle (h2, h4, h5 points)
               int32 h2 = V9_h1_ptr[129];
               int32 h4 = V9_h1_ptr[130];
               int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
               a = h2 + h4 - h5;
               b = h4 - h2;
               c = h5 - h4;
           }
           else
           {
               // 4 triangle (h3, h4, h5 points)
               int32 h3 = V9_h1_ptr[  1];
               int32 h4 = V9_h1_ptr[130];
               int32 h5 = 2 * m_uint8_V8[x_int*128 + y_int];
               a = h4 - h3;
               b = h3 + h4 - h5;
               c = h5 - h4;
           }
       }
       // Calculate height
       return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight;
   }

   float  GridMap::getHeightFromUint16(float x, float y) const
   {
       if (!m_uint16_V8 || !m_uint16_V9)
           return m_gridHeight;

       x = MAP_RESOLUTION * (32 - x/SIZE_OF_GRIDS);
       y = MAP_RESOLUTION * (32 - y/SIZE_OF_GRIDS);

       int x_int = (int)x;
       int y_int = (int)y;
       x -= x_int;
       y -= y_int;
       x_int&=(MAP_RESOLUTION - 1);
       y_int&=(MAP_RESOLUTION - 1);

       int32 a, b, c;
       uint16 *V9_h1_ptr = &m_uint16_V9[x_int*128 + x_int + y_int];
       if (x+y < 1)
       {
           if (x > y)
           {
               // 1 triangle (h1, h2, h5 points)
               int32 h1 = V9_h1_ptr[  0];
               int32 h2 = V9_h1_ptr[129];
               int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
               a = h2-h1;
               b = h5-h1-h2;
               c = h1;
           }
           else
           {
               // 2 triangle (h1, h3, h5 points)
               int32 h1 = V9_h1_ptr[0];
               int32 h3 = V9_h1_ptr[1];
               int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
               a = h5 - h1 - h3;
               b = h3 - h1;
               c = h1;
           }
       }
       else
       {
           if (x > y)
           {
               // 3 triangle (h2, h4, h5 points)
               int32 h2 = V9_h1_ptr[129];
               int32 h4 = V9_h1_ptr[130];
               int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
               a = h2 + h4 - h5;
               b = h4 - h2;
               c = h5 - h4;
           }
           else
           {
               // 4 triangle (h3, h4, h5 points)
               int32 h3 = V9_h1_ptr[  1];
               int32 h4 = V9_h1_ptr[130];
               int32 h5 = 2 * m_uint16_V8[x_int*128 + y_int];
               a = h4 - h3;
               b = h3 + h4 - h5;
               c = h5 - h4;
           }
       }
       // Calculate height
       return (float)((a * x) + (b * y) + c)*m_gridIntHeightMultiplier + m_gridHeight;
   }

GridMapManager.h

#ifndef _GRIDMAPMANAGER_H
#define _GRIDMAPMANAGER_H

#include <string>

namespace VMAP
{

   #define MAX_NUMBER_OF_GRIDS      64

   #define SIZE_OF_GRIDS            533.33333f
   #define CENTER_GRID_ID           (MAX_NUMBER_OF_GRIDS/2)

   #define CENTER_GRID_OFFSET      (SIZE_OF_GRIDS/2)

   #define MAX_NUMBER_OF_CELLS     8
   #define SIZE_OF_GRID_CELL       (SIZE_OF_GRIDS/MAX_NUMBER_OF_CELLS)

   #define CENTER_GRID_CELL_ID     (MAX_NUMBER_OF_CELLS*MAX_NUMBER_OF_GRIDS/2)
   #define CENTER_GRID_CELL_OFFSET (SIZE_OF_GRID_CELL/2)

   #define TOTAL_NUMBER_OF_CELLS_PER_MAP    (MAX_NUMBER_OF_GRIDS*MAX_NUMBER_OF_CELLS)

   #define MAP_RESOLUTION 128

   #define MAP_SIZE                (SIZE_OF_GRIDS*MAX_NUMBER_OF_GRIDS)
   #define MAP_HALFSIZE            (MAP_SIZE/2)


     //================================================

   static char const* MAP_MAGIC         = "MAPS";
   static char const* MAP_VERSION_MAGIC = "v1.1";
   static char const* MAP_AREA_MAGIC    = "AREA";
   static char const* MAP_HEIGHT_MAGIC  = "MHGT";
   static char const* MAP_LIQUID_MAGIC  = "MLIQ";

   typedef unsigned int uint32;
   typedef unsigned short uint16;
   typedef unsigned char uint8;
   typedef signed int int32;

   struct map_fileheader
   {
       uint32 mapMagic;
       uint32 versionMagic;
       uint32 buildMagic;
       uint32 areaMapOffset;
       uint32 areaMapSize;
       uint32 heightMapOffset;
       uint32 heightMapSize;
       uint32 liquidMapOffset;
       uint32 liquidMapSize;
   };

   #define MAP_AREA_NO_AREA      0x0001

   struct map_areaHeader
   {
       uint32 fourcc;
       uint16 flags;
       uint16 gridArea;
   };

   #define MAP_HEIGHT_NO_HEIGHT  0x0001
   #define MAP_HEIGHT_AS_INT16   0x0002
   #define MAP_HEIGHT_AS_INT8    0x0004

   struct map_heightHeader
   {
       uint32 fourcc;
       uint32 flags;
       float  gridHeight;
       float  gridMaxHeight;
   };

   #define MAP_LIQUID_NO_TYPE    0x0001
   #define MAP_LIQUID_NO_HEIGHT  0x0002

   struct map_liquidHeader
   {
       uint32 fourcc;
       uint16 flags;
       uint16 liquidType;
       uint8  offsetX;
       uint8  offsetY;
       uint8  width;
       uint8  height;
       float  liquidLevel;
   };

   enum ZLiquidStatus
   {
       LIQUID_MAP_NO_WATER     = 0x00000000,
       LIQUID_MAP_ABOVE_WATER  = 0x00000001,
       LIQUID_MAP_WATER_WALK   = 0x00000002,
       LIQUID_MAP_IN_WATER     = 0x00000004,
       LIQUID_MAP_UNDER_WATER  = 0x00000008
   };

   #define MAP_LIQUID_TYPE_NO_WATER    0x00
   #define MAP_LIQUID_TYPE_WATER       0x01
   #define MAP_LIQUID_TYPE_OCEAN       0x02
   #define MAP_LIQUID_TYPE_MAGMA       0x04
   #define MAP_LIQUID_TYPE_SLIME       0x08

   #define MAP_ALL_LIQUIDS   (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)

   #define MAP_LIQUID_TYPE_DARK_WATER  0x10
   #define MAP_LIQUID_TYPE_WMO_WATER   0x20

   struct LiquidData
   {
       uint32 type;
       float  level;
       float  depth_level;
   };

   class GridMap
   {
       uint32  m_flags;
       // Area data
       uint16  m_gridArea;
       uint16 *m_area_map;
       // Height level data
       float   m_gridHeight;
       float   m_gridIntHeightMultiplier;
       union{
           float  *m_V9;
           uint16 *m_uint16_V9;
           uint8  *m_uint8_V9;
       };
       union{
           float  *m_V8;
           uint16 *m_uint16_V8;
           uint8  *m_uint8_V8;
       };
       // Liquid data
       uint16  m_liquidType;
       uint8   m_liquid_offX;
       uint8   m_liquid_offY;
       uint8   m_liquid_width;
       uint8   m_liquid_height;
       float   m_liquidLevel;
       uint8  *m_liquid_type;
       float  *m_liquid_map;

       bool  loadAreaData(FILE *in, uint32 offset, uint32 size);
       bool  loadHeightData(FILE *in, uint32 offset, uint32 size);
       bool  loadLiquidData(FILE *in, uint32 offset, uint32 size);

       // Get height functions and pointers
       typedef float (GridMap::*pGetHeightPtr) (float x, float y) const;
       pGetHeightPtr m_gridGetHeight;
       float  getHeightFromFloat(float x, float y) const;
       float  getHeightFromUint16(float x, float y) const;
       float  getHeightFromUint8(float x, float y) const;
       float  getHeightFromFlat(float x, float y) const;

   public:
       GridMap();
       ~GridMap();
       bool  loadData(char *filaname);
       void  unloadData();

       //uint16 getArea(float x, float y);
       inline float getHeight(float x, float y) {return (this->*m_gridGetHeight)(x, y);}
       //float  getLiquidLevel(float x, float y);
       //uint8  getTerrainType(float x, float y);
       //ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData *data = 0);
   };

   //================================================

   class GridMapManager
   {
   private:
       GridMap *iGridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
       bool iMapExist[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
       std::string iBasePath;
       unsigned int iMapId;
   public:
       GridMapManager (const char* pBasePath, unsigned int pMapId);
       ~GridMapManager ();

       bool loadMap (int pX, int pY);
       void unloadMap (int pX, int pY);
       float getHeight (float pX, float pY);
   };

 //================================================
}

#endif

Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. Privacy Policy Terms of Use