Rewritten block entity loading.
Block entities are now loaded based on the blocktype at the coords they specify; before loading, their type ("id" NBT tag) is checked.
The chunk now expects that all block entities given to it via cChunk::SetAllData() have their valid blocktype; asserts if they don't.
Fixes #1354.
This commit is contained in:
@@ -396,7 +396,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
||||
} // for y
|
||||
//*/
|
||||
|
||||
m_World->QueueSetChunkData(cSetChunkDataPtr(new cSetChunkData(
|
||||
cSetChunkDataPtr SetChunkData(new cSetChunkData(
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ,
|
||||
BlockTypes, MetaData,
|
||||
IsLightValid ? BlockLight : NULL,
|
||||
@@ -404,7 +404,8 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
||||
NULL, Biomes,
|
||||
Entities, BlockEntities,
|
||||
false
|
||||
)));
|
||||
));
|
||||
m_World->QueueSetChunkData(SetChunkData);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -581,64 +582,32 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int sID = a_NBT.FindChildByName(Child, "id");
|
||||
if (sID < 0)
|
||||
|
||||
// Get the BlockEntity's position
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, Child, x, y, z))
|
||||
{
|
||||
LOGWARNING("Bad block entity, missing the coords. Will be ignored.");
|
||||
continue;
|
||||
}
|
||||
int RelX = x, RelY = y, RelZ = z, ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
|
||||
if (RelY == 2)
|
||||
{
|
||||
LOGD("HERE");
|
||||
}
|
||||
|
||||
// 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);
|
||||
std::auto_ptr<cBlockEntity> be(LoadBlockEntityFromNBT(a_NBT, Child, x, y, z, BlockType, BlockMeta));
|
||||
if (be.get() == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (strncmp(a_NBT.GetData(sID), "Beacon", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadBeaconFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Chest", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_CHEST);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadCommandBlockFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Dropper", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadDropperFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "FlowerPot", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadFlowerPotFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Furnace", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadFurnaceFromNBT(a_BlockEntities, a_NBT, Child, a_BlockTypes, a_BlockMetas);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Hopper", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadHopperFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Music", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadNoteFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "RecordPlayer", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadJukeboxFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Sign", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadSignFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Skull", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadMobHeadFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "Trap", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child);
|
||||
}
|
||||
else if (strncmp(a_NBT.GetData(sID), "TrappedChest", a_NBT.GetDataLength(sID)) == 0)
|
||||
{
|
||||
LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_TRAPPED_CHEST);
|
||||
}
|
||||
// TODO: Other block entities
|
||||
|
||||
// Add the BlockEntity to the loaded data:
|
||||
a_BlockEntities.push_back(be.release());
|
||||
} // for Child - tag children
|
||||
}
|
||||
|
||||
@@ -646,6 +615,52 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
|
||||
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
// Load the specific BlockEntity type:
|
||||
switch (a_BlockType)
|
||||
{
|
||||
// Specific entity loaders:
|
||||
case E_BLOCK_BEACON: return LoadBeaconFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_CHEST);
|
||||
case E_BLOCK_COMMAND_BLOCK: return LoadCommandBlockFromNBT(a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_DISPENSER: return LoadDispenserFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_DROPPER: return LoadDropperFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_FLOWER_POT: return LoadFlowerPotFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FURNACE, a_BlockMeta);
|
||||
case E_BLOCK_HEAD: return LoadMobHeadFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_HOPPER: return LoadHopperFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_JUKEBOX: return LoadJukeboxFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_LIT_FURNACE: return LoadFurnaceFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LIT_FURNACE, a_BlockMeta);
|
||||
case E_BLOCK_NOTE_BLOCK: return LoadNoteBlockFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ);
|
||||
case E_BLOCK_SIGN_POST: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SIGN_POST);
|
||||
case E_BLOCK_TRAPPED_CHEST: return LoadChestFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_TRAPPED_CHEST);
|
||||
case E_BLOCK_WALLSIGN: return LoadSignFromNBT (a_NBT, a_Tag, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WALLSIGN);
|
||||
|
||||
// Blocktypes that have block entities but don't load their contents from disk:
|
||||
case E_BLOCK_ENDER_CHEST: return NULL;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
TypeName.assign(a_NBT.GetData(TagID), (size_t)a_NBT.GetDataLength(TagID));
|
||||
}
|
||||
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
|
||||
);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
int Type = a_NBT.FindChildByName(a_TagIdx, "id");
|
||||
@@ -656,7 +671,6 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
|
||||
a_Item.m_ItemType = a_NBT.GetShort(Type);
|
||||
if (a_Item.m_ItemType < 0)
|
||||
{
|
||||
LOGD("Encountered an item with negative type (%d). Replacing with an empty item.", a_NBT.GetShort(Type));
|
||||
a_Item.Empty();
|
||||
return true;
|
||||
}
|
||||
@@ -754,16 +768,46 @@ void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadBeaconFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
bool cWSSAnvil::CheckBlockEntityType(const cParsedNBT & a_NBT, int a_TagIdx, const char * a_ExpectedType)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the given tag is a compound:
|
||||
if (a_NBT.GetType(a_TagIdx) != TAG_Compound)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::auto_ptr<cBeaconEntity> Beacon(new cBeaconEntity(x, y, z, m_World));
|
||||
// Get the "id" tag:
|
||||
int TagID = a_NBT.FindChildByName(a_TagIdx, "id");
|
||||
if (TagID < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare the value:
|
||||
if (strncmp(a_NBT.GetData(TagID), a_ExpectedType, (size_t)a_NBT.GetDataLength(TagID)) == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
LOGWARNING("Block entity type mismatch: exp \"%s\", got \"%s\".",
|
||||
a_ExpectedType,
|
||||
AString(a_NBT.GetData(TagID), (size_t)a_NBT.GetDataLength(TagID)).c_str()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBlockEntity * cWSSAnvil::LoadBeaconFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Beacon"))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::auto_ptr<cBeaconEntity> Beacon(new cBeaconEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
|
||||
int CurrentLine = a_NBT.FindChildByName(a_TagIdx, "Levels");
|
||||
if (CurrentLine >= 0)
|
||||
@@ -790,88 +834,128 @@ void cWSSAnvil::LoadBeaconFromNBT(cBlockEntityList & a_BlockEntities, const cPar
|
||||
LoadItemGridFromNBT(Beacon->GetContents(), a_NBT, Items);
|
||||
}
|
||||
|
||||
a_BlockEntities.push_back(Beacon.release());
|
||||
return Beacon.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType)
|
||||
cBlockEntity * cWSSAnvil::LoadChestFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_ChestBlockType)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
// TODO: Does vanilla use "TrappedChest" or not? MCWiki says no, but previous code says yes
|
||||
// Ref.: http://minecraft.gamepedia.com/Trapped_Chest
|
||||
// https://github.com/mc-server/MCServer/blob/d0551e2e0a98a28f31a88d489d17b408e4a7d38d/src/WorldStorage/WSSAnvil.cpp#L637
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Chest") && !CheckBlockEntityType(a_NBT, a_TagIdx, "TrappedChest"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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
|
||||
return NULL; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
|
||||
}
|
||||
std::auto_ptr<cChestEntity> Chest(new cChestEntity(x, y, z, m_World, a_ChestType));
|
||||
std::auto_ptr<cChestEntity> Chest(new cChestEntity(a_BlockX, a_BlockY, a_BlockZ, m_World, a_ChestBlockType));
|
||||
LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items);
|
||||
a_BlockEntities.push_back(Chest.release());
|
||||
return Chest.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadDispenserFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
cBlockEntity * cWSSAnvil::LoadCommandBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Control"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::auto_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
|
||||
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)
|
||||
{
|
||||
CmdBlock->SetResult(a_NBT.GetInt(currentLine));
|
||||
}
|
||||
|
||||
currentLine = a_NBT.FindChildByName(a_TagIdx, "LastOutput");
|
||||
if (currentLine >= 0)
|
||||
{
|
||||
CmdBlock->SetLastOutput(a_NBT.GetString(currentLine));
|
||||
}
|
||||
|
||||
// TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it.
|
||||
|
||||
return CmdBlock.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBlockEntity * cWSSAnvil::LoadDispenserFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Trap"))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
|
||||
if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
|
||||
{
|
||||
return; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this
|
||||
return NULL; // Make it an empty dispenser - the chunk loader will provide an empty cDispenserEntity for this
|
||||
}
|
||||
std::auto_ptr<cDispenserEntity> Dispenser(new cDispenserEntity(x, y, z, m_World));
|
||||
std::auto_ptr<cDispenserEntity> Dispenser(new cDispenserEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
LoadItemGridFromNBT(Dispenser->GetContents(), a_NBT, Items);
|
||||
a_BlockEntities.push_back(Dispenser.release());
|
||||
return Dispenser.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadDropperFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
cBlockEntity * cWSSAnvil::LoadDropperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Dropper"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
|
||||
if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
|
||||
{
|
||||
return; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this
|
||||
return NULL; // Make it an empty dropper - the chunk loader will provide an empty cDropperEntity for this
|
||||
}
|
||||
std::auto_ptr<cDropperEntity> Dropper(new cDropperEntity(x, y, z, m_World));
|
||||
std::auto_ptr<cDropperEntity> Dropper(new cDropperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
LoadItemGridFromNBT(Dropper->GetContents(), a_NBT, Items);
|
||||
a_BlockEntities.push_back(Dropper.release());
|
||||
return Dropper.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadFlowerPotFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
cBlockEntity * cWSSAnvil::LoadFlowerPotFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "FlowerPot"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
std::auto_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(x, y, z, m_World));
|
||||
|
||||
std::auto_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
short ItemType = 0, ItemData = 0;
|
||||
|
||||
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item");
|
||||
@@ -887,37 +971,28 @@ void cWSSAnvil::LoadFlowerPotFromNBT(cBlockEntityList & a_BlockEntities, const c
|
||||
}
|
||||
|
||||
FlowerPot->SetItem(cItem(ItemType, 1, ItemData));
|
||||
a_BlockEntities.push_back(FlowerPot.release());
|
||||
return FlowerPot.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas)
|
||||
cBlockEntity * cWSSAnvil::LoadFurnaceFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Furnace"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
|
||||
if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
|
||||
{
|
||||
return; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this
|
||||
return NULL; // Make it an empty furnace - the chunk loader will provide an empty cFurnaceEntity for this
|
||||
}
|
||||
|
||||
// Convert coords to relative:
|
||||
int RelX = x;
|
||||
int RelZ = z;
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(RelX, y, RelZ, ChunkX, ChunkZ);
|
||||
|
||||
// Create the furnace entity, with proper BlockType and BlockMeta info:
|
||||
BLOCKTYPE BlockType = cChunkDef::GetBlock(a_BlockTypes, RelX, y, RelZ);
|
||||
NIBBLETYPE BlockMeta = cChunkDef::GetNibble(a_BlockMetas, RelX, y, RelZ);
|
||||
std::auto_ptr<cFurnaceEntity> Furnace(new cFurnaceEntity(x, y, z, BlockType, BlockMeta, m_World));
|
||||
std::auto_ptr<cFurnaceEntity> Furnace(new cFurnaceEntity(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, m_World));
|
||||
|
||||
// Load slots:
|
||||
for (int Child = a_NBT.GetFirstChild(Items); Child != -1; Child = a_NBT.GetNextSibling(Child))
|
||||
@@ -954,86 +1029,121 @@ void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cPa
|
||||
|
||||
// Restart cooking:
|
||||
Furnace->ContinueCooking();
|
||||
a_BlockEntities.push_back(Furnace.release());
|
||||
return Furnace.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadHopperFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
cBlockEntity * cWSSAnvil::LoadHopperFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Hopper"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int Items = a_NBT.FindChildByName(a_TagIdx, "Items");
|
||||
if ((Items < 0) || (a_NBT.GetType(Items) != TAG_List))
|
||||
{
|
||||
return; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this
|
||||
return NULL; // Make it an empty hopper - the chunk loader will provide an empty cHopperEntity for this
|
||||
}
|
||||
std::auto_ptr<cHopperEntity> Hopper(new cHopperEntity(x, y, z, m_World));
|
||||
std::auto_ptr<cHopperEntity> Hopper(new cHopperEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
LoadItemGridFromNBT(Hopper->GetContents(), a_NBT, Items);
|
||||
a_BlockEntities.push_back(Hopper.release());
|
||||
return Hopper.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadJukeboxFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
cBlockEntity * cWSSAnvil::LoadJukeboxFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "RecordPlayer"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
std::auto_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(x, y, z, m_World));
|
||||
|
||||
std::auto_ptr<cJukeboxEntity> Jukebox(new cJukeboxEntity(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));
|
||||
}
|
||||
a_BlockEntities.push_back(Jukebox.release());
|
||||
return Jukebox.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadNoteFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
cBlockEntity * cWSSAnvil::LoadMobHeadFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Skull"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
std::auto_ptr<cNoteEntity> Note(new cNoteEntity(x, y, z, m_World));
|
||||
|
||||
std::auto_ptr<cMobHeadEntity> MobHead(new cMobHeadEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
|
||||
int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType");
|
||||
if (currentLine >= 0)
|
||||
{
|
||||
MobHead->SetType(static_cast<eMobHeadType>(a_NBT.GetByte(currentLine)));
|
||||
}
|
||||
|
||||
currentLine = a_NBT.FindChildByName(a_TagIdx, "Rot");
|
||||
if (currentLine >= 0)
|
||||
{
|
||||
MobHead->SetRotation(static_cast<eMobHeadRotation>(a_NBT.GetByte(currentLine)));
|
||||
}
|
||||
|
||||
currentLine = a_NBT.FindChildByName(a_TagIdx, "ExtraType");
|
||||
if (currentLine >= 0)
|
||||
{
|
||||
MobHead->SetOwner(a_NBT.GetString(currentLine));
|
||||
}
|
||||
|
||||
return MobHead.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cBlockEntity * cWSSAnvil::LoadNoteBlockFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Music"))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::auto_ptr<cNoteEntity> NoteBlock(new cNoteEntity(a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
int note = a_NBT.FindChildByName(a_TagIdx, "note");
|
||||
if (note >= 0)
|
||||
{
|
||||
Note->SetPitch(a_NBT.GetByte(note));
|
||||
NoteBlock->SetPitch(a_NBT.GetByte(note));
|
||||
}
|
||||
a_BlockEntities.push_back(Note.release());
|
||||
return NoteBlock.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
cBlockEntity * cWSSAnvil::LoadSignFromNBT(const cParsedNBT & a_NBT, int a_TagIdx, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
// Check if the data has a proper type:
|
||||
if (!CheckBlockEntityType(a_NBT, a_TagIdx, "Sign"))
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
std::auto_ptr<cSignEntity> Sign(new cSignEntity(E_BLOCK_SIGN_POST, x, y, z, m_World));
|
||||
|
||||
std::auto_ptr<cSignEntity> Sign(new cSignEntity(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, m_World));
|
||||
|
||||
int currentLine = a_NBT.FindChildByName(a_TagIdx, "Text1");
|
||||
if (currentLine >= 0)
|
||||
@@ -1059,79 +1169,7 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse
|
||||
Sign->SetLine(3, a_NBT.GetString(currentLine));
|
||||
}
|
||||
|
||||
a_BlockEntities.push_back(Sign.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadMobHeadFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::auto_ptr<cMobHeadEntity> MobHead(new cMobHeadEntity(x, y, z, m_World));
|
||||
|
||||
int currentLine = a_NBT.FindChildByName(a_TagIdx, "SkullType");
|
||||
if (currentLine >= 0)
|
||||
{
|
||||
MobHead->SetType(static_cast<eMobHeadType>(a_NBT.GetByte(currentLine)));
|
||||
}
|
||||
|
||||
currentLine = a_NBT.FindChildByName(a_TagIdx, "Rot");
|
||||
if (currentLine >= 0)
|
||||
{
|
||||
MobHead->SetRotation(static_cast<eMobHeadRotation>(a_NBT.GetByte(currentLine)));
|
||||
}
|
||||
|
||||
currentLine = a_NBT.FindChildByName(a_TagIdx, "ExtraType");
|
||||
if (currentLine >= 0)
|
||||
{
|
||||
MobHead->SetOwner(a_NBT.GetString(currentLine));
|
||||
}
|
||||
|
||||
a_BlockEntities.push_back(MobHead.release());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
|
||||
int x, y, z;
|
||||
if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::auto_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(x, y, z, m_World));
|
||||
|
||||
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)
|
||||
{
|
||||
CmdBlock->SetResult(a_NBT.GetInt(currentLine));
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
a_BlockEntities.push_back(CmdBlock.release());
|
||||
return Sign.release();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user