uox3/source/regions.cpp
2022-06-16 17:29:36 -04:00

1016 lines
38 KiB
C++

#include "uox3.h"
#include "classes.h"
#include "regions.h"
#include "StringUtility.hpp"
#include "ObjectFactory.h"
#include <filesystem>
#define DEBUG_REGIONS 0
CMapHandler *MapRegion;
//o-----------------------------------------------------------------------------------------------o
//| Function - SI32 FileSize( std::string filename )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the filesize of a given file
//o-----------------------------------------------------------------------------------------------o
SI32 FileSize( std::string filename )
{
SI32 retVal = 0;
try {
retVal = static_cast<SI32>(std::filesystem::file_size( filename ));
} catch( ... ) {
retVal = 0;
}
return retVal;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadChar( std::ifstream& readDestination )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Creates a new character object based on data loaded from worldfiles
//o-----------------------------------------------------------------------------------------------o
void LoadChar( std::ifstream& readDestination )
{
CChar *x = static_cast< CChar * >(ObjectFactory::getSingleton().CreateBlankObject( OT_CHAR ));
if( x == nullptr )
return;
if( !x->Load( readDestination ) )
{
x->Cleanup();
ObjectFactory::getSingleton().DestroyObject( x );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadItem( std::ifstream& readDestination )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Creates a new item object based on data loaded from worldfiles
//o-----------------------------------------------------------------------------------------------o
void LoadItem( std::ifstream& readDestination )
{
CItem *x = static_cast< CItem * >(ObjectFactory::getSingleton().CreateBlankObject( OT_ITEM ));
if( x == nullptr )
return;
if( !x->Load( readDestination ) )
{
x->Cleanup();
ObjectFactory::getSingleton().DestroyObject( x );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadMulti( std::ifstream& readDestination )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Creates a new multi object, like a house, based on data loaded from worldfiles
//o-----------------------------------------------------------------------------------------------o
void LoadMulti( std::ifstream& readDestination )
{
CMultiObj *ourHouse = static_cast< CMultiObj * >(ObjectFactory::getSingleton().CreateBlankObject( OT_MULTI ));
if( !ourHouse->Load( readDestination ) ) // if no load, DELETE
{
ourHouse->Cleanup();
ObjectFactory::getSingleton().DestroyObject( ourHouse );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadBoat( std::ifstream& readDestination )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Creates a new boat object based on data loaded from worldfiles
//o-----------------------------------------------------------------------------------------------o
void LoadBoat( std::ifstream& readDestination )
{
CBoatObj *ourBoat = static_cast< CBoatObj * >(ObjectFactory::getSingleton().CreateBlankObject( OT_BOAT ));
if( !ourBoat->Load( readDestination ) ) // if no load, DELETE
{
ourBoat->Cleanup();
ObjectFactory::getSingleton().DestroyObject( ourBoat );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadSpawnItem( std::ifstream& readDestination )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Creates a new spawn object based on data loaded from worldfiles
//o-----------------------------------------------------------------------------------------------o
void LoadSpawnItem( std::ifstream& readDestination )
{
CSpawnItem *ourSpawner = static_cast< CSpawnItem * >(ObjectFactory::getSingleton().CreateBlankObject( OT_SPAWNER ));
if( !ourSpawner->Load( readDestination ) ) // if no load, DELETE
{
ourSpawner->Cleanup();
ObjectFactory::getSingleton().DestroyObject( ourSpawner );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Functio - void SaveToDisk( std::ofstream& writeDestination, std::ofstream &houseDestination )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Save all items and characters inside a subregion reworked SaveChar from WorldMain
//| to deal with pointer based stuff in region rather than index based stuff in array
//| Also saves out all data regardless (in preparation for a simple binary save)
//o-----------------------------------------------------------------------------------------------o
void CMapRegion::SaveToDisk( std::ofstream& writeDestination, std::ofstream &houseDestination )
{
charData.Push();
std::vector<CChar *> removeChar ;
for (const auto &charToWrite: charData.collection()) {
if( !ValidateObject( charToWrite ) ){
removeChar.push_back(charToWrite);
}
else {
#if defined( _MSC_VER )
#pragma todo( "PlayerHTML Dumping needs to be reimplemented" )
#endif
if( charToWrite->ShouldSave() ){
charToWrite->Save( writeDestination );
}
}
}
std::for_each(removeChar.begin(), removeChar.end(), [this](CChar *character) {
charData.Remove(character);
});
std::vector<CItem *> removeItem ;
for (const auto &itemToWrite: itemData.collection()) {
if( !ValidateObject( itemToWrite ) ) {
removeItem.push_back(itemToWrite);
}
else {
if( itemToWrite->ShouldSave() ) {
if( itemToWrite->GetObjType() == OT_MULTI ) {
CMultiObj *iMulti = static_cast<CMultiObj *>(itemToWrite);
iMulti->Save( houseDestination );
}
else if( itemToWrite->GetObjType() == OT_BOAT ) {
CBoatObj *iBoat = static_cast< CBoatObj * >(itemToWrite);
iBoat->Save( houseDestination );
}
else{
itemToWrite->Save( writeDestination );
}
}
}
}
std::for_each(removeItem.begin(), removeItem.end(), [this](CItem *item) {
itemData.Remove(item);
});
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GenericList< CItem * > * GetItemList( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the Item DataList for iteration
//o-----------------------------------------------------------------------------------------------o
GenericList< CItem * > * CMapRegion::GetItemList( void )
{
return &itemData;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GenericList< CChar * > * GetCharList( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the Character DataList for iteration
//o-----------------------------------------------------------------------------------------------o
GenericList< CChar * > * CMapRegion::GetCharList( void )
{
return &charData;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - RegionSerialList< SERIAL > * GetRegionSerialList( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the list of baseobject serials for iteration
//o-----------------------------------------------------------------------------------------------o
RegionSerialList* CMapRegion::GetRegionSerialList()
{
return &regionSerialData;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool HasRegionChanged( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns a flag that says whether the region has seen any updates since last save
//o-----------------------------------------------------------------------------------------------o
bool CMapRegion::HasRegionChanged( void )
{
return hasRegionChanged;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void HasRegionChanged( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Sets a flag that says whether the region has seen any updates since last save
//o-----------------------------------------------------------------------------------------------o
void CMapRegion::HasRegionChanged( bool newVal )
{
hasRegionChanged = newVal;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CMapWorld Constructor/Destructor
//| Date - 17 October, 2005
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Initializes & Clears the MapWorld data
//o-----------------------------------------------------------------------------------------------o
CMapWorld::CMapWorld() : upperArrayX( 0 ), upperArrayY( 0 ), resourceX( 0 ), resourceY( 0 )
{
mapResources.resize( 1 ); // ALWAYS initialize at least one resource region.
mapRegions.resize( 0 );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CMapWorld::CMapWorld( UI08 worldNum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Initializes resource regions for the given world
//o-----------------------------------------------------------------------------------------------o
CMapWorld::CMapWorld( UI08 worldNum )
{
auto [width,height] = Map->sizeOfMap(worldNum);
upperArrayX = static_cast<SI16>(width / MapColSize);
upperArrayY = static_cast<SI16>(height/ MapRowSize);
resourceX = static_cast<UI16>(width / cwmWorldState->ServerData()->ResourceAreaSize());
resourceY = static_cast<UI16>(height / cwmWorldState->ServerData()->ResourceAreaSize());
size_t resourceSize = (static_cast<size_t>(resourceX) * static_cast<size_t>(resourceY));
if( resourceSize < 1 ) // ALWAYS initialize at least one resource region.
resourceSize = 1;
mapResources.resize( resourceSize );
mapRegions.resize( static_cast<size_t>(upperArrayX) * static_cast<size_t>(upperArrayY) );
}
CMapWorld::~CMapWorld()
{
mapResources.resize( 0 );
mapRegions.resize( 0 );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CMapRegion * GetMapRegion( SI16 xOffset, SI16 yOffset )
//| Date - 9/13/2005
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the MapRegion based on its x and y offsets
//o-----------------------------------------------------------------------------------------------o
CMapRegion * CMapWorld::GetMapRegion( SI16 xOffset, SI16 yOffset )
{
CMapRegion *mRegion = nullptr;
const size_t regionIndex = (static_cast<size_t>(xOffset) * static_cast<size_t>(upperArrayY) + static_cast<size_t>(yOffset));
if( xOffset >= 0 && xOffset < upperArrayX && yOffset >= 0 && yOffset < upperArrayY )
{
if( regionIndex < mapRegions.size() )
mRegion = &mapRegions[regionIndex];
}
return mRegion;
}
std::vector< CMapRegion > * CMapWorld::GetMapRegions()
{
return &mapRegions;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - MapResource_st& GetResource( SI16 x, SI16 y )
//| Date - 9/17/2005
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the Resource region x and y is.
//o-----------------------------------------------------------------------------------------------o
MapResource_st& CMapWorld::GetResource( SI16 x, SI16 y )
{
const UI16 gridX = (x / cwmWorldState->ServerData()->ResourceAreaSize());
const UI16 gridY = (y / cwmWorldState->ServerData()->ResourceAreaSize());
size_t resIndex = ((static_cast<size_t>(gridX) * static_cast<size_t>(resourceY)) + static_cast<size_t>(gridY));
if( gridX >= resourceX || gridY >= resourceY || resIndex > mapResources.size() )
resIndex = 0;
return mapResources[resIndex];
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void SaveResources( UI08 worldNum )
//| Date - 9/17/2005
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Saves the Resource data to disk
//o-----------------------------------------------------------------------------------------------o
void CMapWorld::SaveResources( UI08 worldNum )
{
char wBuffer[2];
const std::string resourceFile = cwmWorldState->ServerData()->Directory( CSDDP_SHARED ) + "resource[" + std::to_string( worldNum ) + "].bin";
std::ofstream toWrite( resourceFile.c_str(), std::ios::out | std::ios::trunc | std::ios::binary );
if( toWrite )
{
for( std::vector< MapResource_st >::const_iterator mIter = mapResources.begin(); mIter != mapResources.end(); ++mIter )
{
wBuffer[0] = static_cast<SI08>((*mIter).oreAmt>>8);
wBuffer[1] = static_cast<SI08>((*mIter).oreAmt%256);
toWrite.write( (const char *)&wBuffer, 2 );
wBuffer[0] = static_cast<SI08>((*mIter).logAmt>>8);
wBuffer[1] = static_cast<SI08>((*mIter).logAmt%256);
toWrite.write( (const char *)&wBuffer, 2 );
wBuffer[0] = static_cast<SI08>((*mIter).fishAmt>>8);
wBuffer[1] = static_cast<SI08>((*mIter).fishAmt%256);
toWrite.write( (const char *)&wBuffer, 2 );
}
toWrite.close();
}
else // Can't save resources
Console.error( "Failed to open resource.bin for writing" );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadResources( UI08 worldNum )
//| Date - 9/17/2005
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Loads the Resource data from the disk
//o-----------------------------------------------------------------------------------------------o
void CMapWorld::LoadResources( UI08 worldNum )
{
const SI16 resOre = cwmWorldState->ServerData()->ResOre();
const SI16 resLog = cwmWorldState->ServerData()->ResLogs();
const SI16 resFish = cwmWorldState->ServerData()->ResFish();
const UI32 oreTime = BuildTimeValue( static_cast<R32>(cwmWorldState->ServerData()->ResOreTime()) );
const UI32 logTime = BuildTimeValue( static_cast<R32>(cwmWorldState->ServerData()->ResLogTime()) );
const UI32 fishTime = BuildTimeValue( static_cast<R32>(cwmWorldState->ServerData()->ResFishTime()) );
const std::string resourceFile = cwmWorldState->ServerData()->Directory( CSDDP_SHARED ) + std::string("resource[") + oldstrutil::number( worldNum ) + std::string("].bin");
char rBuffer[2];
std::ifstream toRead ( resourceFile.c_str(), std::ios::in | std::ios::binary );
bool fileExists = ( toRead.is_open() );
if( fileExists )
toRead.seekg( 0, std::ios::beg );
for( std::vector< MapResource_st >::iterator mIter = mapResources.begin(); mIter != mapResources.end(); ++mIter )
{
if( fileExists )
{
toRead.read( rBuffer, 2 );
(*mIter).oreAmt = ( (rBuffer[0]<<8) + rBuffer[1] );
toRead.read( rBuffer, 2 );
(*mIter).logAmt = ( (rBuffer[0]<<8) + rBuffer[1] );
toRead.read( rBuffer, 2 );
(*mIter).fishAmt = ( (rBuffer[0]<<8) + rBuffer[1] );
fileExists = toRead.eof();
}
else
{
(*mIter).oreAmt = resOre;
(*mIter).logAmt = resLog;
(*mIter).fishAmt = resFish;
}
// No need to preserve time. Do a refresh automatically
(*mIter).oreTime = oreTime;
(*mIter).logTime = logTime;
(*mIter).fishTime = fishTime;
}
if( fileExists )
toRead.close();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CMapHandler Constructor/Destructor
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Fills and clears the mapWorlds vector.
//o-----------------------------------------------------------------------------------------------o
auto CMapHandler::startup() ->void {
UI08 numWorlds = Map->MapCount();
mapWorlds.reserve( numWorlds );
for( UI08 i = 0; i < numWorlds; ++i )
{
mapWorlds.push_back( new CMapWorld( i ) );
}
}
CMapHandler::~CMapHandler()
{
for( WORLDLIST_ITERATOR mIter = mapWorlds.begin(); mIter != mapWorlds.end(); ++mIter )
{
if( (*mIter) != nullptr )
{
delete (*mIter);
(*mIter) = nullptr;
}
}
mapWorlds.resize( 0 );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool ChangeRegion( CItem *nItem, SI16 x, SI16 y, UI08 worldNum )
//| Date - February 1, 2006
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Changes an items region ONLY if he has changed regions.
//o-----------------------------------------------------------------------------------------------o
bool CMapHandler::ChangeRegion( CItem *nItem, SI16 x, SI16 y, UI08 worldNum )
{
if( !ValidateObject( nItem ) )
return false;
CMapRegion *curCell = GetMapRegion( nItem );
CMapRegion *newCell = GetMapRegion( GetGridX( x ), GetGridY( y ), worldNum );
if( curCell != newCell )
{
if( !curCell->GetRegionSerialList()->Remove( nItem->GetSerial() ) || !curCell->GetItemList()->Remove( nItem ) )
{
#if DEBUG_REGIONS
Console.warning( oldstrutil::format( "Item 0x%X does not exist in MapRegion, remove failed", nItem->GetSerial() ));
#endif
}
else
{
if( nItem->ShouldSave() )
curCell->HasRegionChanged( true );
}
if( newCell->GetRegionSerialList()->Add( nItem->GetSerial() ))
{
newCell->GetItemList()->Add( nItem, false );
if( nItem->ShouldSave() )
newCell->HasRegionChanged( true );
return true;
}
else
{
#if DEBUG_REGIONS
Console.warning( oldstrutil::format( "Item 0x%X already exists in MapRegion, add failed", nItem->GetSerial() ));
#endif
}
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool ChangeRegion( CChar *nChar, SI16 x, SI16 y, UI08 worldNum )
//| Date - February 1, 2006
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Changes a characters region ONLY if he has changed regions.
//o-----------------------------------------------------------------------------------------------o
bool CMapHandler::ChangeRegion( CChar *nChar, SI16 x, SI16 y, UI08 worldNum )
{
if( !ValidateObject( nChar ) )
return false;
CMapRegion *curCell = GetMapRegion( nChar );
CMapRegion *newCell = GetMapRegion( GetGridX( x ), GetGridY( y ), worldNum );
if( curCell != newCell )
{
if( !curCell->GetRegionSerialList()->Remove( nChar->GetSerial() ) || !curCell->GetCharList()->Remove( nChar ) )
{
#if DEBUG_REGIONS
Console.warning( oldstrutil::format( "Character 0x%X does not exist in MapRegion, remove failed", nChar->GetSerial() ));
#endif
}
else
{
if( nChar->ShouldSave() )
curCell->HasRegionChanged( true );
}
if( newCell->GetRegionSerialList()->Add( nChar->GetSerial() ))
{
newCell->GetCharList()->Add( nChar, false );
if( nChar->ShouldSave() )
newCell->HasRegionChanged( true );
return true;
}
else
{
#if DEBUG_REGIONS
Console.warning( oldstrutil::format( "Character 0x%X already exists in MapRegion, add failed", nChar->GetSerial() ));
#endif
}
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool AddItem( CItem *nItem )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Adds nItem to the proper SubRegion
//o-----------------------------------------------------------------------------------------------o
bool CMapHandler::AddItem( CItem *nItem )
{
if( !ValidateObject( nItem ) )
return false;
CMapRegion *cell = GetMapRegion( nItem );
if( cell->GetRegionSerialList()->Add( nItem->GetSerial() ))
{
cell->GetItemList()->Add( nItem, false );
if( nItem->ShouldSave() )
cell->HasRegionChanged( true );
return true;
}
else
{
#if DEBUG_REGIONS
Console.warning( oldstrutil::format( "Item 0x%X already exists in MapRegion, add failed", nItem->GetSerial() ));
#endif
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool RemoveItem( CItem *nItem )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Removes nItem from it's CURRENT SubRegion. Do this before adjusting the location
//o-----------------------------------------------------------------------------------------------o
bool CMapHandler::RemoveItem( CItem *nItem )
{
if( !ValidateObject( nItem ) )
return false;
CMapRegion *cell = GetMapRegion( nItem );
if( cell->GetRegionSerialList()->Remove( nItem->GetSerial() ) )
{
cell->GetItemList()->Remove( nItem );
if( nItem->ShouldSave() )
cell->HasRegionChanged( true );
}
else
{
#if DEBUG_REGIONS
Console.warning( oldstrutil::format( "Item 0x%X does not exist in MapRegion, remove failed", nItem->GetSerial() ));
#endif
return false;
}
return true;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool AddChar( CChar *toAdd )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Adds toAdd to the proper SubRegion
//o-----------------------------------------------------------------------------------------------o
bool CMapHandler::AddChar( CChar *toAdd )
{
if( !ValidateObject( toAdd ) )
return false;
CMapRegion *cell = GetMapRegion( toAdd );
if( cell->GetRegionSerialList()->Add( toAdd->GetSerial() ))
{
cell->GetCharList()->Add( toAdd, false );
if( toAdd->ShouldSave() )
cell->HasRegionChanged( true );
return true;
}
else
{
#if DEBUG_REGIONS
Console.warning( oldstrutil::format( "Character 0x%X already exists in MapRegion, add failed", toAdd->GetSerial() ));
#endif
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool RemoveChar( CChar *toRemove )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Removes toRemove from it's CURRENT SubRegion. Do this before adjusting the location
//o-----------------------------------------------------------------------------------------------o
bool CMapHandler::RemoveChar( CChar *toRemove )
{
if( !ValidateObject( toRemove ) )
return false;
CMapRegion *cell = GetMapRegion( toRemove );
if( cell->GetRegionSerialList()->Remove( toRemove->GetSerial() ) )
{
cell->GetCharList()->Remove( toRemove );
if( toRemove->ShouldSave() )
cell->HasRegionChanged( true );
}
else
{
#if DEBUG_REGIONS
Console.warning( oldstrutil::format( "Character 0x%X does not exist in MapRegion, remove failed", toRemove->GetSerial() ));
#endif
return false;
}
return true;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI16 GetGridX( SI16 x )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Find the Column of SubRegion we want based on location
//o-----------------------------------------------------------------------------------------------o
SI16 CMapHandler::GetGridX( SI16 x )
{
return static_cast<SI16>(x / MapColSize);
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SI16 GetGridY( SI16 y )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Finds the Row of SubRegion we want based on location
//o-----------------------------------------------------------------------------------------------o
SI16 CMapHandler::GetGridY( SI16 y )
{
return static_cast<SI16>(y / MapRowSize);
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CMapRegion *GetMapRegion( SI16 xOffset, SI16 yOffset, UI08 worldNumber )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the MapRegion based on the offsets
//o-----------------------------------------------------------------------------------------------o
CMapRegion *CMapHandler::GetMapRegion( SI16 xOffset, SI16 yOffset, UI08 worldNumber )
{
CMapRegion * mRegion = mapWorlds[worldNumber]->GetMapRegion( xOffset, yOffset );
if( mRegion == nullptr )
mRegion = &overFlow;
return mRegion;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CMapRegion *GetMapRegion( SI16 x, SI16 y )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the subregion that x,y is in
//o-----------------------------------------------------------------------------------------------o
CMapRegion *CMapHandler::GetMapRegion( CBaseObject *mObj )
{
return GetMapRegion( GetGridX( mObj->GetX() ), GetGridY( mObj->GetY() ), mObj->WorldNumber() );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CMapWorld * GetMapWorld( UI08 worldNum )
//| Date - 9/13/2005
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the MapWorld object associated with the worldNumber
//o-----------------------------------------------------------------------------------------------o
CMapWorld * CMapHandler::GetMapWorld( UI08 worldNum )
{
CMapWorld *mWorld = nullptr;
if( worldNum > mapWorlds.size() )
mWorld = mapWorlds[worldNum];
return mWorld;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - CMapWorld * GetMapWorld( UI08 worldNum )
//| Date - 9/13/2005
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the MapWorld object associated with the worldNumber
//o-----------------------------------------------------------------------------------------------o
MapResource_st * CMapHandler::GetResource( SI16 x, SI16 y, UI08 worldNum )
{
MapResource_st *resData = nullptr;
if( worldNum < mapWorlds.size() )
resData = &mapWorlds[worldNum]->GetResource( x, y );
return resData;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - auto PopulateList( CBaseObject *mObj ) -> std::vector< CMapRegion * >
//| Date - Unknown
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Creates a list of nearby MapRegions based on the object provided
//o-----------------------------------------------------------------------------------------------o
auto CMapHandler::PopulateList( CBaseObject *mObj ) -> std::vector< CMapRegion * > {
return PopulateList( mObj->GetX(), mObj->GetY(), mObj->WorldNumber() );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - auto PopulateList( SI16 x, SI16 y, UI08 worldNumber ) -> std::vector< CMapRegion * >
//| Date - Unknown
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Creates a list of nearby MapRegions based on the coordinates provided
//o-----------------------------------------------------------------------------------------------o
auto CMapHandler::PopulateList( SI16 x, SI16 y, UI08 worldNumber ) -> std::vector< CMapRegion * >
{
std::vector< CMapRegion * > nearbyRegions;
const SI16 xOffset = MapRegion->GetGridX( x );
const SI16 yOffset = MapRegion->GetGridY( y );
for( SI08 counter1 = -1; counter1 <= 1; ++counter1 )
{
for( SI08 counter2 = -1; counter2 <= 1; ++counter2 )
{
CMapRegion *MapArea = GetMapRegion( xOffset + counter1, yOffset + counter2, worldNumber );
if( MapArea == nullptr )
continue;
nearbyRegions.push_back( MapArea );
}
}
return nearbyRegions;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Save( void )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Saves out the MapRegions
//o-----------------------------------------------------------------------------------------------o
void CMapHandler::Save( void )
{
const SI16 AreaX = UpperX / 8; // we're storing 8x8 grid arrays together
const SI16 AreaY = UpperY / 8;
std::ofstream writeDestination, houseDestination;
SI32 onePercent = 0;
//const SI32 onePercent = (SI32)((R32)(UpperX*UpperY*Map->MapCount())/100.0f);
UI08 i = 0;
for( i = 0; i < Map->MapCount(); ++i )
{
auto [width,height] = Map->sizeOfMap(i);
onePercent += static_cast<std::int32_t>((width/MapColSize) * (height/MapRowSize));
}
onePercent /= 100.0f;
const char blockDiscriminator[] = "\n\n---REGION---\n\n";
UI32 count = 0;
const UI32 s_t = getclock();
Console << "Saving Character and Item Map Region data... ";
Console.TurnYellow();
Console << "0%";
std::string basePath = cwmWorldState->ServerData()->Directory( CSDDP_SHARED );
std::string filename = basePath + "house.wsc";
houseDestination.open( filename.c_str() );
for( SI16 counter1 = 0; counter1 < AreaX; ++counter1 ) // move left->right
{
const SI32 baseX = counter1 * 8;
for( SI16 counter2 = 0; counter2 < AreaY; ++counter2 ) // move up->down
{
const SI32 baseY = counter2 * 8; // calculate x grid offset
filename = basePath + oldstrutil::number( counter1 ) + std::string(".") + oldstrutil::number( counter2 ) + std::string(".wsc"); // let's name our file
bool changesDetected = false;
for( UI08 xCnt = 0; !changesDetected && xCnt < 8; ++xCnt ) // walk through each part of the 8x8 grid, left->right
{
for( UI08 yCnt = 0; !changesDetected && yCnt < 8; ++yCnt ) // walk the row
{
for( WORLDLIST_ITERATOR mIter = mapWorlds.begin(); mIter != mapWorlds.end(); ++mIter )
{
CMapRegion * mRegion = (*mIter)->GetMapRegion( (baseX+xCnt), (baseY+yCnt) );
if( mRegion != nullptr )
{
// Only save objects mapRegions marked as "changed" by objects updated in said regions
if( mRegion->HasRegionChanged() )
{
changesDetected = true;
break;
}
}
}
}
}
if( !changesDetected )
continue;
writeDestination.open( filename.c_str() );
if( !writeDestination )
{
Console.error( oldstrutil::format("Failed to open %s for writing", filename.c_str()) );
continue;
}
for( UI08 xCnt = 0; xCnt < 8; ++xCnt ) // walk through each part of the 8x8 grid, left->right
{
for( UI08 yCnt = 0; yCnt < 8; ++yCnt ) // walk the row
{
for( WORLDLIST_ITERATOR mIter = mapWorlds.begin(); mIter != mapWorlds.end(); ++mIter )
{
++count;
if( count%onePercent == 0 )
{
if( count/onePercent <= 10 )
Console << "\b\b" << (UI32)(count/onePercent) << "%";
else if( count/onePercent <= 100 )
Console << "\b\b\b" << (UI32)(count/onePercent) << "%";
}
CMapRegion * mRegion = (*mIter)->GetMapRegion( (baseX+xCnt), (baseY+yCnt) );
if( mRegion != nullptr )
{
mRegion->SaveToDisk( writeDestination, houseDestination );
// Remove "changed" flag from region, to avoid it saving again needlessly on next save
mRegion->HasRegionChanged( false );
}
writeDestination << blockDiscriminator;
}
}
}
writeDestination.close();
}
}
Console << "\b\b\b\b" << (UI32)(100) << "%";
houseDestination.close();
filename = basePath + "overflow.wsc";
writeDestination.open( filename.c_str() );
if( writeDestination.is_open() )
{
overFlow.SaveToDisk( writeDestination, writeDestination );
writeDestination.close();
}
else
{
Console.error( oldstrutil::format("Failed to open %s for writing", filename.c_str()) );
return;
}
Console << "\b\b\b\b";
Console.PrintDone();
const UI32 e_t = getclock();
Console.print( oldstrutil::format("World saved in %.02fsec\n", ((R32)(e_t-s_t))/1000.0f ));
i = 0;
for( WORLDLIST_ITERATOR wIter = mapWorlds.begin(); wIter != mapWorlds.end(); ++wIter )
{
(*wIter)->SaveResources( i );
++i;
}
}
bool PostLoadFunctor( CBaseObject *a, UI32 &b, void *extraData )
{
if( ValidateObject( a ) )
{
if( !a->isFree() )
a->PostLoadProcessing();
}
return true;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Load( void )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Loads in the MapRegions
//o-----------------------------------------------------------------------------------------------o
void CMapHandler::Load( void )
{
const SI16 AreaX = UpperX / 8; // we're storing 8x8 grid arrays together
const SI16 AreaY = UpperY / 8;
// const SI32 onePercent = (SI32)((R32)(AreaX*AreaY)/100.0f);
UI32 count = 0;
std::ifstream readDestination;
Console.TurnYellow();
Console << "0%";
UI32 s_t = getclock();
std::string basePath = cwmWorldState->ServerData()->Directory( CSDDP_SHARED );
std::string filename;
UI32 runningCount = 0;
SI32 fileSizes[AreaX][AreaY];
for( SI16 cx = 0; cx < AreaX; ++cx )
{
for( SI16 cy = 0; cy < AreaY; ++cy )
{
filename = basePath + oldstrutil::number( cx ) + std::string(".") + oldstrutil::number( cy ) + std::string(".wsc"); // let's name our file
fileSizes[cx][cy] = FileSize( filename );
runningCount += fileSizes[cx][cy];
}
}
if( runningCount == 0 )
runningCount = 1;
SI32 runningDone = 0;
for( SI16 counter1 = 0; counter1 < AreaX; ++counter1 ) // move left->right
{
for( SI16 counter2 = 0; counter2 < AreaY; ++counter2 ) // move up->down
{
filename = basePath + oldstrutil::number( counter1 ) + std::string(".") + oldstrutil::number( counter2 ) + std::string(".wsc"); // let's name our file
readDestination.open( filename.c_str()); // let's open it
readDestination.seekg( 0, std::ios::beg );
if( readDestination.eof() || readDestination.fail() )
{
readDestination.close();
readDestination.clear();
continue;
}
++count;
LoadFromDisk( readDestination, runningDone, fileSizes[counter1][counter2], runningCount );
runningDone += fileSizes[counter1][counter2];
float tempVal = (R32)runningDone / (R32)runningCount * 100.0f;
if( tempVal <= 10 )
Console << "\b\b" << (UI32)(tempVal) << "%";
else if( tempVal <= 100 )
Console << "\b\b\b" << (UI32)(tempVal) << "%";
readDestination.close();
readDestination.clear();
}
}
// If runningDone is still 0, there was nothing to load! 100% it
if( runningDone == 0 )
Console << "\b\b" << (UI32)(100) << "%";
Console.TurnNormal();
Console << "\b\b\b";
Console.PrintDone();
filename = basePath + "overflow.wsc";
std::ifstream flowDestination( filename.c_str() );
LoadFromDisk( flowDestination, -1, -1, -1 );
flowDestination.close();
filename = basePath + "house.wsc";
std::ifstream houseDestination( filename.c_str() );
LoadFromDisk( houseDestination, -1, -1, -1 );
UI32 b = 0;
ObjectFactory::getSingleton().IterateOver( OT_MULTI, b, nullptr, &PostLoadFunctor );
ObjectFactory::getSingleton().IterateOver( OT_ITEM, b, nullptr, &PostLoadFunctor );
ObjectFactory::getSingleton().IterateOver( OT_CHAR, b, nullptr, &PostLoadFunctor );
houseDestination.close();
UI32 e_t = getclock();
Console.print( oldstrutil::format("ASCII world loaded in %.02fsec\n", ((R32)(e_t-s_t))/1000.0f ));
UI08 i = 0;
for( WORLDLIST_ITERATOR wIter = mapWorlds.begin(); wIter != mapWorlds.end(); ++wIter )
{
(*wIter)->LoadResources( i );
++i;
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void LoadFromDisk( std::ifstream& readDestination, SI32 baseValue, SI32 fileSize, UI32 maxSize )
//| Date - 23 July, 2000
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Loads in objects from specified file
//o-----------------------------------------------------------------------------------------------o
void CMapHandler::LoadFromDisk( std::ifstream& readDestination, SI32 baseValue, SI32 fileSize, UI32 maxSize )
{
char line[1024];
R32 basePercent = (R32)baseValue / (R32)maxSize * 100.0f;
R32 targPercent = (R32)(baseValue + fileSize) / (R32)maxSize * 100.0f;
R32 diffValue = targPercent - basePercent;
SI32 updateCount = 0;
while( !readDestination.eof() && !readDestination.fail() )
{
readDestination.getline(line, 1023);
line[readDestination.gcount()] = 0;
std::string sLine(line);
sLine = oldstrutil::trim( oldstrutil::removeTrailing( sLine, "//" ));
if( sLine.substr( 0, 1 ) == "[" ) // in a section
{
sLine = sLine.substr( 1, sLine.size() - 2 );
sLine = oldstrutil::upper( oldstrutil::trim( oldstrutil::removeTrailing( sLine, "//" )));
if( sLine == "CHARACTER" )
LoadChar( readDestination );
else if( sLine == "ITEM" )
LoadItem( readDestination );
else if( sLine == "HOUSE" )
LoadMulti( readDestination );
else if( sLine == "BOAT" )
LoadBoat( readDestination );
else if( sLine == "SPAWNITEM" )
LoadSpawnItem( readDestination );
if( fileSize != -1 && (++updateCount)%20 == 0 )
{
R32 curPos = readDestination.tellg();
R32 tempVal = basePercent + ( curPos / fileSize * diffValue );
if( tempVal <= 10 )
Console << "\b\b" << (UI32)(tempVal) << "%";
else
Console << "\b\b\b" << (UI32)(tempVal) << "%";
}
}
else if( sLine == "---REGION---" ) // end of region
continue;
}
}