polserver/pol-core/plib/mapserver.cpp

176 lines
4.7 KiB
C++
Raw Permalink Normal View History

/** @file
*
* @par History
*/
2016-02-11 22:54:43 +01:00
#include "mapserver.h"
#include <stddef.h>
#include <stdexcept>
#include <string>
2016-02-11 22:54:43 +01:00
#include "../clib/binaryfile.h"
#include "../clib/passert.h"
#include "../clib/strutil.h"
#include "filemapserver.h"
#include "inmemorymapserver.h"
#include "mapcell.h"
#include "mapshape.h"
#include "mapsolid.h"
2016-02-11 22:54:43 +01:00
namespace Pol
{
namespace Plib
{
MapServer::MapServer( const RealmDescriptor& descriptor ) : _descriptor( descriptor )
{
LoadSolids();
// the first-level index points into the second-level index, so load the second-level index first.
LoadSecondLevelIndex();
LoadFirstLevelIndex();
}
void MapServer::LoadSolids()
{
std::string filename = _descriptor.path( "solids.dat" );
Clib::BinaryFile infile( filename, std::ios::in );
infile.ReadVector( _shapedata );
}
void MapServer::LoadSecondLevelIndex()
{
std::string filename = _descriptor.path( "solidx2.dat" );
Clib::BinaryFile infile( filename, std::ios::in );
std::fstream::pos_type filesize = infile.FileSize();
if ( filesize < std::fstream::pos_type( SOLIDX2_FILLER_SIZE ) )
throw std::runtime_error( filename + " must have size of at least " +
Clib::tostring( SOLIDX2_FILLER_SIZE ) + " bytes." );
std::fstream::pos_type databytes = filesize - std::fstream::pos_type( SOLIDX2_FILLER_SIZE );
if ( ( databytes % sizeof( SOLIDX2_ELEM ) ) != 0 )
throw std::runtime_error( filename + " does not contain an integral number of elements." );
size_t count = static_cast<size_t>( databytes / sizeof( SOLIDX2_ELEM ) );
_index2.resize( count );
infile.Seek( SOLIDX2_FILLER_SIZE );
infile.Read( &_index2[0], count );
// integrity check
for ( const auto& elem : _index2 )
{
passert( elem.baseindex < _shapedata.size() );
for ( unsigned x = 0; x < SOLIDX_X_SIZE; ++x )
2016-02-11 22:54:43 +01:00
{
for ( unsigned y = 0; y < SOLIDX_Y_SIZE; ++y )
{
size_t idx = elem.baseindex + elem.addindex[x][y];
passert( idx < _shapedata.size() );
}
2016-02-11 22:54:43 +01:00
}
}
}
void MapServer::LoadFirstLevelIndex()
{
std::string filename = _descriptor.path( "solidx1.dat" );
Clib::BinaryFile infile( filename, std::ios::in );
size_t n_blocks = ( _descriptor.width / SOLIDX_X_SIZE ) * ( _descriptor.height / SOLIDX_Y_SIZE );
_index1.resize( n_blocks );
for ( size_t i = 0; i < n_blocks; ++i )
{
unsigned int tmp;
infile.Read( tmp );
if ( tmp )
{
// tmp is an offset, in the file.. turn it into a pointer into the second-level index.
tmp = ( tmp - SOLIDX2_FILLER_SIZE ) / sizeof( SOLIDX2_ELEM );
_index1[i] = &_index2.at( tmp );
}
else
{
_index1[i] = nullptr;
}
}
}
void MapServer::GetMapShapes( MapShapeList& shapes, unsigned short x, unsigned short y,
unsigned int anyflags ) const
{
passert( x < _descriptor.width && y < _descriptor.height );
MAPCELL cell = GetMapCell( x, y );
MapShape shape;
if ( cell.flags & anyflags )
{
shape.flags = cell.flags;
shape.z = cell.z - 1; // assume now map is at z-1 with height 1 for solidity
shape.height = 1;
shapes.push_back( shape );
}
if ( cell.flags & FLAG::MORE_SOLIDS )
{
unsigned short xblock = x >> SOLIDX_X_SHIFT;
unsigned short xcell = x & SOLIDX_X_CELLMASK;
unsigned short yblock = y >> SOLIDX_Y_SHIFT;
unsigned short ycell = y & SOLIDX_Y_CELLMASK;
2016-12-09 20:12:12 +01:00
size_t block = static_cast<size_t>( yblock ) * ( _descriptor.width >> SOLIDX_X_SHIFT ) + xblock;
SOLIDX2_ELEM* pIndex2 = _index1[block];
unsigned int index = pIndex2->baseindex + pIndex2->addindex[xcell][ycell];
const SOLIDS_ELEM* pElem = &_shapedata[index];
for ( ;; )
{
if ( pElem->flags & anyflags )
{
shape.z = pElem->z;
shape.height = pElem->height;
shape.flags = pElem->flags;
shapes.push_back( shape );
}
if ( pElem->flags & FLAG::MORE_SOLIDS )
++pElem;
else
break;
}
}
}
MapServer* MapServer::Create( const RealmDescriptor& descriptor )
{
if ( descriptor.mapserver_type == "memory" )
{
return new InMemoryMapServer( descriptor );
}
else if ( descriptor.mapserver_type == "file" )
{
return new FileMapServer( descriptor );
}
else
{
throw std::runtime_error( "Undefined mapserver type: " + descriptor.mapserver_type );
}
}
size_t MapServer::sizeEstimate() const
{
size_t size = sizeof( *this );
size += _descriptor.sizeEstimate();
size += 3 * sizeof( SOLIDX2_ELEM** ) + _index1.capacity() * sizeof( SOLIDX2_ELEM* );
size += 3 * sizeof( SOLIDX2_ELEM* ) + _index2.capacity() * sizeof( SOLIDX2_ELEM );
size += 3 * sizeof( SOLIDS_ELEM* ) + _shapedata.capacity() * sizeof( SOLIDS_ELEM );
return size;
}
}
2016-12-09 20:12:12 +01:00
}