Extracting height data from ADT menu

Shout-Out

User Tag List

Results 1 to 1 of 1
  1. #1
    DrThum's Avatar Private
    Reputation
    1
    Join Date
    Mar 2012
    Posts
    1
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Extracting height data from ADT

    Hello,

    After 2 weeks scratching my head, I finally decided to ask here for some help. I'm currently working on a new WoW emulator*, and I need to create maps for the server. I like to understand what I'm doing, so I didn't simply copy/paste code from TrinityCore or any other existing emu. At the moment, I am working with a 2.4.3 client, mainly because that's the version I know the most (I have been working on a 2.4.3 fork of TrinityCore for the last 4 years) and also because things were much simpler back then. Here's what I did so far, I hope that someone can show me the errors that I have made.

    Btw, my main source was this page: ADT/v18 - WoWDev and I use StormLib to browse the MPQ files.
    I think I got the adt parsing right, because I got every chunk where they were supposed to be. I used the offsets in the MCIN chunk to read each MCNK chunk.

    This is the struct I used to store the MCNK header:
    Code:
    struct MCNKHeader
    {
        uint32 flags; // 0x1 = has MCSH, 0x2 = impassible, 0x4 = River, 0x8 = Ocean, 0x10 = Magma, 0x20 = Slime, 0x40 = has MCCV
        uint32 indexX;
        uint32 indexY;
        uint32 nLayers; // UNUSED
        uint32 nDoodadRefs; // UNUSED
        // From here, xxxPtr are offsets to various sub-chunks, relative from the beginning of this MCNK chunk
        uint32 mcvtPtr; // Height values
        uint32 mcnrPtr; // UNUSED: Normal vectors for vertex shading
        uint32 mclyPtr; // UNUSED: Texture layers definitions
        uint32 mcrfPtr; // UNUSED: Related to doodads
        uint32 mcalPtr; // UNUSED: Alpha maps for additional texture layers
        uint32 sizeAlpha; // UNUSED: Size of the MCAL sub-chunk
        uint32 mcshPtr; // UNUSED: Static shadows on the terrain
        uint32 sizeShadow; // UNUSED
        uint32 areaId;
        uint32 nMapObjRefs;
        uint32 holes;
        uint16 s1; // UNUSED
        uint16 s2; // UNUSED
        uint32 d1; // UNUSED
        uint32 d2; // UNUSED
        uint32 d3; // UNUSED
        uint32 predTex; // UNUSED
        uint32 nEffectDoodad; // UNUSED
        uint32 mcsePtr; // UNUSED: Sound emitters
        uint32 nSndEmitters; // UNUSED
        uint32 mclqPtr; // Liquid levels
        uint32 sizeLiquid; // Size of the MCLQ sub-chunk
        float  zpos; // Z-position (of what?)
        float  xpos; // X-position (of what?)
        float  ypos; // Y-position (of what?)
        uint32 textureId; // UNUSED: Related to vertex shading
        uint32 props; // UNUSED: Looks like an array of colors
        uint32 effectId; // UNUSED
    };
    Then, I jump to the MCVT subchunk, and read height data with the following code:
    Code:
    float baseY = header->ypos;
    float* cur = (float*) _chunkData; // _chunkData points to the beginning of the array containing 145 floats, aka the beginning of the MCVT subchunk
        for (uint8 j = 0; j < 17; j++) {
            for (uint8 i = 0; i < ((j % 2) ? 8 : 9); i++) {
                float h = *cur;
                cur++;
                float z = h + baseY;
                if (j % 2) {
                    if (isHole(header->holes, i, j))
                        cell.h8x8[i][j/2] = -1000.0f; // TODO: Really what we want?
                    else
                        cell.h8x8[i][j/2] = z;
                }
                else {
                    if (isHole(header->holes, i, j))
                        cell.h9x9[i][j/2] = -1000.0f; // TODO: Really what we want?
                    else
                        cell.h9x9[i][j/2] = z;
                }
            }
        }
    The next step is to write all that in the .map file:
    Code:
    void ADTFile::write(const char* filename)
    {
        std::ofstream out(filename, std::ios::out | std::ios::binary);
        out.write("MORPHEUS_MAP", 12);
        
        for (uint16 c = 0; c < 256; c++) {
            Cell cell = cells[c];
            for (uint8 i = 0; i < 9; i++) {
                for (uint8 j = 0; j < 9; j++) {
                    out.write(reinterpret_cast<char *>(&cell.h9x9[i][j]), sizeof(float));
                    //printf("Writing %f\n", cell.h9x9[i][j]);
                }
            }
            
            for (uint8 i = 0; i < 8; i++) {
                for (uint8 j = 0; j < 8; j++)
                    out.write(reinterpret_cast<char *>(&cell.h8x8[i][j]), sizeof(float));
            }
        }
        
        out.flush();
        out.close();
    }
    Now, let's see the emu part, where I used this data. I implemented 3 classes : Map, CellBlock, and Cell. A map contains 64x64 CellBlocks, a CellBlock contains 16x16 Cells, and each Cell has a 9x9 and a 8x8 float arrays (which I called h9x9 and h8x8 respectively, and are called m_V9 and m_V8 in Trinity). I started my tests with Kalimdor (map 1) and do the following:

    - Load CellBlocks
    Code:
    for (uint16 c = 0; c < 256; c++) {
            float h9x9[9][9];
            memset(&h9x9[0][0], 0, sizeof(float) * 9 * 9);
            for (uint8 i = 0; i < 9; i++) {
                for (uint8 j = 0; j < 9; j++)
                    in.read(reinterpret_cast<char *>(&h9x9[i][j]), sizeof(float));
            }
            cells[c].copy9x9From(&h9x9[0][0]); // cells is a Cell[256]
            // copy9x9From and copy8x8From simply do memcpy from the data read in the file to the corresponding float arrays in the Cell class
    
            float h8x8[8][8];
            memset(&h8x8[0][0], 0, sizeof(float) * 8 * 8);
            for (uint8 i = 0; i < 8; i++) {
                for (uint8 j = 0; j < 8; j++)
                    in.read(reinterpret_cast<char *>(&h8x8[i][j]), sizeof(float));
            }
            cells[c].copy8x8From(&h8x8[0][0]);
        }
    - Calculate the height on a given position (I tested with Tauren starting coordinates, X = -2917.580078, Y = -257.980011, map = 1), first in the map:
    Code:
    #define CELLBLOCK_SIZE          533.333333f
    #define CELLS_PER_BLOCK_SIDE    16
    #define CELL_SIZE               (CELLBLOCK_SIZE / CELLS_PER_BLOCK_SIDE)
    #define CELLCHUNK_SIZE          (CELL_SIZE / 8)
    Code:
    float Map::getHeight(float x, float y)
    {
        x = std::abs(x) + 32 * CELLBLOCK_SIZE;
        y = std::abs(y) + 32 * CELLBLOCK_SIZE;
        
        uint32 blockX = x / CELLBLOCK_SIZE;
        uint32 blockY = y / CELLBLOCK_SIZE;
        
        // I am able to get the same block as TC with the 2 following lines but I still don't get the same height in the end
        /*blockX = 63 - blockX;
        blockY = 63 - blockY;*/
        
        printf("Block: %u, %u\n", blockX, blockY);
        
        float offsetBlockX = fmod(x, CELLBLOCK_SIZE);
        float offsetBlockY = fmod(y, CELLBLOCK_SIZE);
        
        /*offsetBlockX = CELLBLOCK_SIZE - offsetBlockX;
        offsetBlockY = CELLBLOCK_SIZE - offsetBlockY;*/
        
        printf("Offset in block: %f, %f\n", offsetBlockX, offsetBlockY);
        
        blocks[blockX][blockY].getHeight(offsetBlockX, offsetBlockY);
    }
    - Then, in the right block:
    Code:
    float CellBlock::getHeight(float x, float y) const
    {
        printf("X: %f, Y: %f\n", x, y);
        
        uint32 cellX = x / CELL_SIZE;
        uint32 cellY = y / CELL_SIZE;
        
        /*cellX = 15 - cellX;
        cellY = 15 - cellY;*/
        
        printf("Cell %u, %u (= %uth)\n", cellX, cellY, (cellX * 16 + cellY));
        
        const Cell* cell = &cells[cellX * 16 + cellY];
        
        float offsetCellX = fmod(x, CELL_SIZE);
        float offsetCellY = fmod(y, CELL_SIZE);
        
        /*offsetCellX = CELL_SIZE - offsetCellX;
        offsetCellY = CELL_SIZE - offsetCellY;*/
        
        printf("Offset in cell: %f, %f\n", offsetCellX, offsetCellY);
        
        return cell->getHeight(offsetCellX, offsetCellY);
    }
    - And finally, in the right Cell (this code is taken from Trinity)
    Code:
    float Cell::getHeight(float x, float y) const
    {
        // +--------------> 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
        // 
        // h1, h2, h3 and h4 are in h9x9
        // h5 is in h8x8
        
        float a, b, c;
        printf("x: %f y: %f\n", x, y);
        uint32 chunkX = x / CELLCHUNK_SIZE;
        uint32 chunkY = y / CELLCHUNK_SIZE;
        
        /*chunkX = 8 - chunkX;
        chunkY = 8 - chunkY;*/
        
        printf("Chunks: x %u y %u\n", chunkX, chunkY);
        float deltaX = fmod(x, CELLCHUNK_SIZE) / CELLCHUNK_SIZE;
        float deltaY = fmod(y, CELLCHUNK_SIZE) / CELLCHUNK_SIZE;
        printf("Delta x %f y %f\n", deltaX, deltaY);
        if ((deltaX + deltaY) < 1.0f) { // Triangle 1 or 2
            if (deltaX > deltaY) {
                // Triangle 1
                float h1 = h9x9[chunkY][chunkX];
                float h2 = h9x9[chunkY + 1][chunkX];
                float h5 = 2 * h8x8[chunkY][chunkX];
                a = h2 - h1;
                b = h5 - h1 - h2;
                c = h1;
            }
            else {
                // Triangle 2
                float h1 = h9x9[chunkY][chunkX];
                float h3 = h9x9[chunkY][chunkX + 1];
                float h5 = 2 * h8x8[chunkY][chunkX];
                a = h5 - h1 - h3;
                b = h3 - h1;
                c = h1;
            }
        }
        else { // Triangle 3 or 4
            if (deltaX > deltaY)
            {
                // Triangle 3
                float h2 = h9x9[chunkY + 1][chunkX];
                float h4 = h9x9[chunkY + 1][chunkX + 1];
                float h5 = 2 * h8x8[chunkY][chunkX];
                a = h2 + h4 - h5;
                b = h4 - h2;
                c = h5 - h4;
            }
            else {
                // Triangle 4
                float h3 = h9x9[chunkY][chunkX + 1];
                float h4 = h9x9[chunkY + 1][chunkX + 1];
                float h5 = 2 * h8x8[chunkY][chunkX];
                a = h4 - h3;
                b = h3 + h4 - h5;
                c = h5 - h4;
            }
        }
        
        printf("a: %f, b: %f, c: %f, x: %f, y: %f\n", a, b, c, x, y);
        return a * x + b * y + c;
    }
    My problem is that I don't get the same height as Trinity, and not even the same CellBlock (which is called Grid in TC). I guess that my math is off somewhere, but I can't figure out where my mistake is. Don't hesitate to ask for more details if needed.

    Thanks!


    * For those interested, the project is open source and can be browsed here

    Extracting height data from ADT

Similar Threads

  1. Extract data from Replays
    By irongete in forum Heroes of the Storm General
    Replies: 3
    Last Post: 08-20-2014, 12:28 AM
  2. Extract specific data from windows image?
    By 403Forbidden in forum Programming
    Replies: 0
    Last Post: 07-30-2012, 07:12 AM
  3. Extracting data from MPQ
    By Viano in forum WoW Memory Editing
    Replies: 5
    Last Post: 04-01-2010, 01:14 PM
  4. Need a program to find data from WoW.
    By wat-u-doin in forum WoW Memory Editing
    Replies: 45
    Last Post: 11-27-2008, 07:57 PM
  5. Extract into Data Folder?
    By geageee in forum WoW ME Questions and Requests
    Replies: 3
    Last Post: 07-13-2007, 04:38 PM
All times are GMT -5. The time now is 10:43 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search