/* * Ascent MMORPG Server * Copyright (C) 2005-2007 Ascent Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "StdAfx.h" #include #include "TerrainMgr.h" TerrainMgr::TerrainMgr(string MapPath, uint32 MapId, bool Instanced) : mapPath(MapPath), mapId(MapId), Instance(Instanced) { CellInformation = NULL; } TerrainMgr::~TerrainMgr() { #ifndef USE_MEMORY_MAPPING_FOR_MAPS if(FileDescriptor) { // Free up our file pointer. mutex.Acquire(); fclose(FileDescriptor); mutex.Release(); } // Big memory cleanup, whee. if(CellInformation) { for(uint32 x = 0; x < _sizeX; ++x) { for(uint32 y = 0; y < _sizeY; ++y) { if(CellInformation[x][y] != 0) delete CellInformation[x][y]; } delete [] CellInformation[x]; } delete CellInformation; } #else mutex.Acquire(); // Big memory cleanup, whee. for(uint32 x = 0; x < _sizeX; ++x) { for(uint32 y = 0; y < _sizeY; ++y) { if(CellInformation[x][y] != 0) { #ifdef WIN32 UnmapViewOfFile((LPCVOID)CellInformation[x][y]); #else #error moo #endif } } delete [] CellInformation[x]; } delete CellInformation; #ifdef WIN32 UnmapViewOfFile((LPCVOID)CellOffsets); CloseHandle(hMap); CloseHandle(hMappedFile); #else #error moo #endif mutex.Release(); #endif } bool TerrainMgr::LoadTerrainHeader() { // Create the path char File[200]; snprintf(File, 200, "%s/Map_%u.bin", mapPath.c_str(), (unsigned int)mapId); #ifndef USE_MEMORY_MAPPING_FOR_MAPS FileDescriptor = fopen(File, "rb"); if(FileDescriptor == 0) { sLog.outError("Could not load map file header for %s.", File); return false; } /* check file size */ fseek(FileDescriptor, 0, SEEK_END); if(ftell(FileDescriptor) == 1048576) { /* file with no data */ fclose(FileDescriptor); FileDescriptor=NULL; return false; } // Read in the header. fseek(FileDescriptor,0,SEEK_SET); int dread = fread(CellOffsets, 1, TERRAIN_HEADER_SIZE, FileDescriptor); if(dread != TERRAIN_HEADER_SIZE) { fclose(FileDescriptor); FileDescriptor=NULL; return false; } // Allocate both storage arrays. CellInformation = new CellTerrainInformation**[_sizeX]; for(uint32 x = 0; x < _sizeX; ++x) { CellInformation[x] = new CellTerrainInformation*[_sizeY]; for(uint32 y = 0; y < _sizeY; ++y) { // Clear the pointer. CellInformation[x][y] = 0; } } #ifdef USING_BIG_ENDIAN uint32 x,y; for(x=0;x<512;++x) { for(y=0;y<512;++y) { CellOffsets[x][y] = swap32(CellOffsets[x][y]); } } #endif return true; #else #ifdef WIN32 hMappedFile = CreateFile(File, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL); if(hMappedFile == INVALID_HANDLE_VALUE) return false; DWORD bytes; ASSERT(ReadFile(hMappedFile, CellOffsets, TERRAIN_HEADER_SIZE, &bytes, NULL)); ASSERT(bytes == TERRAIN_HEADER_SIZE); SetFilePointer(hMappedFile, 0, 0, FILE_END); mFileSize = GetFileSize(hMappedFile, NULL); hMap = CreateFileMapping(hMappedFile, NULL, PAGE_READONLY, 0, 0, NULL); if(hMap == INVALID_HANDLE_VALUE) { CloseHandle(hMappedFile); hMappedFile = INVALID_HANDLE_VALUE; return false; } // Map the terrain header //CellOffsets = (uint32**)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, TERRAIN_HEADER_SIZE); //memcpy(temp, CellOffsets, TERRAIN_HEADER_SIZE); #else #error unimplemented in *nix #endif return true; #endif } bool TerrainMgr::LoadCellInformation(uint32 x, uint32 y) { #ifdef USE_MEMORY_MAPPING_FOR_MAPS if(!CellOffsets) return false; #else if(!FileDescriptor) return false; #endif // Make sure that we're not already loaded. assert(CellInformation[x][y] == 0); // Find our offset in our cached header. uint32 Offset = CellOffsets[x][y]; // If our offset = 0, it means we don't have cell information for // these coords. if(Offset == 0) return false; // Lock the mutex to prevent double reading. mutex.Acquire(); // Check that we haven't been loaded by another thread. if(CellInformation[x][y] != 0) { mutex.Release(); return true; } #ifdef USE_MEMORY_MAPPING_FOR_MAPS #ifdef WIN32 if(Offset >= mFileSize) { mutex.Release(); return false; } CellInformation[x][y] = (CellTerrainInformation*)MapViewOfFile(hMap, FILE_MAP_READ, 0, Offset, sizeof(CellTerrainInformation)); #else #error moo #endif #else // Seek to our specified offset. if(fseek(FileDescriptor, Offset, SEEK_SET) == 0) { // Allocate the cell information. CellInformation[x][y] = new CellTerrainInformation; // Read from our file into this newly created struct. fread(CellInformation[x][y], sizeof(CellTerrainInformation), 1, FileDescriptor); #ifdef USING_BIG_ENDIAN uint32 i,j; /* Swap all the data */ for(i = 0; j < 2; ++j) { for(j = 0; j < 2; ++j) { CellInformation[x][y]->AreaID[i][j] = swap16(CellInformation[x][y]->AreaID[i][j]); CellInformation[x][y]->LiquidLevel[i][j] = swapfloat(CellInformation[x][y]->LiquidLevel[i][j]); } } for(i = 0; i < 32; ++j) { for(j = 0; j < 32; ++j) { CellInformation[x][y]->Z[i][j] = swapfloat(CellInformation[x][y]->Z[i][j]); } } #endif } #endif // Release the mutex. mutex.Release(); // If we don't equal 0, it means the load was successful. if(CellInformation[x][y] != 0) return true; else return false; } bool TerrainMgr::UnloadCellInformation(uint32 x, uint32 y) { uint32 Start = getMSTime(); assert(!Instance); // Find our information pointer. CellTerrainInformation * ptr = CellInformation[x][y]; assert(ptr != 0); // Set the spot to unloaded (null). CellInformation[x][y] = 0; #ifdef USE_MEMORY_MAPPING_FOR_MAPS #ifdef WIN32 if(!UnmapViewOfFile((LPCVOID)ptr)) Log.Error("TerrainMgr", "Could not unmap view of file at memory address 0x%.8X", ptr); #else #error moo #endif #else // Free the memory. delete ptr; #endif sLog.outDetail("Unloaded cell information for cell [%u][%u] in %ums.", x, y, getMSTime() - Start); // Success return true; } uint8 TerrainMgr::GetWaterType(float x, float y) { if(!AreCoordinatesValid(x, y)) return 0; // Convert the co-ordinates to cells. uint32 CellX = ConvertGlobalXCoordinate(x); uint32 CellY = ConvertGlobalYCoordinate(y); if(!CellInformationLoaded(CellX, CellY)) return 0; // Convert the co-ordinates to cell's internal // system. float IntX = ConvertInternalXCoordinate(x, CellX); float IntY = ConvertInternalYCoordinate(y, CellY); // Find the offset in the 2d array. return GetCellInformation(CellX, CellY)->LiquidType[ConvertTo2dArray(IntX)][ConvertTo2dArray(IntY)]; } float TerrainMgr::GetWaterHeight(float x, float y) { if(!AreCoordinatesValid(x, y)) return 0.0f; // Convert the co-ordinates to cells. uint32 CellX = ConvertGlobalXCoordinate(x); uint32 CellY = ConvertGlobalYCoordinate(y); if(!CellInformationLoaded(CellX, CellY)) return 0.0f; // Convert the co-ordinates to cell's internal // system. float IntX = ConvertInternalXCoordinate(x, CellX); float IntY = ConvertInternalYCoordinate(y, CellY); // Find the offset in the 2d array. return GetCellInformation(CellX, CellY)->LiquidLevel[ConvertTo2dArray(IntX)][ConvertTo2dArray(IntY)]; } uint8 TerrainMgr::GetWalkableState(float x, float y) { // This has to be implemented. return 1; } uint16 TerrainMgr::GetAreaID(float x, float y) { if(!AreCoordinatesValid(x, y)) return 0; // Convert the co-ordinates to cells. uint32 CellX = ConvertGlobalXCoordinate(x); uint32 CellY = ConvertGlobalYCoordinate(y); if(!CellInformationLoaded(CellX, CellY) && !LoadCellInformation(CellX, CellY)) return 0; // Convert the co-ordinates to cell's internal // system. float IntX = ConvertInternalXCoordinate(x, CellX); float IntY = ConvertInternalYCoordinate(y, CellY); // Find the offset in the 2d array. return GetCellInformation(CellX, CellY)->AreaID[ConvertTo2dArray(IntX)][ConvertTo2dArray(IntY)]; } float TerrainMgr::GetLandHeight(float x, float y) { if(!AreCoordinatesValid(x, y)) return 0.0f; // Convert the co-ordinates to cells. uint32 CellX = ConvertGlobalXCoordinate(x); uint32 CellY = ConvertGlobalYCoordinate(y); if(!CellInformationLoaded(CellX, CellY) && !LoadCellInformation(CellX, CellY)) return 0.0f; // Convert the co-ordinates to cell's internal // system. float IntX = ConvertInternalXCoordinate(x, CellX); float IntY = ConvertInternalYCoordinate(y, CellY); // Calculate x index. float TempFloat = IntX * (MAP_RESOLUTION / CellsPerTile / _cellSize); uint32 XOffset = FL2UINT(TempFloat); if((TempFloat - (XOffset * _cellSize)) >= 0.5f) ++XOffset; // Calculate y index. TempFloat = IntY * (MAP_RESOLUTION / CellsPerTile / _cellSize); uint32 YOffset = FL2UINT(TempFloat); if((TempFloat - (YOffset * _cellSize)) >= 0.5f) ++YOffset; // Return our cached information. return GetCellInformation(CellX, CellY)->Z[XOffset][YOffset]; } void TerrainMgr::CellGoneActive(uint32 x, uint32 y) { // Load cell information if it's not already loaded. if(!CellInformationLoaded(x, y)) LoadCellInformation(x, y); } void TerrainMgr::CellGoneIdle(uint32 x, uint32 y) { // If we're not an instance, unload our cell info. if(!Instance && CellInformationLoaded(x, y) && sWorld.UnloadMapFiles) UnloadCellInformation(x, y); }