polserver/pol-core/plib/mapwriter.cpp
2018-12-22 00:32:47 +01:00

322 lines
9.7 KiB
C++

/** @file
*
* @par History
*/
#include "mapwriter.h"
#include <string.h>
#include "../clib/cfgelem.h"
#include "../clib/cfgfile.h"
#include "../clib/fileutil.h"
#include "../clib/iohelp.h"
#include "mapcell.h"
#include "mapsolid.h"
#include "uofile.h"
namespace Pol
{
namespace Plib
{
extern unsigned int num_map_patches;
extern unsigned int num_static_patches;
MapWriter::MapWriter()
: _realm_name( "" ),
_width( 0 ),
_height( 0 ),
_ofs_base(),
_cur_mapblock_index( -1 ),
_ofs_solidx1(),
_ofs_solidx2(),
_ofs_solids(),
_ofs_maptile(),
_cur_maptile_index( -1 ),
solidx2_offset( 0 ),
solids_offset( 0 )
{
_ofs_base.exceptions( std::ios_base::failbit | std::ios_base::badbit );
_ofs_solidx1.exceptions( std::ios_base::failbit | std::ios_base::badbit );
_ofs_solidx2.exceptions( std::ios_base::failbit | std::ios_base::badbit );
_ofs_solids.exceptions( std::ios_base::failbit | std::ios_base::badbit );
_ofs_maptile.exceptions( std::ios_base::failbit | std::ios_base::badbit );
}
void MapWriter::WriteConfigFile()
{
std::string filename = "realm/" + _realm_name + "/realm.cfg";
std::ofstream ofs_cfg;
ofs_cfg.exceptions( std::ios_base::failbit | std::ios_base::badbit );
Clib::open_file( ofs_cfg, filename, std::ios::trunc | std::ios::out );
ofs_cfg << "Realm " << _realm_name << std::endl;
ofs_cfg << "{" << std::endl;
ofs_cfg << " width " << _width << std::endl;
ofs_cfg << " height " << _height << std::endl;
ofs_cfg << " mapserver memory" << std::endl;
ofs_cfg << " uomapid " << uo_mapid << std::endl;
ofs_cfg << " uodif " << uo_usedif << std::endl;
ofs_cfg << " num_static_patches " << num_static_patches << std::endl;
ofs_cfg << " num_map_patches " << num_map_patches << std::endl;
ofs_cfg << " season 1" << std::endl;
ofs_cfg << "}" << std::endl;
}
void MapWriter::CreateBaseDat( const std::string& /*realm_name*/, const std::string& directory )
{
using std::ios;
std::string filename = directory + "base.dat";
Clib::open_file( _ofs_base, filename, ios::trunc | ios::in | ios::out | ios::binary );
MAPBLOCK empty;
memset( &empty, 0, sizeof empty );
for ( unsigned i = 0; i < total_blocks(); ++i )
{
_ofs_base.write( reinterpret_cast<const char*>( &empty ), sizeof empty );
}
}
void MapWriter::CreateSolidx1Dat( const std::string& /*realm_name*/, const std::string& directory )
{
using std::ios;
std::string filename = directory + "solidx1.dat";
Clib::open_file( _ofs_solidx1, filename, ios::trunc | ios::in | ios::out | ios::binary );
SOLIDX1_ELEM elem;
elem.offset = 0;
for ( unsigned i = 0; i < total_solid_blocks(); ++i )
{
_ofs_solidx1.write( reinterpret_cast<const char*>( &elem ), sizeof elem );
}
}
void MapWriter::CreateSolidx2Dat( const std::string& /*realm_name*/, const std::string& directory )
{
using std::ios;
std::string filename = directory + "solidx2.dat";
Clib::open_file( _ofs_solidx2, filename, ios::trunc | ios::in | ios::out | ios::binary );
_ofs_solidx2.write( "fill", 4 );
solidx2_offset = 4;
}
void MapWriter::CreateSolidsDat( const std::string& /*realm_name*/, const std::string& directory )
{
using std::ios;
std::string filename = directory + "solids.dat";
Clib::open_file( _ofs_solids, filename, ios::trunc | ios::in | ios::out | ios::binary );
_ofs_solids.write( "filler", 6 ); // multiple of 3
solids_offset = 6;
}
void MapWriter::CreateMaptileDat( const std::string& /*realm_name*/, const std::string& directory )
{
using std::ios;
std::string filename = directory + "maptile.dat";
Clib::open_file( _ofs_maptile, filename, ios::trunc | ios::in | ios::out | ios::binary );
MAPTILE_BLOCK maptile_empty;
memset( &maptile_empty, 0, sizeof maptile_empty );
for ( unsigned i = 0; i < total_maptile_blocks(); ++i )
{
_ofs_maptile.write( reinterpret_cast<const char*>( &maptile_empty ), sizeof maptile_empty );
}
}
void MapWriter::CreateNewFiles( const std::string& realm_name, unsigned short width,
unsigned short height )
{
_realm_name = realm_name;
_width = width;
_height = height;
std::string directory = "realm/" + _realm_name + "/";
Clib::make_dir( directory.c_str() );
CreateBaseDat( realm_name, directory );
// First-level Solids index (solidx1)
CreateSolidx1Dat( realm_name, directory );
// Second-level Solids index (solidx2)
CreateSolidx2Dat( realm_name, directory );
// Solids data (solids)
CreateSolidsDat( realm_name, directory );
// Maptile file (maptile.dat)
CreateMaptileDat( realm_name, directory );
}
void MapWriter::OpenExistingFiles( const std::string& realm_name )
{
using std::ios;
_realm_name = realm_name;
std::string directory = "realm/" + _realm_name + "/";
std::string realm_cfg_filename = directory + "realm.cfg";
Clib::ConfigFile cf( realm_cfg_filename, "REALM" );
Clib::ConfigElem elem;
if ( !cf.read( elem ) )
throw std::runtime_error( "Unable to read realm from " + realm_cfg_filename );
_width = elem.remove_ushort( "width" );
_height = elem.remove_ushort( "height" );
std::string filename = directory + "base.dat";
Clib::open_file( _ofs_base, filename, ios::in | ios::out | ios::binary );
// First-level Solids index (solidx1)
filename = directory + "solidx1.dat";
Clib::open_file( _ofs_solidx1, filename, ios::in | ios::out | ios::binary );
// Second-level Solids index (solidx2)
filename = directory + "solidx2.dat";
Clib::open_file( _ofs_solidx2, filename, ios::in | ios::out | ios::binary );
_ofs_solidx2.seekp( 0, ios::end );
solidx2_offset = _ofs_solidx2.tellp();
// Solids data (solids)
filename = directory + "solids.dat";
Clib::open_file( _ofs_solids, filename, ios::in | ios::out | ios::binary );
_ofs_solids.seekp( 0, ios::end );
solids_offset = _ofs_solids.tellp();
// Maptile (maptile.dat)
filename = directory + "maptile.dat";
Clib::open_file( _ofs_maptile, filename, ios::in | ios::out | ios::binary );
_ofs_maptile.seekp( 0, ios::end );
}
MapWriter::~MapWriter()
{
Flush();
}
void MapWriter::Flush()
{
FlushBaseFile();
FlushMapTileFile();
}
std::fstream::pos_type MapWriter::total_size()
{
return total_blocks() * sizeof( MAPBLOCK );
}
unsigned int MapWriter::total_blocks()
{
return _width * _height / MAPBLOCK_CHUNK / MAPBLOCK_CHUNK;
}
unsigned int MapWriter::total_solid_blocks()
{
return _width * _height / SOLIDX_X_SIZE / SOLIDX_Y_SIZE;
}
unsigned int MapWriter::total_maptile_blocks()
{
return _width * _height / MAPTILE_CHUNK / MAPTILE_CHUNK;
}
void MapWriter::SetMapCell( unsigned short x, unsigned short y, MAPCELL cell )
{
unsigned short xblock = x >> MAPBLOCK_SHIFT;
unsigned short xcell = x & MAPBLOCK_CELLMASK;
unsigned short yblock = y >> MAPBLOCK_SHIFT;
unsigned short ycell = y & MAPBLOCK_CELLMASK;
// doh, need to know map geometry here.
int blockIdx = yblock * ( _width >> MAPBLOCK_SHIFT ) + xblock;
if ( blockIdx != _cur_mapblock_index )
{
if ( _cur_mapblock_index >= 0 )
{
FlushBaseFile();
}
// read the existing block in
size_t offset = blockIdx * sizeof( _block );
_ofs_base.seekg( offset, std::ios_base::beg );
_ofs_base.read( reinterpret_cast<char*>( &_block ), sizeof _block );
_cur_mapblock_index = blockIdx;
}
_block.cell[xcell][ycell] = cell;
}
void MapWriter::SetMapTile( unsigned short x, unsigned short y, MAPTILE_CELL cell )
{
unsigned short xblock = x >> MAPTILE_SHIFT;
unsigned short xcell = x & MAPTILE_CELLMASK;
unsigned short yblock = y >> MAPTILE_SHIFT;
unsigned short ycell = y & MAPTILE_CELLMASK;
// doh, need to know map geometry here.
int blockIdx = yblock * ( _width >> MAPTILE_SHIFT ) + xblock;
if ( blockIdx != _cur_maptile_index )
{
if ( _cur_maptile_index >= 0 )
{
FlushMapTileFile();
}
// read the existing block in
size_t offset = blockIdx * sizeof _maptile_block;
_ofs_maptile.seekg( offset, std::ios_base::beg );
_ofs_maptile.read( reinterpret_cast<char*>( &_maptile_block ), sizeof _maptile_block );
_cur_maptile_index = blockIdx;
}
_maptile_block.cell[xcell][ycell] = cell;
}
void MapWriter::FlushBaseFile()
{
if ( _cur_mapblock_index >= 0 )
{
size_t offset = _cur_mapblock_index * sizeof( _block );
_ofs_base.seekp( offset, std::ios_base::beg );
_ofs_base.write( reinterpret_cast<const char*>( &_block ), sizeof _block );
}
}
void MapWriter::FlushMapTileFile()
{
if ( _cur_maptile_index >= 0 )
{
size_t offset = _cur_maptile_index * sizeof( _maptile_block );
_ofs_maptile.seekp( offset, std::ios_base::beg );
_ofs_maptile.write( reinterpret_cast<const char*>( &_maptile_block ), sizeof _maptile_block );
}
}
unsigned int MapWriter::NextSolidOffset()
{
return static_cast<unsigned int>( solids_offset );
}
unsigned int MapWriter::NextSolidIndex()
{
return NextSolidOffset() / sizeof( SOLIDS_ELEM );
}
unsigned int MapWriter::NextSolidx2Offset()
{
return static_cast<unsigned int>( solidx2_offset );
}
void MapWriter::AppendSolid( const SOLIDS_ELEM& solid )
{
_ofs_solids.write( reinterpret_cast<const char*>( &solid ), sizeof( SOLIDS_ELEM ) );
solids_offset += sizeof( SOLIDS_ELEM );
}
void MapWriter::AppendSolidx2Elem( const SOLIDX2_ELEM& elem )
{
_ofs_solidx2.write( reinterpret_cast<const char*>( &elem ), sizeof elem );
solidx2_offset += sizeof elem;
}
void MapWriter::SetSolidx2Offset( unsigned short x_base, unsigned short y_base,
unsigned int offset )
{
unsigned int elems_per_row = ( _width / SOLIDX_X_SIZE );
unsigned int index = ( y_base / SOLIDX_Y_SIZE ) * elems_per_row + ( x_base / SOLIDX_X_SIZE );
size_t file_offset = index * sizeof( SOLIDX1_ELEM );
_ofs_solidx1.seekp( file_offset, std::ios_base::beg );
_ofs_solidx1.write( reinterpret_cast<const char*>( &offset ), sizeof offset );
}
} // namespace Plib
} // namespace Pol