@ -33,6 +33,7 @@
# include <framework/core/resourcemanager.h>
# include <framework/core/filestream.h>
# include <framework/core/binarytree.h>
# include <framework/core/application.h>
Map g_map ;
@ -59,67 +60,59 @@ void Map::notificateTileUpdateToMapViews(const Position& pos)
mapView - > onTileUpdate ( pos ) ;
}
bool Map : : loadOtbm ( const std : : string & fileName )
void Map : : loadOtbm ( const std : : string & fileName )
{
FileStreamPtr fin = g_resources . openFile ( fileName ) ;
if ( ! fin ) {
g_logger . error ( stdext : : format ( " Unable to load map '%s' " , fileName ) ) ;
return false ;
}
if ( ! fin )
stdext : : throw_exception ( stdext : : format ( " Unable to load map '%s' " , fileName ) ) ;
if ( ! g_things . isOtbLoaded ( ) /* || !g_things.isXmlLoaded()*/ ) {
g_logger . error ( " OTB and XML are not loaded yet to load a map. " ) ;
return false ;
}
fin - > cache ( ) ;
if ( ! g_things . isOtbLoaded ( ) )
stdext : : throw_exception ( " OTB isn't loaded yet to load a map. " ) ;
if ( fin - > getU32 ( ) )
stdext : : throw_exception ( " Unknown file version detected " ) ;
assert ( fin - > getU32 ( ) = = 0 ) ;
BinaryTreePtr root = fin - > getBinaryTree ( ) ;
root - > skip ( 1 ) ; // Not sure, what exactly that is... perhaps node type?
if ( root - > getU8 ( ) )
stdext : : throw_exception ( " could not read root property! " ) ;
uint32 headerVersion = root - > getU32 ( ) ;
dump < < headerVersion ;
if ( ! headerVersion | | headerVersion > 3 ) {
g_logger . error ( " Unknown OTBM version detected. " ) ;
return false ;
}
if ( ! headerVersion | | headerVersion > 3 )
stdext : : throw_exception ( stdext : : format ( " Unknown OTBM version detected: %u. " , headerVersion ) ) ;
m_width = root - > getU16 ( ) ;
m_height = root - > getU16 ( ) ;
dump < < " Map size: " < < m_width < < " x " < < m_height ;
root - > skip ( 1 ) ; // ??
uint32 headerMajorItems = root - > getU8 ( ) ;
dump < < headerMajorItems ;
dump < < " major: " < < g_things . getOtbMajorVersion ( ) ;
if ( headerMajorItems < 3 ) {
g_logger. error ( " This map needs to be upgraded. " ) ;
return false ;
stdext : : throw_exception ( stdext : : format ( " This map needs to be upgraded. read %d what it's supposed to be: %u " ,
headerMajorItems , g_things . getOtbMajorVersion ( ) ) ) ;
}
if ( headerMajorItems > g_things . getOtbMajorVersion ( ) ) {
g_logger. error ( " This map was saved with different OTB version. " ) ;
return false ;
stdext: : throw_exception ( stdext : : format ( " This map was saved with different OTB version. read %d what it's supposed to be: %d " ,
headerMajorItems , g_things . getOtbMajorVersion ( ) ) ) ;
}
root - > skip ( 1) ; /// ??
uint32 headerMinorItems = root - > getU 8 ( ) ;
dump < < headerMinorItems ;
dump < < " minor: " < < g_things . getOtbMinorVersion ( ) ;
if ( headerMinorItems > g_things . getOtbMinorVersion ( ) )
g_logger . warning ( " This map needs an updated OTB. " ) ;
root - > skip ( 3) ;
uint32 headerMinorItems = root - > getU 32 ( ) ;
if ( headerMinorItems > g_things . getOtbMinorVersion ( ) ) {
g_logger . warning ( stdext : : format ( " This map needs an updated OTB. read %d what it's supposed to be: %d " ,
headerMinorItems , g_things . getOtbMinorVersion ( ) ) ) ;
}
BinaryTreePtr node = root - > getChildren ( ) [ 0 ] ;
if ( node - > getU8 ( ) ! = OTBM_MAP_DATA ) {
g_logger . error ( " Could not read data node. " ) ;
return false ;
}
if ( node - > getU8 ( ) ! = OTBM_MAP_DATA )
stdext : : throw_exception ( " Could not read root data node " ) ;
std : : string tmp ;
uint8 attribute ;
while ( node - > canRead ( ) ) {
attribute = node - > getU8 ( ) ;
tmp = node - > getString ( ) ;
uint8 attribute = node - > getU8 ( ) ;
std: : string tmp = node - > getString ( ) ;
switch ( attribute ) {
case OTBM_ATTR_DESCRIPTION :
if ( ! m_description . empty ( ) )
m_description + = " \n " + tmp ;
else
m_description = tmp ;
m_description + = tmp + " \n " ;
break ;
case OTBM_ATTR_SPAWN_FILE :
m_spawnFile = fileName . substr ( 0 , fileName . rfind ( ' / ' ) + 1 ) + tmp ;
@ -128,151 +121,260 @@ bool Map::loadOtbm(const std::string& fileName)
m_houseFile = fileName . substr ( 0 , fileName . rfind ( ' / ' ) + 1 ) + tmp ;
break ;
default :
g_logger . error ( stdext : : format ( " Invalid attribute '%c' " , attribute ) ) ;
break ;
stdext : : throw_exception ( stdext : : format ( " Invalid attribute '%c' " , attribute ) ) ;
}
}
dump < < m_description ;
dump < < m_houseFile ;
dump < < m_spawnFile ;
for ( const BinaryTreePtr & nodeMapData : node - > getChildren ( ) ) {
uint8 mapDataType = nodeMapData - > getU8 ( ) ;
dump < < " mapData: " < < ( int ) mapDataType ;
if ( mapDataType = = OTBM_TILE_AREA ) {
dump < < " Tile: reading pos... " ;
uint16 baseX = nodeMapData - > getU16 ( ) , baseY = nodeMapData - > getU16 ( ) ;
uint8 pz = nodeMapData - > getU8 ( ) ;
for ( const BinaryTreePtr & nodeTile : nodeMapData - > getChildren ( ) ) {
uint8 type = nodeTile - > getU8 ( ) ;
if ( type = = OTBM_TILE | | type = = OTBM_HOUSETILE ) {
TilePtr tile = 0 ;
ItemPtr ground = 0 ;
uint32 flags = 0 ;
uint16 px = baseX + nodeTile - > getU16 ( ) , py = baseY + nodeTile - > getU16 ( ) ;
Position pos ( px , py , pz ) ;
// TODO: Houses.
if ( type = = OTBM_HOUSETILE ) {
uint32 hId = nodeTile - > getU32 ( ) ;
tile = createTile ( pos ) ;
// TODO: add it to house.
if ( type ! = OTBM_TILE & & type ! = OTBM_HOUSETILE )
stdext : : throw_exception ( stdext : : format ( " invalid node tile type %d " , ( int ) type ) ) ;
TilePtr tile = nullptr ;
ItemPtr ground = nullptr ;
HousePtr house = nullptr ;
uint32 flags = TILESTATE_NONE ;
uint16 px = baseX + nodeTile - > getU8 ( ) , py = baseY + nodeTile - > getU8 ( ) ;
Position pos ( px , py , pz ) ;
if ( type = = OTBM_HOUSETILE ) {
uint32 hId = nodeTile - > getU32 ( ) ;
tile = createTile ( pos ) ;
if ( ! ( house = m_houses . getHouse ( hId ) ) ) {
house = HousePtr ( new House ( hId ) ) ;
m_houses . addHouse ( house ) ;
}
house - > setTile ( tile ) ;
}
uint8 tileAttr ;
while ( nodeTile - > canRead ( ) ) {
tileAttr = nodeTile - > getU8 ( ) ;
switch ( tileAttr ) {
while ( nodeTile - > canRead ( ) ) {
uint8 tileAttr = nodeTile - > getU8 ( ) ;
switch ( tileAttr ) {
case OTBM_ATTR_TILE_FLAGS : {
uint32 _flags = nodeTile - > getU32 ( ) ;
if ( ( _flags & TILESTATE_PROTECTIONZONE ) = = TILESTATE_PROTECTIONZONE )
flags | = TILESTATE_PROTECTIONZONE ;
else if ( ( _flags & TILESTATE_OPTIONALZONE ) = = TILESTATE_OPTIONALZONE )
flags | = TILESTATE_OPTIONALZONE ;
else if ( ( _flags & TILESTATE_H PP ARDCOREZONE) = = TILESTATE_H PP ARDCOREZONE)
flags | = TILESTATE_H PP ARDCOREZONE;
else if ( ( _flags & TILESTATE_H ARDCOREZONE) = = TILESTATE_H ARDCOREZONE)
flags | = TILESTATE_H ARDCOREZONE;
if ( ( _flags & TILESTATE_NOLOGOUT ) = = TILESTATE_NOLOGOUT )
flags | = TILESTATE_NOLOGOUT ;
if ( ( _flags & TILESTATE_REFRESH ) = = TILESTATE_REFRESH )
flags | = TILESTATE_REFRESH ;
break ;
} case OTBM_ATTR_ITEM : {
}
case OTBM_ATTR_ITEM : {
ItemPtr item = Item : : createFromOtb ( nodeTile - > getU16 ( ) ) ;
if ( ! item ) {
g_logger . error ( stdext : : format ( " failed to create new item at tile pos %d, %d, %d " , px , py , pz ) ) ;
return false ;
}
if ( tile ) {
tile - > addThing ( item ) ;
} else if ( item - > isGround ( ) ) {
if ( tile )
addThing ( item , pos , 255 ) ;
else if ( item - > isGround ( ) )
ground = item ;
} else {
tile = createTile ( pos ) ;
tile - > addThing ( ground ) ;
tile - > addThing ( item ) ;
}
} default : {
g_logger . error ( stdext : : format ( " invalid tile attribute at pos %d, %d, %d " , px , py , pz ) ) ;
return false ;
}
else
tile = createTileEx ( pos , ground , item ) ;
break ;
}
default :
stdext : : throw_exception ( stdext : : format ( " invalid tile attribute %d at pos %d, %d, %d " ,
( int ) tileAttr , px , py , pz ) ) ;
}
}
for ( const BinaryTreePtr & nodeItem : nodeTile - > getChildren ( ) ) {
if ( nodeItem - > getU8 ( ) = = OTBM_ITEM ) {
ItemPtr item = Item : : createFromOtb ( nodeItem - > getU16 ( ) ) ;
if ( ! item ) {
g_logger . error ( stdext : : format ( " failed to create new item at pos %d, %d, %d " , px , py , pz ) ) ;
return false ;
}
if ( item - > unserializeItemNode ( nodeItem ) ) {
if ( /* house && */ item - > isMoveable ( ) ) {
g_logger . warning ( stdext : : format ( " Moveable item found in house: %d at pos %d %d %d " , item - > getId ( ) ,
px , py , pz ) ) ;
item = nullptr ;
} else if ( tile ) {
tile - > addThing ( item ) ;
} else if ( item - > isGround ( ) ) {
ground = item ;
} else {
tile = createTile ( pos ) ;
tile - > addThing ( ground ) ;
tile - > addThing ( item ) ;
}
} else {
g_logger . error ( stdext : : format ( " failed to unserialize item with %d at pos %d %d %d " , item - > getId ( ) ,
px , py , pz ) ) ;
return false ;
}
} else {
g_logger . error ( stdext : : format ( " Unknown item node type %d " , type ) ) ;
return false ;
for ( const BinaryTreePtr & nodeItem : nodeTile - > getChildren ( ) ) {
if ( nodeItem - > getU8 ( ) ! = OTBM_ITEM )
stdext : : throw_exception ( " invalid item node " ) ;
ItemPtr item = Item : : createFromOtb ( nodeItem - > getU16 ( ) ) ;
item - > unserializeItem ( nodeItem ) ;
if ( item - > isContainer ( ) ) {
// This is a temporary way for reading container items.
MapContainerPtr mapContainer ( new MapContainer ) ;
for ( const BinaryTreePtr & insideItem : nodeItem - > getChildren ( ) ) {
if ( insideItem - > getU8 ( ) ! = OTBM_ITEM )
stdext : : throw_exception ( " invalid container item node " ) ;
ItemPtr newItem = Item : : createFromOtb ( insideItem - > getU16 ( ) ) ;
newItem - > unserializeItem ( insideItem ) ;
mapContainer - > add ( newItem ) ;
}
m_containers . push_back ( mapContainer ) ;
}
if ( ! tile ) {
tile = createTile ( pos ) ;
tile - > addThing ( ground ) ;
}
tile - > setFlags ( ( tileflags_t ) flags ) ;
} else {
g_logger . error ( stdext : : format ( " Unknown tile node type %d " , type ) ) ;
return false ;
if ( house ) {
if ( item - > isMoveable ( ) ) {
g_logger . warning ( stdext : : format ( " Movable item found in house: %d at pos %d %d %d - escaping... " , item - > getId ( ) ,
px , py , pz ) ) ;
item = nullptr ;
} else if ( item - > isDoor ( ) )
house - > addDoor ( item - > getDoorId ( ) , pos ) ;
} else if ( tile )
addThing ( item , pos , 255 ) ;
else if ( item - > isGround ( ) )
ground = item ;
else
tile = createTileEx ( pos , ground , item ) ;
}
if ( ! tile )
tile = createTileEx ( pos , ground ) ;
tile - > setFlags ( ( tileflags_t ) flags ) ;
}
} else if ( mapDataType = = OTBM_TOWNS ) {
TownPtr town = nullptr ;
for ( const BinaryTreePtr & nodeTown : nodeMapData - > getChildren ( ) ) {
if ( nodeTown - > getU8 ( ) = = OTBM_TOWN ) {
uint32 townId = nodeTown - > getU32 ( ) ;
std : : string townName = nodeTown - > getString ( ) ;
Position townCoords ( nodeTown - > getU16 ( ) , nodeTown - > getU16 ( ) , nodeTown - > getU8 ( ) ) ;
} else
return false ;
if ( nodeTown - > getU8 ( ) ! = OTBM_TOWN )
stdext : : throw_exception ( " invalid town node. " ) ;
uint32 townId = nodeTown - > getU32 ( ) ;
std : : string townName = nodeTown - > getString ( ) ;
Position townCoords ( nodeTown - > getU16 ( ) , nodeTown - > getU16 ( ) , nodeTown - > getU8 ( ) ) ;
if ( ! ( town = m_towns . getTown ( townId ) ) ) {
town = TownPtr ( new Town ( townId , townName , townCoords ) ) ;
m_towns . addTown ( town ) ;
} else {
// override data
town - > setName ( townName ) ;
town - > setPos ( townCoords ) ;
town - > setId ( townId ) ;
}
}
} else if ( mapDataType = = OTBM_WAYPOINTS & & headerVersion > 1 ) {
for ( const BinaryTreePtr & nodeWaypoint : nodeMapData - > getChildren ( ) ) {
if ( nodeWaypoint - > getU8 ( ) = = OTBM_WAYPOINT ) {
std : : string name = nodeWaypoint - > getString ( ) ;
Position waypointPos ( nodeWaypoint - > getU16 ( ) , nodeWaypoint - > getU16 ( ) , nodeWaypoint - > getU8 ( ) ) ;
}
if ( nodeWaypoint - > getU8 ( ) ! = OTBM_WAYPOINT )
stdext : : throw_exception ( " invalid waypoint node. " ) ;
std : : string name = nodeWaypoint - > getString ( ) ;
Position waypointPos ( nodeWaypoint - > getU16 ( ) , nodeWaypoint - > getU16 ( ) , nodeWaypoint - > getU8 ( ) ) ;
if ( waypointPos . isValid ( ) & & ! name . empty ( ) & & m_waypoints . find ( waypointPos ) = = m_waypoints . end ( ) )
m_waypoints . insert ( std : : make_pair ( waypointPos , name ) ) ;
}
} else
return false ;
stdext : : throw_exception ( " Unknown map data node " ) ;
}
// TODO: Load house & spawns.
return true ;
g_logger . debug ( " OTBM read successfully. " ) ;
fin - > close ( ) ;
/// TODO read XML Stuff (houses & spawns).
}
void Map : : saveOtbm ( const std : : string & fileName )
{
// TODO: Continue sleepy work.
#if 0
/// TODO: Use binary trees for this
FileStreamPtr fin = g_resources . openFile ( fileName ) ;
if ( ! fin )
stdext : : throw_exception ( stdext : : format ( " failed to open file '%s' " , fileName ) ) ;
std : : string dir ;
if ( fileName . find_last_of ( ' / ' ) < = 0 )
dir = g_resources . getWorkDir ( ) ;
else
dir = fileName . substr ( 0 , fileName . find_last_of ( ' / ' ) ) ;
if ( m_houseFile . empty ( ) )
m_houseFile = " houses.xml " ;
if ( m_spawnFile . empty ( ) )
m_spawnFile = " spawns.xml " ;
#if 0
if ( ! m_houses - > save ( dir + " / " + m_houseFile ) )
;
if ( ! m_spawns - > save ( dir + " / " + m_spawnFile ) )
;
# endif
uint32 ver ;
if ( g_things . getOtbMajorVersion ( ) < 2 )
ver = 0 ;
else if ( g_things . getOtbMajorVersion ( ) < 10 )
ver = 1 ;
else
ver = 2 ;
fin - > addU32 ( 0x00 ) ; // file version
{
fin - > startNode ( 0x00 ) ; // root
fin - > addU32 ( ver ) ;
fin - > addU16 ( m_width ) ; // some random width.
fin - > addU16 ( m_height ) ; // some random height.
fin - > addU32 ( g_things . getOtbMajorVersion ( ) ) ;
fin - > addU32 ( g_things . getOtbMinorVersion ( ) ) ;
fin - > startNode ( OTBM_MAP_DATA ) ; // map data node
{
// own description.
fin - > addU8 ( OTBM_ATTR_DESCRIPTION ) ;
fin - > addString ( m_description ) ;
// special one
fin - > addU8 ( OTBM_ATTR_DESCRIPTION ) ;
fin - > addString ( stdext : : format ( " Saved with %s v%d " , g_app . getName ( ) , stdext : : unsafe_cast < int > ( g_app . getVersion ( ) ) ) ) ;
// spawn file.
fin - > addU8 ( OTBM_ATTR_SPAWN_FILE ) ;
fin - > addString ( m_spawnFile ) ;
// house file.
if ( ver > 1 ) {
fin - > addU8 ( OTBM_ATTR_HOUSE_FILE ) ;
fin - > addString ( m_houseFile ) ;
}
Position pos ( - 1 , - 1 , - 1 ) ;
Boolean < true > first ;
for ( auto & pair : m_tiles ) {
TilePtr tile = pair . second ;
if ( ! tile | | tile - > isEmpty ( ) )
continue ;
Position tilePos = pair . first ;
if ( tilePos . x < pos . x | | tilePos . x > = pos . x + 256 | |
tilePos . y < pos . y | | tilePos . y > = pos . y + 256 | |
tilePos . z ! = pos . z ) {
if ( ! first )
fin - > endNode ( ) ;
pos . x = tilePos . x & 0xFF00 ;
pos . y = tilePos . y & 0xFF00 ;
pos . z = tilePos . z ;
fin - > addU16 ( pos . x ) ;
fin - > addU16 ( pos . y ) ;
fin - > addU8 ( pos . z ) ;
}
// TODO: hOUSES.
fin - > startNode ( OTBM_TILE ) ;
fin - > addU8 ( tilePos . x ) ;
fin - > addU8 ( tilePos . y ) ;
#if 0
// TODO: hOUSES again.
if ( is house tile )
add u32 house id . . . ;
# endif
if ( tile - > flags ( ) ) {
fin - > addU8 ( OTBM_ATTR_TILE_FLAGS ) ;
fin - > addU32 ( tile - > flags ( ) ) ;
}
}
}
}
# endif
}
bool Map : : loadOtcm ( const std : : string & fileName )
@ -300,7 +402,7 @@ bool Map::loadOtcm(const std::string& fileName)
fin - > getString ( ) ; // world name
if ( datSignature ! = g_things . getDatSignature ( ) )
g_logger . warning ( " otcm map loaded is was created with a different dat signature" ) ;
g_logger . warning ( " otcm map loaded was created with a different dat signature" ) ;
break ;
}
@ -417,6 +519,11 @@ void Map::clean()
{
cleanDynamicThings ( ) ;
m_tiles . clear ( ) ;
m_waypoints . clear ( ) ;
// This is a fix to a segfault on exit.
m_towns . clear ( ) ;
m_houses . clear ( ) ;
}
void Map : : cleanDynamicThings ( )
@ -538,6 +645,17 @@ bool Map::removeThingByPos(const Position& pos, int stackPos)
return false ;
}
template < typename . . . Items >
TilePtr Map : : createTileEx ( const Position & pos , const Items & . . . items )
{
TilePtr tile = getOrCreateTile ( pos ) ;
auto vec = { items . . . } ;
for ( auto it : vec )
addThing ( it , pos , 255 ) ;
return tile ;
}
TilePtr Map : : createTile ( const Position & pos )
{
TilePtr tile = TilePtr ( new Tile ( pos ) ) ;