2012-06-14 09:06:06 -04:00
// WSSAnvil.cpp
// Implements the cWSSAnvil class representing the Anvil world storage scheme
# include "Globals.h"
# include "WSSAnvil.h"
2013-03-09 09:35:43 -05:00
# include "NBTChunkSerializer.h"
2013-12-25 11:07:52 -05:00
# include "FastNBT.h"
2014-01-19 10:38:59 -05:00
# include "EnchantmentSerializer.h"
2013-11-27 02:40:59 -05:00
# include "zlib/zlib.h"
2017-06-21 01:47:26 -04:00
# include "json/json.h"
2013-12-25 11:07:52 -05:00
# include "../World.h"
2012-09-23 16:22:46 -04:00
# include "../BlockID.h"
2013-12-25 11:07:52 -05:00
# include "../Item.h"
# include "../ItemGrid.h"
# include "../StringCompression.h"
2014-07-24 12:32:05 -04:00
# include "../SetChunkData.h"
2014-08-03 16:03:48 -04:00
# include "../Root.h"
2013-12-25 11:07:52 -05:00
2014-07-30 16:50:34 -04:00
# include "../BlockEntities/BeaconEntity.h"
2015-09-24 04:48:33 -04:00
# include "../BlockEntities/BrewingstandEntity.h"
2013-05-28 15:12:47 -04:00
# include "../BlockEntities/ChestEntity.h"
2014-01-18 08:40:47 -05:00
# include "../BlockEntities/CommandBlockEntity.h"
2013-05-28 15:12:47 -04:00
# include "../BlockEntities/DispenserEntity.h"
# include "../BlockEntities/DropperEntity.h"
# include "../BlockEntities/FurnaceEntity.h"
2013-06-13 03:36:43 -04:00
# include "../BlockEntities/HopperEntity.h"
2013-05-28 15:12:47 -04:00
# include "../BlockEntities/JukeboxEntity.h"
# include "../BlockEntities/NoteEntity.h"
# include "../BlockEntities/SignEntity.h"
2014-02-19 08:45:09 -05:00
# include "../BlockEntities/MobHeadEntity.h"
2014-11-18 09:33:41 -05:00
# include "../BlockEntities/MobSpawnerEntity.h"
2014-03-06 19:30:34 -05:00
# include "../BlockEntities/FlowerPotEntity.h"
2013-12-25 11:07:52 -05:00
2013-08-25 15:32:17 -04:00
# include "../Mobs/Monster.h"
2013-12-25 11:07:52 -05:00
# include "../Mobs/IncludeAllMonsters.h"
2013-09-07 19:14:57 -04:00
# include "../Entities/Boat.h"
2014-03-25 14:59:33 -04:00
# include "../Entities/EnderCrystal.h"
2013-08-19 05:39:13 -04:00
# include "../Entities/FallingBlock.h"
# include "../Entities/Minecart.h"
# include "../Entities/Pickup.h"
2014-04-27 20:03:06 -04:00
# include "../Entities/ArrowEntity.h"
2014-07-11 21:58:11 -04:00
# include "../Entities/SplashPotionEntity.h"
2014-04-27 20:03:06 -04:00
# include "../Entities/ThrownEggEntity.h"
# include "../Entities/ThrownEnderPearlEntity.h"
# include "../Entities/ThrownSnowballEntity.h"
# include "../Entities/FireChargeEntity.h"
# include "../Entities/GhastFireballEntity.h"
2014-03-08 04:25:46 -05:00
# include "../Entities/TNTEntity.h"
2014-03-14 19:32:49 -04:00
# include "../Entities/ExpOrb.h"
2014-03-14 21:45:25 -04:00
# include "../Entities/HangingEntity.h"
# include "../Entities/ItemFrame.h"
2015-03-13 19:05:06 -04:00
# include "../Entities/Painting.h"
2012-06-14 09:06:06 -04:00
2014-08-03 16:03:48 -04:00
# include "../Protocol/MojangAPI.h"
2014-09-24 09:17:20 -04:00
# include "Server.h"
2014-08-03 16:03:48 -04:00
2012-06-14 09:06:06 -04:00
2013-05-05 10:48:18 -04: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 16:50:58 -04:00
/** Maximum number of MCA files that are cached in memory.
2012-06-14 09:06:06 -04: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 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-06-14 09:06:06 -04:00
// cWSSAnvil:
2014-01-17 14:01:14 -05:00
cWSSAnvil : : cWSSAnvil ( cWorld * a_World , int a_CompressionFactor ) :
super ( a_World ) ,
m_CompressionFactor ( a_CompressionFactor )
2012-06-14 09:06:06 -04:00
{
// Create a level.dat file for mapping tools, if it doesn't already exist:
AString fnam ;
2015-05-09 03:25:09 -04:00
Printf ( fnam , " %s%clevel.dat " , a_World - > GetName ( ) . c_str ( ) , cFile : : PathSeparator ) ;
2012-06-14 09:06:06 -04:00
if ( ! cFile : : Exists ( fnam ) )
{
cFastNBTWriter Writer ;
2014-09-23 13:16:17 -04:00
Writer . BeginCompound ( " Data " ) ;
Writer . AddByte ( " allowCommands " , 1 ) ;
Writer . AddByte ( " Difficulty " , 2 ) ;
2014-09-24 09:17:20 -04:00
Writer . AddByte ( " hardcore " , cRoot : : Get ( ) - > GetServer ( ) - > IsHardcore ( ) ? 1 : 0 ) ;
2014-09-23 13:16:17 -04: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 11:04:03 -04:00
Writer . AddInt ( " GameType " , static_cast < int > ( a_World - > GetGameMode ( ) ) ) ;
2014-09-23 13:16:17 -04:00
Writer . AddInt ( " generatorVersion " , 1 ) ;
2015-06-24 10:38:40 -04: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 13:16:17 -04:00
Writer . AddInt ( " version " , 19133 ) ;
2015-06-24 10:38:40 -04:00
Writer . AddLong ( " DayTime " , a_World - > GetTimeOfDay ( ) ) ;
2014-09-23 13:16:17 -04: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 09:06:06 -04:00
Writer . EndCompound ( ) ;
Writer . Finish ( ) ;
2016-02-05 16:45:45 -05:00
2012-11-16 17:06:12 -05:00
gzFile gz = gzopen ( ( FILE_IO_PREFIX + fnam ) . c_str ( ) , " wb " ) ;
2014-10-20 16:55:07 -04:00
if ( gz ! = nullptr )
2012-06-14 09:06:06 -04:00
{
2015-07-09 13:15:37 -04:00
gzwrite ( gz , Writer . GetResult ( ) . data ( ) , static_cast < unsigned > ( Writer . GetResult ( ) . size ( ) ) ) ;
2012-06-14 09:06:06 -04: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 ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
return LoadChunkFromData ( a_Chunk , ChunkData ) ;
}
bool cWSSAnvil : : SaveChunk ( const cChunkCoords & a_Chunk )
{
AString ChunkData ;
if ( ! SaveChunkToData ( a_Chunk , ChunkData ) )
{
2013-04-13 17:02:10 -04:00
LOGWARNING ( " Cannot serialize chunk [%d, %d] into data " , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
if ( ! SetChunkData ( a_Chunk , ChunkData ) )
{
2013-04-13 17:02:10 -04:00
LOGWARNING ( " Cannot store chunk [%d, %d] data " , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// Everything successful
return true ;
}
2015-07-28 09:53:28 -04: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 09:06:06 -04:00
bool cWSSAnvil : : GetChunkData ( const cChunkCoords & a_Chunk , AString & a_Data )
{
cCSLock Lock ( m_CS ) ;
cMCAFile * File = LoadMCAFile ( a_Chunk ) ;
2014-10-20 16:55:07 -04:00
if ( File = = nullptr )
2012-06-14 09:06:06 -04: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 16:55:07 -04:00
if ( File = = nullptr )
2012-06-14 09:06:06 -04: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 05:01:20 -05:00
ASSERT ( m_CS . IsLocked ( ) ) ;
2012-06-14 09:06:06 -04:00
2013-02-27 05:01:20 -05: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 09:35:43 -05: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 ) ;
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// Is it already cached?
for ( cMCAFiles : : iterator itr = m_Files . begin ( ) ; itr ! = m_Files . end ( ) ; + + itr )
{
2014-10-20 16:55:07 -04:00
if ( ( ( * itr ) ! = nullptr ) & & ( ( * itr ) - > GetRegionX ( ) = = RegionX ) & & ( ( * itr ) - > GetRegionZ ( ) = = RegionZ ) )
2012-06-14 09:06:06 -04: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 ;
}
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// Load it anew:
AString FileName ;
2015-05-09 03:25:09 -04:00
Printf ( FileName , " %s%cregion " , m_World - > GetName ( ) . c_str ( ) , cFile : : PathSeparator ) ;
2013-10-09 03:57:48 -04:00
cFile : : CreateFolder ( FILE_IO_PREFIX + FileName ) ;
2012-06-14 09:06:06 -04:00
AppendPrintf ( FileName , " /r.%d.%d.mca " , RegionX , RegionZ ) ;
2015-07-28 09:53:28 -04:00
cMCAFile * f = new cMCAFile ( * this , FileName , RegionX , RegionZ ) ;
2014-10-20 16:55:07 -04:00
if ( f = = nullptr )
2012-06-14 09:06:06 -04:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-06-14 09:06:06 -04:00
}
m_Files . push_front ( f ) ;
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// 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 13:36:53 -04:00
// Uncompress the data:
AString Uncompressed ;
int res = InflateString ( a_Data . data ( ) , a_Data . size ( ) , Uncompressed ) ;
if ( res ! = Z_OK )
2012-06-14 09:06:06 -04:00
{
2014-09-03 13:36:53 -04:00
LOGWARNING ( " Uncompressing chunk [%d, %d] failed: %d " , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , res ) ;
2015-07-28 09:53:28 -04:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , " InflateString() failed " , a_Data ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// Parse the NBT data:
2014-09-03 13:36:53 -04:00
cParsedNBT NBT ( Uncompressed . data ( ) , Uncompressed . size ( ) ) ;
2012-06-14 09:06:06 -04:00
if ( ! NBT . IsValid ( ) )
{
// NBT Parsing failed
2015-07-28 09:53:28 -04:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , " NBT parsing failed " , a_Data ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
// Load the data from NBT:
2015-07-28 09:53:28 -04:00
return LoadChunkFromNBT ( a_Chunk , NBT , a_Data ) ;
2012-06-14 09:06:06 -04:00
}
bool cWSSAnvil : : SaveChunkToData ( const cChunkCoords & a_Chunk , AString & a_Data )
{
cFastNBTWriter Writer ;
if ( ! SaveChunkToNBT ( a_Chunk , Writer ) )
{
2013-04-13 17:02:10 -04:00
LOGWARNING ( " Cannot save chunk [%d, %d] to NBT " , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
Writer . Finish ( ) ;
2016-02-05 16:45:45 -05:00
2014-01-17 14:01:14 -05:00
CompressString ( Writer . GetResult ( ) . data ( ) , Writer . GetResult ( ) . size ( ) , a_Data , m_CompressionFactor ) ;
2012-06-14 09:06:06 -04:00
return true ;
}
2015-07-28 09:53:28 -04:00
bool cWSSAnvil : : LoadChunkFromNBT ( const cChunkCoords & a_Chunk , const cParsedNBT & a_NBT , const AString & a_RawChunkData )
2012-06-14 09:06:06 -04:00
{
2015-05-09 03:25:09 -04:00
// The data arrays, in MCA-native y / z / x ordering (will be reordered for the final chunk data)
2012-06-14 09:06:06 -04:00
cChunkDef : : BlockTypes BlockTypes ;
cChunkDef : : BlockNibbles MetaData ;
cChunkDef : : BlockNibbles BlockLight ;
cChunkDef : : BlockNibbles SkyLight ;
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
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 ) ) ;
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// Load the blockdata, blocklight and skylight:
int Level = a_NBT . FindChildByName ( 0 , " Level " ) ;
if ( Level < 0 )
{
2015-07-28 09:53:28 -04:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , " Missing NBT tag: Level " , a_RawChunkData ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
int Sections = a_NBT . FindChildByName ( Level , " Sections " ) ;
2014-09-05 16:55:39 -04:00
if ( ( Sections < 0 ) | | ( a_NBT . GetType ( Sections ) ! = TAG_List ) )
{
2015-07-28 09:53:28 -04:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , " Missing NBT tag: Sections " , a_RawChunkData ) ;
2014-09-05 16:55:39 -04:00
return false ;
}
eTagType SectionsType = a_NBT . GetChildrenType ( Sections ) ;
if ( ( SectionsType ! = TAG_Compound ) & & ( SectionsType ! = TAG_End ) )
2012-06-14 09:06:06 -04:00
{
2015-07-28 09:53:28 -04:00
ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , " NBT tag has wrong type: Sections " , a_RawChunkData ) ;
2012-06-14 09:06:06 -04: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 11:04:03 -04: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 09:06:06 -04:00
} // for itr - LevelSections[]
2016-02-05 16:45:45 -05:00
2012-10-28 13:30:10 -04:00
// Load the biomes from NBT, if present and valid. First try MCS-style, then Vanilla-style:
2012-06-14 09:06:06 -04:00
cChunkDef : : BiomeMap BiomeMap ;
2012-10-28 13:30:10 -04:00
cChunkDef : : BiomeMap * Biomes = LoadBiomeMapFromNBT ( & BiomeMap , a_NBT , a_NBT . FindChildByName ( Level , " MCSBiomes " ) ) ;
2014-10-20 16:55:07 -04:00
if ( Biomes = = nullptr )
2012-10-28 13:30:10 -04:00
{
// MCS-style biomes not available, load vanilla-style:
Biomes = LoadVanillaBiomeMapFromNBT ( & BiomeMap , a_NBT , a_NBT . FindChildByName ( Level , " Biomes " ) ) ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// Load the entities from NBT:
cEntityList Entities ;
2017-05-22 16:27:55 -04:00
cBlockEntities BlockEntities ;
2012-06-14 09:06:06 -04:00
LoadEntitiesFromNBT ( Entities , a_NBT , a_NBT . FindChildByName ( Level , " Entities " ) ) ;
2013-06-20 07:41:44 -04:00
LoadBlockEntitiesFromNBT ( BlockEntities , a_NBT , a_NBT . FindChildByName ( Level , " TileEntities " ) , BlockTypes , MetaData ) ;
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
bool IsLightValid = ( a_NBT . FindChildByName ( Level , " MCSIsLightValid " ) > 0 ) ;
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
/*
// 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 13:07:46 -04:00
BlockTypes [ Index ] = ( BlockTypes [ Index ] = = E_BLOCK_AIR ) ? E_BLOCK_STONE : E_BLOCK_AIR ;
2012-06-14 09:06:06 -04:00
}
else
{
2012-07-21 13:07:46 -04:00
switch ( BlockTypes [ Index ] )
{
case E_BLOCK_AIR :
case E_BLOCK_LEAVES :
2014-03-16 09:01:22 -04:00
case E_BLOCK_NEW_LEAVES :
2012-07-21 13:07:46 -04:00
{
// nothing needed
break ;
}
default :
{
ShouldInvert [ x + cChunkDef : : Width * z ] = true ;
}
}
BlockTypes [ Index ] = E_BLOCK_AIR ;
2012-06-14 09:06:06 -04:00
}
}
} // for y
//*/
2016-02-05 16:45:45 -05:00
2014-08-29 12:19:27 -04:00
cSetChunkDataPtr SetChunkData ( new cSetChunkData (
2013-04-13 17:02:10 -04:00
a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ ,
2014-07-17 16:50:58 -04:00
BlockTypes , MetaData ,
2014-10-20 16:55:07 -04:00
IsLightValid ? BlockLight : nullptr ,
IsLightValid ? SkyLight : nullptr ,
nullptr , Biomes ,
2015-04-27 15:18:21 -04:00
std : : move ( Entities ) , std : : move ( BlockEntities ) ,
2012-06-14 09:06:06 -04:00
false
2014-08-29 12:19:27 -04:00
) ) ;
m_World - > QueueSetChunkData ( SetChunkData ) ;
2012-06-14 09:06:06 -04:00
return true ;
}
2014-05-09 13:57:59 -04: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 09:06:06 -04: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 13:16:17 -04:00
2012-06-14 09:06:06 -04:00
cNBTChunkSerializer Serializer ( a_Writer ) ;
2013-04-13 17:02:10 -04:00
if ( ! m_World - > GetChunkData ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , Serializer ) )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
LOGWARNING ( " Cannot get chunk [%d, %d] data for NBT saving " , a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
Serializer . Finish ( ) ; // Close NBT tags
2016-02-05 16:45:45 -05:00
2012-10-28 13:30:10 -04:00
// Save biomes, both MCS (IntArray) and MC-vanilla (ByteArray):
2012-11-13 10:58:27 -05:00
if ( Serializer . m_BiomesAreValid )
{
2015-07-29 11:04:03 -04: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 10:58:27 -05:00
}
2014-09-23 13:16:17 -04:00
// Save heightmap (Vanilla require this):
2015-07-29 11:04:03 -04:00
a_Writer . AddIntArray ( " HeightMap " , reinterpret_cast < const int * > ( Serializer . m_VanillaHeightMap ) , ARRAYCOUNT ( Serializer . m_VanillaHeightMap ) ) ;
2014-09-23 13:16:17 -04:00
2012-06-14 09:06:06 -04:00
// Save blockdata:
a_Writer . BeginList ( " Sections " , TAG_Compound ) ;
2014-05-09 13:57:59 -04:00
size_t SliceSizeBlock = cChunkDef : : Width * cChunkDef : : Width * 16 ;
size_t SliceSizeNibble = SliceSizeBlock / 2 ;
2015-07-29 11:04:03 -04:00
const char * BlockTypes = reinterpret_cast < const char * > ( Serializer . m_BlockTypes ) ;
const char * BlockMetas = reinterpret_cast < const char * > ( Serializer . m_BlockMetas ) ;
2013-05-05 10:48:18 -04:00
# ifdef DEBUG_SKYLIGHT
2015-07-29 11:04:03 -04:00
const char * BlockLight = reinterpret_cast < const char * > ( Serializer . m_BlockSkyLight ) ;
2013-05-05 10:48:18 -04:00
# else
2015-07-29 11:04:03 -04:00
const char * BlockLight = reinterpret_cast < const char * > ( Serializer . m_BlockLight ) ;
2014-07-17 16:50:58 -04:00
# endif
2015-07-29 11:04:03 -04:00
const char * BlockSkyLight = reinterpret_cast < const char * > ( Serializer . m_BlockSkyLight ) ;
2012-06-14 09:06:06 -04:00
for ( int Y = 0 ; Y < 16 ; Y + + )
{
a_Writer . BeginCompound ( " " ) ;
2015-07-29 11:04:03 -04: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 13:15:37 -04:00
a_Writer . AddByte ( " Y " , static_cast < unsigned char > ( Y ) ) ;
2012-06-14 09:06:06 -04:00
a_Writer . EndCompound ( ) ;
}
a_Writer . EndList ( ) ; // "Sections"
2016-02-05 16:45:45 -05:00
2014-07-17 16:50:58 -04:00
// Store the information that the lighting is valid.
2012-06-14 09:06:06 -04: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 13:16:17 -04:00
// Save the world age to the chunk data. Required by vanilla and mcedit.
a_Writer . AddLong ( " LastUpdate " , m_World - > GetWorldAge ( ) ) ;
2016-02-05 16:45:45 -05:00
2014-06-20 15:30:11 -04:00
// Store the flag that the chunk has all the ores, trees, dungeons etc. MCS chunks are always complete.
a_Writer . AddByte ( " TerrainPopulated " , 1 ) ;
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
a_Writer . EndCompound ( ) ; // "Level"
return true ;
}
2012-10-28 13:30:10 -04:00
cChunkDef : : BiomeMap * cWSSAnvil : : LoadVanillaBiomeMapFromNBT ( cChunkDef : : BiomeMap * a_BiomeMap , const cParsedNBT & a_NBT , int a_TagIdx )
2012-06-14 09:06:06 -04:00
{
if ( ( a_TagIdx < 0 ) | | ( a_NBT . GetType ( a_TagIdx ) ! = TAG_ByteArray ) )
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-06-14 09:06:06 -04:00
}
2013-04-07 17:04:54 -04:00
if ( a_NBT . GetDataLength ( a_TagIdx ) ! = 16 * 16 )
2012-06-14 09:06:06 -04:00
{
// The biomes stored don't match in size
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-06-14 09:06:06 -04:00
}
2015-07-29 11:04:03 -04:00
const unsigned char * VanillaBiomeData = reinterpret_cast < const unsigned char * > ( a_NBT . GetData ( a_TagIdx ) ) ;
2013-12-20 10:01:34 -05:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( * a_BiomeMap ) ; i + + )
2012-10-28 13:30:10 -04:00
{
if ( ( VanillaBiomeData ) [ i ] = = 0xff )
{
// Unassigned biomes
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-10-28 13:30:10 -04:00
}
2015-07-29 11:04:03 -04:00
( * a_BiomeMap ) [ i ] = static_cast < EMCSBiome > ( VanillaBiomeData [ i ] ) ;
2012-10-28 13:30:10 -04: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 16:55:07 -04:00
return nullptr ;
2012-10-28 13:30:10 -04:00
}
if ( a_NBT . GetDataLength ( a_TagIdx ) ! = sizeof ( * a_BiomeMap ) )
{
// The biomes stored don't match in size
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-10-28 13:30:10 -04:00
}
2014-03-10 14:34:20 -04:00
const char * BiomeData = ( a_NBT . GetData ( a_TagIdx ) ) ;
2013-12-20 10:01:34 -05:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( * a_BiomeMap ) ; i + + )
2012-06-14 09:06:06 -04:00
{
2015-07-29 11:04:03 -04:00
( * a_BiomeMap ) [ i ] = static_cast < EMCSBiome > ( GetBEInt ( & BiomeData [ i * 4 ] ) ) ;
2012-06-14 09:06:06 -04:00
if ( ( * a_BiomeMap ) [ i ] = = 0xff )
{
// Unassigned biomes
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-06-14 09:06:06 -04:00
}
}
return a_BiomeMap ;
}
2013-03-09 09:35:43 -05:00
void cWSSAnvil : : LoadEntitiesFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
2012-06-14 09:06:06 -04:00
{
2013-03-09 09:35:43 -05:00
if ( ( a_TagIdx < 0 ) | | ( a_NBT . GetType ( a_TagIdx ) ! = TAG_List ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-03-09 09:35:43 -05:00
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 09:06:06 -04:00
}
2017-05-22 16:27:55 -04:00
void cWSSAnvil : : LoadBlockEntitiesFromNBT ( cBlockEntities & a_BlockEntities , const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE * a_BlockTypes , NIBBLETYPE * a_BlockMetas )
2012-06-14 09:06:06 -04:00
{
if ( ( a_TagIdx < 0 ) | | ( a_NBT . GetType ( a_TagIdx ) ! = TAG_List ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
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 12:19:27 -04:00
// Get the BlockEntity's position
int x , y , z ;
2014-09-05 09:40:03 -04:00
if ( ! GetBlockEntityNBTPos ( a_NBT , Child , x , y , z ) | | ( y < 0 ) | | ( y > = cChunkDef : : Height ) )
2012-06-14 09:06:06 -04:00
{
2014-08-29 12:19:27 -04:00
LOGWARNING ( " Bad block entity, missing the coords. Will be ignored. " ) ;
2012-06-14 09:06:06 -04:00
continue ;
}
2014-08-29 12:19:27 -04: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 17:02:49 -05:00
std : : unique_ptr < cBlockEntity > be ( LoadBlockEntityFromNBT ( a_NBT , Child , x , y , z , BlockType , BlockMeta ) ) ;
2014-10-20 16:55:07 -04:00
if ( be . get ( ) = = nullptr )
2014-07-06 18:50:22 -04:00
{
2014-08-29 12:19:27 -04:00
continue ;
2014-07-06 18:50:22 -04:00
}
2014-08-29 12:19:27 -04:00
// Add the BlockEntity to the loaded data:
2017-05-22 16:27:55 -04:00
auto Idx = cChunkDef : : MakeIndex ( be - > GetRelX ( ) , be - > GetPosY ( ) , be - > GetRelZ ( ) ) ;
a_BlockEntities . insert ( { Idx , be . get ( ) } ) ;
// Release after inserting in case it throws.
be . release ( ) ;
2012-06-14 09:06:06 -04:00
} // for Child - tag children
}
2014-08-29 12:19:27 -04: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 12:59:17 -04:00
ASSERT ( ( a_BlockY > = 0 ) & & ( a_BlockY < cChunkDef : : Height ) ) ;
2014-08-29 12:19:27 -04:00
// Load the specific BlockEntity type:
switch ( a_BlockType )
{
// Specific entity loaders:
2017-06-15 09:32:33 -04:00
case E_BLOCK_BEACON : return LoadBeaconFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_BREWING_STAND : return LoadBrewingstandFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_CHEST : return LoadChestFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_COMMAND_BLOCK : return LoadCommandBlockFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_DISPENSER : return LoadDispenserFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_DROPPER : return LoadDropperFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_FLOWER_POT : return LoadFlowerPotFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_FURNACE : return LoadFurnaceFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_HEAD : return LoadMobHeadFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_HOPPER : return LoadHopperFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_JUKEBOX : return LoadJukeboxFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_LIT_FURNACE : return LoadFurnaceFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_MOB_SPAWNER : return LoadMobSpawnerFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_NOTE_BLOCK : return LoadNoteBlockFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_SIGN_POST : return LoadSignFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_TRAPPED_CHEST : return LoadChestFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
case E_BLOCK_WALLSIGN : return LoadSignFromNBT ( a_NBT , a_Tag , a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ ) ;
2014-08-29 12:19:27 -04:00
// Blocktypes that have block entities but don't load their contents from disk:
2014-10-20 16:55:07 -04:00
case E_BLOCK_ENDER_CHEST : return nullptr ;
2014-08-29 12:19:27 -04: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 11:04:03 -04:00
TypeName . assign ( a_NBT . GetData ( TagID ) , static_cast < size_t > ( a_NBT . GetDataLength ( TagID ) ) ) ;
2014-08-29 12:19:27 -04: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 16:55:07 -04:00
return nullptr ;
2014-08-29 12:19:27 -04:00
}
2013-03-09 09:35:43 -05:00
bool cWSSAnvil : : LoadItemFromNBT ( cItem & a_Item , const cParsedNBT & a_NBT , int a_TagIdx )
{
2014-01-26 08:43:54 -05:00
int Type = a_NBT . FindChildByName ( a_TagIdx , " id " ) ;
2014-10-29 10:47:43 -04:00
if ( Type < = 0 )
2013-03-09 09:35:43 -05:00
{
return false ;
}
2014-10-29 10:47:43 -04: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 08:43:54 -05:00
if ( a_Item . m_ItemType < 0 )
{
a_Item . Empty ( ) ;
return true ;
}
2016-02-05 16:45:45 -05:00
2013-03-09 09:35:43 -05:00
int Damage = a_NBT . FindChildByName ( a_TagIdx , " Damage " ) ;
2014-05-07 06:30:30 -04:00
if ( ( Damage > 0 ) & & ( a_NBT . GetType ( Damage ) = = TAG_Short ) )
2013-03-09 09:35:43 -05:00
{
2014-05-07 06:30:30 -04:00
a_Item . m_ItemDamage = a_NBT . GetShort ( Damage ) ;
2013-03-09 09:35:43 -05:00
}
2016-02-05 16:45:45 -05:00
2013-03-09 09:35:43 -05:00
int Count = a_NBT . FindChildByName ( a_TagIdx , " Count " ) ;
2014-05-07 06:30:30 -04:00
if ( ( Count > 0 ) & & ( a_NBT . GetType ( Count ) = = TAG_Byte ) )
2013-03-09 09:35:43 -05:00
{
2015-07-29 11:04:03 -04:00
a_Item . m_ItemCount = static_cast < char > ( a_NBT . GetByte ( Count ) ) ;
2013-03-09 09:35:43 -05:00
}
2016-02-05 16:45:45 -05:00
2013-06-02 17:21:32 -04: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 06:30:30 -04:00
// Load repair cost:
int RepairCost = a_NBT . FindChildByName ( TagTag , " RepairCost " ) ;
if ( ( RepairCost > 0 ) & & ( a_NBT . GetType ( RepairCost ) = = TAG_Int ) )
{
2014-05-07 14:43:37 -04:00
a_Item . m_RepairCost = a_NBT . GetInt ( RepairCost ) ;
2014-05-07 06:30:30 -04: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 17:21:32 -04: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 11:52:45 -05:00
EnchantmentSerializer : : ParseFromNBT ( a_Item . m_Enchantments , a_NBT , EnchTag ) ;
2013-06-02 17:21:32 -04:00
}
2014-02-26 18:29:14 -05:00
2014-05-07 06:30:30 -04:00
// Load firework data:
2017-03-22 09:18:48 -04:00
int FireworksTag = a_NBT . FindChildByName ( TagTag , ( ( a_Item . m_ItemType = = E_ITEM_FIREWORK_STAR ) ? " Explosion " : " Fireworks " ) ) ;
if ( FireworksTag > 0 )
2014-02-26 18:29:14 -05:00
{
2015-07-29 11:04:03 -04:00
cFireworkItem : : ParseFromNBT ( a_Item . m_FireworkItem , a_NBT , FireworksTag , static_cast < ENUM_ITEM_ID > ( a_Item . m_ItemType ) ) ;
2014-02-26 18:29:14 -05:00
}
2016-02-05 16:45:45 -05:00
2013-03-09 09:35:43 -05:00
return true ;
}
2013-05-26 11:29:43 -04: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 11:04:03 -04:00
int SlotNum = static_cast < int > ( a_NBT . GetByte ( SlotTag ) ) - a_SlotOffset ;
2013-05-26 11:29:43 -04: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[]
}
2017-06-21 01:47:26 -04:00
AString cWSSAnvil : : DecodeSignLine ( const AString & a_Line )
{
if ( a_Line . empty ( ) )
{
return AString ( ) ;
}
if ( a_Line [ 0 ] ! = ' { ' )
{
return a_Line ;
}
// Try to parse the JSON:
Json : : Value root ;
Json : : Reader reader ;
if ( ! reader . parse ( a_Line , root , false ) | | ! root . isObject ( ) )
{
return a_Line ;
}
const auto & txt = root [ " text " ] ;
if ( txt . isString ( ) )
{
return txt . asString ( ) ;
}
return a_Line ;
}
bool cWSSAnvil : : CheckBlockEntityType ( const cParsedNBT & a_NBT , int a_TagIdx , const AStringVector & a_ExpectedTypes , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-07-30 16:50:34 -04:00
{
2014-08-29 12:19:27 -04:00
// Check if the given tag is a compound:
if ( a_NBT . GetType ( a_TagIdx ) ! = TAG_Compound )
2014-07-30 16:50:34 -04:00
{
2014-08-29 12:19:27 -04:00
return false ;
}
// Get the "id" tag:
int TagID = a_NBT . FindChildByName ( a_TagIdx , " id " ) ;
if ( TagID < 0 )
{
return false ;
}
// Compare the value:
2017-06-21 01:47:26 -04:00
for ( const auto & et : a_ExpectedTypes )
2014-08-29 12:19:27 -04:00
{
2017-06-21 01:47:26 -04:00
if ( strncmp ( a_NBT . GetData ( TagID ) , et . c_str ( ) , static_cast < size_t > ( a_NBT . GetDataLength ( TagID ) ) ) = = 0 )
{
return true ;
}
}
// Expectation not met, output an error into the log:
AString expectedTypes ;
for ( const auto & et : a_ExpectedTypes )
{
expectedTypes . append ( " , \" " ) ;
expectedTypes . append ( et ) ;
expectedTypes . push_back ( ' \" ' ) ;
2014-08-29 12:19:27 -04:00
}
2017-06-21 01:47:26 -04:00
LOGWARNING ( " Block entity type mismatch: exp %s, got \" %s \" . The block entity at {%d, %d, %d} will lose all its properties. " ,
expectedTypes . c_str ( ) + 2 , // Skip the first ", " that is extra in the string
2017-06-15 09:32:33 -04:00
AString ( a_NBT . GetData ( TagID ) , static_cast < size_t > ( a_NBT . GetDataLength ( TagID ) ) ) . c_str ( ) ,
a_BlockX , a_BlockY , a_BlockZ
2014-08-29 12:19:27 -04:00
) ;
return false ;
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadBeaconFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-08-29 12:19:27 -04:00
{
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Beacon " , " minecraft:beacon " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2014-08-29 12:19:27 -04:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2014-07-30 16:50:34 -04:00
}
2017-06-15 09:32:33 -04:00
auto Beacon = cpp14 : : make_unique < cBeaconEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2014-07-30 16:50:34 -04:00
int CurrentLine = a_NBT . FindChildByName ( a_TagIdx , " Levels " ) ;
if ( CurrentLine > = 0 )
{
2015-07-29 11:04:03 -04:00
Beacon - > SetBeaconLevel ( static_cast < char > ( a_NBT . GetInt ( CurrentLine ) ) ) ;
2014-07-30 16:50:34 -04:00
}
CurrentLine = a_NBT . FindChildByName ( a_TagIdx , " Primary " ) ;
if ( CurrentLine > = 0 )
{
2015-07-29 11:04:03 -04:00
Beacon - > SetPrimaryEffect ( static_cast < cEntityEffect : : eType > ( a_NBT . GetInt ( CurrentLine ) ) ) ;
2014-07-30 16:50:34 -04:00
}
CurrentLine = a_NBT . FindChildByName ( a_TagIdx , " Secondary " ) ;
if ( CurrentLine > = 0 )
{
2015-07-29 11:04:03 -04:00
Beacon - > SetSecondaryEffect ( static_cast < cEntityEffect : : eType > ( a_NBT . GetInt ( CurrentLine ) ) ) ;
2014-07-30 16:50:34 -04:00
}
2015-05-09 03:25:09 -04:00
// We are better than mojang, we load / save the beacon inventory!
2014-07-30 16:50:34 -04: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 12:19:27 -04:00
return Beacon . release ( ) ;
2014-07-30 16:50:34 -04:00
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadBrewingstandFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2015-09-24 04:48:33 -04:00
{
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Brewingstand " , " minecraft:brewing_stand " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2015-09-24 04:48:33 -04:00
{
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
}
2017-06-15 09:32:33 -04:00
auto Brewingstand = cpp14 : : make_unique < cBrewingstandEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2015-09-24 04:48:33 -04:00
2017-05-05 05:58:21 -04:00
// Fuel has to be loaded at first, because of slot events:
int Fuel = a_NBT . FindChildByName ( a_TagIdx , " Fuel " ) ;
if ( Fuel > = 0 )
{
Int16 tb = a_NBT . GetShort ( Fuel ) ;
Brewingstand - > SetRemainingFuel ( tb ) ;
}
2015-09-24 04:48:33 -04:00
// 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 ) ;
2017-05-05 05:58:21 -04:00
Brewingstand - > SetTimeBrewed ( tb ) ;
2015-09-24 04:48:33 -04:00
}
// Restart brewing:
2017-05-05 05:58:21 -04:00
Brewingstand - > LoadRecipes ( ) ;
2015-09-24 04:48:33 -04:00
Brewingstand - > ContinueBrewing ( ) ;
return Brewingstand . release ( ) ;
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadChestFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-06-14 09:06:06 -04:00
{
2014-08-29 12:19:27 -04:00
// Check if the data has a proper type:
2016-11-07 15:16:55 -05:00
// Note that older Cuberite code used "TrappedChest" for trapped chests; new code mimics vanilla and uses "Chest" throughout, but we allow migration here:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Chest " , " TrappedChest " , " minecraft:chest " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2016-11-07 15:16:55 -05:00
{
return nullptr ;
}
2014-08-29 12:19:27 -04:00
2012-06-14 09:06:06 -04:00
int Items = a_NBT . FindChildByName ( a_TagIdx , " Items " ) ;
if ( ( Items < 0 ) | | ( a_NBT . GetType ( Items ) ! = TAG_List ) )
{
2014-10-20 16:55:07 -04:00
return nullptr ; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
2012-06-14 09:06:06 -04:00
}
2017-06-15 09:32:33 -04:00
auto Chest = cpp14 : : make_unique < cChestEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2013-05-26 11:29:43 -04:00
LoadItemGridFromNBT ( Chest - > GetContents ( ) , a_NBT , Items ) ;
2014-08-29 12:19:27 -04:00
return Chest . release ( ) ;
2012-06-14 09:06:06 -04:00
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadCommandBlockFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-12-19 16:19:36 -05:00
{
2014-08-29 12:19:27 -04:00
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Control " , " minecraft:command_block " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2012-12-19 16:19:36 -05:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2014-08-29 12:19:27 -04:00
}
2017-06-15 09:32:33 -04:00
auto CmdBlock = cpp14 : : make_unique < cCommandBlockEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2014-08-29 12:19:27 -04: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 11:04:03 -04:00
CmdBlock - > SetResult ( static_cast < NIBBLETYPE > ( a_NBT . GetInt ( currentLine ) ) ) ;
2014-08-29 12:19:27 -04: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 ( ) ;
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadDispenserFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-08-29 12:19:27 -04:00
{
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Trap " , " minecraft:dispenser " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2014-08-29 12:19:27 -04:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-12-19 16:19:36 -05:00
}
2014-08-29 12:19:27 -04:00
2012-12-19 16:19:36 -05:00
int Items = a_NBT . FindChildByName ( a_TagIdx , " Items " ) ;
if ( ( Items < 0 ) | | ( a_NBT . GetType ( Items ) ! = TAG_List ) )
{
2014-10-20 16:55:07 -04:00
return nullptr ; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this
2012-12-19 16:19:36 -05:00
}
2017-06-15 09:32:33 -04:00
auto Dispenser = cpp14 : : make_unique < cDispenserEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2013-05-26 11:29:43 -04:00
LoadItemGridFromNBT ( Dispenser - > GetContents ( ) , a_NBT , Items ) ;
2014-08-29 12:19:27 -04:00
return Dispenser . release ( ) ;
2012-12-19 16:19:36 -05:00
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadDropperFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2013-05-26 11:29:43 -04:00
{
2014-08-29 12:19:27 -04:00
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Dropper " , " minecraft:dropper " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2013-05-26 11:29:43 -04:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2013-05-26 11:29:43 -04:00
}
2014-08-29 12:19:27 -04:00
2013-05-26 11:29:43 -04:00
int Items = a_NBT . FindChildByName ( a_TagIdx , " Items " ) ;
if ( ( Items < 0 ) | | ( a_NBT . GetType ( Items ) ! = TAG_List ) )
{
2014-10-20 16:55:07 -04:00
return nullptr ; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this
2013-05-26 11:29:43 -04:00
}
2017-06-15 09:32:33 -04:00
auto Dropper = cpp14 : : make_unique < cDropperEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2013-05-26 11:29:43 -04:00
LoadItemGridFromNBT ( Dropper - > GetContents ( ) , a_NBT , Items ) ;
2014-08-29 12:19:27 -04:00
return Dropper . release ( ) ;
2013-05-26 11:29:43 -04:00
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadFlowerPotFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-03-06 19:30:34 -05:00
{
2014-08-29 12:19:27 -04:00
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " FlowerPot " , " minecraft:flower_pot " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2014-03-06 19:30:34 -05:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2014-03-06 19:30:34 -05:00
}
2014-08-29 12:19:27 -04:00
2017-06-15 09:32:33 -04:00
auto FlowerPot = cpp14 : : make_unique < cFlowerPotEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2015-02-18 17:33:27 -05:00
cItem Item ;
2014-03-06 19:30:34 -05:00
int currentLine = a_NBT . FindChildByName ( a_TagIdx , " Item " ) ;
if ( currentLine > = 0 )
{
2015-02-18 17:33:27 -05: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 11:04:03 -04:00
Item . m_ItemType = static_cast < short > ( a_NBT . GetInt ( currentLine ) ) ;
2015-02-18 17:33:27 -05:00
}
2014-03-06 19:30:34 -05:00
}
currentLine = a_NBT . FindChildByName ( a_TagIdx , " Data " ) ;
2015-02-18 17:33:27 -05:00
if ( ( currentLine > = 0 ) & & ( a_NBT . GetType ( currentLine ) = = TAG_Int ) )
2014-03-06 19:30:34 -05:00
{
2015-07-29 11:04:03 -04:00
Item . m_ItemDamage = static_cast < short > ( a_NBT . GetInt ( currentLine ) ) ;
2014-03-06 19:30:34 -05:00
}
2015-02-18 17:33:27 -05:00
FlowerPot - > SetItem ( Item ) ;
2014-08-29 12:19:27 -04:00
return FlowerPot . release ( ) ;
2014-03-06 19:30:34 -05:00
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadFurnaceFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-06-14 09:06:06 -04:00
{
2014-08-29 12:19:27 -04:00
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Furnace " , " minecraft:furnace " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2012-06-14 09:06:06 -04:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-06-14 09:06:06 -04:00
}
2014-08-29 12:19:27 -04:00
2012-06-14 09:06:06 -04:00
int Items = a_NBT . FindChildByName ( a_TagIdx , " Items " ) ;
if ( ( Items < 0 ) | | ( a_NBT . GetType ( Items ) ! = TAG_List ) )
{
2014-10-20 16:55:07 -04:00
return nullptr ; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this
2012-06-14 09:06:06 -04:00
}
2016-02-05 16:45:45 -05:00
2017-06-15 09:32:33 -04:00
auto Furnace = cpp14 : : make_unique < cFurnaceEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2015-06-02 20:26:21 -04:00
Furnace - > SetLoading ( true ) ;
2013-06-20 07:41:44 -04:00
// Load slots:
2012-06-14 09:06:06 -04: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 09:35:43 -05:00
if ( LoadItemFromNBT ( Item , a_NBT , Child ) )
2012-06-14 09:06:06 -04:00
{
2013-03-09 09:35:43 -05:00
Furnace - > SetSlot ( a_NBT . GetByte ( Slot ) , Item ) ;
2012-06-14 09:06:06 -04:00
}
} // for itr - ItemDefs[]
2016-02-05 16:45:45 -05:00
2013-06-20 07:41:44 -04:00
// Load burn time:
2012-06-14 09:06:06 -04: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 16:24:07 -04:00
Furnace - > SetBurnTimes ( bt , 0 ) ;
2012-06-14 09:06:06 -04:00
}
2016-02-05 16:45:45 -05:00
2013-06-20 07:41:44 -04:00
// Load cook time:
2012-06-14 09:06:06 -04:00
int CookTime = a_NBT . FindChildByName ( a_TagIdx , " CookTime " ) ;
if ( CookTime > = 0 )
{
Int16 ct = a_NBT . GetShort ( CookTime ) ;
2013-06-16 16:24:07 -04: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 09:06:06 -04:00
}
2013-06-20 07:41:44 -04:00
// Restart cooking:
2012-06-14 09:06:06 -04:00
Furnace - > ContinueCooking ( ) ;
2015-06-02 20:26:21 -04:00
Furnace - > SetLoading ( false ) ;
2014-08-29 12:19:27 -04:00
return Furnace . release ( ) ;
2012-06-14 09:06:06 -04:00
}
2017-06-21 01:47:26 -04:00
cBlockEntity * cWSSAnvil : : LoadHopperFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
{
// Check if the data has a proper type:
static const AStringVector expectedTypes ( { " Hopper " , " minecraft:hopper " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
{
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 hopper - the chunk loader will provide an empty cHopperEntity for this
}
auto Hopper = cpp14 : : make_unique < cHopperEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
LoadItemGridFromNBT ( Hopper - > GetContents ( ) , a_NBT , Items ) ;
return Hopper . release ( ) ;
}
cBlockEntity * cWSSAnvil : : LoadJukeboxFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
{
// Check if the data has a proper type:
static const AStringVector expectedTypes ( { " RecordPlayer " , " minecraft:jukebox " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
{
return nullptr ;
}
auto Jukebox = cpp14 : : make_unique < cJukeboxEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
int Record = a_NBT . FindChildByName ( a_TagIdx , " Record " ) ;
if ( Record > = 0 )
{
Jukebox - > SetRecord ( a_NBT . GetInt ( Record ) ) ;
}
return Jukebox . release ( ) ;
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadMobSpawnerFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-11-18 09:33:41 -05:00
{
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " MobSpawner " , " minecraft:mob_spawner " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2014-11-18 09:33:41 -05:00
{
return nullptr ;
}
2017-06-15 09:32:33 -04:00
auto MobSpawner = cpp14 : : make_unique < cMobSpawnerEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2014-11-18 09:33:41 -05:00
2015-09-25 04:14:17 -04:00
// Load entity (Cuberite worlds):
2014-11-18 09:33:41 -05: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 ( ) ;
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadMobHeadFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2012-10-21 03:46:28 -04:00
{
2014-08-29 12:19:27 -04:00
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Skull " , " minecraft:skull " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2012-10-21 03:46:28 -04:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2012-10-21 03:46:28 -04:00
}
2013-06-13 03:36:43 -04:00
2017-06-15 09:32:33 -04:00
auto MobHead = cpp14 : : make_unique < cMobHeadEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2013-06-13 03:36:43 -04:00
2014-08-29 12:19:27 -04:00
int currentLine = a_NBT . FindChildByName ( a_TagIdx , " SkullType " ) ;
2013-06-13 03:36:43 -04:00
if ( currentLine > = 0 )
{
2014-08-29 12:19:27 -04:00
MobHead - > SetType ( static_cast < eMobHeadType > ( a_NBT . GetByte ( currentLine ) ) ) ;
2013-06-13 03:36:43 -04:00
}
2014-08-29 12:19:27 -04:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , " Rot " ) ;
2013-06-13 03:36:43 -04:00
if ( currentLine > = 0 )
{
2014-08-29 12:19:27 -04:00
MobHead - > SetRotation ( static_cast < eMobHeadRotation > ( a_NBT . GetByte ( currentLine ) ) ) ;
2013-06-13 03:36:43 -04:00
}
2016-01-11 11:55:32 -05:00
int ownerLine = a_NBT . FindChildByName ( a_TagIdx , " Owner " ) ;
if ( ownerLine > = 0 )
2013-06-13 03:36:43 -04:00
{
2016-01-11 11:55:32 -05:00
AString OwnerName , OwnerUUID , OwnerTexture , OwnerTextureSignature ;
currentLine = a_NBT . FindChildByName ( ownerLine , " Id " ) ;
if ( currentLine > = 0 )
{
OwnerUUID = a_NBT . GetString ( currentLine ) ;
}
currentLine = a_NBT . FindChildByName ( ownerLine , " Name " ) ;
if ( currentLine > = 0 )
{
OwnerName = a_NBT . GetString ( currentLine ) ;
}
int textureLine = a_NBT . GetFirstChild ( // The first texture of
a_NBT . FindChildByName ( // The texture list of
a_NBT . FindChildByName ( // The Properties compound of
ownerLine , // The Owner compound
" Properties "
) ,
" textures "
)
) ;
if ( textureLine > = 0 )
{
currentLine = a_NBT . FindChildByName ( textureLine , " Signature " ) ;
if ( currentLine > = 0 )
{
OwnerTextureSignature = a_NBT . GetString ( currentLine ) ;
}
currentLine = a_NBT . FindChildByName ( textureLine , " Value " ) ;
if ( currentLine > = 0 )
{
OwnerTexture = a_NBT . GetString ( currentLine ) ;
}
}
MobHead - > SetOwner ( OwnerUUID , OwnerName , OwnerTexture , OwnerTextureSignature ) ;
2013-06-13 03:36:43 -04:00
}
2014-08-29 12:19:27 -04:00
return MobHead . release ( ) ;
2012-10-21 03:46:28 -04:00
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadNoteBlockFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-02-17 14:14:08 -05:00
{
2014-08-29 12:19:27 -04:00
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Music " , " minecraft:noteblock " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2014-02-17 14:14:08 -05:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2014-02-17 14:14:08 -05:00
}
2017-06-15 09:32:33 -04:00
auto NoteBlock = cpp14 : : make_unique < cNoteEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2014-08-29 12:19:27 -04:00
int note = a_NBT . FindChildByName ( a_TagIdx , " note " ) ;
if ( note > = 0 )
2014-02-17 14:14:08 -05:00
{
2015-07-29 11:04:03 -04:00
NoteBlock - > SetPitch ( static_cast < char > ( a_NBT . GetByte ( note ) ) ) ;
2014-02-17 14:14:08 -05:00
}
2014-08-29 12:19:27 -04:00
return NoteBlock . release ( ) ;
2014-02-17 14:14:08 -05:00
}
2017-06-15 09:32:33 -04:00
cBlockEntity * cWSSAnvil : : LoadSignFromNBT ( const cParsedNBT & a_NBT , int a_TagIdx , BLOCKTYPE a_BlockType , NIBBLETYPE a_BlockMeta , int a_BlockX , int a_BlockY , int a_BlockZ )
2014-01-18 08:40:47 -05:00
{
2014-08-29 12:19:27 -04:00
// Check if the data has a proper type:
2017-06-21 01:47:26 -04:00
static const AStringVector expectedTypes ( { " Sign " , " minecraft:sign " } ) ;
if ( ! CheckBlockEntityType ( a_NBT , a_TagIdx , expectedTypes , a_BlockX , a_BlockY , a_BlockZ ) )
2014-01-18 08:40:47 -05:00
{
2014-10-20 16:55:07 -04:00
return nullptr ;
2014-01-18 08:40:47 -05:00
}
2017-06-15 09:32:33 -04:00
auto Sign = cpp14 : : make_unique < cSignEntity > ( a_BlockType , a_BlockMeta , a_BlockX , a_BlockY , a_BlockZ , m_World ) ;
2014-08-29 12:19:27 -04:00
int currentLine = a_NBT . FindChildByName ( a_TagIdx , " Text1 " ) ;
2014-01-18 08:40:47 -05:00
if ( currentLine > = 0 )
{
2017-06-21 01:47:26 -04:00
Sign - > SetLine ( 0 , DecodeSignLine ( a_NBT . GetString ( currentLine ) ) ) ;
2014-01-18 08:40:47 -05:00
}
2014-08-29 12:19:27 -04:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , " Text2 " ) ;
2014-01-18 08:40:47 -05:00
if ( currentLine > = 0 )
{
2017-06-21 01:47:26 -04:00
Sign - > SetLine ( 1 , DecodeSignLine ( a_NBT . GetString ( currentLine ) ) ) ;
2014-01-18 08:40:47 -05:00
}
2014-08-29 12:19:27 -04:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , " Text3 " ) ;
2014-01-18 08:40:47 -05:00
if ( currentLine > = 0 )
{
2017-06-21 01:47:26 -04:00
Sign - > SetLine ( 2 , DecodeSignLine ( a_NBT . GetString ( currentLine ) ) ) ;
2014-01-18 08:40:47 -05:00
}
2014-08-29 12:19:27 -04:00
currentLine = a_NBT . FindChildByName ( a_TagIdx , " Text4 " ) ;
if ( currentLine > = 0 )
{
2017-06-21 01:47:26 -04:00
Sign - > SetLine ( 3 , DecodeSignLine ( a_NBT . GetString ( currentLine ) ) ) ;
2014-08-29 12:19:27 -04:00
}
2014-01-18 08:40:47 -05:00
2014-08-29 12:19:27 -04:00
return Sign . release ( ) ;
2014-01-18 08:40:47 -05:00
}
2014-05-09 13:33:22 -04: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 09:35:43 -05:00
{
2017-06-22 11:30:11 -04:00
typedef void ( cWSSAnvil : : * EntityLoaderFunc ) ( cEntityList & , const cParsedNBT & , int a_EntityTagIdx ) ;
typedef std : : map < AString , EntityLoaderFunc > EntityLoaderMap ;
static const EntityLoaderMap EntityTypeToFunction
{
{ " Boat " , & cWSSAnvil : : LoadBoatFromNBT } ,
{ " minecraft:boat " , & cWSSAnvil : : LoadBoatFromNBT } ,
{ " EnderCrystal " , & cWSSAnvil : : LoadEnderCrystalFromNBT } ,
{ " minecraft:ender_crystal " , & cWSSAnvil : : LoadEnderCrystalFromNBT } ,
{ " FallingBlock " , & cWSSAnvil : : LoadFallingBlockFromNBT } ,
{ " minecraft:falling_block " , & cWSSAnvil : : LoadFallingBlockFromNBT } ,
{ " Minecart " , & cWSSAnvil : : LoadOldMinecartFromNBT } ,
{ " MinecartChest " , & cWSSAnvil : : LoadMinecartCFromNBT } ,
{ " minecraft:chest_minecart " , & cWSSAnvil : : LoadMinecartCFromNBT } ,
{ " MinecartFurnace " , & cWSSAnvil : : LoadMinecartFFromNBT } ,
{ " minecraft:furnace_minecart " , & cWSSAnvil : : LoadMinecartFFromNBT } ,
{ " MinecartTNT " , & cWSSAnvil : : LoadMinecartTFromNBT } ,
{ " minecraft:tnt_minecart " , & cWSSAnvil : : LoadMinecartTFromNBT } ,
{ " MinecartHopper " , & cWSSAnvil : : LoadMinecartHFromNBT } ,
{ " minecraft:hopper_minecart " , & cWSSAnvil : : LoadMinecartHFromNBT } ,
{ " MinecartRideable " , & cWSSAnvil : : LoadMinecartRFromNBT } ,
{ " minecraft:minecart " , & cWSSAnvil : : LoadMinecartRFromNBT } ,
{ " Item " , & cWSSAnvil : : LoadPickupFromNBT } ,
{ " minecraft:item " , & cWSSAnvil : : LoadPickupFromNBT } ,
{ " Painting " , & cWSSAnvil : : LoadPaintingFromNBT } ,
{ " minecraft:painting " , & cWSSAnvil : : LoadPaintingFromNBT } ,
{ " PrimedTnt " , & cWSSAnvil : : LoadTNTFromNBT } ,
{ " minecraft:tnt " , & cWSSAnvil : : LoadTNTFromNBT } ,
{ " XPOrb " , & cWSSAnvil : : LoadExpOrbFromNBT } ,
{ " minecraft:xp_orb " , & cWSSAnvil : : LoadExpOrbFromNBT } ,
{ " ItemFrame " , & cWSSAnvil : : LoadItemFrameFromNBT } ,
{ " minecraft:item_frame " , & cWSSAnvil : : LoadItemFrameFromNBT } ,
{ " Arrow " , & cWSSAnvil : : LoadArrowFromNBT } ,
{ " minecraft:arrow " , & cWSSAnvil : : LoadArrowFromNBT } ,
{ " SplashPotion " , & cWSSAnvil : : LoadSplashPotionFromNBT } ,
{ " minecraft:potion " , & cWSSAnvil : : LoadSplashPotionFromNBT } ,
{ " Snowball " , & cWSSAnvil : : LoadSnowballFromNBT } ,
{ " minecraft:snowball " , & cWSSAnvil : : LoadSnowballFromNBT } ,
{ " Egg " , & cWSSAnvil : : LoadEggFromNBT } ,
{ " minecraft:egg " , & cWSSAnvil : : LoadEggFromNBT } ,
{ " Fireball " , & cWSSAnvil : : LoadFireballFromNBT } ,
{ " minecraft:fireball " , & cWSSAnvil : : LoadFireballFromNBT } ,
{ " SmallFireball " , & cWSSAnvil : : LoadFireChargeFromNBT } ,
{ " minecraft:small_fireball " , & cWSSAnvil : : LoadFireChargeFromNBT } ,
{ " ThrownEnderpearl " , & cWSSAnvil : : LoadThrownEnderpearlFromNBT } ,
{ " minecraft:ender_pearl " , & cWSSAnvil : : LoadThrownEnderpearlFromNBT } ,
{ " Bat " , & cWSSAnvil : : LoadBatFromNBT } ,
{ " minecraft:bat " , & cWSSAnvil : : LoadBatFromNBT } ,
{ " Blaze " , & cWSSAnvil : : LoadBlazeFromNBT } ,
{ " minecraft:blaze " , & cWSSAnvil : : LoadBlazeFromNBT } ,
{ " CaveSpider " , & cWSSAnvil : : LoadCaveSpiderFromNBT } ,
{ " minecraft:cave_spider " , & cWSSAnvil : : LoadCaveSpiderFromNBT } ,
{ " Chicken " , & cWSSAnvil : : LoadChickenFromNBT } ,
{ " minecraft:chicken " , & cWSSAnvil : : LoadChickenFromNBT } ,
{ " Cow " , & cWSSAnvil : : LoadCowFromNBT } ,
{ " minecraft:cow " , & cWSSAnvil : : LoadCowFromNBT } ,
{ " Creeper " , & cWSSAnvil : : LoadCreeperFromNBT } ,
{ " minecraft:creeper " , & cWSSAnvil : : LoadCreeperFromNBT } ,
{ " EnderDragon " , & cWSSAnvil : : LoadEnderDragonFromNBT } ,
{ " minecraft:ender_dragon " , & cWSSAnvil : : LoadEnderDragonFromNBT } ,
{ " Enderman " , & cWSSAnvil : : LoadEndermanFromNBT } ,
{ " minecraft:enderman " , & cWSSAnvil : : LoadEndermanFromNBT } ,
{ " Ghast " , & cWSSAnvil : : LoadGhastFromNBT } ,
{ " minecraft:ghast " , & cWSSAnvil : : LoadGhastFromNBT } ,
{ " Giant " , & cWSSAnvil : : LoadGiantFromNBT } ,
{ " minecraft:giant " , & cWSSAnvil : : LoadGiantFromNBT } ,
{ " Guardian " , & cWSSAnvil : : LoadGuardianFromNBT } ,
{ " minecraft:guardian " , & cWSSAnvil : : LoadGuardianFromNBT } ,
{ " Horse " , & cWSSAnvil : : LoadHorseFromNBT } ,
{ " minecraft:horse " , & cWSSAnvil : : LoadHorseFromNBT } ,
{ " Villager " , & cWSSAnvil : : LoadVillagerFromNBT } ,
{ " minecraft:villager " , & cWSSAnvil : : LoadVillagerFromNBT } ,
{ " VillagerGolem " , & cWSSAnvil : : LoadIronGolemFromNBT } ,
{ " minecraft:villager_golem " , & cWSSAnvil : : LoadIronGolemFromNBT } ,
{ " LavaSlime " , & cWSSAnvil : : LoadMagmaCubeFromNBT } ,
{ " minecraft:magma_cube " , & cWSSAnvil : : LoadMagmaCubeFromNBT } ,
{ " MushroomCow " , & cWSSAnvil : : LoadMooshroomFromNBT } ,
{ " minecraft:mooshroom " , & cWSSAnvil : : LoadMooshroomFromNBT } ,
{ " Ozelot " , & cWSSAnvil : : LoadOcelotFromNBT } ,
{ " minecraft:ocelot " , & cWSSAnvil : : LoadOcelotFromNBT } ,
{ " Pig " , & cWSSAnvil : : LoadPigFromNBT } ,
{ " minecraft:pig " , & cWSSAnvil : : LoadPigFromNBT } ,
{ " Rabbit " , & cWSSAnvil : : LoadRabbitFromNBT } ,
{ " minecraft:rabbit " , & cWSSAnvil : : LoadRabbitFromNBT } ,
{ " Sheep " , & cWSSAnvil : : LoadSheepFromNBT } ,
{ " minecraft:sheep " , & cWSSAnvil : : LoadSheepFromNBT } ,
{ " Silverfish " , & cWSSAnvil : : LoadSilverfishFromNBT } ,
{ " minecraft:silverfish " , & cWSSAnvil : : LoadSilverfishFromNBT } ,
{ " Skeleton " , & cWSSAnvil : : LoadSkeletonFromNBT } ,
{ " minecraft:skeleton " , & cWSSAnvil : : LoadSkeletonFromNBT } ,
{ " Slime " , & cWSSAnvil : : LoadSlimeFromNBT } ,
{ " minecraft:slime " , & cWSSAnvil : : LoadSlimeFromNBT } ,
{ " SnowMan " , & cWSSAnvil : : LoadSnowGolemFromNBT } ,
{ " minecraft:snowman " , & cWSSAnvil : : LoadSnowGolemFromNBT } ,
{ " Spider " , & cWSSAnvil : : LoadSpiderFromNBT } ,
{ " minecraft:spider " , & cWSSAnvil : : LoadSpiderFromNBT } ,
{ " Squid " , & cWSSAnvil : : LoadSquidFromNBT } ,
{ " minecraft:squid " , & cWSSAnvil : : LoadSquidFromNBT } ,
{ " Witch " , & cWSSAnvil : : LoadWitchFromNBT } ,
{ " minecraft:witch " , & cWSSAnvil : : LoadWitchFromNBT } ,
{ " WitherBoss " , & cWSSAnvil : : LoadWitherFromNBT } ,
{ " minecraft:wither " , & cWSSAnvil : : LoadWitherFromNBT } ,
{ " Wolf " , & cWSSAnvil : : LoadWolfFromNBT } ,
{ " minecraft:wolf " , & cWSSAnvil : : LoadWolfFromNBT } ,
{ " Zombie " , & cWSSAnvil : : LoadZombieFromNBT } ,
{ " minecraft:zombie " , & cWSSAnvil : : LoadZombieFromNBT } ,
{ " PigZombie " , & cWSSAnvil : : LoadPigZombieFromNBT } ,
{ " minecraft:zombie_pigman " , & cWSSAnvil : : LoadPigZombieFromNBT } ,
} ;
auto it = EntityTypeToFunction . find ( AString ( a_IDTag , a_IDTagLength ) ) ;
if ( it ! = EntityTypeToFunction . end ( ) )
{
( this - > * it - > second ) ( a_Entities , a_NBT , a_EntityTagIdx ) ;
2013-12-25 11:07:52 -05:00
}
2017-06-22 11:30:11 -04:00
// TODO: other entities
}
void cWSSAnvil : : LoadOldMinecartFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
// It is a minecart, old style, find out the type:
int TypeTag = a_NBT . FindChildByName ( a_TagIdx , " Type " ) ;
if ( ( TypeTag < 0 ) | | ( a_NBT . GetType ( TypeTag ) ! = TAG_Int ) )
2013-12-25 11:07:52 -05:00
{
2017-06-22 11:30:11 -04:00
return ;
2013-12-25 11:07:52 -05:00
}
2017-06-22 11:30:11 -04:00
switch ( a_NBT . GetInt ( TypeTag ) )
2013-12-25 11:07:52 -05:00
{
2017-06-22 11:30:11 -04:00
case 0 : LoadMinecartRFromNBT ( a_Entities , a_NBT , a_TagIdx ) ; break ; // Rideable minecart
case 1 : LoadMinecartCFromNBT ( a_Entities , a_NBT , a_TagIdx ) ; break ; // Minecart with chest
case 2 : LoadMinecartFFromNBT ( a_Entities , a_NBT , a_TagIdx ) ; break ; // Minecart with furnace
case 3 : LoadMinecartTFromNBT ( a_Entities , a_NBT , a_TagIdx ) ; break ; // Minecart with TNT
case 4 : LoadMinecartHFromNBT ( a_Entities , a_NBT , a_TagIdx ) ; break ; // Minecart with Hopper
2013-12-25 11:07:52 -05:00
}
2013-03-09 09:35:43 -05:00
}
2013-09-07 19:14:57 -04:00
void cWSSAnvil : : LoadBoatFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2017-05-09 08:21:25 -04:00
std : : unique_ptr < cBoat > Boat = cpp14 : : make_unique < cBoat > ( 0 , 0 , 0 , cBoat : : bmOak ) ;
2013-09-07 19:14:57 -04:00
if ( ! LoadEntityBaseFromNBT ( * Boat . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2017-05-09 08:21:25 -04:00
int TypeIdx = a_NBT . FindChildByName ( a_TagIdx , " Type " ) ;
if ( TypeIdx > 0 )
{
Boat - > SetMaterial ( cBoat : : StringToMaterial ( a_NBT . GetString ( TypeIdx ) ) ) ;
}
2013-09-07 19:14:57 -04:00
a_Entities . push_back ( Boat . release ( ) ) ;
}
2014-03-25 14:59:33 -04:00
void cWSSAnvil : : LoadEnderCrystalFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cEnderCrystal > EnderCrystal = cpp14 : : make_unique < cEnderCrystal > ( 0 , 0 , 0 ) ;
2014-03-25 14:59:33 -04:00
if ( ! LoadEntityBaseFromNBT ( * EnderCrystal . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
a_Entities . push_back ( EnderCrystal . release ( ) ) ;
}
2013-03-09 09:35:43 -05:00
void cWSSAnvil : : LoadFallingBlockFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2013-12-25 11:07:52 -05:00
int TypeIdx = a_NBT . FindChildByName ( a_TagIdx , " TileID " ) ;
int MetaIdx = a_NBT . FindChildByName ( a_TagIdx , " Data " ) ;
2014-12-05 10:59:11 -05:00
if ( ( TypeIdx < 0 ) | | ( MetaIdx < 0 ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
2015-07-31 10:49:10 -04:00
BLOCKTYPE Type = static_cast < BLOCKTYPE > ( a_NBT . GetInt ( TypeIdx ) ) ;
2015-07-29 11:04:03 -04:00
NIBBLETYPE Meta = static_cast < NIBBLETYPE > ( a_NBT . GetByte ( MetaIdx ) ) ;
2013-12-25 11:07:52 -05:00
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cFallingBlock > FallingBlock = cpp14 : : make_unique < cFallingBlock > ( Vector3i ( 0 , 0 , 0 ) , Type , Meta ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * FallingBlock . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
a_Entities . push_back ( FallingBlock . release ( ) ) ;
2013-03-09 09:35:43 -05:00
}
void cWSSAnvil : : LoadMinecartRFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04: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 15:08:39 -05:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
a_Entities . push_back ( Minecart . release ( ) ) ;
2013-03-09 09:35:43 -05:00
}
void cWSSAnvil : : LoadMinecartCFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2013-03-09 15:08:39 -05: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 14:58:19 -04:00
std : : unique_ptr < cMinecartWithChest > Minecart = cpp14 : : make_unique < cMinecartWithChest > ( 0 , 0 , 0 ) ;
2013-03-09 15:08:39 -05: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 09:35:43 -05:00
}
void cWSSAnvil : : LoadMinecartFFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cMinecartWithFurnace > Minecart = cpp14 : : make_unique < cMinecartWithFurnace > ( 0 , 0 , 0 ) ;
2013-03-09 15:08:39 -05:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-03-09 15:08:39 -05:00
// TODO: Load the Push and Fuel tags
2016-02-05 16:45:45 -05:00
2013-03-09 15:08:39 -05:00
a_Entities . push_back ( Minecart . release ( ) ) ;
2013-03-09 09:35:43 -05:00
}
2013-08-16 08:04:06 -04:00
void cWSSAnvil : : LoadMinecartTFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cMinecartWithTNT > Minecart = cpp14 : : make_unique < cMinecartWithTNT > ( 0 , 0 , 0 ) ;
2013-08-16 08:04:06 -04:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-08-25 15:32:17 -04:00
// TODO: Everything to do with TNT carts
2013-08-16 08:04:06 -04:00
a_Entities . push_back ( Minecart . release ( ) ) ;
}
void cWSSAnvil : : LoadMinecartHFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cMinecartWithHopper > Minecart = cpp14 : : make_unique < cMinecartWithHopper > ( 0 , 0 , 0 ) ;
2013-08-16 08:04:06 -04:00
if ( ! LoadEntityBaseFromNBT ( * Minecart . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-08-25 15:32:17 -04:00
// TODO: Everything to do with hopper carts
2013-08-16 08:04:06 -04:00
a_Entities . push_back ( Minecart . release ( ) ) ;
}
2013-03-09 09:35:43 -05:00
void cWSSAnvil : : LoadPickupFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2014-03-14 19:43:38 -04:00
// Load item:
2013-03-09 09:35:43 -05: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 ;
}
2016-02-05 16:45:45 -05:00
2015-07-12 14:58:19 -04: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 09:35:43 -05:00
if ( ! LoadEntityBaseFromNBT ( * Pickup . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-03-14 19:43:38 -04:00
// Load age:
int Age = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( Age > 0 )
{
Pickup - > SetAge ( a_NBT . GetShort ( Age ) ) ;
}
2014-03-14 19:32:49 -04:00
2013-03-09 09:35:43 -05:00
a_Entities . push_back ( Pickup . release ( ) ) ;
}
2014-03-14 19:32:49 -04:00
void cWSSAnvil : : LoadTNTFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cTNTEntity > TNT = cpp14 : : make_unique < cTNTEntity > ( 0.0 , 0.0 , 0.0 , 0 ) ;
2014-03-14 19:32:49 -04:00
if ( ! LoadEntityBaseFromNBT ( * TNT . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-03-14 19:32:49 -04:00
// Load Fuse Ticks:
int FuseTicks = a_NBT . FindChildByName ( a_TagIdx , " Fuse " ) ;
if ( FuseTicks > 0 )
{
2015-07-29 11:04:03 -04:00
TNT - > SetFuseTicks ( static_cast < int > ( a_NBT . GetByte ( FuseTicks ) ) ) ;
2014-03-14 19:32:49 -04:00
}
2016-02-05 16:45:45 -05:00
2014-03-14 19:32:49 -04:00
a_Entities . push_back ( TNT . release ( ) ) ;
}
void cWSSAnvil : : LoadExpOrbFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cExpOrb > ExpOrb = cpp14 : : make_unique < cExpOrb > ( 0.0 , 0.0 , 0.0 , 0 ) ;
2014-03-14 19:32:49 -04: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-14 21:45:25 -04:00
void cWSSAnvil : : LoadHangingFromNBT ( cHangingEntity & a_Hanging , const cParsedNBT & a_NBT , int a_TagIdx )
{
2014-10-21 16:02:30 -04: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 18:29:27 -04:00
if ( Facing < 0 )
2014-03-14 21:45:25 -04:00
{
2015-03-13 18:29:27 -04:00
return ;
2014-03-14 21:45:25 -04:00
}
2015-03-13 18:29:27 -04:00
a_Hanging . SetProtocolFacing ( a_NBT . GetByte ( Facing ) ) ;
2014-03-14 21:45:25 -04: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 18:29:27 -04:00
static_cast < double > ( a_NBT . GetInt ( TileX ) ) ,
static_cast < double > ( a_NBT . GetInt ( TileY ) ) ,
static_cast < double > ( a_NBT . GetInt ( TileZ ) )
2014-03-14 21:45:25 -04: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 ;
}
2016-02-05 16:45:45 -05:00
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cItemFrame > ItemFrame = cpp14 : : make_unique < cItemFrame > ( BLOCK_FACE_NONE , 0.0 , 0.0 , 0.0 ) ;
2014-03-14 21:45:25 -04:00
if ( ! LoadEntityBaseFromNBT ( * ItemFrame . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
ItemFrame - > SetItem ( Item ) ;
LoadHangingFromNBT ( * ItemFrame . get ( ) , a_NBT , a_TagIdx ) ;
2016-02-05 16:45:45 -05:00
2014-03-14 21:45:25 -04:00
// Load Rotation:
int Rotation = a_NBT . FindChildByName ( a_TagIdx , " ItemRotation " ) ;
if ( Rotation > 0 )
{
2015-07-29 11:04:03 -04:00
ItemFrame - > SetItemRotation ( static_cast < Byte > ( a_NBT . GetByte ( Rotation ) ) ) ;
2014-03-14 21:45:25 -04:00
}
2016-02-05 16:45:45 -05:00
2014-03-14 21:45:25 -04:00
a_Entities . push_back ( ItemFrame . release ( ) ) ;
}
2015-03-13 19:05:06 -04: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 14:58:19 -04: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 19:05:06 -04: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 15:32:17 -04:00
void cWSSAnvil : : LoadArrowFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cArrowEntity > Arrow = cpp14 : : make_unique < cArrowEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ) ) ;
2013-09-07 15:26:17 -04:00
if ( ! LoadProjectileBaseFromNBT ( * Arrow . get ( ) , a_NBT , a_TagIdx ) )
2013-08-25 15:32:17 -04:00
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-08-25 15:32:17 -04:00
// Load pickup state:
int PickupIdx = a_NBT . FindChildByName ( a_TagIdx , " pickup " ) ;
2014-09-25 13:01:44 -04:00
if ( ( PickupIdx > 0 ) & & ( a_NBT . GetType ( PickupIdx ) = = TAG_Byte ) )
2013-08-25 15:32:17 -04:00
{
2015-07-29 11:04:03 -04:00
Arrow - > SetPickupState ( static_cast < cArrowEntity : : ePickupState > ( a_NBT . GetByte ( PickupIdx ) ) ) ;
2013-08-25 15:32:17 -04:00
}
else
{
// Try the older "player" tag:
int PlayerIdx = a_NBT . FindChildByName ( a_TagIdx , " player " ) ;
2014-09-25 13:01:44 -04:00
if ( ( PlayerIdx > 0 ) & & ( a_NBT . GetType ( PlayerIdx ) = = TAG_Byte ) )
2013-08-25 15:32:17 -04:00
{
Arrow - > SetPickupState ( ( a_NBT . GetByte ( PlayerIdx ) = = 0 ) ? cArrowEntity : : psNoPickup : cArrowEntity : : psInSurvivalOrCreative ) ;
}
}
2016-02-05 16:45:45 -05:00
2013-08-25 15:32:17 -04:00
// Load damage:
int DamageIdx = a_NBT . FindChildByName ( a_TagIdx , " damage " ) ;
2014-09-25 13:01:44 -04:00
if ( ( DamageIdx > 0 ) & & ( a_NBT . GetType ( DamageIdx ) = = TAG_Double ) )
2013-08-25 15:32:17 -04:00
{
Arrow - > SetDamageCoeff ( a_NBT . GetDouble ( DamageIdx ) ) ;
}
2016-02-05 16:45:45 -05:00
2014-07-02 16:07:34 -04: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 04:14:11 -05:00
eTagType typeX = a_NBT . GetType ( InBlockXIdx ) ;
if ( ( typeX = = a_NBT . GetType ( InBlockYIdx ) ) & & ( typeX = = a_NBT . GetType ( InBlockZIdx ) ) )
2014-09-25 13:01:44 -04:00
{
2014-11-26 04:14:11 -05:00
switch ( typeX )
2014-09-25 13:01:44 -04: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 10:38:40 -04:00
Arrow - > SetBlockHit ( Vector3i ( a_NBT . GetShort ( InBlockXIdx ) , a_NBT . GetShort ( InBlockYIdx ) , a_NBT . GetShort ( InBlockZIdx ) ) ) ;
2014-09-25 13:01:44 -04:00
break ;
}
2014-11-26 04:14:11 -05:00
default :
{
// No hit block, the arrow is still flying?
break ;
}
2014-09-25 13:01:44 -04:00
}
}
2014-07-02 16:07:34 -04:00
}
2016-02-05 16:45:45 -05:00
2013-08-25 15:32:17 -04:00
// Store the new arrow in the entities list:
a_Entities . push_back ( Arrow . release ( ) ) ;
}
2014-07-11 21:58:11 -04:00
void cWSSAnvil : : LoadSplashPotionFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cSplashPotionEntity > SplashPotion = cpp14 : : make_unique < cSplashPotionEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ) , cItem ( ) ) ;
2014-07-11 21:58:11 -04:00
if ( ! LoadProjectileBaseFromNBT ( * SplashPotion . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-07-11 21:58:11 -04:00
int EffectDuration = a_NBT . FindChildByName ( a_TagIdx , " EffectDuration " ) ;
int EffectIntensity = a_NBT . FindChildByName ( a_TagIdx , " EffectIntensity " ) ;
int EffectDistanceModifier = a_NBT . FindChildByName ( a_TagIdx , " EffectDistanceModifier " ) ;
2016-02-05 16:45:45 -05:00
2015-07-29 11:04:03 -04: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 05:51:39 -04:00
SplashPotion - > SetPotionColor ( a_NBT . FindChildByName ( a_TagIdx , " PotionName " ) ) ;
2016-02-05 16:45:45 -05:00
2014-07-11 21:58:11 -04:00
// Store the new splash potion in the entities list:
a_Entities . push_back ( SplashPotion . release ( ) ) ;
}
2013-08-25 15:32:17 -04:00
2013-09-07 15:26:17 -04:00
void cWSSAnvil : : LoadSnowballFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cThrownSnowballEntity > Snowball = cpp14 : : make_unique < cThrownSnowballEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ) ) ;
2013-09-07 15:26:17 -04:00
if ( ! LoadProjectileBaseFromNBT ( * Snowball . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-09-07 15:26:17 -04:00
// 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 14:58:19 -04:00
std : : unique_ptr < cThrownEggEntity > Egg = cpp14 : : make_unique < cThrownEggEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ) ) ;
2013-09-07 15:26:17 -04:00
if ( ! LoadProjectileBaseFromNBT ( * Egg . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-09-07 15:26:17 -04:00
// 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 14:58:19 -04:00
std : : unique_ptr < cGhastFireballEntity > Fireball = cpp14 : : make_unique < cGhastFireballEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ) ) ;
2013-09-07 15:26:17 -04:00
if ( ! LoadProjectileBaseFromNBT ( * Fireball . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-09-07 15:26:17 -04:00
// 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 14:58:19 -04:00
std : : unique_ptr < cFireChargeEntity > FireCharge = cpp14 : : make_unique < cFireChargeEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ) ) ;
2013-09-07 15:26:17 -04:00
if ( ! LoadProjectileBaseFromNBT ( * FireCharge . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-09-07 15:26:17 -04:00
// 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 14:58:19 -04:00
std : : unique_ptr < cThrownEnderPearlEntity > Enderpearl = cpp14 : : make_unique < cThrownEnderPearlEntity > ( nullptr , 0 , 0 , 0 , Vector3d ( 0 , 0 , 0 ) ) ;
2013-09-07 15:26:17 -04:00
if ( ! LoadProjectileBaseFromNBT ( * Enderpearl . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2013-09-07 15:26:17 -04:00
// Store the new enderpearl in the entities list:
a_Entities . push_back ( Enderpearl . release ( ) ) ;
}
2013-12-25 11:07:52 -05:00
void cWSSAnvil : : LoadBatFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cBat > Monster = cpp14 : : make_unique < cBat > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadBlazeFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cBlaze > Monster = cpp14 : : make_unique < cBlaze > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadCaveSpiderFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cCaveSpider > Monster = cpp14 : : make_unique < cCaveSpider > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadChickenFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cChicken > Monster = cpp14 : : make_unique < cChicken > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadCowFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cCow > Monster = cpp14 : : make_unique < cCow > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadCreeperFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cCreeper > Monster = cpp14 : : make_unique < cCreeper > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadEnderDragonFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cEnderDragon > Monster = cpp14 : : make_unique < cEnderDragon > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadEndermanFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cEnderman > Monster = cpp14 : : make_unique < cEnderman > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadGhastFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cGhast > Monster = cpp14 : : make_unique < cGhast > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadGiantFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cGiant > Monster = cpp14 : : make_unique < cGiant > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
2014-12-18 13:30:32 -05:00
void cWSSAnvil : : LoadGuardianFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cGuardian > Monster = cpp14 : : make_unique < cGuardian > ( ) ;
2014-12-18 13:30:32 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-12-18 13:30:32 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
a_Entities . push_back ( Monster . release ( ) ) ;
}
2013-12-25 11:07:52 -05:00
void cWSSAnvil : : LoadHorseFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2014-12-05 10:59:11 -05:00
int TypeIdx = a_NBT . FindChildByName ( a_TagIdx , " Type " ) ;
2013-12-25 11:07:52 -05:00
int ColorIdx = a_NBT . FindChildByName ( a_TagIdx , " Color " ) ;
int StyleIdx = a_NBT . FindChildByName ( a_TagIdx , " Style " ) ;
2014-12-05 10:59:11 -05:00
if ( ( TypeIdx < 0 ) | | ( ColorIdx < 0 ) | | ( StyleIdx < 0 ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
int Type = a_NBT . GetInt ( TypeIdx ) ;
int Color = a_NBT . GetInt ( ColorIdx ) ;
int Style = a_NBT . GetInt ( StyleIdx ) ;
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cHorse > Monster = cpp14 : : make_unique < cHorse > ( Type , Color , Style , 1 ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadIronGolemFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cIronGolem > Monster = cpp14 : : make_unique < cIronGolem > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05: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 06:43:21 -04:00
if ( SizeIdx < 0 )
{
return ;
}
2013-12-25 11:07:52 -05:00
int Size = a_NBT . GetInt ( SizeIdx ) ;
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cMagmaCube > Monster = cpp14 : : make_unique < cMagmaCube > ( Size ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadMooshroomFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cMooshroom > Monster = cpp14 : : make_unique < cMooshroom > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadOcelotFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cOcelot > Monster = cpp14 : : make_unique < cOcelot > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadPigFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cPig > Monster = cpp14 : : make_unique < cPig > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
2014-12-20 04:31:34 -05:00
void cWSSAnvil : : LoadRabbitFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-16 19:09:06 -04: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 04:31:34 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-12-20 04:31:34 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2014-12-20 04:31:34 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
2013-12-25 11:07:52 -05: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 07:19:32 -04:00
int Color = - 1 ;
if ( ColorIdx > 0 )
{
2015-07-29 11:04:03 -04:00
Color = static_cast < int > ( a_NBT . GetByte ( ColorIdx ) ) ;
2014-06-28 07:19:32 -04:00
}
2013-12-25 11:07:52 -05:00
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cSheep > Monster = cpp14 : : make_unique < cSheep > ( Color ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
2014-06-28 07:19:32 -04:00
int ShearedIdx = a_NBT . FindChildByName ( a_TagIdx , " Sheared " ) ;
if ( ShearedIdx > 0 )
{
2014-06-28 19:01:10 -04:00
Monster - > SetSheared ( a_NBT . GetByte ( ShearedIdx ) ! = 0 ) ;
2014-06-28 07:19:32 -04:00
}
2016-02-05 16:45:45 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadSilverfishFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cSilverfish > Monster = cpp14 : : make_unique < cSilverfish > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05: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 10:59:11 -05:00
if ( TypeIdx < 0 )
{
return ;
}
2013-12-25 11:07:52 -05:00
bool Type = ( ( a_NBT . GetByte ( TypeIdx ) = = 1 ) ? true : false ) ;
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cSkeleton > Monster = cpp14 : : make_unique < cSkeleton > ( Type ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05: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 06:43:21 -04:00
if ( SizeIdx < 0 )
{
return ;
}
2013-12-25 11:07:52 -05:00
int Size = a_NBT . GetInt ( SizeIdx ) ;
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cSlime > Monster = cpp14 : : make_unique < cSlime > ( Size ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadSnowGolemFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cSnowGolem > Monster = cpp14 : : make_unique < cSnowGolem > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadSpiderFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cSpider > Monster = cpp14 : : make_unique < cSpider > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadSquidFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cSquid > Monster = cpp14 : : make_unique < cSquid > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05: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 10:59:11 -05:00
if ( TypeIdx < 0 )
{
return ;
}
2013-12-25 11:07:52 -05:00
int Type = a_NBT . GetInt ( TypeIdx ) ;
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cVillager > Monster = cpp14 : : make_unique < cVillager > ( cVillager : : eVillagerType ( Type ) ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadWitchFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cWitch > Monster = cpp14 : : make_unique < cWitch > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadWitherFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cWither > Monster = cpp14 : : make_unique < cWither > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2013-12-25 11:07:52 -05:00
2014-03-24 06:29:19 -04:00
int CurrLine = a_NBT . FindChildByName ( a_TagIdx , " Invul " ) ;
if ( CurrLine > 0 )
{
2015-07-29 11:04:03 -04:00
Monster - > SetWitherInvulnerableTicks ( static_cast < unsigned int > ( a_NBT . GetInt ( CurrLine ) ) ) ;
2014-03-24 06:29:19 -04:00
}
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadWolfFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cWolf > Monster = cpp14 : : make_unique < cWolf > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-08-03 16:03:48 -04:00
LoadWolfOwner ( * Monster . get ( ) , a_NBT , a_TagIdx ) ;
2014-02-02 04:56:55 -05:00
int SittingIdx = a_NBT . FindChildByName ( a_TagIdx , " Sitting " ) ;
2014-09-23 16:11:25 -04:00
if ( ( SittingIdx > 0 ) & & ( a_NBT . GetType ( SittingIdx ) = = TAG_Byte ) )
2014-01-31 12:34:00 -05:00
{
2014-02-02 04:56:55 -05:00
bool Sitting = ( ( a_NBT . GetByte ( SittingIdx ) = = 1 ) ? true : false ) ;
Monster - > SetIsSitting ( Sitting ) ;
2014-01-31 12:34:00 -05:00
}
2014-02-02 05:28:42 -05:00
int AngryIdx = a_NBT . FindChildByName ( a_TagIdx , " Angry " ) ;
2014-09-23 16:11:25 -04:00
if ( ( AngryIdx > 0 ) & & ( a_NBT . GetType ( AngryIdx ) = = TAG_Byte ) )
2014-02-02 05:28:42 -05:00
{
bool Angry = ( ( a_NBT . GetByte ( AngryIdx ) = = 1 ) ? true : false ) ;
Monster - > SetIsAngry ( Angry ) ;
}
2014-02-01 11:16:42 -05:00
int CollarColorIdx = a_NBT . FindChildByName ( a_TagIdx , " CollarColor " ) ;
2014-09-23 16:22:38 -04:00
if ( CollarColorIdx > 0 )
2014-02-01 11:16:42 -05:00
{
2014-09-23 16:22:38 -04:00
switch ( a_NBT . GetType ( CollarColorIdx ) )
{
case TAG_Byte :
{
// Vanilla uses this
2016-08-24 15:45:03 -04:00
Monster - > SetCollarColor ( a_NBT . GetByte ( CollarColorIdx ) ) ;
2014-09-23 16:22:38 -04:00
break ;
}
case TAG_Int :
{
// Old MCS code used this, keep reading it for compatibility reasons:
Monster - > SetCollarColor ( a_NBT . GetInt ( CollarColorIdx ) ) ;
break ;
}
2016-08-24 15:45:03 -04:00
default :
{
// No other values are interpreted
break ;
}
2014-09-23 16:22:38 -04:00
}
2014-02-01 11:16:42 -05:00
}
2016-02-05 16:45:45 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2013-12-25 11:07:52 -05: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 10:59:11 -05:00
if ( IsVillagerIdx < 0 )
{
return ;
}
2013-12-25 11:07:52 -05:00
bool IsVillagerZombie = ( ( a_NBT . GetByte ( IsVillagerIdx ) = = 1 ) ? true : false ) ;
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cZombie > Monster = cpp14 : : make_unique < cZombie > ( IsVillagerZombie ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
void cWSSAnvil : : LoadPigZombieFromNBT ( cEntityList & a_Entities , const cParsedNBT & a_NBT , int a_TagIdx )
{
2015-07-12 14:58:19 -04:00
std : : unique_ptr < cZombiePigman > Monster = cpp14 : : make_unique < cZombiePigman > ( ) ;
2013-12-25 11:07:52 -05:00
if ( ! LoadEntityBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2014-02-23 13:44:58 -05:00
if ( ! LoadMonsterBaseFromNBT ( * Monster . get ( ) , a_NBT , a_TagIdx ) )
{
return ;
}
2016-02-05 16:45:45 -05:00
2015-07-12 12:00:56 -04:00
int AgeableIdx = a_NBT . FindChildByName ( a_TagIdx , " Age " ) ;
if ( AgeableIdx > 0 )
{
2015-08-24 17:05:15 -04: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 12:00:56 -04:00
}
2016-02-05 16:45:45 -05:00
2013-12-25 11:07:52 -05:00
a_Entities . push_back ( Monster . release ( ) ) ;
}
2014-08-03 16:03:48 -04: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 05:16:19 -04:00
OwnerUUID = a_NBT . GetString ( OwnerUUIDIdx ) ;
2014-08-03 16:03:48 -04: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 ;
}
2016-02-05 16:45:45 -05:00
2014-08-03 16:03:48 -04:00
// 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 05:16:19 -04:00
else
{
// Normalize the UUID:
OwnerUUID = cMojangAPI : : MakeUUIDShort ( OwnerUUID ) ;
}
2016-02-05 16:45:45 -05:00
2014-08-03 16:03:48 -04: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 ;
}
}
2016-02-05 16:45:45 -05:00
2014-08-03 16:03:48 -04:00
a_Wolf . SetOwner ( OwnerName , OwnerUUID ) ;
a_Wolf . SetIsTame ( true ) ;
}
2013-03-09 09:35:43 -05: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 ] ) ;
2016-02-05 16:45:45 -05:00
2013-03-09 09:35:43 -05:00
double Speed [ 3 ] ;
if ( ! LoadDoublesListFromNBT ( Speed , 3 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , " Motion " ) ) )
{
2014-01-24 03:57:12 -05:00
// Provide default speed:
Speed [ 0 ] = 0 ;
Speed [ 1 ] = 0 ;
Speed [ 2 ] = 0 ;
2013-03-09 09:35:43 -05:00
}
a_Entity . SetSpeed ( Speed [ 0 ] , Speed [ 1 ] , Speed [ 2 ] ) ;
2016-02-05 16:45:45 -05:00
2013-03-09 09:35:43 -05:00
double Rotation [ 3 ] ;
if ( ! LoadDoublesListFromNBT ( Rotation , 2 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , " Rotation " ) ) )
{
2014-01-24 03:57:12 -05:00
// Provide default rotation:
Rotation [ 0 ] = 0 ;
Rotation [ 1 ] = 0 ;
2013-03-09 09:35:43 -05:00
}
2014-01-16 14:00:49 -05:00
a_Entity . SetYaw ( Rotation [ 0 ] ) ;
2014-01-20 09:10:39 -05:00
a_Entity . SetRoll ( Rotation [ 1 ] ) ;
2014-06-24 10:06:26 -04:00
// Load health:
int Health = a_NBT . FindChildByName ( a_TagIdx , " Health " ) ;
2014-07-29 15:50:30 -04:00
a_Entity . SetHealth ( Health > 0 ? a_NBT . GetShort ( Health ) : a_Entity . GetMaxHealth ( ) ) ;
2016-02-05 16:45:45 -05:00
2013-03-09 09:35:43 -05:00
return true ;
}
2014-02-23 13:44:58 -05:00
bool cWSSAnvil : : LoadMonsterBaseFromNBT ( cMonster & a_Monster , const cParsedNBT & a_NBT , int a_TagIdx )
{
float DropChance [ 5 ] ;
2017-06-22 11:30:11 -04:00
if ( LoadFloatsListFromNBT ( DropChance , 5 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , " DropChances " ) ) )
2014-02-23 13:44:58 -05:00
{
2017-06-22 11:30:11 -04:00
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 ] ) ;
}
if ( LoadFloatsListFromNBT ( DropChance , 2 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , " HandDropChances " ) ) )
{
a_Monster . SetDropChanceWeapon ( DropChance [ 0 ] ) ;
}
if ( LoadFloatsListFromNBT ( DropChance , 4 , a_NBT , a_NBT . FindChildByName ( a_TagIdx , " ArmorDropChances " ) ) )
{
a_Monster . SetDropChanceHelmet ( DropChance [ 0 ] ) ;
a_Monster . SetDropChanceChestplate ( DropChance [ 1 ] ) ;
a_Monster . SetDropChanceLeggings ( DropChance [ 2 ] ) ;
a_Monster . SetDropChanceBoots ( DropChance [ 3 ] ) ;
2014-02-23 13:44:58 -05:00
}
2014-06-04 15:52:54 -04: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 13:34:58 -04: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 13:44:58 -05:00
return true ;
}
2013-09-07 15:26:17 -04:00
bool cWSSAnvil : : LoadProjectileBaseFromNBT ( cProjectileEntity & a_Entity , const cParsedNBT & a_NBT , int a_TagIdx )
{
if ( ! LoadEntityBaseFromNBT ( a_Entity , a_NBT , a_TagIdx ) )
{
return false ;
}
2016-02-05 16:45:45 -05:00
2013-09-07 15:26:17 -04:00
bool IsInGround = false ;
int InGroundIdx = a_NBT . FindChildByName ( a_TagIdx , " inGround " ) ;
if ( InGroundIdx > 0 )
{
IsInGround = ( a_NBT . GetByte ( InGroundIdx ) ! = 0 ) ;
}
a_Entity . SetIsInGround ( IsInGround ) ;
2016-02-05 16:45:45 -05:00
2013-09-07 15:26:17 -04:00
return true ;
}
2013-03-09 09:35:43 -05: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 13:44:58 -05: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 09:06:06 -04: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 16:37:48 -05: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 09:06:06 -04:00
return true ;
}
2014-07-17 16:15:34 -04:00
////////////////////////////////////////////////////////////////////////////////
2012-06-14 09:06:06 -04:00
// cWSSAnvil::cMCAFile:
2015-07-28 09:53:28 -04:00
cWSSAnvil : : cMCAFile : : cMCAFile ( cWSSAnvil & a_ParentSchema , const AString & a_FileName , int a_RegionX , int a_RegionZ ) :
m_ParentSchema ( a_ParentSchema ) ,
2012-06-14 09:06:06 -04:00
m_RegionX ( a_RegionX ) ,
m_RegionZ ( a_RegionZ ) ,
m_FileName ( a_FileName )
{
}
bool cWSSAnvil : : cMCAFile : : OpenFile ( bool a_IsForReading )
{
2014-12-08 14:23:19 -05:00
bool writeOutNeeded = false ;
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
if ( m_File . IsOpen ( ) )
{
// Already open
return true ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
if ( a_IsForReading )
{
if ( ! cFile : : Exists ( m_FileName ) )
{
// We want to read and the file doesn't exist. Fail.
return false ;
}
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
if ( ! m_File . Open ( m_FileName , cFile : : fmReadWrite ) )
{
// The file failed to open
return false ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// 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 14:23:19 -05:00
// Try writing a nullptr header for chunk offsets:
2012-06-14 09:06:06 -04:00
memset ( m_Header , 0 , sizeof ( m_Header ) ) ;
2014-12-08 14:23:19 -05:00
writeOutNeeded = true ;
2012-06-14 09:06:06 -04:00
}
2014-12-07 17:44:08 -05: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 14:23:19 -05:00
// Try writing a nullptr header for timestamps:
2014-12-07 17:44:08 -05:00
memset ( m_TimeStamps , 0 , sizeof ( m_TimeStamps ) ) ;
2014-12-08 14:23:19 -05:00
writeOutNeeded = true ;
}
2016-02-05 16:45:45 -05:00
2014-12-08 14:23:19 -05:00
if ( writeOutNeeded )
{
2014-12-11 08:34:09 -05:00
m_File . Seek ( 0 ) ;
2012-06-14 09:06:06 -04:00
if (
2014-12-11 08:34:09 -05: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 09:06:06 -04: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 ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
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 07:32:16 -04:00
if ( ChunkOffset < 2 )
2014-09-02 16:40:24 -04:00
{
return false ;
}
2016-02-05 16:45:45 -05:00
2015-06-24 10:38:40 -04:00
m_File . Seek ( static_cast < int > ( ChunkOffset * 4096 ) ) ;
2016-02-05 16:45:45 -05:00
2015-06-24 10:38:40 -04:00
UInt32 ChunkSize = 0 ;
2012-06-14 09:06:06 -04:00
if ( m_File . Read ( & ChunkSize , 4 ) ! = 4 )
{
2015-07-28 09:53:28 -04:00
m_ParentSchema . ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , " Cannot read chunk size " , " " ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
2015-06-24 10:38:40 -04:00
ChunkSize = ntohl ( ChunkSize ) ;
if ( ChunkSize < 1 )
{
// Chunk size too small
2015-07-28 09:53:28 -04:00
m_ParentSchema . ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , " Chunk size too small " , " " ) ;
2015-06-24 10:38:40 -04:00
return false ;
}
2012-06-14 09:06:06 -04:00
char CompressionType = 0 ;
if ( m_File . Read ( & CompressionType , 1 ) ! = 1 )
{
2015-07-28 09:53:28 -04:00
m_ParentSchema . ChunkLoadFailed ( a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , " Cannot read chunk compression " , " " ) ;
2012-06-14 09:06:06 -04:00
return false ;
}
2015-07-28 09:53:28 -04:00
ChunkSize - - ;
2016-02-05 16:45:45 -05:00
2015-07-28 09:53:28 -04:00
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 09:06:06 -04:00
if ( CompressionType ! = 2 )
{
// Chunk is in an unknown compression
2015-07-28 09:53:28 -04: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 09:06:06 -04:00
return false ;
}
2014-09-02 16:40:24 -04:00
return true ;
}
2012-06-14 09:06:06 -04:00
bool cWSSAnvil : : cMCAFile : : SetChunkData ( const cChunkCoords & a_Chunk , const AString & a_Data )
{
if ( ! OpenFile ( false ) )
{
2013-03-09 09:35:43 -05: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 09:06:06 -04: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 ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
unsigned ChunkSector = FindFreeLocation ( LocalX , LocalZ , a_Data ) ;
// Store the chunk data:
2015-07-29 11:04:03 -04:00
m_File . Seek ( static_cast < int > ( ChunkSector * 4096 ) ) ;
2016-08-24 15:45:03 -04:00
UInt32 ChunkSize = htonl ( static_cast < UInt32 > ( a_Data . size ( ) + 1 ) ) ;
2012-06-14 09:06:06 -04:00
if ( m_File . Write ( & ChunkSize , 4 ) ! = 4 )
{
2013-03-09 09:35:43 -05: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 09:06:06 -04:00
return false ;
}
char CompressionType = 2 ;
if ( m_File . Write ( & CompressionType , 1 ) ! = 1 )
{
2013-03-09 09:35:43 -05: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 09:06:06 -04:00
return false ;
}
2015-07-29 11:04:03 -04:00
if ( m_File . Write ( a_Data . data ( ) , a_Data . size ( ) ) ! = static_cast < int > ( a_Data . size ( ) ) )
2012-06-14 09:06:06 -04:00
{
2013-03-09 09:35:43 -05: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 09:06:06 -04:00
return false ;
}
2016-02-05 16:45:45 -05:00
2014-05-01 12:00:10 -04:00
// Add padding to 4K boundary:
size_t BytesWritten = a_Data . size ( ) + MCA_CHUNK_HEADER_LENGTH ;
2015-02-08 06:24:15 -05:00
if ( BytesWritten % 4096 ! = 0 )
{
static const char Padding [ 4095 ] = { 0 } ;
m_File . Write ( Padding , 4096 - ( BytesWritten % 4096 ) ) ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// Store the header:
2016-08-24 15:45:03 -04:00
ChunkSize = ( static_cast < UInt32 > ( 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 08:00:54 -04: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 13:15:37 -04:00
a_Chunk . m_ChunkX , a_Chunk . m_ChunkZ , static_cast < unsigned > ( ChunkSize * 4 )
2014-09-04 08:00:54 -04:00
) ;
return false ;
}
2016-02-05 16:45:45 -05:00
2014-12-07 17:44:08 -05:00
// Store the header info in the table
2016-08-24 15:45:03 -04:00
m_Header [ LocalX + 32 * LocalZ ] = htonl ( static_cast < UInt32 > ( ( ChunkSector < < 8 ) | ChunkSize ) ) ;
2014-12-07 17:44:08 -05:00
// Set the modification time
2016-08-24 15:45:03 -04:00
m_TimeStamps [ LocalX + 32 * LocalZ ] = htonl ( static_cast < UInt32 > ( time ( nullptr ) ) ) ;
2014-12-07 17:44:08 -05:00
2013-03-09 09:35:43 -05: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 09:06:06 -04:00
if ( m_File . Write ( m_Header , sizeof ( m_Header ) ) ! = sizeof ( m_Header ) )
{
2013-03-09 09:35:43 -05: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 09:06:06 -04:00
return false ;
}
2014-12-08 14:23:19 -05:00
if ( m_File . Write ( m_TimeStamps , sizeof ( m_TimeStamps ) ) ! = sizeof ( m_TimeStamps ) )
2014-12-07 17:44:08 -05: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 ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04: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 ;
}
2016-02-05 16:45:45 -05:00
2012-06-14 09:06:06 -04:00
// 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 10:01:34 -05:00
for ( size_t i = 0 ; i < ARRAYCOUNT ( m_Header ) ; i + + )
2012-06-14 09:06:06 -04: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 13:50:42 -04:00