void MapChunk::save(sExtendableArray &lADTFile, int &lCurrentPosition, int &lMCIN_Position, std::map<std::string, int> &lTextures, std::map<int, WMOInstance> &lObjectInstances, std::map<int, ModelInstance> &lModelInstances) { int lID; int lMCNK_Size = 0x80; int lMCNK_Position = lCurrentPosition; lADTFile.Extend(8 + 0x80); // This is only the size of the header. More chunks will increase the size. SetChunkHeader(lADTFile, lCurrentPosition, 'MCNK', lMCNK_Size); lADTFile.GetPointer<MCIN>(lMCIN_Position + 8)->mEntries[py * 16 + px].offset = lCurrentPosition; // check this // MCNK data lADTFile.Insert(lCurrentPosition + 8, 0x80, reinterpret_cast<char*>(&(header))); MapChunkHeader *lMCNK_header = lADTFile.GetPointer<MapChunkHeader>(lCurrentPosition + 8); lMCNK_header->flags = Flags; lMCNK_header->holes = holes; lMCNK_header->areaid = areaID; lMCNK_header->nLayers = -1; lMCNK_header->nDoodadRefs = -1; lMCNK_header->ofsHeight = -1; lMCNK_header->ofsNormal = -1; lMCNK_header->ofsLayer = -1; lMCNK_header->ofsRefs = -1; lMCNK_header->ofsAlpha = -1; lMCNK_header->sizeAlpha = -1; lMCNK_header->ofsShadow = -1; lMCNK_header->sizeShadow = -1; lMCNK_header->nMapObjRefs = -1; lMCNK_header->ofsMCCV = -1; //! \todo Implement sound emitter support. Or not. lMCNK_header->ofsSndEmitters = 0; lMCNK_header->nSndEmitters = 0; lMCNK_header->ofsLiquid = 0; //! \todo Is this still 8 if no chunk is present? Or did they correct that? lMCNK_header->sizeLiquid = 8; memset(lMCNK_header->low_quality_texture_map, 0, 0x10); static const size_t minimum_value_to_overwrite(128); for (size_t layer(1); layer < textureSet->num(); ++layer) { for (size_t y(0); y < 8; ++y) { for (size_t x(0); x < 8; ++x) { size_t sum(0); for (size_t j(0); j < 8; ++j) { for (size_t i(0); i < 8; ++i) { sum += textureSet->getAlpha(layer - 1, (y * 8 + j) * 64 + (x * 8 + i)); } } if (sum > minimum_value_to_overwrite * 8 * 8) { const size_t array_index((y * 8 + x) / 4); const size_t bit_index(((y * 8 + x) % 4) * 2); lMCNK_header->low_quality_texture_map[array_index] |= ((layer & 3) << bit_index); } } } } lCurrentPosition += 8 + 0x80; // MCVT int lMCVT_Size = mapbufsize * 4; lADTFile.Extend(8 + lMCVT_Size); SetChunkHeader(lADTFile, lCurrentPosition, 'MCVT', lMCVT_Size); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsHeight = lCurrentPosition - lMCNK_Position; float* lHeightmap = lADTFile.GetPointer<float>(lCurrentPosition + 8); float lMedian = 0.0f; for (int i = 0; i < mapbufsize; ++i) lMedian += mVertices[i].y; lMedian = lMedian / mapbufsize; lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ypos = lMedian; for (int i = 0; i < mapbufsize; ++i) lHeightmap[i] = mVertices[i].y - lMedian; lCurrentPosition += 8 + lMCVT_Size; lMCNK_Size += 8 + lMCVT_Size; // MCCV int lMCCV_Size = mapbufsize * sizeof(unsigned int); lADTFile.Extend(8 + lMCCV_Size); SetChunkHeader(lADTFile, lCurrentPosition, 'MCCV', lMCCV_Size); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsMCCV = lCurrentPosition - lMCNK_Position; unsigned int *lmccv = lADTFile.GetPointer<unsigned int>(lCurrentPosition + 8); memcpy(lmccv, mccv.data(), lMCCV_Size); for (int i = 0; i < mapbufsize; ++i) lmccv[i] = Reverse(lmccv[i], false); lCurrentPosition += 8 + lMCCV_Size; lMCNK_Size += 8 + lMCCV_Size; // MCNR int lMCNR_Size = mapbufsize * 3; lADTFile.Extend(8 + lMCNR_Size); SetChunkHeader(lADTFile, lCurrentPosition, 'MCNR', lMCNR_Size); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsNormal = lCurrentPosition - lMCNK_Position; char * lNormals = lADTFile.GetPointer<char>(lCurrentPosition + 8); // recalculate the normals recalcNorms(); for (int i = 0; i < mapbufsize; ++i) { lNormals[i * 3 + 0] = misc::roundc(-mNormals[i].z * 127); lNormals[i * 3 + 1] = misc::roundc(-mNormals[i].x * 127); lNormals[i * 3 + 2] = misc::roundc(mNormals[i].y * 127); } lCurrentPosition += 8 + lMCNR_Size; lMCNK_Size += 8 + lMCNR_Size; // } // Unknown MCNR bytes // These are not in as we have data or something but just to make the files more blizzlike. // { lADTFile.Extend(13); lCurrentPosition += 13; lMCNK_Size += 13; // } // MCLY // { size_t lMCLY_Size = textureSet->num() * 0x10; lADTFile.Extend(8 + lMCLY_Size); SetChunkHeader(lADTFile, lCurrentPosition, 'MCLY', lMCLY_Size); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsLayer = lCurrentPosition - lMCNK_Position; lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->nLayers = textureSet->num(); // MCLY data for (size_t j = 0; j < textureSet->num(); ++j) { ENTRY_MCLY * lLayer = lADTFile.GetPointer<ENTRY_MCLY>(lCurrentPosition + 8 + 0x10 * j); lLayer->textureID = lTextures.find(textureSet->filename(j))->second; lLayer->flags = textureSet->flag(j); // if not first, have alpha layer, if first, have not. never have compression. lLayer->flags = (j > 0 ? lLayer->flags | FLAG_USE_ALPHA : lLayer->flags & (~FLAG_USE_ALPHA)) & (~FLAG_ALPHA_COMPRESSED); lLayer->ofsAlpha = (j == 0 ? 0 : (mBigAlpha ? 64 * 64 * (j - 1) : 32 * 64 * (j - 1))); lLayer->effectID = textureSet->effect(j); } lCurrentPosition += 8 + lMCLY_Size; lMCNK_Size += 8 + lMCLY_Size; // } // MCRF // { std::list<int> lDoodadIDs; std::list<int> lObjectIDs; Vec3D lChunkExtents[2]; lChunkExtents[0] = Vec3D(xbase, 0.0f, zbase); lChunkExtents[1] = Vec3D(xbase + CHUNKSIZE, 0.0f, zbase + CHUNKSIZE); // search all wmos that are inside this chunk lID = 0; for (std::map<int, WMOInstance>::iterator it = lObjectInstances.begin(); it != lObjectInstances.end(); ++it) { if (it->second.isInsideChunk(lChunkExtents)) lObjectIDs.push_back(lID); lID++; } // search all models that are inside this chunk lID = 0; for (std::map<int, ModelInstance>::iterator it = lModelInstances.begin(); it != lModelInstances.end(); ++it) { if (it->second.isInsideChunk(lChunkExtents)) lDoodadIDs.push_back(lID); lID++; } int lMCRF_Size = 4 * (lDoodadIDs.size() + lObjectIDs.size()); lADTFile.Extend(8 + lMCRF_Size); SetChunkHeader(lADTFile, lCurrentPosition, 'MCRF', lMCRF_Size); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsRefs = lCurrentPosition - lMCNK_Position; lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->nDoodadRefs = lDoodadIDs.size(); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->nMapObjRefs = lObjectIDs.size(); // MCRF data int *lReferences = lADTFile.GetPointer<int>(lCurrentPosition + 8); lID = 0; for (std::list<int>::iterator it = lDoodadIDs.begin(); it != lDoodadIDs.end(); ++it) { lReferences[lID] = *it; lID++; } for (std::list<int>::iterator it = lObjectIDs.begin(); it != lObjectIDs.end(); ++it) { lReferences[lID] = *it; lID++; } lCurrentPosition += 8 + lMCRF_Size; lMCNK_Size += 8 + lMCRF_Size; // } // MCSH // { //! \todo Somehow determine if we need to write this or not? //! \todo This sometime gets all shadows black. if (Flags & 1) { int lMCSH_Size = 0x200; lADTFile.Extend(8 + lMCSH_Size); SetChunkHeader(lADTFile, lCurrentPosition, 'MCSH', lMCSH_Size); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsShadow = lCurrentPosition - lMCNK_Position; lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->sizeShadow = 0x200; char * lLayer = lADTFile.GetPointer<char>(lCurrentPosition + 8); memcpy(lLayer, mShadowMap, 0x200); lCurrentPosition += 8 + lMCSH_Size; lMCNK_Size += 8 + lMCSH_Size; } else { lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsShadow = 0; lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->sizeShadow = 0; } // MCAL int lDimensions = 64 * (mBigAlpha ? 64 : 32); size_t lMaps = textureSet->num() ? textureSet->num() - 1U : 0U; int lMCAL_Size = lDimensions * lMaps; lADTFile.Extend(8 + lMCAL_Size); SetChunkHeader(lADTFile, lCurrentPosition, 'MCAL', lMCAL_Size); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsAlpha = lCurrentPosition - lMCNK_Position; lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->sizeAlpha = 8 + lMCAL_Size; char * lAlphaMaps = lADTFile.GetPointer<char>(lCurrentPosition + 8); for (size_t j = 0; j < lMaps; j++) { //First thing we have to do is downsample the alpha maps before we can write them if (mBigAlpha) for (int k = 0; k < lDimensions; k++) lAlphaMaps[lDimensions * j + k] = textureSet->getAlpha(j, k); else { unsigned char upperNibble, lowerNibble; for (int k = 0; k < lDimensions; k++) { lowerNibble = static_cast<unsigned char>(std::max(std::min((static_cast<float>(textureSet->getAlpha(j, k * 2 + 0))) * 0.05882f + 0.5f, 15.0f), 0.0f)); upperNibble = static_cast<unsigned char>(std::max(std::min((static_cast<float>(textureSet->getAlpha(j, k * 2 + 1))) * 0.05882f + 0.5f, 15.0f), 0.0f)); lAlphaMaps[lDimensions * j + k] = (upperNibble << 4) + lowerNibble; } } } lCurrentPosition += 8 + lMCAL_Size; lMCNK_Size += 8 + lMCAL_Size; // } //! Don't write anything MCLQ related anymore... // MCSE int lMCSE_Size = 0; lADTFile.Extend(8 + lMCSE_Size); SetChunkHeader(lADTFile, lCurrentPosition, 'MCSE', lMCSE_Size); lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->ofsSndEmitters = lCurrentPosition - lMCNK_Position; lADTFile.GetPointer<MapChunkHeader>(lMCNK_Position + 8)->nSndEmitters = lMCSE_Size / 0x1C; lCurrentPosition += 8 + lMCSE_Size; lMCNK_Size += 8 + lMCSE_Size; lADTFile.GetPointer<sChunkHeader>(lMCNK_Position)->mSize = lMCNK_Size; lADTFile.GetPointer<MCIN>(lMCIN_Position + 8)->mEntries[py * 16 + px].size = lMCNK_Size; }
void MapTile::saveTile() { Log << "Saving ADT \"" << mFilename << "\"." << std::endl; LogDebug << "CHANGED FLAG " << changed << std::endl; int lID; // This is a global counting variable. Do not store something in here you need later. // Collect some information we need later. // Check which doodads and WMOs are on this ADT. Vec3D lTileExtents[2]; unsigned int UID(0); std::map<int, WMOInstance> lObjectInstances; std::map<int, ModelInstance> lModelInstances; lTileExtents[0] = Vec3D(this->xbase, 0.0f, this->zbase); lTileExtents[1] = Vec3D(this->xbase + TILESIZE, 0.0f, this->zbase + TILESIZE); UID += mPositionX * 10000000; UID += mPositionZ * 100000; for (std::map<int, WMOInstance>::iterator it = gWorld->mWMOInstances.begin(); it != gWorld->mWMOInstances.end(); ++it) { if (!it->second.isInsideTile(lTileExtents)) continue; if (!it->second.hasUIDLock()) { it->second.mUniqueID = UID++; it->second.lockUID(); } lObjectInstances[it->second.mUniqueID] = it->second; } for (std::map<int, ModelInstance>::iterator it = gWorld->mModelInstances.begin(); it != gWorld->mModelInstances.end(); ++it) { if (!it->second.isInsideTile(lTileExtents)) continue; if (!it->second.hasUIDLock()) { it->second.d1 = UID++; it->second.lockUID(); } lModelInstances[it->second.d1] = it->second; } filenameOffsetThing nullyThing = { 0, 0 }; std::map<std::string, filenameOffsetThing> lModels; for (std::map<int, ModelInstance>::iterator it = lModelInstances.begin(); it != lModelInstances.end(); ++it) if (lModels.find(it->second.model->_filename) == lModels.end()) lModels.insert(std::pair<std::string, filenameOffsetThing>(it->second.model->_filename, nullyThing)); lID = 0; for (std::map<std::string, filenameOffsetThing>::iterator it = lModels.begin(); it != lModels.end(); ++it) it->second.nameID = lID++; std::map<std::string, filenameOffsetThing> lObjects; for (std::map<int, WMOInstance>::iterator it = lObjectInstances.begin(); it != lObjectInstances.end(); ++it) if (lObjects.find(it->second.wmo->_filename) == lObjects.end()) lObjects.insert(std::pair<std::string, filenameOffsetThing>((it->second.wmo->_filename), nullyThing)); lID = 0; for (std::map<std::string, filenameOffsetThing>::iterator it = lObjects.begin(); it != lObjects.end(); ++it) it->second.nameID = lID++; // Check which textures are on this ADT. std::map<std::string, int> lTextures; for (int i = 0; i < 16; ++i) for (int j = 0; j < 16; ++j) for (size_t tex = 0; tex < mChunks[i][j]->textureSet->num(); tex++) if (lTextures.find(mChunks[i][j]->textureSet->filename(tex)) == lTextures.end()) lTextures.insert(std::pair<std::string, int>(mChunks[i][j]->textureSet->filename(tex), -1)); lID = 0; for (std::map<std::string, int>::iterator it = lTextures.begin(); it != lTextures.end(); ++it) it->second = lID++; // Now write the file. sExtendableArray *lADTFile = new sExtendableArray(); int lCurrentPosition = 0; // MVER lADTFile->Extend(8 + 0x4); SetChunkHeader(*lADTFile, lCurrentPosition, 'MVER', 4); // MVER data *(lADTFile->GetPointer<int>(8)) = 18; lCurrentPosition += 8 + 0x4; // MHDR int lMHDR_Position = lCurrentPosition; lADTFile->Extend(8 + 0x40); SetChunkHeader(*lADTFile, lCurrentPosition, 'MHDR', 0x40); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->flags = mFlags; lCurrentPosition += 8 + 0x40; // MCIN int lMCIN_Position = lCurrentPosition; lADTFile->Extend(8 + 256 * 0x10); SetChunkHeader(*lADTFile, lCurrentPosition, 'MCIN', 256 * 0x10); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mcin = lCurrentPosition - 0x14; lCurrentPosition += 8 + 256 * 0x10; // MTEX int lMTEX_Position = lCurrentPosition; lADTFile->Extend(8 + 0); // We don't yet know how big this will be. SetChunkHeader(*lADTFile, lCurrentPosition, 'MTEX'); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mtex = lCurrentPosition - 0x14; lCurrentPosition += 8 + 0; // MTEX data for (std::map<std::string, int>::iterator it = lTextures.begin(); it != lTextures.end(); ++it) { lADTFile->Insert(lCurrentPosition, it->first.size() + 1, it->first.c_str()); lCurrentPosition += it->first.size() + 1; lADTFile->GetPointer<sChunkHeader>(lMTEX_Position)->mSize += it->first.size() + 1; LogDebug << "Added texture \"" << it->first << "\"." << std::endl; } // MMDX int lMMDX_Position = lCurrentPosition; lADTFile->Extend(8 + 0); // We don't yet know how big this will be. SetChunkHeader(*lADTFile, lCurrentPosition, 'MMDX'); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mmdx = lCurrentPosition - 0x14; lCurrentPosition += 8 + 0; // MMDX data for (std::map<std::string, filenameOffsetThing>::iterator it = lModels.begin(); it != lModels.end(); ++it) { it->second.filenamePosition = lADTFile->GetPointer<sChunkHeader>(lMMDX_Position)->mSize; lADTFile->Insert(lCurrentPosition, it->first.size() + 1, it->first.c_str()); lCurrentPosition += it->first.size() + 1; lADTFile->GetPointer<sChunkHeader>(lMMDX_Position)->mSize += it->first.size() + 1; LogDebug << "Added model \"" << it->first << "\"." << std::endl; } // MMID int lMMID_Size = 4 * lModels.size(); lADTFile->Extend(8 + lMMID_Size); SetChunkHeader(*lADTFile, lCurrentPosition, 'MMID', lMMID_Size); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mmid = lCurrentPosition - 0x14; // MMID data int * lMMID_Data = lADTFile->GetPointer<int>(lCurrentPosition + 8); lID = 0; for (std::map<std::string, filenameOffsetThing>::iterator it = lModels.begin(); it != lModels.end(); ++it) lMMID_Data[lID++] = it->second.filenamePosition; lCurrentPosition += 8 + lMMID_Size; // MWMO int lMWMO_Position = lCurrentPosition; lADTFile->Extend(8 + 0); // We don't yet know how big this will be. SetChunkHeader(*lADTFile, lCurrentPosition, 'MWMO'); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mwmo = lCurrentPosition - 0x14; lCurrentPosition += 8 + 0; // MWMO data for (std::map<std::string, filenameOffsetThing>::iterator it = lObjects.begin(); it != lObjects.end(); ++it) { it->second.filenamePosition = lADTFile->GetPointer<sChunkHeader>(lMWMO_Position)->mSize; lADTFile->Insert(lCurrentPosition, it->first.size() + 1, it->first.c_str()); lCurrentPosition += it->first.size() + 1; lADTFile->GetPointer<sChunkHeader>(lMWMO_Position)->mSize += it->first.size() + 1; LogDebug << "Added object \"" << it->first << "\"." << std::endl; } // MWID int lMWID_Size = 4 * lObjects.size(); lADTFile->Extend(8 + lMWID_Size); SetChunkHeader(*lADTFile, lCurrentPosition, 'MWID', lMWID_Size); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mwid = lCurrentPosition - 0x14; // MWID data int * lMWID_Data = lADTFile->GetPointer<int>(lCurrentPosition + 8); lID = 0; for (std::map<std::string, filenameOffsetThing>::iterator it = lObjects.begin(); it != lObjects.end(); ++it) lMWID_Data[lID++] = it->second.filenamePosition; lCurrentPosition += 8 + lMWID_Size; // MDDF int lMDDF_Size = 0x24 * lModelInstances.size(); lADTFile->Extend(8 + lMDDF_Size); SetChunkHeader(*lADTFile, lCurrentPosition, 'MDDF', lMDDF_Size); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mddf = lCurrentPosition - 0x14; // MDDF data ENTRY_MDDF* lMDDF_Data = lADTFile->GetPointer<ENTRY_MDDF>(lCurrentPosition + 8); lID = 0; for (std::map<int, ModelInstance>::iterator it = lModelInstances.begin(); it != lModelInstances.end(); ++it) { std::map<std::string, filenameOffsetThing>::iterator lMyFilenameThingey = lModels.find(it->second.model->_filename); if (lMyFilenameThingey == lModels.end()) { LogError << "There is a problem with saving the doodads. We have a doodad that somehow changed the name during the saving function. However this got produced, you can get a reward from schlumpf by pasting him this line." << std::endl; return; } lMDDF_Data[lID].nameID = lMyFilenameThingey->second.nameID; lMDDF_Data[lID].uniqueID = it->second.d1; lMDDF_Data[lID].pos[0] = it->second.pos.x; lMDDF_Data[lID].pos[1] = it->second.pos.y; lMDDF_Data[lID].pos[2] = it->second.pos.z; lMDDF_Data[lID].rot[0] = it->second.dir.x; lMDDF_Data[lID].rot[1] = it->second.dir.y; lMDDF_Data[lID].rot[2] = it->second.dir.z; lMDDF_Data[lID].scale = (uint16_t)(it->second.sc * 1024); lMDDF_Data[lID].flags = 0; lID++; } lCurrentPosition += 8 + lMDDF_Size; LogDebug << "Added " << lID << " doodads to MDDF" << std::endl; // MODF int lMODF_Size = 0x40 * lObjectInstances.size(); lADTFile->Extend(8 + lMODF_Size); SetChunkHeader(*lADTFile, lCurrentPosition, 'MODF', lMODF_Size); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->modf = lCurrentPosition - 0x14; // MODF data ENTRY_MODF *lMODF_Data = lADTFile->GetPointer<ENTRY_MODF>(lCurrentPosition + 8); lID = 0; for (std::map<int, WMOInstance>::iterator it = lObjectInstances.begin(); it != lObjectInstances.end(); ++it) { std::map<std::string, filenameOffsetThing>::iterator lMyFilenameThingey = lObjects.find(it->second.wmo->_filename); if (lMyFilenameThingey == lObjects.end()) { LogError << "There is a problem with saving the objects. We have an object that somehow changed the name during the saving function. However this got produced, you can get a reward from schlumpf by pasting him this line." << std::endl; return; } lMODF_Data[lID].nameID = lMyFilenameThingey->second.nameID; lMODF_Data[lID].uniqueID = it->second.mUniqueID; lMODF_Data[lID].pos[0] = it->second.pos.x; lMODF_Data[lID].pos[1] = it->second.pos.y; lMODF_Data[lID].pos[2] = it->second.pos.z; lMODF_Data[lID].rot[0] = it->second.dir.x; lMODF_Data[lID].rot[1] = it->second.dir.y; lMODF_Data[lID].rot[2] = it->second.dir.z; lMODF_Data[lID].extents[0][0] = it->second.extents[0].x; lMODF_Data[lID].extents[0][1] = it->second.extents[0].y; lMODF_Data[lID].extents[0][2] = it->second.extents[0].z; lMODF_Data[lID].extents[1][0] = it->second.extents[1].x; lMODF_Data[lID].extents[1][1] = it->second.extents[1].y; lMODF_Data[lID].extents[1][2] = it->second.extents[1].z; lMODF_Data[lID].flags = it->second.mFlags; lMODF_Data[lID].doodadSet = it->second.doodadset; lMODF_Data[lID].nameSet = it->second.mNameset; lMODF_Data[lID].unknown = it->second.mUnknown; lID++; } LogDebug << "Added " << lID << " wmos to MODF" << std::endl; lCurrentPosition += 8 + lMODF_Size; //MH2O Water->saveToFile(*lADTFile, lMHDR_Position, lCurrentPosition); // MCNK for (int y = 0; y < 16; ++y) { for (int x = 0; x < 16; ++x) { mChunks[y][x]->save(*lADTFile, lCurrentPosition, lMCIN_Position, lTextures, lObjectInstances, lModelInstances); } } // MFBO if (mFlags & 1) { size_t chunkSize = sizeof(int16_t) * 9 * 2; lADTFile->Extend(8 + chunkSize); SetChunkHeader(*lADTFile, lCurrentPosition, 'MFBO', chunkSize); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mfbo = lCurrentPosition - 0x14; int16_t *lMFBO_Data = lADTFile->GetPointer<int16_t>(lCurrentPosition + 8); lID = 0; for (int i = 0; i < 9; ++i) lMFBO_Data[lID++] = (int16_t)mMinimumValues[i * 3 + 1]; for (int i = 0; i < 9; ++i) lMFBO_Data[lID++] = (int16_t)mMaximumValues[i * 3 + 1]; lCurrentPosition += 8 + chunkSize; } //! \todo Do not do bullshit here in MTFX. #if 0 if (!mTextureEffects.empty()) { //! \todo check if nTexEffects == nTextures, correct order etc. lADTFile->Extend(8 + 4 * mTextureEffects.size()); SetChunkHeader(*lADTFile, lCurrentPosition, 'MTFX', 4 * mTextureEffects.size()); lADTFile->GetPointer<MHDR>(lMHDR_Position + 8)->mtfx = lCurrentPosition - 0x14; uint32_t* lMTFX_Data = lADTFile->GetPointer<uint32_t>(lCurrentPosition + 8); lID = 0; //they should be in the correct order... for (std::vector<int>::iterator it = mTextureEffects.begin(); it != mTextureEffects.end(); ++it) { lMTFX_Data[lID] = *it; ++lID; } lCurrentPosition += 8 + sizeof(uint32_t) * mTextureEffects.size(); } #endif lADTFile->Extend(lCurrentPosition - lADTFile->mSize); // cleaning unused nulls at the end of file MPQFile *f = new MPQFile(mFilename); f->setBuffer(lADTFile->GetPointer<char>(), lADTFile->mSize); f->SaveFile(); f->close(); gWorld->mapIndex->markOnDisc(this->mPositionX, this->mPositionZ, true); lObjectInstances.clear(); lModelInstances.clear(); lModels.clear(); delete f; }
void MapIndex::save() { std::stringstream filename; filename << "World\\Maps\\" << basename << "\\" << basename << ".wdt"; Log << "Saving WDT \"" << filename << "\"." << std::endl; sExtendableArray wdtFile = sExtendableArray(); int curPos = 0; // MVER // { wdtFile.Extend(8 + 0x4); SetChunkHeader(wdtFile, curPos, 'MVER', 4); // MVER data *( wdtFile.GetPointer<int>( 8 ) ) = 18; curPos += 8 + 0x4; // } // MPHD // { wdtFile.Extend(8); SetChunkHeader(wdtFile, curPos, 'MPHD', sizeof(MPHD)); curPos += 8; wdtFile.Insert(curPos, sizeof(MPHD), (char*)&mphd); curPos += sizeof(MPHD); // } // MAIN // { wdtFile.Extend(8); SetChunkHeader(wdtFile, curPos, 'MAIN', 64*64*8); curPos += 8; for( int j = 0; j < 64; ++j ) { for( int i = 0; i < 64; ++i ) { wdtFile.Insert(curPos, 4, (char*)&mTiles[j][i].flags); wdtFile.Extend(4); curPos += 8; } } // } if(mHasAGlobalWMO) { // MWMO // { wdtFile.Extend(8); SetChunkHeader(wdtFile, curPos, 'MWMO', globalWMOName.size()); curPos += 8; wdtFile.Insert(curPos, globalWMOName.size(), globalWMOName.data()); curPos += globalWMOName.size(); // } // MODF // { wdtFile.Extend(8); SetChunkHeader(wdtFile, curPos, 'MODF', sizeof(ENTRY_MODF)); curPos += 8; wdtFile.Insert(curPos, sizeof(ENTRY_MODF), (char*)&wmoEntry); curPos += sizeof(ENTRY_MODF); // } } MPQFile f(filename.str()); f.setBuffer(wdtFile.GetPointer<char>(), wdtFile.mSize); f.SaveFile(); f.close(); changed = false; }