2012-06-14 13:06:06 +00:00
// WSSAnvil.cpp
// Implements the cWSSAnvil class representing the Anvil world storage scheme
#include "Globals.h"
#include "WSSAnvil.h"
2013-03-09 14:35:43 +00:00
#include "NBTChunkSerializer.h"
2013-12-25 16:07:52 +00:00
#include "FastNBT.h"
2014-01-19 07:38:59 -08:00
#include "EnchantmentSerializer.h"
2013-11-27 07:40:59 +00:00
#include "zlib/zlib.h"
2013-12-25 16:07:52 +00:00
#include "../World.h"
2012-09-23 20:22:46 +00:00
#include "../BlockID.h"
2013-12-25 16:07:52 +00:00
#include "../Item.h"
#include "../ItemGrid.h"
#include "../StringCompression.h"
2014-07-24 18:32:05 +02:00
#include "../SetChunkData.h"
2014-08-03 22:03:48 +02:00
#include "../Root.h"
2013-12-25 16:07:52 +00:00
2014-07-30 22:50:34 +02:00
#include "../BlockEntities/BeaconEntity.h"
2015-09-24 10:48:33 +02:00
#include "../BlockEntities/BrewingstandEntity.h"
2013-05-28 19:12:47 +00:00
#include "../BlockEntities/ChestEntity.h"
2014-01-18 15:40:47 +02:00
#include "../BlockEntities/CommandBlockEntity.h"
2013-05-28 19:12:47 +00:00
#include "../BlockEntities/DispenserEntity.h"
#include "../BlockEntities/DropperEntity.h"
#include "../BlockEntities/FurnaceEntity.h"
2013-06-13 07:36:43 +00:00
#include "../BlockEntities/HopperEntity.h"
2013-05-28 19:12:47 +00:00
#include "../BlockEntities/JukeboxEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
2014-02-19 14:45:09 +01:00
#include "../BlockEntities/MobHeadEntity.h"
2014-11-18 15:33:41 +01:00
#include "../BlockEntities/MobSpawnerEntity.h"
2014-03-07 01:30:34 +01:00
#include "../BlockEntities/FlowerPotEntity.h"
2013-12-25 16:07:52 +00:00
2013-08-25 21:32:17 +02:00
#include "../Mobs/Monster.h"
2013-12-25 16:07:52 +00:00
#include "../Mobs/IncludeAllMonsters.h"
2013-09-08 00:14:57 +01:00
#include "../Entities/Boat.h"
2014-03-25 20:59:33 +02:00
#include "../Entities/EnderCrystal.h"
2013-08-19 11:39:13 +02:00
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
2014-04-27 17:03:06 -07:00
#include "../Entities/ArrowEntity.h"
2014-07-11 18:58:11 -07:00
#include "../Entities/SplashPotionEntity.h"
2014-04-27 17:03:06 -07:00
#include "../Entities/ThrownEggEntity.h"
#include "../Entities/ThrownEnderPearlEntity.h"
#include "../Entities/ThrownSnowballEntity.h"
#include "../Entities/FireChargeEntity.h"
#include "../Entities/GhastFireballEntity.h"
2014-03-08 10:25:46 +01:00
#include "../Entities/TNTEntity.h"
2014-03-15 00:32:49 +01:00
#include "../Entities/ExpOrb.h"
2014-03-15 02:45:25 +01:00
#include "../Entities/HangingEntity.h"
#include "../Entities/ItemFrame.h"
2015-03-13 23:05:06 +00:00
#include "../Entities/Painting.h"
2012-06-14 13:06:06 +00:00
2014-08-03 22:03:48 +02:00
#include "../Protocol/MojangAPI.h"
2014-09-24 15:17:20 +02:00
#include "Server.h"
2014-08-03 22:03:48 +02:00
2012-06-14 13:06:06 +00:00
2013-05-05 14:48:18 +00:00
/** If defined, the BlockSkyLight values will be copied over to BlockLight upon chunk saving,
thus making skylight visible in Minutor's Lighting mode
*/
// #define DEBUG_SKYLIGHT
2014-07-17 22:50:58 +02:00
/** Maximum number of MCA files that are cached in memory.
2012-06-14 13:06:06 +00:00
Since only the header is actually in the memory, this number can be high, but still, each file means an OS FS handle.
*/
#define MAX_MCA_FILES 32
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2012-06-14 13:06:06 +00:00
// cWSSAnvil:
2014-01-17 11:01:14 -08:00
cWSSAnvil :: cWSSAnvil ( cWorld * a_World , int a_CompressionFactor ) :
super ( a_World ),
m_CompressionFactor ( a_CompressionFactor )
2012-06-14 13:06:06 +00:00
{
// Create a level.dat file for mapping tools, if it doesn't already exist:
AString fnam ;
2015-05-09 09:25:09 +02:00
Printf ( fnam , "%s%clevel.dat" , a_World -> GetName (). c_str (), cFile :: PathSeparator );
2012-06-14 13:06:06 +00:00
if ( ! cFile :: Exists ( fnam ))
{
cFastNBTWriter Writer ;
2014-09-23 19:16:17 +02:00
Writer . BeginCompound ( "Data" );
Writer . AddByte ( "allowCommands" , 1 );
Writer . AddByte ( "Difficulty" , 2 );
2014-09-24 15:17:20 +02:00
Writer . AddByte ( "hardcore" , cRoot :: Get () -> GetServer () -> IsHardcore () ? 1 : 0 );
2014-09-23 19:16:17 +02:00
Writer . AddByte ( "initialized" , 1 );
Writer . AddByte ( "MapFeatures" , 1 );
Writer . AddByte ( "raining" , a_World -> IsWeatherRain () ? 1 : 0 );
Writer . AddByte ( "thundering" , a_World -> IsWeatherStorm () ? 1 : 0 );
2015-07-29 09:04:03 -06:00
Writer . AddInt ( "GameType" , static_cast < int > ( a_World -> GetGameMode ()));
2014-09-23 19:16:17 +02:00
Writer . AddInt ( "generatorVersion" , 1 );
2015-06-24 16:38:40 +02:00
Writer . AddInt ( "SpawnX" , FloorC ( a_World -> GetSpawnX ()));
Writer . AddInt ( "SpawnY" , FloorC ( a_World -> GetSpawnY ()));
Writer . AddInt ( "SpawnZ" , FloorC ( a_World -> GetSpawnZ ()));
2014-09-23 19:16:17 +02:00
Writer . AddInt ( "version" , 19133 );
2015-06-24 16:38:40 +02:00
Writer . AddLong ( "DayTime" , a_World -> GetTimeOfDay ());
2014-09-23 19:16:17 +02:00
Writer . AddLong ( "Time" , a_World -> GetWorldAge ());
Writer . AddLong ( "SizeOnDisk" , 0 );
Writer . AddString ( "generatorName" , "default" );
Writer . AddString ( "generatorOptions" , "" );
Writer . AddString ( "LevelName" , a_World -> GetName ());
2012-06-14 13:06:06 +00:00
Writer . EndCompound ();
Writer . Finish ();
2012-11-16 22:06:12 +00:00
gzFile gz = gzopen (( FILE_IO_PREFIX + fnam ). c_str (), "wb" );
2014-10-20 21:55:07 +01:00
if ( gz != nullptr )
2012-06-14 13:06:06 +00:00
{
2015-07-09 11:15:37 -06:00
gzwrite ( gz , Writer . GetResult (). data (), static_cast < unsigned > ( Writer . GetResult (). size ()));
2012-06-14 13:06:06 +00:00
}
gzclose ( gz );
}
}
cWSSAnvil ::~ cWSSAnvil ()
{
cCSLock Lock ( m_CS );
for ( cMCAFiles :: iterator itr = m_Files . begin (); itr != m_Files . end (); ++ itr )
{
delete * itr ;
} // for itr - m_Files[]
}
bool cWSSAnvil :: LoadChunk ( const cChunkCoords & a_Chunk )
{
AString ChunkData ;
if ( ! GetChunkData ( a_Chunk , ChunkData ))
{
// The reason for failure is already printed in GetChunkData()
return false ;
}
return LoadChunkFromData ( a_Chunk , ChunkData );
}
bool cWSSAnvil :: SaveChunk ( const cChunkCoords & a_Chunk )
{
AString ChunkData ;
if ( ! SaveChunkToData ( a_Chunk , ChunkData ))
{
2013-04-13 21:02:10 +00:00
LOGWARNING ( "Cannot serialize chunk [%d, %d] into data" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ );
2012-06-14 13:06:06 +00:00
return false ;
}
if ( ! SetChunkData ( a_Chunk , ChunkData ))
{
2013-04-13 21:02:10 +00:00
LOGWARNING ( "Cannot store chunk [%d, %d] data" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ );
2012-06-14 13:06:06 +00:00
return false ;
}
// Everything successful
return true ;
}
2015-07-28 15:53:28 +02:00
void cWSSAnvil :: ChunkLoadFailed ( int a_ChunkX , int a_ChunkZ , const AString & a_Reason , const AString & a_ChunkDataToSave )
{
// Construct the filename for offloading:
AString OffloadFileName ;
Printf ( OffloadFileName , "%s%cregion%cbadchunks" , m_World -> GetName (). c_str (), cFile :: PathSeparator , cFile :: PathSeparator );
cFile :: CreateFolder ( FILE_IO_PREFIX + OffloadFileName );
auto t = time ( nullptr );
struct tm stm ;
#ifdef _MSC_VER
localtime_s ( & stm , & t );
#else
localtime_r ( & t , & stm );
#endif
AppendPrintf ( OffloadFileName , "%cch.%d.%d.%d-%02d-%02d-%02d-%02d-%02d.dat" ,
cFile :: PathSeparator , a_ChunkX , a_ChunkZ ,
stm . tm_year + 1900 , stm . tm_mon + 1 , stm . tm_mday , stm . tm_hour , stm . tm_min , stm . tm_sec
);
// Log the warning to console:
const int RegionX = FAST_FLOOR_DIV ( a_ChunkX , 32 );
const int RegionZ = FAST_FLOOR_DIV ( a_ChunkZ , 32 );
AString Info = Printf ( "Loading chunk [%d, %d] for world %s from file r.%d.%d.mca failed: %s. Offloading old chunk data to file %s and regenerating chunk." ,
a_ChunkX , a_ChunkZ , m_World -> GetName (). c_str (), RegionX , RegionZ , a_Reason . c_str (), OffloadFileName . c_str ()
);
LOGWARNING ( "%s" , Info . c_str ());
// Write the data:
cFile f ;
if ( ! f . Open ( OffloadFileName , cFile :: fmWrite ))
{
LOGWARNING ( "Cannot open file %s for writing! Old chunk data is lost." , OffloadFileName . c_str ());
return ;
}
f . Write ( a_ChunkDataToSave . data (), a_ChunkDataToSave . size ());
f . Close ();
// Write a description file:
if ( ! f . Open ( OffloadFileName + ".info" , cFile :: fmWrite ))
{
LOGWARNING ( "Cannot open file %s.info for writing! The information about the failed chunk will not be written." , OffloadFileName . c_str ());
return ;
}
f . Write ( Info . c_str (), Info . size ());
f . Close ();
}
2012-06-14 13:06:06 +00:00
bool cWSSAnvil :: GetChunkData ( const cChunkCoords & a_Chunk , AString & a_Data )
{
cCSLock Lock ( m_CS );
cMCAFile * File = LoadMCAFile ( a_Chunk );
2014-10-20 21:55:07 +01:00
if ( File == nullptr )
2012-06-14 13:06:06 +00:00
{
return false ;
}
return File -> GetChunkData ( a_Chunk , a_Data );
}
bool cWSSAnvil :: SetChunkData ( const cChunkCoords & a_Chunk , const AString & a_Data )
{
cCSLock Lock ( m_CS );
cMCAFile * File = LoadMCAFile ( a_Chunk );
2014-10-20 21:55:07 +01:00
if ( File == nullptr )
2012-06-14 13:06:06 +00:00
{
return false ;
}
return File -> SetChunkData ( a_Chunk , a_Data );
}
cWSSAnvil :: cMCAFile * cWSSAnvil :: LoadMCAFile ( const cChunkCoords & a_Chunk )
{
// ASSUME m_CS is locked
2013-02-27 10:01:20 +00:00
ASSERT ( m_CS . IsLocked ());
2012-06-14 13:06:06 +00:00
2013-02-27 10:01:20 +00:00
const int RegionX = FAST_FLOOR_DIV ( a_Chunk . m_ChunkX , 32 );
const int RegionZ = FAST_FLOOR_DIV ( a_Chunk . m_ChunkZ , 32 );
2013-03-09 14:35:43 +00:00
ASSERT ( a_Chunk . m_ChunkX - RegionX * 32 >= 0 );
ASSERT ( a_Chunk . m_ChunkZ - RegionZ * 32 >= 0 );
ASSERT ( a_Chunk . m_ChunkX - RegionX * 32 < 32 );
ASSERT ( a_Chunk . m_ChunkZ - RegionZ * 32 < 32 );
2012-06-14 13:06:06 +00:00
// Is it already cached?
for ( cMCAFiles :: iterator itr = m_Files . begin (); itr != m_Files . end (); ++ itr )
{
2014-10-20 21:55:07 +01:00
if ((( * itr ) != nullptr ) && (( * itr ) -> GetRegionX () == RegionX ) && (( * itr ) -> GetRegionZ () == RegionZ ))
2012-06-14 13:06:06 +00:00
{
// Move the file to front and return it:
cMCAFile * f = * itr ;
if ( itr != m_Files . begin ())
{
m_Files . erase ( itr );
m_Files . push_front ( f );
}
return f ;
}
}
// Load it anew:
AString FileName ;
2015-05-09 09:25:09 +02:00
Printf ( FileName , "%s%cregion" , m_World -> GetName (). c_str (), cFile :: PathSeparator );
2013-10-09 09:57:48 +02:00
cFile :: CreateFolder ( FILE_IO_PREFIX + FileName );
2012-06-14 13:06:06 +00:00
AppendPrintf ( FileName , "/r.%d.%d.mca" , RegionX , RegionZ );
2015-07-28 15:53:28 +02:00
cMCAFile * f = new cMCAFile ( * this , FileName , RegionX , RegionZ );
2014-10-20 21:55:07 +01:00
if ( f == nullptr )
2012-06-14 13:06:06 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-06-14 13:06:06 +00:00
}
m_Files . push_front ( f );
// If there are too many MCA files cached, delete the last one used:
if ( m_Files . size () > MAX_MCA_FILES )
{
delete m_Files . back ();
m_Files . pop_back ();
}
return f ;
}
bool cWSSAnvil :: LoadChunkFromData ( const cChunkCoords & a_Chunk , const AString & a_Data )
{
2014-09-03 19:36:53 +02:00
// Uncompress the data:
AString Uncompressed ;
int res = InflateString ( a_Data . data (), a_Data . size (), Uncompressed );
if ( res != Z_OK )
2012-06-14 13:06:06 +00:00
{
2014-09-03 19:36:53 +02:00
LOGWARNING ( "Uncompressing chunk [%d, %d] failed: %d" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , res );
2015-07-28 15:53:28 +02:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "InflateString() failed" , a_Data );
2012-06-14 13:06:06 +00:00
return false ;
}
// Parse the NBT data:
2014-09-03 19:36:53 +02:00
cParsedNBT NBT ( Uncompressed . data (), Uncompressed . size ());
2012-06-14 13:06:06 +00:00
if ( ! NBT . IsValid ())
{
// NBT Parsing failed
2015-07-28 15:53:28 +02:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "NBT parsing failed" , a_Data );
2012-06-14 13:06:06 +00:00
return false ;
}
// Load the data from NBT:
2015-07-28 15:53:28 +02:00
return LoadChunkFromNBT ( a_Chunk , NBT , a_Data );
2012-06-14 13:06:06 +00:00
}
bool cWSSAnvil :: SaveChunkToData ( const cChunkCoords & a_Chunk , AString & a_Data )
{
cFastNBTWriter Writer ;
if ( ! SaveChunkToNBT ( a_Chunk , Writer ))
{
2013-04-13 21:02:10 +00:00
LOGWARNING ( "Cannot save chunk [%d, %d] to NBT" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ );
2012-06-14 13:06:06 +00:00
return false ;
}
Writer . Finish ();
2013-03-09 14:35:43 +00:00
2014-01-17 11:01:14 -08:00
CompressString ( Writer . GetResult (). data (), Writer . GetResult (). size (), a_Data , m_CompressionFactor );
2012-06-14 13:06:06 +00:00
return true ;
}
2015-07-28 15:53:28 +02:00
bool cWSSAnvil :: LoadChunkFromNBT ( const cChunkCoords & a_Chunk , const cParsedNBT & a_NBT , const AString & a_RawChunkData )
2012-06-14 13:06:06 +00:00
{
2015-05-09 09:25:09 +02:00
// The data arrays, in MCA-native y / z / x ordering (will be reordered for the final chunk data)
2012-06-14 13:06:06 +00:00
cChunkDef :: BlockTypes BlockTypes ;
cChunkDef :: BlockNibbles MetaData ;
cChunkDef :: BlockNibbles BlockLight ;
cChunkDef :: BlockNibbles SkyLight ;
memset ( BlockTypes , E_BLOCK_AIR , sizeof ( BlockTypes ));
memset ( MetaData , 0 , sizeof ( MetaData ));
memset ( SkyLight , 0xff , sizeof ( SkyLight )); // By default, data not present in the NBT means air, which means full skylight
memset ( BlockLight , 0x00 , sizeof ( BlockLight ));
// Load the blockdata, blocklight and skylight:
int Level = a_NBT . FindChildByName ( 0 , "Level" );
if ( Level < 0 )
{
2015-07-28 15:53:28 +02:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "Missing NBT tag: Level" , a_RawChunkData );
2012-06-14 13:06:06 +00:00
return false ;
}
int Sections = a_NBT . FindChildByName ( Level , "Sections" );
2014-09-05 22:55:39 +02:00
if (( Sections < 0 ) || ( a_NBT . GetType ( Sections ) != TAG_List ))
{
2015-07-28 15:53:28 +02:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "Missing NBT tag: Sections" , a_RawChunkData );
2014-09-05 22:55:39 +02:00
return false ;
}
eTagType SectionsType = a_NBT . GetChildrenType ( Sections );
if (( SectionsType != TAG_Compound ) && ( SectionsType != TAG_End ))
2012-06-14 13:06:06 +00:00
{
2015-07-28 15:53:28 +02:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "NBT tag has wrong type: Sections" , a_RawChunkData );
2012-06-14 13:06:06 +00:00
return false ;
}
for ( int Child = a_NBT . GetFirstChild ( Sections ); Child >= 0 ; Child = a_NBT . GetNextSibling ( Child ))
{
int y = 0 ;
int SectionY = a_NBT . FindChildByName ( Child , "Y" );
if (( SectionY < 0 ) || ( a_NBT . GetType ( SectionY ) != TAG_Byte ))
{
continue ;
}
y = a_NBT . GetByte ( SectionY );
if (( y < 0 ) || ( y > 15 ))
{
continue ;
}
2015-07-29 09:04:03 -06:00
CopyNBTData ( a_NBT , Child , "Blocks" , reinterpret_cast < char *> ( & ( BlockTypes [ y * 4096 ])), 4096 );
CopyNBTData ( a_NBT , Child , "Data" , reinterpret_cast < char *> ( & ( MetaData [ y * 2048 ])), 2048 );
CopyNBTData ( a_NBT , Child , "SkyLight" , reinterpret_cast < char *> ( & ( SkyLight [ y * 2048 ])), 2048 );
CopyNBTData ( a_NBT , Child , "BlockLight" , reinterpret_cast < char *> ( & ( BlockLight [ y * 2048 ])), 2048 );
2012-06-14 13:06:06 +00:00
} // for itr - LevelSections[]
2012-10-28 17:30:10 +00:00
// Load the biomes from NBT, if present and valid. First try MCS-style, then Vanilla-style:
2012-06-14 13:06:06 +00:00
cChunkDef :: BiomeMap BiomeMap ;
2012-10-28 17:30:10 +00:00
cChunkDef :: BiomeMap * Biomes = LoadBiomeMapFromNBT ( & BiomeMap , a_NBT , a_NBT . FindChildByName ( Level , "MCSBiomes" ));
2014-10-20 21:55:07 +01:00
if ( Biomes == nullptr )
2012-10-28 17:30:10 +00:00
{
// MCS-style biomes not available, load vanilla-style:
Biomes = LoadVanillaBiomeMapFromNBT ( & BiomeMap , a_NBT , a_NBT . FindChildByName ( Level , "Biomes" ));
}
2012-06-14 13:06:06 +00:00
// Load the entities from NBT:
cEntityList Entities ;
cBlockEntityList BlockEntities ;
LoadEntitiesFromNBT ( Entities , a_NBT , a_NBT . FindChildByName ( Level , "Entities" ));
2013-06-20 11:41:44 +00:00
LoadBlockEntitiesFromNBT ( BlockEntities , a_NBT , a_NBT . FindChildByName ( Level , "TileEntities" ), BlockTypes , MetaData );
2012-06-14 13:06:06 +00:00
bool IsLightValid = ( a_NBT . FindChildByName ( Level , "MCSIsLightValid" ) > 0 );
/*
// Uncomment this block for really cool stuff :)
// DEBUG magic: Invert the underground, so that we can see the MC generator in action :)
bool ShouldInvert[cChunkDef::Width * cChunkDef::Width];
memset(ShouldInvert, 0, sizeof(ShouldInvert));
for (int y = cChunkDef::Height - 1; y >= 0; y--)
{
for (int x = 0; x < cChunkDef::Width; x++) for (int z = 0; z < cChunkDef::Width; z++)
{
int Index = cChunkDef::MakeIndexNoCheck(x, y, z);
if (ShouldInvert[x + cChunkDef::Width * z])
{
2012-07-21 17:07:46 +00:00
BlockTypes[Index] = (BlockTypes[Index] == E_BLOCK_AIR) ? E_BLOCK_STONE : E_BLOCK_AIR;
2012-06-14 13:06:06 +00:00
}
else
{
2012-07-21 17:07:46 +00:00
switch (BlockTypes[Index])
{
case E_BLOCK_AIR:
case E_BLOCK_LEAVES:
2014-03-16 14:01:22 +01:00
case E_BLOCK_NEW_LEAVES:
2012-07-21 17:07:46 +00:00
{
// nothing needed
break;
}
default:
{
ShouldInvert[x + cChunkDef::Width * z] = true;
}
}
BlockTypes[Index] = E_BLOCK_AIR;
2012-06-14 13:06:06 +00:00
}
}
} // for y
//*/
2014-08-29 19:19:27 +03:00
cSetChunkDataPtr SetChunkData ( new cSetChunkData (
2013-04-13 21:02:10 +00:00
a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ ,
2014-07-17 22:50:58 +02:00
BlockTypes , MetaData ,
2014-10-20 21:55:07 +01:00
IsLightValid ? BlockLight : nullptr ,
IsLightValid ? SkyLight : nullptr ,
nullptr , Biomes ,
2015-04-27 21:18:21 +02:00
std :: move ( Entities ), std :: move ( BlockEntities ),
2012-06-14 13:06:06 +00:00
false
2014-08-29 19:19:27 +03:00
));
m_World -> QueueSetChunkData ( SetChunkData );
2012-06-14 13:06:06 +00:00
return true ;
}
2014-05-09 19:57:59 +02:00
void cWSSAnvil :: CopyNBTData ( const cParsedNBT & a_NBT , int a_Tag , const AString & a_ChildName , char * a_Destination , size_t a_Length )
2012-06-14 13:06:06 +00:00
{
int Child = a_NBT . FindChildByName ( a_Tag , a_ChildName );
if (( Child >= 0 ) && ( a_NBT . GetType ( Child ) == TAG_ByteArray ) && ( a_NBT . GetDataLength ( Child ) == a_Length ))
{
memcpy ( a_Destination , a_NBT . GetData ( Child ), a_Length );
}
}
bool cWSSAnvil :: SaveChunkToNBT ( const cChunkCoords & a_Chunk , cFastNBTWriter & a_Writer )
{
a_Writer . BeginCompound ( "Level" );
a_Writer . AddInt ( "xPos" , a_Chunk . m_ChunkX );
a_Writer . AddInt ( "zPos" , a_Chunk . m_ChunkZ );
2014-09-23 19:16:17 +02:00
2012-06-14 13:06:06 +00:00
cNBTChunkSerializer Serializer ( a_Writer );
2013-04-13 21:02:10 +00:00
if ( ! m_World -> GetChunkData ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , Serializer ))
2012-06-14 13:06:06 +00:00
{
2013-04-13 21:02:10 +00:00
LOGWARNING ( "Cannot get chunk [%d, %d] data for NBT saving" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ );
2012-06-14 13:06:06 +00:00
return false ;
}
Serializer . Finish (); // Close NBT tags
2012-10-28 17:30:10 +00:00
// Save biomes, both MCS (IntArray) and MC-vanilla (ByteArray):
2012-11-13 15:58:27 +00:00
if ( Serializer . m_BiomesAreValid )
{
2015-07-29 09:04:03 -06:00
a_Writer . AddByteArray ( "Biomes" , reinterpret_cast < const char *> ( Serializer . m_VanillaBiomes ), ARRAYCOUNT ( Serializer . m_VanillaBiomes ));
a_Writer . AddIntArray ( "MCSBiomes" , reinterpret_cast < const int *> ( Serializer . m_Biomes ), ARRAYCOUNT ( Serializer . m_Biomes ));
2012-11-13 15:58:27 +00:00
}
2014-09-23 19:16:17 +02:00
// Save heightmap (Vanilla require this):
2015-07-29 09:04:03 -06:00
a_Writer . AddIntArray ( "HeightMap" , reinterpret_cast < const int *> ( Serializer . m_VanillaHeightMap ), ARRAYCOUNT ( Serializer . m_VanillaHeightMap ));
2014-09-23 19:16:17 +02:00
2012-06-14 13:06:06 +00:00
// Save blockdata:
a_Writer . BeginList ( "Sections" , TAG_Compound );
2014-05-09 19:57:59 +02:00
size_t SliceSizeBlock = cChunkDef :: Width * cChunkDef :: Width * 16 ;
size_t SliceSizeNibble = SliceSizeBlock / 2 ;
2015-07-29 09:04:03 -06:00
const char * BlockTypes = reinterpret_cast < const char *> ( Serializer . m_BlockTypes );
const char * BlockMetas = reinterpret_cast < const char *> ( Serializer . m_BlockMetas );
2013-05-05 14:48:18 +00:00
#ifdef DEBUG_SKYLIGHT
2015-07-29 09:04:03 -06:00
const char * BlockLight = reinterpret_cast < const char *> ( Serializer . m_BlockSkyLight );
2013-05-05 14:48:18 +00:00
#else
2015-07-29 09:04:03 -06:00
const char * BlockLight = reinterpret_cast < const char *> ( Serializer . m_BlockLight );
2014-07-17 22:50:58 +02:00
#endif
2015-07-29 09:04:03 -06:00
const char * BlockSkyLight = reinterpret_cast < const char *> ( Serializer . m_BlockSkyLight );
2012-06-14 13:06:06 +00:00
for ( int Y = 0 ; Y < 16 ; Y ++ )
{
a_Writer . BeginCompound ( "" );
2015-07-29 09:04:03 -06:00
a_Writer . AddByteArray ( "Blocks" , BlockTypes + static_cast < unsigned int > ( Y ) * SliceSizeBlock , SliceSizeBlock );
a_Writer . AddByteArray ( "Data" , BlockMetas + static_cast < unsigned int > ( Y ) * SliceSizeNibble , SliceSizeNibble );
a_Writer . AddByteArray ( "SkyLight" , BlockSkyLight + static_cast < unsigned int > ( Y ) * SliceSizeNibble , SliceSizeNibble );
a_Writer . AddByteArray ( "BlockLight" , BlockLight + static_cast < unsigned int > ( Y ) * SliceSizeNibble , SliceSizeNibble );
2015-07-09 11:15:37 -06:00
a_Writer . AddByte ( "Y" , static_cast < unsigned char > ( Y ));
2012-06-14 13:06:06 +00:00
a_Writer . EndCompound ();
}
a_Writer . EndList (); // "Sections"
2014-07-17 22:50:58 +02:00
// Store the information that the lighting is valid.
2012-06-14 13:06:06 +00:00
// For compatibility reason, the default is "invalid" (missing) - this means older data is re-lighted upon loading.
if ( Serializer . IsLightValid ())
{
a_Writer . AddByte ( "MCSIsLightValid" , 1 );
}
2014-09-23 19:16:17 +02:00
// Save the world age to the chunk data. Required by vanilla and mcedit.
a_Writer . AddLong ( "LastUpdate" , m_World -> GetWorldAge ());
2012-06-14 13:06:06 +00:00
2014-06-20 21:30:11 +02:00
// Store the flag that the chunk has all the ores, trees, dungeons etc. MCS chunks are always complete.
a_Writer . AddByte ( "TerrainPopulated" , 1 );
2012-06-14 13:06:06 +00:00
a_Writer . EndCompound (); // "Level"
return true ;
}
2012-10-28 17:30:10 +00:00
cChunkDef :: BiomeMap * cWSSAnvil :: LoadVanillaBiomeMapFromNBT ( cChunkDef :: BiomeMap * a_BiomeMap , const cParsedNBT & a_NBT , int a_TagIdx )
2012-06-14 13:06:06 +00:00
{
if (( a_TagIdx < 0 ) || ( a_NBT . GetType ( a_TagIdx ) != TAG_ByteArray ))
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-06-14 13:06:06 +00:00
}
2013-04-07 21:04:54 +00:00
if ( a_NBT . GetDataLength ( a_TagIdx ) != 16 * 16 )
2012-06-14 13:06:06 +00:00
{
// The biomes stored don't match in size
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-06-14 13:06:06 +00:00
}
2015-07-29 09:04:03 -06:00
const unsigned char * VanillaBiomeData = reinterpret_cast < const unsigned char *> ( a_NBT . GetData ( a_TagIdx ));
2013-12-20 16:01:34 +01:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( * a_BiomeMap ); i ++ )
2012-10-28 17:30:10 +00:00
{
if (( VanillaBiomeData )[ i ] == 0xff )
{
// Unassigned biomes
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-10-28 17:30:10 +00:00
}
2015-07-29 09:04:03 -06:00
( * a_BiomeMap )[ i ] = static_cast < EMCSBiome > ( VanillaBiomeData [ i ]);
2012-10-28 17:30:10 +00:00
}
return a_BiomeMap ;
}
cChunkDef :: BiomeMap * cWSSAnvil :: LoadBiomeMapFromNBT ( cChunkDef :: BiomeMap * a_BiomeMap , const cParsedNBT & a_NBT , int a_TagIdx )
{
if (( a_TagIdx < 0 ) || ( a_NBT . GetType ( a_TagIdx ) != TAG_IntArray ))
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-10-28 17:30:10 +00:00
}
if ( a_NBT . GetDataLength ( a_TagIdx ) != sizeof ( * a_BiomeMap ))
{
// The biomes stored don't match in size
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-10-28 17:30:10 +00:00
}
2014-03-10 11:34:20 -07:00
const char * BiomeData = ( a_NBT . GetData ( a_TagIdx ));
2013-12-20 16:01:34 +01:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( * a_BiomeMap ); i ++ )
2012-06-14 13:06:06 +00:00
{
2015-07-29 09:04:03 -06:00
( * a_BiomeMap )[ i ] = static_cast < EMCSBiome > ( GetBEInt ( & BiomeData [ i * 4 ]));
2012-06-14 13:06:06 +00:00
if (( * a_BiomeMap )[ i ] == 0xff )
{
// Unassigned biomes
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-06-14 13:06:06 +00:00
}
}
return a_BiomeMap ;
}
2013-03-09 14:35:43 +00:00
void cWSSAnvil :: LoadEntitiesFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
2012-06-14 13:06:06 +00:00
{
2013-03-09 14:35:43 +00:00
if (( a_TagIdx < 0 ) || ( a_NBT . GetType ( a_TagIdx ) != TAG_List ))
{
return ;
}
for ( int Child = a_NBT . GetFirstChild ( a_TagIdx ); Child != - 1 ; Child = a_NBT . GetNextSibling ( Child ))
{
if ( a_NBT . GetType ( Child ) != TAG_Compound )
{
continue ;
}
int sID = a_NBT . FindChildByName ( Child , "id" );
if ( sID < 0 )
{
continue ;
}
LoadEntityFromNBT ( a_Entities , a_NBT , Child , a_NBT . GetData ( sID ), a_NBT . GetDataLength ( sID ));
} // for Child - a_NBT[]
2012-06-14 13:06:06 +00:00
}
2013-06-20 11:41:44 +00:00
void cWSSAnvil :: LoadBlockEntitiesFromNBT ( cBlockEntityList & a_BlockEntities , const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE * a_BlockTypes , NIBBLETYPE * a_BlockMetas )
2012-06-14 13:06:06 +00:00
{
if (( a_TagIdx < 0 ) || ( a_NBT . GetType ( a_TagIdx ) != TAG_List ))
{
return ;
}
for ( int Child = a_NBT . GetFirstChild ( a_TagIdx ); Child != - 1 ; Child = a_NBT . GetNextSibling ( Child ))
{
if ( a_NBT . GetType ( Child ) != TAG_Compound )
{
continue ;
}
2014-08-29 19:19:27 +03:00
// Get the BlockEntity's position
int x , y , z ;
2014-09-05 16:40:03 +03:00
if ( ! GetBlockEntityNBTPos ( a_NBT , Child , x , y , z ) || ( y < 0 ) || ( y >= cChunkDef :: Height ))
2012-06-14 13:06:06 +00:00
{
2014-08-29 19:19:27 +03:00
LOGWARNING ( "Bad block entity, missing the coords. Will be ignored." );
2012-06-14 13:06:06 +00:00
continue ;
}
2014-08-29 19:19:27 +03:00
int RelX = x , RelY = y , RelZ = z , ChunkX , ChunkZ ;
cChunkDef :: AbsoluteToRelative ( RelX , RelY , RelZ , ChunkX , ChunkZ );
// Load the proper BlockEntity type based on the block type:
BLOCKTYPE BlockType = cChunkDef :: GetBlock ( a_BlockTypes , RelX , RelY , RelZ );
NIBBLETYPE BlockMeta = cChunkDef :: GetNibble ( a_BlockMetas , RelX , RelY , RelZ );
2014-12-06 23:02:49 +01:00
std :: unique_ptr < cBlockEntity > be ( LoadBlockEntityFromNBT ( a_NBT , Child , x , y , z , BlockType , BlockMeta ));
2014-10-20 21:55:07 +01:00
if ( be . get () == nullptr )
2014-07-06 23:50:22 +01:00
{
2014-08-29 19:19:27 +03:00
continue ;
2014-07-06 23:50:22 +01:00
}
2014-08-29 19:19:27 +03:00
// Add the BlockEntity to the loaded data:
a_BlockEntities . push_back ( be . release ());
2012-06-14 13:06:06 +00:00
} // for Child - tag children
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadBlockEntityFromNBT ( const cParsedNBT & a_NBT , int a_Tag , int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta )
{
2014-09-06 18:59:17 +02:00
ASSERT (( a_BlockY >= 0 ) && ( a_BlockY < cChunkDef :: Height ));
2014-08-29 19:19:27 +03:00
// Load the specific BlockEntity type:
switch ( a_BlockType )
{
// Specific entity loaders:
case E_BLOCK_BEACON : return LoadBeaconFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
2015-09-24 10:48:33 +02:00
case E_BLOCK_BREWING_STAND : return LoadBrewingstandFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ , E_BLOCK_BREWING_STAND , a_BlockMeta );
2014-08-29 19:19:27 +03:00
case E_BLOCK_CHEST : return LoadChestFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ , E_BLOCK_CHEST );
case E_BLOCK_COMMAND_BLOCK : return LoadCommandBlockFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
case E_BLOCK_DISPENSER : return LoadDispenserFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
case E_BLOCK_DROPPER : return LoadDropperFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
case E_BLOCK_FLOWER_POT : return LoadFlowerPotFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
case E_BLOCK_FURNACE : return LoadFurnaceFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ , E_BLOCK_FURNACE , a_BlockMeta );
case E_BLOCK_HEAD : return LoadMobHeadFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
case E_BLOCK_HOPPER : return LoadHopperFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
case E_BLOCK_JUKEBOX : return LoadJukeboxFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
case E_BLOCK_LIT_FURNACE : return LoadFurnaceFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ , E_BLOCK_LIT_FURNACE , a_BlockMeta );
2014-11-18 15:33:41 +01:00
case E_BLOCK_MOB_SPAWNER : return LoadMobSpawnerFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
2014-08-29 19:19:27 +03:00
case E_BLOCK_NOTE_BLOCK : return LoadNoteBlockFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ );
case E_BLOCK_SIGN_POST : return LoadSignFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ , E_BLOCK_SIGN_POST );
case E_BLOCK_TRAPPED_CHEST : return LoadChestFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ , E_BLOCK_TRAPPED_CHEST );
case E_BLOCK_WALLSIGN : return LoadSignFromNBT ( a_NBT , a_Tag , a_BlockX , a_BlockY , a_BlockZ , E_BLOCK_WALLSIGN );
// Blocktypes that have block entities but don't load their contents from disk:
2014-10-20 21:55:07 +01:00
case E_BLOCK_ENDER_CHEST : return nullptr ;
2014-08-29 19:19:27 +03:00
}
// All the other blocktypes should have no entities assigned to them. Report an error:
// Get the "id" tag:
int TagID = a_NBT . FindChildByName ( a_Tag , "id" );
AString TypeName ( "<unknown>" );
if ( TagID >= 0 )
{
2015-07-29 09:04:03 -06:00
TypeName . assign ( a_NBT . GetData ( TagID ), static_cast < size_t > ( a_NBT . GetDataLength ( TagID )));
2014-08-29 19:19:27 +03:00
}
LOGINFO ( "WorldLoader(%s): Block entity mismatch: block type %s (%d), type \" %s \" , at {%d, %d, %d}; the entity will be lost." ,
m_World -> GetName (). c_str (),
ItemTypeToString ( a_BlockType ). c_str (), a_BlockType , TypeName . c_str (),
a_BlockX , a_BlockY , a_BlockZ
);
2014-10-20 21:55:07 +01:00
return nullptr ;
2014-08-29 19:19:27 +03:00
}
2013-03-09 14:35:43 +00:00
bool cWSSAnvil :: LoadItemFromNBT ( cItem & a_Item , const cParsedNBT & a_NBT , int a_TagIdx )
{
2014-01-26 14:43:54 +01:00
int Type = a_NBT . FindChildByName ( a_TagIdx , "id" );
2014-10-29 15:47:43 +01:00
if ( Type <= 0 )
2013-03-09 14:35:43 +00:00
{
return false ;
}
2014-10-29 15:47:43 +01:00
if ( a_NBT . GetType ( Type ) == TAG_String )
{
if ( ! StringToItem ( a_NBT . GetString ( Type ), a_Item ))
{
// Can't resolve item type
return false ;
}
}
else if ( a_NBT . GetType ( Type ) == TAG_Short )
{
a_Item . m_ItemType = a_NBT . GetShort ( Type );
}
else
{
return false ;
}
2014-01-26 14:43:54 +01:00
if ( a_Item . m_ItemType < 0 )
{
a_Item . Empty ();
return true ;
}
2013-03-09 14:35:43 +00:00
int Damage = a_NBT . FindChildByName ( a_TagIdx , "Damage" );
2014-05-07 12:30:30 +02:00
if (( Damage > 0 ) && ( a_NBT . GetType ( Damage ) == TAG_Short ))
2013-03-09 14:35:43 +00:00
{
2014-05-07 12:30:30 +02:00
a_Item . m_ItemDamage = a_NBT . GetShort ( Damage );
2013-03-09 14:35:43 +00:00
}
int Count = a_NBT . FindChildByName ( a_TagIdx , "Count" );
2014-05-07 12:30:30 +02:00
if (( Count > 0 ) && ( a_NBT . GetType ( Count ) == TAG_Byte ))
2013-03-09 14:35:43 +00:00
{
2015-07-29 09:04:03 -06:00
a_Item . m_ItemCount = static_cast < char > ( a_NBT . GetByte ( Count ));
2013-03-09 14:35:43 +00:00
}
2013-06-02 21:21:32 +00:00
// Find the "tag" tag, used for enchantments and other extra data
int TagTag = a_NBT . FindChildByName ( a_TagIdx , "tag" );
if ( TagTag <= 0 )
{
// No extra data
return true ;
}
2014-05-07 12:30:30 +02:00
// Load repair cost:
int RepairCost = a_NBT . FindChildByName ( TagTag , "RepairCost" );
if (( RepairCost > 0 ) && ( a_NBT . GetType ( RepairCost ) == TAG_Int ))
{
2014-05-07 20:43:37 +02:00
a_Item . m_RepairCost = a_NBT . GetInt ( RepairCost );
2014-05-07 12:30:30 +02:00
}
// Load display name:
int DisplayTag = a_NBT . FindChildByName ( TagTag , "display" );
if ( DisplayTag > 0 )
{
int DisplayName = a_NBT . FindChildByName ( DisplayTag , "Name" );
if (( DisplayName > 0 ) && ( a_NBT . GetType ( DisplayName ) == TAG_String ))
{
a_Item . m_CustomName = a_NBT . GetString ( DisplayName );
}
int Lore = a_NBT . FindChildByName ( DisplayTag , "Lore" );
if (( Lore > 0 ) && ( a_NBT . GetType ( Lore ) == TAG_String ))
{
a_Item . m_Lore = a_NBT . GetString ( Lore );
}
}
2013-06-02 21:21:32 +00:00
// Load enchantments:
const char * EnchName = ( a_Item . m_ItemType == E_ITEM_BOOK ) ? "StoredEnchantments" : "ench" ;
int EnchTag = a_NBT . FindChildByName ( TagTag , EnchName );
if ( EnchTag > 0 )
{
2014-01-19 08:52:45 -08:00
EnchantmentSerializer :: ParseFromNBT ( a_Item . m_Enchantments , a_NBT , EnchTag );
2013-06-02 21:21:32 +00:00
}
2014-02-26 23:29:14 +00:00
2014-05-07 12:30:30 +02:00
// Load firework data:
2014-02-26 23:29:14 +00:00
int FireworksTag = a_NBT . FindChildByName ( TagTag , (( a_Item . m_ItemType == E_ITEM_FIREWORK_STAR ) ? "Fireworks" : "Explosion" ));
if ( EnchTag > 0 )
{
2015-07-29 09:04:03 -06:00
cFireworkItem :: ParseFromNBT ( a_Item . m_FireworkItem , a_NBT , FireworksTag , static_cast < ENUM_ITEM_ID > ( a_Item . m_ItemType ));
2014-02-26 23:29:14 +00:00
}
2013-06-02 21:21:32 +00:00
2013-03-09 14:35:43 +00:00
return true ;
}
2013-05-26 15:29:43 +00:00
void cWSSAnvil :: LoadItemGridFromNBT ( cItemGrid & a_ItemGrid , const cParsedNBT & a_NBT , int a_ItemsTagIdx , int a_SlotOffset )
{
int NumSlots = a_ItemGrid . GetNumSlots ();
for ( int Child = a_NBT . GetFirstChild ( a_ItemsTagIdx ); Child != - 1 ; Child = a_NBT . GetNextSibling ( Child ))
{
int SlotTag = a_NBT . FindChildByName ( Child , "Slot" );
if (( SlotTag < 0 ) || ( a_NBT . GetType ( SlotTag ) != TAG_Byte ))
{
continue ;
}
2015-07-29 09:04:03 -06:00
int SlotNum = static_cast < int > ( a_NBT . GetByte ( SlotTag )) - a_SlotOffset ;
2013-05-26 15:29:43 +00:00
if (( SlotNum < 0 ) || ( SlotNum >= NumSlots ))
{
// SlotNum outside of the range
continue ;
}
cItem Item ;
if ( LoadItemFromNBT ( Item , a_NBT , Child ))
{
a_ItemGrid . SetSlot ( SlotNum , Item );
}
} // for itr - ItemDefs[]
}
2014-08-29 19:19:27 +03:00
bool cWSSAnvil :: CheckBlockEntityType ( const cParsedNBT & a_NBT , int a_TagIdx , const char * a_ExpectedType )
2014-07-30 22:50:34 +02:00
{
2014-08-29 19:19:27 +03:00
// Check if the given tag is a compound:
if ( a_NBT . GetType ( a_TagIdx ) != TAG_Compound )
2014-07-30 22:50:34 +02:00
{
2014-08-29 19:19:27 +03:00
return false ;
}
// Get the "id" tag:
int TagID = a_NBT . FindChildByName ( a_TagIdx , "id" );
if ( TagID < 0 )
{
return false ;
}
// Compare the value:
2015-07-29 09:04:03 -06:00
if ( strncmp ( a_NBT . GetData ( TagID ), a_ExpectedType , static_cast < size_t > ( a_NBT . GetDataLength ( TagID ))) == 0 )
2014-08-29 19:19:27 +03:00
{
return true ;
}
LOGWARNING ( "Block entity type mismatch: exp \" %s \" , got \" %s \" ." ,
a_ExpectedType ,
2015-07-29 09:04:03 -06:00
AString ( a_NBT . GetData ( TagID ), static_cast < size_t > ( a_NBT . GetDataLength ( TagID ))). c_str ()
2014-08-29 19:19:27 +03:00
);
return false ;
}
cBlockEntity * cWSSAnvil :: LoadBeaconFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
{
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Beacon" ))
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2014-07-30 22:50:34 +02:00
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cBeaconEntity > Beacon = cpp14 :: make_unique < cBeaconEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2014-07-30 22:50:34 +02:00
int CurrentLine = a_NBT . FindChildByName ( a_TagIdx , "Levels" );
if ( CurrentLine >= 0 )
{
2015-07-29 09:04:03 -06:00
Beacon -> SetBeaconLevel ( static_cast < char > ( a_NBT . GetInt ( CurrentLine )));
2014-07-30 22:50:34 +02:00
}
CurrentLine = a_NBT . FindChildByName ( a_TagIdx , "Primary" );
if ( CurrentLine >= 0 )
{
2015-07-29 09:04:03 -06:00
Beacon -> SetPrimaryEffect ( static_cast < cEntityEffect :: eType > ( a_NBT . GetInt ( CurrentLine )));
2014-07-30 22:50:34 +02:00
}
CurrentLine = a_NBT . FindChildByName ( a_TagIdx , "Secondary" );
if ( CurrentLine >= 0 )
{
2015-07-29 09:04:03 -06:00
Beacon -> SetSecondaryEffect ( static_cast < cEntityEffect :: eType > ( a_NBT . GetInt ( CurrentLine )));
2014-07-30 22:50:34 +02:00
}
2015-05-09 09:25:09 +02:00
// We are better than mojang, we load / save the beacon inventory!
2014-07-30 22:50:34 +02:00
int Items = a_NBT . FindChildByName ( a_TagIdx , "Items" );
if (( Items >= 0 ) && ( a_NBT . GetType ( Items ) == TAG_List ))
{
LoadItemGridFromNBT ( Beacon -> GetContents (), a_NBT , Items );
}
2014-08-29 19:19:27 +03:00
return Beacon . release ();
2014-07-30 22:50:34 +02:00
}
2015-09-24 10:48:33 +02:00
cBlockEntity * cWSSAnvil :: LoadBrewingstandFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta )
{
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Brewingstand" ))
{
return nullptr ;
}
int Items = a_NBT . FindChildByName ( a_TagIdx , "Items" );
if (( Items < 0 ) || ( a_NBT . GetType ( Items ) != TAG_List ))
{
return nullptr ; // Make it an empty brewingstand - the chunk loader will provide an empty cBrewingstandEntity for this
}
std :: unique_ptr < cBrewingstandEntity > Brewingstand ( new cBrewingstandEntity ( a_BlockX , a_BlockY , a_BlockZ , a_BlockType , a_BlockMeta , m_World ));
// Load slots:
for ( int Child = a_NBT . GetFirstChild ( Items ); Child != - 1 ; Child = a_NBT . GetNextSibling ( Child ))
{
int Slot = a_NBT . FindChildByName ( Child , "Slot" );
if (( Slot < 0 ) || ( a_NBT . GetType ( Slot ) != TAG_Byte ))
{
continue ;
}
cItem Item ;
if ( LoadItemFromNBT ( Item , a_NBT , Child ))
{
Brewingstand -> SetSlot ( a_NBT . GetByte ( Slot ), Item );
}
} // for itr - ItemDefs[]
// Load brewing time:
int BrewTime = a_NBT . FindChildByName ( a_TagIdx , "BrewTime" );
if ( BrewTime >= 0 )
{
Int16 tb = a_NBT . GetShort ( BrewTime );
Brewingstand -> setTimeBrewed ( tb );
}
// Restart brewing:
Brewingstand -> GetRecipes ();
Brewingstand -> ContinueBrewing ();
return Brewingstand . release ();
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadChestFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_ChestBlockType )
2012-06-14 13:06:06 +00:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
// TODO: Does vanilla use "TrappedChest" or not? MCWiki says no, but previous code says yes
// Ref.: http://minecraft.gamepedia.com/Trapped_Chest
// https://github.com/mc-server/MCServer/blob/d0551e2e0a98a28f31a88d489d17b408e4a7d38d/src/WorldStorage/WSSAnvil.cpp#L637
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Chest" ) && ! CheckBlockEntityType ( a_NBT , a_TagIdx , "TrappedChest" ))
2012-06-14 13:06:06 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-06-14 13:06:06 +00:00
}
2014-08-29 19:19:27 +03:00
2012-06-14 13:06:06 +00:00
int Items = a_NBT . FindChildByName ( a_TagIdx , "Items" );
if (( Items < 0 ) || ( a_NBT . GetType ( Items ) != TAG_List ))
{
2014-10-20 21:55:07 +01:00
return nullptr ; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
2012-06-14 13:06:06 +00:00
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cChestEntity > Chest = cpp14 :: make_unique < cChestEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World , a_ChestBlockType );
2013-05-26 15:29:43 +00:00
LoadItemGridFromNBT ( Chest -> GetContents (), a_NBT , Items );
2014-08-29 19:19:27 +03:00
return Chest . release ();
2012-06-14 13:06:06 +00:00
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadCommandBlockFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-12-19 21:19:36 +00:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Control" ))
2012-12-19 21:19:36 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2014-08-29 19:19:27 +03:00
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cCommandBlockEntity > CmdBlock = cpp14 :: make_unique < cCommandBlockEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2014-08-29 19:19:27 +03:00
int currentLine = a_NBT . FindChildByName ( a_TagIdx , "Command" );
if ( currentLine >= 0 )
{
CmdBlock -> SetCommand ( a_NBT . GetString ( currentLine ));
}
currentLine = a_NBT . FindChildByName ( a_TagIdx , "SuccessCount" );
if ( currentLine >= 0 )
{
2015-07-29 09:04:03 -06:00
CmdBlock -> SetResult ( static_cast < NIBBLETYPE > ( a_NBT . GetInt ( currentLine )));
2014-08-29 19:19:27 +03:00
}
currentLine = a_NBT . FindChildByName ( a_TagIdx , "LastOutput" );
if ( currentLine >= 0 )
{
CmdBlock -> SetLastOutput ( a_NBT . GetString ( currentLine ));
}
// TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it.
return CmdBlock . release ();
}
cBlockEntity * cWSSAnvil :: LoadDispenserFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
{
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Trap" ))
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-12-19 21:19:36 +00:00
}
2014-08-29 19:19:27 +03:00
2012-12-19 21:19:36 +00:00
int Items = a_NBT . FindChildByName ( a_TagIdx , "Items" );
if (( Items < 0 ) || ( a_NBT . GetType ( Items ) != TAG_List ))
{
2014-10-20 21:55:07 +01:00
return nullptr ; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this
2012-12-19 21:19:36 +00:00
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cDispenserEntity > Dispenser = cpp14 :: make_unique < cDispenserEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2013-05-26 15:29:43 +00:00
LoadItemGridFromNBT ( Dispenser -> GetContents (), a_NBT , Items );
2014-08-29 19:19:27 +03:00
return Dispenser . release ();
2012-12-19 21:19:36 +00:00
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadDropperFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
2013-05-26 15:29:43 +00:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Dropper" ))
2013-05-26 15:29:43 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2013-05-26 15:29:43 +00:00
}
2014-08-29 19:19:27 +03:00
2013-05-26 15:29:43 +00:00
int Items = a_NBT . FindChildByName ( a_TagIdx , "Items" );
if (( Items < 0 ) || ( a_NBT . GetType ( Items ) != TAG_List ))
{
2014-10-20 21:55:07 +01:00
return nullptr ; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this
2013-05-26 15:29:43 +00:00
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cDropperEntity > Dropper = cpp14 :: make_unique < cDropperEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2013-05-26 15:29:43 +00:00
LoadItemGridFromNBT ( Dropper -> GetContents (), a_NBT , Items );
2014-08-29 19:19:27 +03:00
return Dropper . release ();
2013-05-26 15:29:43 +00:00
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadFlowerPotFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-03-07 01:30:34 +01:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "FlowerPot" ))
2014-03-07 01:30:34 +01:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2014-03-07 01:30:34 +01:00
}
2014-08-29 19:19:27 +03:00
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cFlowerPotEntity > FlowerPot = cpp14 :: make_unique < cFlowerPotEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2015-02-18 23:33:27 +01:00
cItem Item ;
2014-03-07 01:30:34 +01:00
int currentLine = a_NBT . FindChildByName ( a_TagIdx , "Item" );
if ( currentLine >= 0 )
{
2015-02-18 23:33:27 +01:00
if ( a_NBT . GetType ( currentLine ) == TAG_String )
{
StringToItem ( a_NBT . GetString ( currentLine ), Item );
}
else if ( a_NBT . GetType ( currentLine ) == TAG_Int )
{
2015-07-29 09:04:03 -06:00
Item . m_ItemType = static_cast < short > ( a_NBT . GetInt ( currentLine ));
2015-02-18 23:33:27 +01:00
}
2014-03-07 01:30:34 +01:00
}
currentLine = a_NBT . FindChildByName ( a_TagIdx , "Data" );
2015-02-18 23:33:27 +01:00
if (( currentLine >= 0 ) && ( a_NBT . GetType ( currentLine ) == TAG_Int ))
2014-03-07 01:30:34 +01:00
{
2015-07-29 09:04:03 -06:00
Item . m_ItemDamage = static_cast < short > ( a_NBT . GetInt ( currentLine ));
2014-03-07 01:30:34 +01:00
}
2015-02-18 23:33:27 +01:00
FlowerPot -> SetItem ( Item );
2014-08-29 19:19:27 +03:00
return FlowerPot . release ();
2014-03-07 01:30:34 +01:00
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadFurnaceFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta )
2012-06-14 13:06:06 +00:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Furnace" ))
2012-06-14 13:06:06 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-06-14 13:06:06 +00:00
}
2014-08-29 19:19:27 +03:00
2012-06-14 13:06:06 +00:00
int Items = a_NBT . FindChildByName ( a_TagIdx , "Items" );
if (( Items < 0 ) || ( a_NBT . GetType ( Items ) != TAG_List ))
{
2014-10-20 21:55:07 +01:00
return nullptr ; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this
2012-06-14 13:06:06 +00:00
}
2013-06-20 11:41:44 +00:00
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cFurnaceEntity > Furnace = cpp14 :: make_unique < cFurnaceEntity > ( a_BlockX , a_BlockY , a_BlockZ , a_BlockType , a_BlockMeta , m_World );
2015-06-02 17:26:21 -07:00
Furnace -> SetLoading ( true );
2013-06-20 11:41:44 +00:00
// Load slots:
2012-06-14 13:06:06 +00:00
for ( int Child = a_NBT . GetFirstChild ( Items ); Child != - 1 ; Child = a_NBT . GetNextSibling ( Child ))
{
int Slot = a_NBT . FindChildByName ( Child , "Slot" );
if (( Slot < 0 ) || ( a_NBT . GetType ( Slot ) != TAG_Byte ))
{
continue ;
}
cItem Item ;
2013-03-09 14:35:43 +00:00
if ( LoadItemFromNBT ( Item , a_NBT , Child ))
2012-06-14 13:06:06 +00:00
{
2013-03-09 14:35:43 +00:00
Furnace -> SetSlot ( a_NBT . GetByte ( Slot ), Item );
2012-06-14 13:06:06 +00:00
}
} // for itr - ItemDefs[]
2013-06-20 11:41:44 +00:00
// Load burn time:
2012-06-14 13:06:06 +00:00
int BurnTime = a_NBT . FindChildByName ( a_TagIdx , "BurnTime" );
if ( BurnTime >= 0 )
{
Int16 bt = a_NBT . GetShort ( BurnTime );
// Anvil doesn't store the time that the fuel can burn. We simply "reset" the current value to be the 100%
2013-06-16 20:24:07 +00:00
Furnace -> SetBurnTimes ( bt , 0 );
2012-06-14 13:06:06 +00:00
}
2013-06-20 11:41:44 +00:00
// Load cook time:
2012-06-14 13:06:06 +00:00
int CookTime = a_NBT . FindChildByName ( a_TagIdx , "CookTime" );
if ( CookTime >= 0 )
{
Int16 ct = a_NBT . GetShort ( CookTime );
2013-06-16 20:24:07 +00:00
// Anvil doesn't store the time that an item takes to cook. We simply use the default - 10 seconds (200 ticks)
Furnace -> SetCookTimes ( 200 , ct );
2012-06-14 13:06:06 +00:00
}
2013-06-20 11:41:44 +00:00
// Restart cooking:
2012-06-14 13:06:06 +00:00
Furnace -> ContinueCooking ();
2015-06-02 17:26:21 -07:00
Furnace -> SetLoading ( false );
2014-08-29 19:19:27 +03:00
return Furnace . release ();
2012-06-14 13:06:06 +00:00
}
2014-11-18 15:33:41 +01:00
cBlockEntity * cWSSAnvil :: LoadMobSpawnerFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
{
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "MobSpawner" ))
{
return nullptr ;
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cMobSpawnerEntity > MobSpawner = cpp14 :: make_unique < cMobSpawnerEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2014-11-18 15:33:41 +01:00
2015-09-25 10:14:17 +02:00
// Load entity (Cuberite worlds):
2014-11-18 15:33:41 +01:00
int Type = a_NBT . FindChildByName ( a_TagIdx , "Entity" );
if (( Type >= 0 ) && ( a_NBT . GetType ( Type ) == TAG_Short ))
{
short MonsterType = a_NBT . GetShort ( Type );
if (( MonsterType >= 50 ) && ( MonsterType <= 120 ))
{
MobSpawner -> SetEntity ( static_cast < eMonsterType > ( MonsterType ));
}
}
else
{
// Load entity (vanilla worlds):
Type = a_NBT . FindChildByName ( a_TagIdx , "EntityId" );
if (( Type >= 0 ) && ( a_NBT . GetType ( Type ) == TAG_String ))
{
eMonsterType MonsterType = cMonster :: StringToMobType ( a_NBT . GetString ( Type ));
if ( MonsterType != eMonsterType :: mtInvalidType )
{
MobSpawner -> SetEntity ( MonsterType );
}
}
}
// Load delay:
int Delay = a_NBT . FindChildByName ( a_TagIdx , "Delay" );
if (( Delay >= 0 ) && ( a_NBT . GetType ( Delay ) == TAG_Short ))
{
MobSpawner -> SetSpawnDelay ( a_NBT . GetShort ( Delay ));
}
return MobSpawner . release ();
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadHopperFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-06-15 20:58:52 +00:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Hopper" ))
2012-06-15 20:58:52 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-06-15 20:58:52 +00:00
}
2014-08-29 19:19:27 +03:00
2013-06-13 07:36:43 +00:00
int Items = a_NBT . FindChildByName ( a_TagIdx , "Items" );
if (( Items < 0 ) || ( a_NBT . GetType ( Items ) != TAG_List ))
2012-08-26 17:50:42 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this
2012-08-26 17:50:42 +00:00
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cHopperEntity > Hopper = cpp14 :: make_unique < cHopperEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2013-06-13 07:36:43 +00:00
LoadItemGridFromNBT ( Hopper -> GetContents (), a_NBT , Items );
2014-08-29 19:19:27 +03:00
return Hopper . release ();
2013-06-13 07:36:43 +00:00
}
2012-08-26 17:50:42 +00:00
2013-06-13 07:36:43 +00:00
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadJukeboxFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
2013-06-13 07:36:43 +00:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "RecordPlayer" ))
2012-06-15 20:58:52 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-06-15 20:58:52 +00:00
}
2014-08-29 19:19:27 +03:00
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cJukeboxEntity > Jukebox = cpp14 :: make_unique < cJukeboxEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2013-06-13 07:36:43 +00:00
int Record = a_NBT . FindChildByName ( a_TagIdx , "Record" );
if ( Record >= 0 )
2012-08-26 17:50:42 +00:00
{
2013-06-13 07:36:43 +00:00
Jukebox -> SetRecord ( a_NBT . GetInt ( Record ));
2012-08-26 17:50:42 +00:00
}
2014-08-29 19:19:27 +03:00
return Jukebox . release ();
2012-08-26 17:50:42 +00:00
}
2012-06-15 20:58:52 +00:00
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadMobHeadFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-10-21 07:46:28 +00:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Skull" ))
2012-10-21 07:46:28 +00:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2012-10-21 07:46:28 +00:00
}
2013-06-13 07:36:43 +00:00
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cMobHeadEntity > MobHead = cpp14 :: make_unique < cMobHeadEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2013-06-13 07:36:43 +00:00
2014-08-29 19:19:27 +03:00
int currentLine = a_NBT . FindChildByName ( a_TagIdx , "SkullType" );
2013-06-13 07:36:43 +00:00
if ( currentLine >= 0 )
{
2014-08-29 19:19:27 +03:00
MobHead -> SetType ( static_cast < eMobHeadType > ( a_NBT . GetByte ( currentLine )));
2013-06-13 07:36:43 +00:00
}
2014-08-29 19:19:27 +03:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , "Rot" );
2013-06-13 07:36:43 +00:00
if ( currentLine >= 0 )
{
2014-08-29 19:19:27 +03:00
MobHead -> SetRotation ( static_cast < eMobHeadRotation > ( a_NBT . GetByte ( currentLine )));
2013-06-13 07:36:43 +00:00
}
2014-08-29 19:19:27 +03:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , "ExtraType" );
2013-06-13 07:36:43 +00:00
if ( currentLine >= 0 )
{
2014-08-29 19:19:27 +03:00
MobHead -> SetOwner ( a_NBT . GetString ( currentLine ));
2013-06-13 07:36:43 +00:00
}
2014-08-29 19:19:27 +03:00
return MobHead . release ();
2012-10-21 07:46:28 +00:00
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadNoteBlockFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-02-17 20:14:08 +01:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Music" ))
2014-02-17 20:14:08 +01:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2014-02-17 20:14:08 +01:00
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cNoteEntity > NoteBlock = cpp14 :: make_unique < cNoteEntity > ( a_BlockX , a_BlockY , a_BlockZ , m_World );
2014-08-29 19:19:27 +03:00
int note = a_NBT . FindChildByName ( a_TagIdx , "note" );
if ( note >= 0 )
2014-02-17 20:14:08 +01:00
{
2015-07-29 09:04:03 -06:00
NoteBlock -> SetPitch ( static_cast < char > ( a_NBT . GetByte ( note )));
2014-02-17 20:14:08 +01:00
}
2014-08-29 19:19:27 +03:00
return NoteBlock . release ();
2014-02-17 20:14:08 +01:00
}
2014-08-29 19:19:27 +03:00
cBlockEntity * cWSSAnvil :: LoadSignFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , int a_BlockX , int a_BlockY , int a_BlockZ , BLOCKTYPE a_BlockType )
2014-01-18 15:40:47 +02:00
{
2014-08-29 19:19:27 +03:00
// Check if the data has a proper type:
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , "Sign" ))
2014-01-18 15:40:47 +02:00
{
2014-10-20 21:55:07 +01:00
return nullptr ;
2014-01-18 15:40:47 +02:00
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSignEntity > Sign = cpp14 :: make_unique < cSignEntity > ( a_BlockType , a_BlockX , a_BlockY , a_BlockZ , m_World );
2014-08-29 19:19:27 +03:00
int currentLine = a_NBT . FindChildByName ( a_TagIdx , "Text1" );
2014-01-18 15:40:47 +02:00
if ( currentLine >= 0 )
{
2014-08-29 19:19:27 +03:00
Sign -> SetLine ( 0 , a_NBT . GetString ( currentLine ));
2014-01-18 15:40:47 +02:00
}
2014-08-29 19:19:27 +03:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , "Text2" );
2014-01-18 15:40:47 +02:00
if ( currentLine >= 0 )
{
2014-08-29 19:19:27 +03:00
Sign -> SetLine ( 1 , a_NBT . GetString ( currentLine ));
2014-01-18 15:40:47 +02:00
}
2014-08-29 19:19:27 +03:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , "Text3" );
2014-01-18 15:40:47 +02:00
if ( currentLine >= 0 )
{
2014-08-29 19:19:27 +03:00
Sign -> SetLine ( 2 , a_NBT . GetString ( currentLine ));
2014-01-18 15:40:47 +02:00
}
2014-08-29 19:19:27 +03:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , "Text4" );
if ( currentLine >= 0 )
{
Sign -> SetLine ( 3 , a_NBT . GetString ( currentLine ));
}
2014-01-18 15:40:47 +02:00
2014-08-29 19:19:27 +03:00
return Sign . release ();
2014-01-18 15:40:47 +02:00
}
2014-05-09 19:33:22 +02:00
void cWSSAnvil :: LoadEntityFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_EntityTagIdx , const char * a_IDTag , size_t a_IDTagLength )
2013-03-09 14:35:43 +00:00
{
2013-09-08 00:14:57 +01:00
if ( strncmp ( a_IDTag , "Boat" , a_IDTagLength ) == 0 )
{
LoadBoatFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2014-03-25 20:59:33 +02:00
else if ( strncmp ( a_IDTag , "EnderCrystal" , a_IDTagLength ) == 0 )
{
LoadEnderCrystalFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-09-08 00:14:57 +01:00
else if ( strncmp ( a_IDTag , "FallingBlock" , a_IDTagLength ) == 0 )
2013-03-09 14:35:43 +00:00
{
LoadFallingBlockFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Minecart" , a_IDTagLength ) == 0 )
{
// It is a minecart, old style, find out the type:
int TypeTag = a_NBT . FindChildByName ( a_EntityTagIdx , "Type" );
if (( TypeTag < 0 ) || ( a_NBT . GetType ( TypeTag ) != TAG_Int ))
{
return ;
}
switch ( a_NBT . GetInt ( TypeTag ))
{
case 0 : LoadMinecartRFromNBT ( a_Entities , a_NBT , a_EntityTagIdx ); break ; // Rideable minecart
case 1 : LoadMinecartCFromNBT ( a_Entities , a_NBT , a_EntityTagIdx ); break ; // Minecart with chest
case 2 : LoadMinecartFFromNBT ( a_Entities , a_NBT , a_EntityTagIdx ); break ; // Minecart with furnace
2013-08-16 11:23:24 +01:00
case 3 : LoadMinecartTFromNBT ( a_Entities , a_NBT , a_EntityTagIdx ); break ; // Minecart with TNT
case 4 : LoadMinecartHFromNBT ( a_Entities , a_NBT , a_EntityTagIdx ); break ; // Minecart with Hopper
2013-03-09 14:35:43 +00:00
}
}
else if ( strncmp ( a_IDTag , "MinecartRideable" , a_IDTagLength ) == 0 )
{
LoadMinecartRFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "MinecartChest" , a_IDTagLength ) == 0 )
{
LoadMinecartCFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "MinecartFurnace" , a_IDTagLength ) == 0 )
{
LoadMinecartFFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-08-16 13:04:06 +01:00
else if ( strncmp ( a_IDTag , "MinecartTNT" , a_IDTagLength ) == 0 )
{
LoadMinecartTFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "MinecartHopper" , a_IDTagLength ) == 0 )
{
LoadMinecartHFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-09-07 21:26:17 +02:00
else if ( strncmp ( a_IDTag , "Item" , a_IDTagLength ) == 0 )
2013-03-09 14:35:43 +00:00
{
LoadPickupFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2015-03-13 23:05:06 +00:00
else if ( strncmp ( a_IDTag , "Painting" , a_IDTagLength ) == 0 )
{
LoadPaintingFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2014-03-15 00:32:49 +01:00
else if ( strncmp ( a_IDTag , "PrimedTnt" , a_IDTagLength ) == 0 )
{
LoadTNTFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "XPOrb" , a_IDTagLength ) == 0 )
{
LoadExpOrbFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2014-03-15 02:45:25 +01:00
else if ( strncmp ( a_IDTag , "ItemFrame" , a_IDTagLength ) == 0 )
{
LoadItemFrameFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-09-07 21:26:17 +02:00
else if ( strncmp ( a_IDTag , "Arrow" , a_IDTagLength ) == 0 )
2013-08-25 21:32:17 +02:00
{
LoadArrowFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2014-07-11 18:58:11 -07:00
else if ( strncmp ( a_IDTag , "SplashPotion" , a_IDTagLength ) == 0 )
{
LoadSplashPotionFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-09-07 21:26:17 +02:00
else if ( strncmp ( a_IDTag , "Snowball" , a_IDTagLength ) == 0 )
{
LoadSnowballFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Egg" , a_IDTagLength ) == 0 )
{
LoadEggFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Fireball" , a_IDTagLength ) == 0 )
{
LoadFireballFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "SmallFireball" , a_IDTagLength ) == 0 )
{
LoadFireChargeFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "ThrownEnderpearl" , a_IDTagLength ) == 0 )
{
LoadThrownEnderpearlFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-12-25 16:07:52 +00:00
else if ( strncmp ( a_IDTag , "Bat" , a_IDTagLength ) == 0 )
{
LoadBatFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Blaze" , a_IDTagLength ) == 0 )
{
LoadBlazeFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "CaveSpider" , a_IDTagLength ) == 0 )
{
LoadCaveSpiderFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Chicken" , a_IDTagLength ) == 0 )
{
LoadChickenFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Cow" , a_IDTagLength ) == 0 )
{
LoadCowFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Creeper" , a_IDTagLength ) == 0 )
{
LoadCreeperFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "EnderDragon" , a_IDTagLength ) == 0 )
{
LoadEnderDragonFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Enderman" , a_IDTagLength ) == 0 )
{
LoadEndermanFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Ghast" , a_IDTagLength ) == 0 )
{
LoadGhastFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Giant" , a_IDTagLength ) == 0 )
{
LoadGiantFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2014-12-18 19:30:32 +01:00
else if ( strncmp ( a_IDTag , "Guardian" , a_IDTagLength ) == 0 )
{
LoadGuardianFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-12-25 16:07:52 +00:00
else if ( strncmp ( a_IDTag , "Horse" , a_IDTagLength ) == 0 )
{
LoadHorseFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2014-02-12 19:07:17 +01:00
else if ( strncmp ( a_IDTag , "Villager" , a_IDTagLength ) == 0 )
{
LoadVillagerFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-12-25 16:07:52 +00:00
else if ( strncmp ( a_IDTag , "VillagerGolem" , a_IDTagLength ) == 0 )
{
LoadIronGolemFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "LavaSlime" , a_IDTagLength ) == 0 )
{
LoadMagmaCubeFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "MushroomCow" , a_IDTagLength ) == 0 )
{
LoadMooshroomFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Ozelot" , a_IDTagLength ) == 0 )
{
LoadOcelotFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Pig" , a_IDTagLength ) == 0 )
{
LoadPigFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2014-12-20 10:31:34 +01:00
else if ( strncmp ( a_IDTag , "Rabbit" , a_IDTagLength ) == 0 )
{
LoadRabbitFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-12-25 16:07:52 +00:00
else if ( strncmp ( a_IDTag , "Sheep" , a_IDTagLength ) == 0 )
{
LoadSheepFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Silverfish" , a_IDTagLength ) == 0 )
{
LoadSilverfishFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Skeleton" , a_IDTagLength ) == 0 )
{
LoadSkeletonFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Slime" , a_IDTagLength ) == 0 )
{
LoadSlimeFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "SnowMan" , a_IDTagLength ) == 0 )
{
LoadSnowGolemFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Spider" , a_IDTagLength ) == 0 )
{
LoadSpiderFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Squid" , a_IDTagLength ) == 0 )
{
LoadSquidFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Witch" , a_IDTagLength ) == 0 )
{
LoadWitchFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2014-03-24 12:29:19 +02:00
else if ( strncmp ( a_IDTag , "WitherBoss" , a_IDTagLength ) == 0 )
2013-12-25 16:07:52 +00:00
{
LoadWitherFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Wolf" , a_IDTagLength ) == 0 )
{
LoadWolfFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "Zombie" , a_IDTagLength ) == 0 )
{
LoadZombieFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
else if ( strncmp ( a_IDTag , "PigZombie" , a_IDTagLength ) == 0 )
{
LoadPigZombieFromNBT ( a_Entities , a_NBT , a_EntityTagIdx );
}
2013-03-09 14:35:43 +00:00
// TODO: other entities
}
2013-09-08 00:14:57 +01:00
void cWSSAnvil :: LoadBoatFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cBoat > Boat = cpp14 :: make_unique < cBoat > ( 0 , 0 , 0 );
2013-09-08 00:14:57 +01:00
if ( ! LoadEntityBaseFromNBT ( * Boat . get (), a_NBT , a_TagIdx ))
{
return ;
}
a_Entities . push_back ( Boat . release ());
}
2014-03-25 20:59:33 +02:00
void cWSSAnvil :: LoadEnderCrystalFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cEnderCrystal > EnderCrystal = cpp14 :: make_unique < cEnderCrystal > ( 0 , 0 , 0 );
2014-03-25 20:59:33 +02:00
if ( ! LoadEntityBaseFromNBT ( * EnderCrystal . get (), a_NBT , a_TagIdx ))
{
return ;
}
a_Entities . push_back ( EnderCrystal . release ());
}
2013-03-09 14:35:43 +00:00
void cWSSAnvil :: LoadFallingBlockFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2013-12-25 16:07:52 +00:00
int TypeIdx = a_NBT . FindChildByName ( a_TagIdx , "TileID" );
int MetaIdx = a_NBT . FindChildByName ( a_TagIdx , "Data" );
2014-12-05 16:59:11 +01:00
if (( TypeIdx < 0 ) || ( MetaIdx < 0 ))
{
return ;
}
2013-12-25 16:07:52 +00:00
2015-07-31 16:49:10 +02:00
BLOCKTYPE Type = static_cast < BLOCKTYPE > ( a_NBT . GetInt ( TypeIdx ));
2015-07-29 09:04:03 -06:00
NIBBLETYPE Meta = static_cast < NIBBLETYPE > ( a_NBT . GetByte ( MetaIdx ));
2013-12-25 16:07:52 +00:00
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cFallingBlock > FallingBlock = cpp14 :: make_unique < cFallingBlock > ( Vector3i ( 0 , 0 , 0 ), Type , Meta );
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * FallingBlock . get (), a_NBT , a_TagIdx ))
{
return ;
}
a_Entities . push_back ( FallingBlock . release ());
2013-03-09 14:35:43 +00:00
}
void cWSSAnvil :: LoadMinecartRFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cRideableMinecart > Minecart = cpp14 :: make_unique < cRideableMinecart > ( 0 , 0 , 0 , cItem (), 1 ); // TODO: Load the block and the height
2013-03-09 20:08:39 +00:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get (), a_NBT , a_TagIdx ))
{
return ;
}
a_Entities . push_back ( Minecart . release ());
2013-03-09 14:35:43 +00:00
}
void cWSSAnvil :: LoadMinecartCFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2013-03-09 20:08:39 +00:00
int Items = a_NBT . FindChildByName ( a_TagIdx , "Items" );
if (( Items < 0 ) || ( a_NBT . GetType ( Items ) != TAG_List ))
{
return ; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cMinecartWithChest > Minecart = cpp14 :: make_unique < cMinecartWithChest > ( 0 , 0 , 0 );
2013-03-09 20:08:39 +00:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get (), a_NBT , a_TagIdx ))
{
return ;
}
for ( int Child = a_NBT . GetFirstChild ( Items ); Child != - 1 ; Child = a_NBT . GetNextSibling ( Child ))
{
int Slot = a_NBT . FindChildByName ( Child , "Slot" );
if (( Slot < 0 ) || ( a_NBT . GetType ( Slot ) != TAG_Byte ))
{
continue ;
}
cItem Item ;
if ( LoadItemFromNBT ( Item , a_NBT , Child ))
{
Minecart -> SetSlot ( a_NBT . GetByte ( Slot ), Item );
}
} // for itr - ItemDefs[]
a_Entities . push_back ( Minecart . release ());
2013-03-09 14:35:43 +00:00
}
void cWSSAnvil :: LoadMinecartFFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cMinecartWithFurnace > Minecart = cpp14 :: make_unique < cMinecartWithFurnace > ( 0 , 0 , 0 );
2013-03-09 20:08:39 +00:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get (), a_NBT , a_TagIdx ))
{
return ;
}
// TODO: Load the Push and Fuel tags
a_Entities . push_back ( Minecart . release ());
2013-03-09 14:35:43 +00:00
}
2013-08-16 13:04:06 +01:00
void cWSSAnvil :: LoadMinecartTFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cMinecartWithTNT > Minecart = cpp14 :: make_unique < cMinecartWithTNT > ( 0 , 0 , 0 );
2013-08-16 13:04:06 +01:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-08-25 21:32:17 +02:00
// TODO: Everything to do with TNT carts
2013-08-16 13:04:06 +01:00
a_Entities . push_back ( Minecart . release ());
}
void cWSSAnvil :: LoadMinecartHFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cMinecartWithHopper > Minecart = cpp14 :: make_unique < cMinecartWithHopper > ( 0 , 0 , 0 );
2013-08-16 13:04:06 +01:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-08-25 21:32:17 +02:00
// TODO: Everything to do with hopper carts
2013-08-16 13:04:06 +01:00
a_Entities . push_back ( Minecart . release ());
}
2013-03-09 14:35:43 +00:00
void cWSSAnvil :: LoadPickupFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2014-03-15 00:43:38 +01:00
// Load item:
2013-03-09 14:35:43 +00:00
int ItemTag = a_NBT . FindChildByName ( a_TagIdx , "Item" );
if (( ItemTag < 0 ) || ( a_NBT . GetType ( ItemTag ) != TAG_Compound ))
{
return ;
}
cItem Item ;
if ( ! LoadItemFromNBT ( Item , a_NBT , ItemTag ))
{
return ;
}
2014-03-15 00:43:38 +01:00
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cPickup > Pickup = cpp14 :: make_unique < cPickup > ( 0 , 0 , 0 , Item , false ); // Pickup delay doesn't matter, just say false
2013-03-09 14:35:43 +00:00
if ( ! LoadEntityBaseFromNBT ( * Pickup . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-03-15 00:43:38 +01:00
// Load age:
int Age = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( Age > 0 )
{
Pickup -> SetAge ( a_NBT . GetShort ( Age ));
}
2014-03-15 00:32:49 +01:00
2013-03-09 14:35:43 +00:00
a_Entities . push_back ( Pickup . release ());
}
2014-03-15 00:32:49 +01:00
void cWSSAnvil :: LoadTNTFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cTNTEntity > TNT = cpp14 :: make_unique < cTNTEntity > ( 0.0 , 0.0 , 0.0 , 0 );
2014-03-15 00:32:49 +01:00
if ( ! LoadEntityBaseFromNBT ( * TNT . get (), a_NBT , a_TagIdx ))
{
return ;
}
// Load Fuse Ticks:
int FuseTicks = a_NBT . FindChildByName ( a_TagIdx , "Fuse" );
if ( FuseTicks > 0 )
{
2015-07-29 09:04:03 -06:00
TNT -> SetFuseTicks ( static_cast < int > ( a_NBT . GetByte ( FuseTicks )));
2014-03-15 00:32:49 +01:00
}
a_Entities . push_back ( TNT . release ());
}
void cWSSAnvil :: LoadExpOrbFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cExpOrb > ExpOrb = cpp14 :: make_unique < cExpOrb > ( 0.0 , 0.0 , 0.0 , 0 );
2014-03-15 00:32:49 +01:00
if ( ! LoadEntityBaseFromNBT ( * ExpOrb . get (), a_NBT , a_TagIdx ))
{
return ;
}
// Load Age:
int Age = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( Age > 0 )
{
ExpOrb -> SetAge ( a_NBT . GetShort ( Age ));
}
// Load Reward (Value):
int Reward = a_NBT . FindChildByName ( a_TagIdx , "Value" );
if ( Reward > 0 )
{
ExpOrb -> SetReward ( a_NBT . GetShort ( Reward ));
}
a_Entities . push_back ( ExpOrb . release ());
}
2014-03-15 02:45:25 +01:00
void cWSSAnvil :: LoadHangingFromNBT ( cHangingEntity & a_Hanging , const cParsedNBT & a_NBT , int a_TagIdx )
{
2014-10-21 22:02:30 +02:00
// "Facing" tag is the prime source of the Facing; if not available, translate from older "Direction" or "Dir"
int Facing = a_NBT . FindChildByName ( a_TagIdx , "Facing" );
2015-03-13 22:29:27 +00:00
if ( Facing < 0 )
2014-03-15 02:45:25 +01:00
{
2015-03-13 22:29:27 +00:00
return ;
2014-03-15 02:45:25 +01:00
}
2015-03-13 22:29:27 +00:00
a_Hanging . SetProtocolFacing ( a_NBT . GetByte ( Facing ));
2014-03-15 02:45:25 +01:00
int TileX = a_NBT . FindChildByName ( a_TagIdx , "TileX" );
int TileY = a_NBT . FindChildByName ( a_TagIdx , "TileY" );
int TileZ = a_NBT . FindChildByName ( a_TagIdx , "TileZ" );
if (( TileX > 0 ) && ( TileY > 0 ) && ( TileZ > 0 ))
{
a_Hanging . SetPosition (
2015-03-13 22:29:27 +00:00
static_cast < double > ( a_NBT . GetInt ( TileX )),
static_cast < double > ( a_NBT . GetInt ( TileY )),
static_cast < double > ( a_NBT . GetInt ( TileZ ))
2014-03-15 02:45:25 +01:00
);
}
}
void cWSSAnvil :: LoadItemFrameFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
// Load item:
int ItemTag = a_NBT . FindChildByName ( a_TagIdx , "Item" );
if (( ItemTag < 0 ) || ( a_NBT . GetType ( ItemTag ) != TAG_Compound ))
{
return ;
}
cItem Item ;
if ( ! LoadItemFromNBT ( Item , a_NBT , ItemTag ))
{
return ;
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cItemFrame > ItemFrame = cpp14 :: make_unique < cItemFrame > ( BLOCK_FACE_NONE , 0.0 , 0.0 , 0.0 );
2014-03-15 02:45:25 +01:00
if ( ! LoadEntityBaseFromNBT ( * ItemFrame . get (), a_NBT , a_TagIdx ))
{
return ;
}
ItemFrame -> SetItem ( Item );
LoadHangingFromNBT ( * ItemFrame . get (), a_NBT , a_TagIdx );
// Load Rotation:
int Rotation = a_NBT . FindChildByName ( a_TagIdx , "ItemRotation" );
if ( Rotation > 0 )
{
2015-07-29 09:04:03 -06:00
ItemFrame -> SetItemRotation ( static_cast < Byte > ( a_NBT . GetByte ( Rotation )));
2014-03-15 02:45:25 +01:00
}
a_Entities . push_back ( ItemFrame . release ());
}
2015-03-13 23:05:06 +00:00
void cWSSAnvil :: LoadPaintingFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
// Load painting name:
int MotiveTag = a_NBT . FindChildByName ( a_TagIdx , "Motive" );
if (( MotiveTag < 0 ) || ( a_NBT . GetType ( MotiveTag ) != TAG_String ))
{
return ;
}
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cPainting > Painting = cpp14 :: make_unique < cPainting > ( a_NBT . GetString ( MotiveTag ), BLOCK_FACE_NONE , 0.0 , 0.0 , 0.0 );
2015-03-13 23:05:06 +00:00
if ( ! LoadEntityBaseFromNBT ( * Painting . get (), a_NBT , a_TagIdx ))
{
return ;
}
LoadHangingFromNBT ( * Painting . get (), a_NBT , a_TagIdx );
a_Entities . push_back ( Painting . release ());
}
2013-08-25 21:32:17 +02:00
void cWSSAnvil :: LoadArrowFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cArrowEntity > Arrow = cpp14 :: make_unique < cArrowEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ));
2013-09-07 21:26:17 +02:00
if ( ! LoadProjectileBaseFromNBT ( * Arrow . get (), a_NBT , a_TagIdx ))
2013-08-25 21:32:17 +02:00
{
return ;
}
// Load pickup state:
int PickupIdx = a_NBT . FindChildByName ( a_TagIdx , "pickup" );
2014-09-25 19:01:44 +02:00
if (( PickupIdx > 0 ) && ( a_NBT . GetType ( PickupIdx ) == TAG_Byte ))
2013-08-25 21:32:17 +02:00
{
2015-07-29 09:04:03 -06:00
Arrow -> SetPickupState ( static_cast < cArrowEntity :: ePickupState > ( a_NBT . GetByte ( PickupIdx )));
2013-08-25 21:32:17 +02:00
}
else
{
// Try the older "player" tag:
int PlayerIdx = a_NBT . FindChildByName ( a_TagIdx , "player" );
2014-09-25 19:01:44 +02:00
if (( PlayerIdx > 0 ) && ( a_NBT . GetType ( PlayerIdx ) == TAG_Byte ))
2013-08-25 21:32:17 +02:00
{
Arrow -> SetPickupState (( a_NBT . GetByte ( PlayerIdx ) == 0 ) ? cArrowEntity :: psNoPickup : cArrowEntity :: psInSurvivalOrCreative );
}
}
// Load damage:
int DamageIdx = a_NBT . FindChildByName ( a_TagIdx , "damage" );
2014-09-25 19:01:44 +02:00
if (( DamageIdx > 0 ) && ( a_NBT . GetType ( DamageIdx ) == TAG_Double ))
2013-08-25 21:32:17 +02:00
{
Arrow -> SetDamageCoeff ( a_NBT . GetDouble ( DamageIdx ));
}
2014-07-02 21:07:34 +01:00
// Load block hit:
int InBlockXIdx = a_NBT . FindChildByName ( a_TagIdx , "xTile" );
int InBlockYIdx = a_NBT . FindChildByName ( a_TagIdx , "yTile" );
int InBlockZIdx = a_NBT . FindChildByName ( a_TagIdx , "zTile" );
if (( InBlockXIdx > 0 ) && ( InBlockYIdx > 0 ) && ( InBlockZIdx > 0 ))
{
2014-11-26 10:14:11 +01:00
eTagType typeX = a_NBT . GetType ( InBlockXIdx );
if (( typeX == a_NBT . GetType ( InBlockYIdx )) && ( typeX == a_NBT . GetType ( InBlockZIdx )))
2014-09-25 19:01:44 +02:00
{
2014-11-26 10:14:11 +01:00
switch ( typeX )
2014-09-25 19:01:44 +02:00
{
case TAG_Int :
{
// Old MCS code used this, keep reading it for compatibility reasons:
Arrow -> SetBlockHit ( Vector3i ( a_NBT . GetInt ( InBlockXIdx ), a_NBT . GetInt ( InBlockYIdx ), a_NBT . GetInt ( InBlockZIdx )));
break ;
}
case TAG_Short :
{
// Vanilla uses this
2015-06-24 16:38:40 +02:00
Arrow -> SetBlockHit ( Vector3i ( a_NBT . GetShort ( InBlockXIdx ), a_NBT . GetShort ( InBlockYIdx ), a_NBT . GetShort ( InBlockZIdx )));
2014-09-25 19:01:44 +02:00
break ;
}
2014-11-26 10:14:11 +01:00
default :
{
// No hit block, the arrow is still flying?
break ;
}
2014-09-25 19:01:44 +02:00
}
}
2014-07-02 21:07:34 +01:00
}
2013-08-25 21:32:17 +02:00
// Store the new arrow in the entities list:
a_Entities . push_back ( Arrow . release ());
}
2014-07-11 18:58:11 -07:00
void cWSSAnvil :: LoadSplashPotionFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSplashPotionEntity > SplashPotion = cpp14 :: make_unique < cSplashPotionEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ), cItem ());
2014-07-11 18:58:11 -07:00
if ( ! LoadProjectileBaseFromNBT ( * SplashPotion . get (), a_NBT , a_TagIdx ))
{
return ;
}
int EffectDuration = a_NBT . FindChildByName ( a_TagIdx , "EffectDuration" );
int EffectIntensity = a_NBT . FindChildByName ( a_TagIdx , "EffectIntensity" );
int EffectDistanceModifier = a_NBT . FindChildByName ( a_TagIdx , "EffectDistanceModifier" );
2015-07-29 09:04:03 -06:00
SplashPotion -> SetEntityEffectType ( static_cast < cEntityEffect :: eType > ( a_NBT . FindChildByName ( a_TagIdx , "EffectType" )));
SplashPotion -> SetEntityEffect ( cEntityEffect ( EffectDuration , static_cast < Int16 > ( EffectIntensity ), EffectDistanceModifier ));
2014-07-19 02:51:39 -07:00
SplashPotion -> SetPotionColor ( a_NBT . FindChildByName ( a_TagIdx , "PotionName" ));
2014-07-11 18:58:11 -07:00
// Store the new splash potion in the entities list:
a_Entities . push_back ( SplashPotion . release ());
}
2013-08-25 21:32:17 +02:00
2013-09-07 21:26:17 +02:00
void cWSSAnvil :: LoadSnowballFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cThrownSnowballEntity > Snowball = cpp14 :: make_unique < cThrownSnowballEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ));
2013-09-07 21:26:17 +02:00
if ( ! LoadProjectileBaseFromNBT ( * Snowball . get (), a_NBT , a_TagIdx ))
{
return ;
}
// Store the new snowball in the entities list:
a_Entities . push_back ( Snowball . release ());
}
void cWSSAnvil :: LoadEggFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cThrownEggEntity > Egg = cpp14 :: make_unique < cThrownEggEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ));
2013-09-07 21:26:17 +02:00
if ( ! LoadProjectileBaseFromNBT ( * Egg . get (), a_NBT , a_TagIdx ))
{
return ;
}
// Store the new egg in the entities list:
a_Entities . push_back ( Egg . release ());
}
void cWSSAnvil :: LoadFireballFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cGhastFireballEntity > Fireball = cpp14 :: make_unique < cGhastFireballEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ));
2013-09-07 21:26:17 +02:00
if ( ! LoadProjectileBaseFromNBT ( * Fireball . get (), a_NBT , a_TagIdx ))
{
return ;
}
// Store the new fireball in the entities list:
a_Entities . push_back ( Fireball . release ());
}
void cWSSAnvil :: LoadFireChargeFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cFireChargeEntity > FireCharge = cpp14 :: make_unique < cFireChargeEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ));
2013-09-07 21:26:17 +02:00
if ( ! LoadProjectileBaseFromNBT ( * FireCharge . get (), a_NBT , a_TagIdx ))
{
return ;
}
// Store the new FireCharge in the entities list:
a_Entities . push_back ( FireCharge . release ());
}
void cWSSAnvil :: LoadThrownEnderpearlFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cThrownEnderPearlEntity > Enderpearl = cpp14 :: make_unique < cThrownEnderPearlEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ));
2013-09-07 21:26:17 +02:00
if ( ! LoadProjectileBaseFromNBT ( * Enderpearl . get (), a_NBT , a_TagIdx ))
{
return ;
}
// Store the new enderpearl in the entities list:
a_Entities . push_back ( Enderpearl . release ());
}
2013-12-25 16:07:52 +00:00
void cWSSAnvil :: LoadBatFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cBat > Monster = cpp14 :: make_unique < cBat > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadBlazeFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cBlaze > Monster = cpp14 :: make_unique < cBlaze > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadCaveSpiderFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cCaveSpider > Monster = cpp14 :: make_unique < cCaveSpider > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadChickenFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cChicken > Monster = cpp14 :: make_unique < cChicken > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadCowFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cCow > Monster = cpp14 :: make_unique < cCow > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadCreeperFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cCreeper > Monster = cpp14 :: make_unique < cCreeper > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadEnderDragonFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cEnderDragon > Monster = cpp14 :: make_unique < cEnderDragon > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadEndermanFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cEnderman > Monster = cpp14 :: make_unique < cEnderman > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadGhastFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cGhast > Monster = cpp14 :: make_unique < cGhast > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadGiantFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cGiant > Monster = cpp14 :: make_unique < cGiant > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
2014-12-18 19:30:32 +01:00
void cWSSAnvil :: LoadGuardianFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cGuardian > Monster = cpp14 :: make_unique < cGuardian > ();
2014-12-18 19:30:32 +01:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
a_Entities . push_back ( Monster . release ());
}
2013-12-25 16:07:52 +00:00
void cWSSAnvil :: LoadHorseFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2014-12-05 16:59:11 +01:00
int TypeIdx = a_NBT . FindChildByName ( a_TagIdx , "Type" );
2013-12-25 16:07:52 +00:00
int ColorIdx = a_NBT . FindChildByName ( a_TagIdx , "Color" );
int StyleIdx = a_NBT . FindChildByName ( a_TagIdx , "Style" );
2014-12-05 16:59:11 +01:00
if (( TypeIdx < 0 ) || ( ColorIdx < 0 ) || ( StyleIdx < 0 ))
{
return ;
}
2013-12-25 16:07:52 +00:00
int Type = a_NBT . GetInt ( TypeIdx );
int Color = a_NBT . GetInt ( ColorIdx );
int Style = a_NBT . GetInt ( StyleIdx );
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cHorse > Monster = cpp14 :: make_unique < cHorse > ( Type , Color , Style , 1 );
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadIronGolemFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cIronGolem > Monster = cpp14 :: make_unique < cIronGolem > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadMagmaCubeFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
int SizeIdx = a_NBT . FindChildByName ( a_TagIdx , "Size" );
2014-05-07 12:43:21 +02:00
if ( SizeIdx < 0 )
{
return ;
}
2013-12-25 16:07:52 +00:00
int Size = a_NBT . GetInt ( SizeIdx );
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cMagmaCube > Monster = cpp14 :: make_unique < cMagmaCube > ( Size );
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadMooshroomFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cMooshroom > Monster = cpp14 :: make_unique < cMooshroom > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadOcelotFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cOcelot > Monster = cpp14 :: make_unique < cOcelot > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadPigFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cPig > Monster = cpp14 :: make_unique < cPig > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
2014-12-20 10:31:34 +01:00
void cWSSAnvil :: LoadRabbitFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-17 01:09:06 +02:00
int TypeIdx = a_NBT . FindChildByName ( a_TagIdx , "RabbitType" );
int MoreCarrotTicksIdx = a_NBT . FindChildByName ( a_TagIdx , "MoreCarrotTicks" );
if (( TypeIdx < 0 ) || ( MoreCarrotTicksIdx < 0 ))
{
return ;
}
int Type = a_NBT . GetInt ( TypeIdx );
int MoreCarrotTicks = a_NBT . GetInt ( MoreCarrotTicksIdx );
std :: unique_ptr < cRabbit > Monster = cpp14 :: make_unique < cRabbit > ( static_cast < eRabbitType > ( Type ), MoreCarrotTicks );
2014-12-20 10:31:34 +01:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2014-12-20 10:31:34 +01:00
a_Entities . push_back ( Monster . release ());
}
2013-12-25 16:07:52 +00:00
void cWSSAnvil :: LoadSheepFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
int ColorIdx = a_NBT . FindChildByName ( a_TagIdx , "Color" );
2014-06-28 13:19:32 +02:00
int Color = - 1 ;
if ( ColorIdx > 0 )
{
2015-07-29 09:04:03 -06:00
Color = static_cast < int > ( a_NBT . GetByte ( ColorIdx ));
2014-06-28 13:19:32 +02:00
}
2013-12-25 16:07:52 +00:00
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSheep > Monster = cpp14 :: make_unique < cSheep > ( Color );
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
2014-06-28 13:19:32 +02:00
int ShearedIdx = a_NBT . FindChildByName ( a_TagIdx , "Sheared" );
if ( ShearedIdx > 0 )
{
2014-06-29 01:01:10 +02:00
Monster -> SetSheared ( a_NBT . GetByte ( ShearedIdx ) != 0 );
2014-06-28 13:19:32 +02:00
}
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadSilverfishFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSilverfish > Monster = cpp14 :: make_unique < cSilverfish > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadSkeletonFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
int TypeIdx = a_NBT . FindChildByName ( a_TagIdx , "SkeletonType" );
2014-12-05 16:59:11 +01:00
if ( TypeIdx < 0 )
{
return ;
}
2013-12-25 16:07:52 +00:00
bool Type = (( a_NBT . GetByte ( TypeIdx ) == 1 ) ? true : false );
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSkeleton > Monster = cpp14 :: make_unique < cSkeleton > ( Type );
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadSlimeFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
int SizeIdx = a_NBT . FindChildByName ( a_TagIdx , "Size" );
2014-05-07 12:43:21 +02:00
if ( SizeIdx < 0 )
{
return ;
}
2013-12-25 16:07:52 +00:00
int Size = a_NBT . GetInt ( SizeIdx );
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSlime > Monster = cpp14 :: make_unique < cSlime > ( Size );
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadSnowGolemFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSnowGolem > Monster = cpp14 :: make_unique < cSnowGolem > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadSpiderFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSpider > Monster = cpp14 :: make_unique < cSpider > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadSquidFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cSquid > Monster = cpp14 :: make_unique < cSquid > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadVillagerFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
int TypeIdx = a_NBT . FindChildByName ( a_TagIdx , "Profession" );
2014-12-05 16:59:11 +01:00
if ( TypeIdx < 0 )
{
return ;
}
2013-12-25 16:07:52 +00:00
int Type = a_NBT . GetInt ( TypeIdx );
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cVillager > Monster = cpp14 :: make_unique < cVillager > ( cVillager :: eVillagerType ( Type ));
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadWitchFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cWitch > Monster = cpp14 :: make_unique < cWitch > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadWitherFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cWither > Monster = cpp14 :: make_unique < cWither > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2013-12-25 16:07:52 +00:00
2014-03-24 12:29:19 +02:00
int CurrLine = a_NBT . FindChildByName ( a_TagIdx , "Invul" );
if ( CurrLine > 0 )
{
2015-07-29 09:04:03 -06:00
Monster -> SetWitherInvulnerableTicks ( static_cast < unsigned int > ( a_NBT . GetInt ( CurrLine )));
2014-03-24 12:29:19 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadWolfFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cWolf > Monster = cpp14 :: make_unique < cWolf > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-08-03 22:03:48 +02:00
LoadWolfOwner ( * Monster . get (), a_NBT , a_TagIdx );
2014-02-02 13:56:55 +04:00
int SittingIdx = a_NBT . FindChildByName ( a_TagIdx , "Sitting" );
2014-09-23 22:11:25 +02:00
if (( SittingIdx > 0 ) && ( a_NBT . GetType ( SittingIdx ) == TAG_Byte ))
2014-01-31 21:34:00 +04:00
{
2014-02-02 13:56:55 +04:00
bool Sitting = (( a_NBT . GetByte ( SittingIdx ) == 1 ) ? true : false );
Monster -> SetIsSitting ( Sitting );
2014-01-31 21:34:00 +04:00
}
2014-02-02 14:28:42 +04:00
int AngryIdx = a_NBT . FindChildByName ( a_TagIdx , "Angry" );
2014-09-23 22:11:25 +02:00
if (( AngryIdx > 0 ) && ( a_NBT . GetType ( AngryIdx ) == TAG_Byte ))
2014-02-02 14:28:42 +04:00
{
bool Angry = (( a_NBT . GetByte ( AngryIdx ) == 1 ) ? true : false );
Monster -> SetIsAngry ( Angry );
}
2014-02-01 20:16:42 +04:00
int CollarColorIdx = a_NBT . FindChildByName ( a_TagIdx , "CollarColor" );
2014-09-23 22:22:38 +02:00
if ( CollarColorIdx > 0 )
2014-02-01 20:16:42 +04:00
{
2014-09-23 22:22:38 +02:00
switch ( a_NBT . GetType ( CollarColorIdx ))
{
case TAG_Byte :
{
// Vanilla uses this
unsigned char CollarColor = a_NBT . GetByte ( CollarColorIdx );
Monster -> SetCollarColor ( CollarColor );
break ;
}
case TAG_Int :
{
// Old MCS code used this, keep reading it for compatibility reasons:
Monster -> SetCollarColor ( a_NBT . GetInt ( CollarColorIdx ));
break ;
}
}
2014-02-01 20:16:42 +04:00
}
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadZombieFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
int IsVillagerIdx = a_NBT . FindChildByName ( a_TagIdx , "IsVillager" );
2014-12-05 16:59:11 +01:00
if ( IsVillagerIdx < 0 )
{
return ;
}
2013-12-25 16:07:52 +00:00
bool IsVillagerZombie = (( a_NBT . GetByte ( IsVillagerIdx ) == 1 ) ? true : false );
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cZombie > Monster = cpp14 :: make_unique < cZombie > ( IsVillagerZombie );
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
void cWSSAnvil :: LoadPigZombieFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 20:58:19 +02:00
std :: unique_ptr < cZombiePigman > Monster = cpp14 :: make_unique < cZombiePigman > ();
2013-12-25 16:07:52 +00:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2014-02-23 19:44:58 +01:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get (), a_NBT , a_TagIdx ))
{
return ;
}
2015-07-12 18:00:56 +02:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , "Age" );
if ( AgeableIdx > 0 )
{
2015-08-24 23:05:15 +02:00
int Age ;
switch ( a_NBT . GetType ( AgeableIdx ))
{
case TAG_Byte : Age = static_cast < int > ( a_NBT . GetByte ( AgeableIdx )); break ;
case TAG_Int : Age = a_NBT . GetInt ( AgeableIdx ); break ;
default : Age = 0 ; break ;
}
Monster -> SetAge ( Age );
2015-07-12 18:00:56 +02:00
}
2013-12-25 16:07:52 +00:00
a_Entities . push_back ( Monster . release ());
}
2014-08-03 22:03:48 +02:00
void cWSSAnvil :: LoadWolfOwner ( cWolf & a_Wolf , const cParsedNBT & a_NBT , int a_TagIdx )
{
// Load the owner information. OwnerUUID or Owner may be specified, possibly both:
AString OwnerUUID , OwnerName ;
int OwnerUUIDIdx = a_NBT . FindChildByName ( a_TagIdx , "OwnerUUID" );
if ( OwnerUUIDIdx > 0 )
{
2014-08-04 11:16:19 +02:00
OwnerUUID = a_NBT . GetString ( OwnerUUIDIdx );
2014-08-03 22:03:48 +02:00
}
int OwnerIdx = a_NBT . FindChildByName ( a_TagIdx , "Owner" );
if ( OwnerIdx > 0 )
{
OwnerName = a_NBT . GetString ( OwnerIdx );
}
if ( OwnerName . empty () && OwnerUUID . empty ())
{
// There is no owner, bail out:
return ;
}
// Convert name to UUID, if needed:
if ( OwnerUUID . empty ())
{
// This wolf has only playername stored (pre-1.7.6), look up the UUID
// The lookup is blocking, but we're running in a separate thread, so it's ok
OwnerUUID = cRoot :: Get () -> GetMojangAPI (). GetUUIDFromPlayerName ( OwnerName );
if ( OwnerUUID . empty ())
{
// Not a known player, un-tame the wolf by bailing out
return ;
}
}
2014-08-04 11:16:19 +02:00
else
{
// Normalize the UUID:
OwnerUUID = cMojangAPI :: MakeUUIDShort ( OwnerUUID );
}
2014-08-03 22:03:48 +02:00
// Convert UUID to name, if needed:
if ( OwnerName . empty ())
{
// The lookup is blocking, but we're running in a separate thread, so it's ok
OwnerName = cRoot :: Get () -> GetMojangAPI (). GetPlayerNameFromUUID ( OwnerUUID );
if ( OwnerName . empty ())
{
// Not a known player, un-tame the wolf by bailing out
return ;
}
}
a_Wolf . SetOwner ( OwnerName , OwnerUUID );
a_Wolf . SetIsTame ( true );
}
2013-03-09 14:35:43 +00:00
bool cWSSAnvil :: LoadEntityBaseFromNBT ( cEntity & a_Entity , const cParsedNBT & a_NBT , int a_TagIdx )
{
double Pos [ 3 ];
if ( ! LoadDoublesListFromNBT ( Pos , 3 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , "Pos" )))
{
return false ;
}
a_Entity . SetPosition ( Pos [ 0 ], Pos [ 1 ], Pos [ 2 ]);
double Speed [ 3 ];
if ( ! LoadDoublesListFromNBT ( Speed , 3 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , "Motion" )))
{
2014-01-24 09:57:12 +01:00
// Provide default speed:
Speed [ 0 ] = 0 ;
Speed [ 1 ] = 0 ;
Speed [ 2 ] = 0 ;
2013-03-09 14:35:43 +00:00
}
a_Entity . SetSpeed ( Speed [ 0 ], Speed [ 1 ], Speed [ 2 ]);
double Rotation [ 3 ];
if ( ! LoadDoublesListFromNBT ( Rotation , 2 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , "Rotation" )))
{
2014-01-24 09:57:12 +01:00
// Provide default rotation:
Rotation [ 0 ] = 0 ;
Rotation [ 1 ] = 0 ;
2013-03-09 14:35:43 +00:00
}
2014-01-16 19:00:49 +00:00
a_Entity . SetYaw ( Rotation [ 0 ]);
2014-01-20 16:10:39 +02:00
a_Entity . SetRoll ( Rotation [ 1 ]);
2014-06-24 16:06:26 +02:00
// Load health:
int Health = a_NBT . FindChildByName ( a_TagIdx , "Health" );
2014-07-29 20:50:30 +01:00
a_Entity . SetHealth ( Health > 0 ? a_NBT . GetShort ( Health ) : a_Entity . GetMaxHealth ());
2013-03-09 14:35:43 +00:00
return true ;
}
2014-02-23 19:44:58 +01:00
bool cWSSAnvil :: LoadMonsterBaseFromNBT ( cMonster & a_Monster , const cParsedNBT & a_NBT , int a_TagIdx )
{
float DropChance [ 5 ];
2014-06-04 09:22:19 +01:00
if ( ! LoadFloatsListFromNBT ( DropChance , 5 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , "DropChances" )))
2014-02-23 19:44:58 +01:00
{
return false ;
}
a_Monster . SetDropChanceWeapon ( DropChance [ 0 ]);
a_Monster . SetDropChanceHelmet ( DropChance [ 1 ]);
a_Monster . SetDropChanceChestplate ( DropChance [ 2 ]);
a_Monster . SetDropChanceLeggings ( DropChance [ 3 ]);
a_Monster . SetDropChanceBoots ( DropChance [ 4 ]);
2014-06-04 20:52:54 +01:00
int LootTag = a_NBT . FindChildByName ( a_TagIdx , "CanPickUpLoot" );
if ( LootTag > 0 )
{
bool CanPickUpLoot = ( a_NBT . GetByte ( LootTag ) == 1 );
a_Monster . SetCanPickUpLoot ( CanPickUpLoot );
}
2014-09-02 19:34:58 +02:00
int CustomNameTag = a_NBT . FindChildByName ( a_TagIdx , "CustomName" );
if (( CustomNameTag > 0 ) && ( a_NBT . GetType ( CustomNameTag ) == TAG_String ))
{
a_Monster . SetCustomName ( a_NBT . GetString ( CustomNameTag ));
}
int CustomNameVisibleTag = a_NBT . FindChildByName ( a_TagIdx , "CustomNameVisible" );
if (( CustomNameVisibleTag > 0 ) && ( a_NBT . GetType ( CustomNameVisibleTag ) == TAG_Byte ))
{
bool CustomNameVisible = ( a_NBT . GetByte ( CustomNameVisibleTag ) == 1 );
a_Monster . SetCustomNameAlwaysVisible ( CustomNameVisible );
}
2014-02-23 19:44:58 +01:00
return true ;
}
2013-09-07 21:26:17 +02:00
bool cWSSAnvil :: LoadProjectileBaseFromNBT ( cProjectileEntity & a_Entity , const cParsedNBT & a_NBT , int a_TagIdx )
{
if ( ! LoadEntityBaseFromNBT ( a_Entity , a_NBT , a_TagIdx ))
{
return false ;
}
bool IsInGround = false ;
int InGroundIdx = a_NBT . FindChildByName ( a_TagIdx , "inGround" );
if ( InGroundIdx > 0 )
{
IsInGround = ( a_NBT . GetByte ( InGroundIdx ) != 0 );
}
a_Entity . SetIsInGround ( IsInGround );
return true ;
}
2013-03-09 14:35:43 +00:00
bool cWSSAnvil :: LoadDoublesListFromNBT ( double * a_Doubles , int a_NumDoubles , const cParsedNBT & a_NBT , int a_TagIdx )
{
if (( a_TagIdx < 0 ) || ( a_NBT . GetType ( a_TagIdx ) != TAG_List ) || ( a_NBT . GetChildrenType ( a_TagIdx ) != TAG_Double ))
{
return false ;
}
int idx = 0 ;
for ( int Tag = a_NBT . GetFirstChild ( a_TagIdx ); ( Tag > 0 ) && ( idx < a_NumDoubles ); Tag = a_NBT . GetNextSibling ( Tag ), ++ idx )
{
a_Doubles [ idx ] = a_NBT . GetDouble ( Tag );
} // for Tag - PosTag[]
return ( idx == a_NumDoubles ); // Did we read enough doubles?
}
2014-02-23 19:44:58 +01:00
bool cWSSAnvil :: LoadFloatsListFromNBT ( float * a_Floats , int a_NumFloats , const cParsedNBT & a_NBT , int a_TagIdx )
{
if (( a_TagIdx < 0 ) || ( a_NBT . GetType ( a_TagIdx ) != TAG_List ) || ( a_NBT . GetChildrenType ( a_TagIdx ) != TAG_Float ))
{
return false ;
}
int idx = 0 ;
for ( int Tag = a_NBT . GetFirstChild ( a_TagIdx ); ( Tag > 0 ) && ( idx < a_NumFloats ); Tag = a_NBT . GetNextSibling ( Tag ), ++ idx )
{
a_Floats [ idx ] = a_NBT . GetFloat ( Tag );
} // for Tag - PosTag[]
return ( idx == a_NumFloats ); // Did we read enough doubles?
}
2012-06-14 13:06:06 +00:00
bool cWSSAnvil :: GetBlockEntityNBTPos ( const cParsedNBT & a_NBT , int a_TagIdx , int & a_X , int & a_Y , int & a_Z )
{
int x = a_NBT . FindChildByName ( a_TagIdx , "x" );
if (( x < 0 ) || ( a_NBT . GetType ( x ) != TAG_Int ))
{
return false ;
}
int y = a_NBT . FindChildByName ( a_TagIdx , "y" );
if (( y < 0 ) || ( a_NBT . GetType ( y ) != TAG_Int ))
{
return false ;
}
int z = a_NBT . FindChildByName ( a_TagIdx , "z" );
if (( z < 0 ) || ( a_NBT . GetType ( z ) != TAG_Int ))
{
return false ;
}
2014-12-21 22:37:48 +01:00
a_X = Clamp ( a_NBT . GetInt ( x ), - 40000000 , 40000000 ); // World is limited to 30M blocks in XZ, we clamp to 40M
a_Y = Clamp ( a_NBT . GetInt ( y ), - 10000 , 10000 ); // Y is limited to 0 .. 255, we clamp to 10K
a_Z = Clamp ( a_NBT . GetInt ( z ), - 40000000 , 40000000 );
2012-06-14 13:06:06 +00:00
return true ;
}
2014-07-17 22:15:34 +02:00
////////////////////////////////////////////////////////////////////////////////
2012-06-14 13:06:06 +00:00
// cWSSAnvil::cMCAFile:
2015-07-28 15:53:28 +02:00
cWSSAnvil :: cMCAFile :: cMCAFile ( cWSSAnvil & a_ParentSchema , const AString & a_FileName , int a_RegionX , int a_RegionZ ) :
m_ParentSchema ( a_ParentSchema ),
2012-06-14 13:06:06 +00:00
m_RegionX ( a_RegionX ),
m_RegionZ ( a_RegionZ ),
m_FileName ( a_FileName )
{
}
bool cWSSAnvil :: cMCAFile :: OpenFile ( bool a_IsForReading )
{
2014-12-08 11:23:19 -08:00
bool writeOutNeeded = false ;
2012-06-14 13:06:06 +00:00
if ( m_File . IsOpen ())
{
// Already open
return true ;
}
if ( a_IsForReading )
{
if ( ! cFile :: Exists ( m_FileName ))
{
// We want to read and the file doesn't exist. Fail.
return false ;
}
}
if ( ! m_File . Open ( m_FileName , cFile :: fmReadWrite ))
{
// The file failed to open
return false ;
}
// Load the header:
if ( m_File . Read ( m_Header , sizeof ( m_Header )) != sizeof ( m_Header ))
{
// Cannot read the header - perhaps the file has just been created?
2014-12-08 11:23:19 -08:00
// Try writing a nullptr header for chunk offsets:
2012-06-14 13:06:06 +00:00
memset ( m_Header , 0 , sizeof ( m_Header ));
2014-12-08 11:23:19 -08:00
writeOutNeeded = true ;
2012-06-14 13:06:06 +00:00
}
2014-12-07 14:44:08 -08:00
// Load the TimeStamps:
if ( m_File . Read ( m_TimeStamps , sizeof ( m_TimeStamps )) != sizeof ( m_TimeStamps ))
{
// Cannot read the time stamps - perhaps the file has just been created?
2014-12-08 11:23:19 -08:00
// Try writing a nullptr header for timestamps:
2014-12-07 14:44:08 -08:00
memset ( m_TimeStamps , 0 , sizeof ( m_TimeStamps ));
2014-12-08 11:23:19 -08:00
writeOutNeeded = true ;
}
if ( writeOutNeeded )
{
2014-12-11 14:34:09 +01:00
m_File . Seek ( 0 );
2012-06-14 13:06:06 +00:00
if (
2014-12-11 14:34:09 +01:00
( m_File . Write ( m_Header , sizeof ( m_Header )) != sizeof ( m_Header )) || // Write chunk offsets
( m_File . Write ( m_TimeStamps , sizeof ( m_TimeStamps )) != sizeof ( m_TimeStamps )) // Write chunk timestamps
)
2012-06-14 13:06:06 +00:00
{
LOGWARNING ( "Cannot process MCA header in file \" %s \" , chunks in that file will be lost" , m_FileName . c_str ());
m_File . Close ();
return false ;
}
}
return true ;
}
bool cWSSAnvil :: cMCAFile :: GetChunkData ( const cChunkCoords & a_Chunk , AString & a_Data )
{
if ( ! OpenFile ( true ))
{
return false ;
}
int LocalX = a_Chunk . m_ChunkX % 32 ;
if ( LocalX < 0 )
{
LocalX = 32 + LocalX ;
}
int LocalZ = a_Chunk . m_ChunkZ % 32 ;
if ( LocalZ < 0 )
{
LocalZ = 32 + LocalZ ;
}
unsigned ChunkLocation = ntohl ( m_Header [ LocalX + 32 * LocalZ ]);
unsigned ChunkOffset = ChunkLocation >> 8 ;
2014-09-06 13:32:16 +02:00
if ( ChunkOffset < 2 )
2014-09-02 22:40:24 +02:00
{
return false ;
}
2012-06-14 13:06:06 +00:00
2015-06-24 16:38:40 +02:00
m_File . Seek ( static_cast < int > ( ChunkOffset * 4096 ));
2012-06-14 13:06:06 +00:00
2015-06-24 16:38:40 +02:00
UInt32 ChunkSize = 0 ;
2012-06-14 13:06:06 +00:00
if ( m_File . Read ( & ChunkSize , 4 ) != 4 )
{
2015-07-28 15:53:28 +02:00
m_ParentSchema . ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "Cannot read chunk size" , "" );
2012-06-14 13:06:06 +00:00
return false ;
}
2015-06-24 16:38:40 +02:00
ChunkSize = ntohl ( ChunkSize );
if ( ChunkSize < 1 )
{
// Chunk size too small
2015-07-28 15:53:28 +02:00
m_ParentSchema . ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "Chunk size too small" , "" );
2015-06-24 16:38:40 +02:00
return false ;
}
2012-06-14 13:06:06 +00:00
char CompressionType = 0 ;
if ( m_File . Read ( & CompressionType , 1 ) != 1 )
{
2015-07-28 15:53:28 +02:00
m_ParentSchema . ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "Cannot read chunk compression" , "" );
2012-06-14 13:06:06 +00:00
return false ;
}
2015-07-28 15:53:28 +02:00
ChunkSize -- ;
a_Data = m_File . Read ( ChunkSize );
if ( a_Data . size () != ChunkSize )
{
m_ParentSchema . ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , "Cannot read entire chunk data" , a_Data );
return false ;
}
2012-06-14 13:06:06 +00:00
if ( CompressionType != 2 )
{
// Chunk is in an unknown compression
2015-07-28 15:53:28 +02:00
m_ParentSchema . ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , Printf ( "Unknown chunk compression: %d" , CompressionType ). c_str (), a_Data );
2012-06-14 13:06:06 +00:00
return false ;
}
2014-09-02 22:40:24 +02:00
return true ;
}
2012-06-14 13:06:06 +00:00
bool cWSSAnvil :: cMCAFile :: SetChunkData ( const cChunkCoords & a_Chunk , const AString & a_Data )
{
if ( ! OpenFile ( false ))
{
2013-03-09 14:35:43 +00:00
LOGWARNING ( "Cannot save chunk [%d, %d], opening file \" %s \" failed" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , GetFileName (). c_str ());
2012-06-14 13:06:06 +00:00
return false ;
}
int LocalX = a_Chunk . m_ChunkX % 32 ;
if ( LocalX < 0 )
{
LocalX = 32 + LocalX ;
}
int LocalZ = a_Chunk . m_ChunkZ % 32 ;
if ( LocalZ < 0 )
{
LocalZ = 32 + LocalZ ;
}
unsigned ChunkSector = FindFreeLocation ( LocalX , LocalZ , a_Data );
// Store the chunk data:
2015-07-29 09:04:03 -06:00
m_File . Seek ( static_cast < int > ( ChunkSector * 4096 ));
2015-07-09 11:15:37 -06:00
u_long ChunkSize = htonl ( static_cast < u_long > ( a_Data . size ()) + 1 );
2012-06-14 13:06:06 +00:00
if ( m_File . Write ( & ChunkSize , 4 ) != 4 )
{
2013-03-09 14:35:43 +00:00
LOGWARNING ( "Cannot save chunk [%d, %d], writing(1) data to file \" %s \" failed" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , GetFileName (). c_str ());
2012-06-14 13:06:06 +00:00
return false ;
}
char CompressionType = 2 ;
if ( m_File . Write ( & CompressionType , 1 ) != 1 )
{
2013-03-09 14:35:43 +00:00
LOGWARNING ( "Cannot save chunk [%d, %d], writing(2) data to file \" %s \" failed" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , GetFileName (). c_str ());
2012-06-14 13:06:06 +00:00
return false ;
}
2015-07-29 09:04:03 -06:00
if ( m_File . Write ( a_Data . data (), a_Data . size ()) != static_cast < int > ( a_Data . size ()))
2012-06-14 13:06:06 +00:00
{
2013-03-09 14:35:43 +00:00
LOGWARNING ( "Cannot save chunk [%d, %d], writing(3) data to file \" %s \" failed" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , GetFileName (). c_str ());
2012-06-14 13:06:06 +00:00
return false ;
}
2014-05-01 18:00:10 +02:00
// Add padding to 4K boundary:
size_t BytesWritten = a_Data . size () + MCA_CHUNK_HEADER_LENGTH ;
2015-02-08 12:24:15 +01:00
if ( BytesWritten % 4096 != 0 )
{
static const char Padding [ 4095 ] = { 0 };
m_File . Write ( Padding , 4096 - ( BytesWritten % 4096 ));
}
2014-05-01 18:00:10 +02:00
2012-06-14 13:06:06 +00:00
// Store the header:
2015-07-09 11:15:37 -06:00
ChunkSize = ( static_cast < u_long > ( a_Data . size ()) + MCA_CHUNK_HEADER_LENGTH + 4095 ) / 4096 ; // Round data size up to nearest 4KB sector, make it a sector number
2014-09-04 14:00:54 +02:00
if ( ChunkSize > 255 )
{
LOGWARNING ( "Cannot save chunk [%d, %d], the data is too large (%u KiB, maximum is 1024 KiB). Remove some entities and retry." ,
2015-07-09 11:15:37 -06:00
a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , static_cast < unsigned > ( ChunkSize * 4 )
2014-09-04 14:00:54 +02:00
);
return false ;
}
2014-12-08 08:22:40 -08:00
2014-12-07 14:44:08 -08:00
// Store the header info in the table
2012-06-14 13:06:06 +00:00
m_Header [ LocalX + 32 * LocalZ ] = htonl (( ChunkSector << 8 ) | ChunkSize );
2014-12-07 14:44:08 -08:00
// Set the modification time
2014-12-11 14:34:09 +01:00
m_TimeStamps [ LocalX + 32 * LocalZ ] = htonl ( static_cast < u_long > ( time ( nullptr )));
2014-12-07 14:44:08 -08:00
2013-03-09 14:35:43 +00:00
if ( m_File . Seek ( 0 ) < 0 )
{
LOGWARNING ( "Cannot save chunk [%d, %d], seeking in file \" %s \" failed" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , GetFileName (). c_str ());
return false ;
}
2012-06-14 13:06:06 +00:00
if ( m_File . Write ( m_Header , sizeof ( m_Header )) != sizeof ( m_Header ))
{
2013-03-09 14:35:43 +00:00
LOGWARNING ( "Cannot save chunk [%d, %d], writing header to file \" %s \" failed" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , GetFileName (). c_str ());
2012-06-14 13:06:06 +00:00
return false ;
}
2014-12-08 11:23:19 -08:00
if ( m_File . Write ( m_TimeStamps , sizeof ( m_TimeStamps )) != sizeof ( m_TimeStamps ))
2014-12-07 14:44:08 -08:00
{
LOGWARNING ( "Cannot save chunk [%d, %d], writing timestamps to file \" %s \" failed" , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , GetFileName (). c_str ());
return false ;
}
2012-06-14 13:06:06 +00:00
return true ;
}
unsigned cWSSAnvil :: cMCAFile :: FindFreeLocation ( int a_LocalX , int a_LocalZ , const AString & a_Data )
{
// See if it fits the current location:
unsigned ChunkLocation = ntohl ( m_Header [ a_LocalX + 32 * a_LocalZ ]);
unsigned ChunkLen = ChunkLocation & 0xff ;
if ( a_Data . size () + MCA_CHUNK_HEADER_LENGTH <= ( ChunkLen * 4096 ))
{
return ChunkLocation >> 8 ;
}
// Doesn't fit, append to the end of file (we're wasting a lot of space, TODO: fix this later)
unsigned MaxLocation = 2 << 8 ; // Minimum sector is #2 - after the headers
2013-12-20 16:01:34 +01:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( m_Header ); i ++ )
2012-06-14 13:06:06 +00:00
{
ChunkLocation = ntohl ( m_Header [ i ]);
ChunkLocation = ChunkLocation + (( ChunkLocation & 0xff ) << 8 ); // Add the number of sectors used; don't care about the 4th byte
if ( MaxLocation < ChunkLocation )
{
MaxLocation = ChunkLocation ;
}
} // for i - m_Header[]
return MaxLocation >> 8 ;
}
2012-08-26 17:50:42 +00:00