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; }