예제 #1
0
파일: MapTile.cpp 프로젝트: Ikesters/noggit
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;
}