void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0))); if (!LoadProjectileBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx)) { return; } // Load pickup state: int PickupIdx = a_NBT.FindChildByName(a_TagIdx, "pickup"); if (PickupIdx > 0) { Arrow->SetPickupState((cArrowEntity::ePickupState)a_NBT.GetByte(PickupIdx)); } else { // Try the older "player" tag: int PlayerIdx = a_NBT.FindChildByName(a_TagIdx, "player"); if (PlayerIdx > 0) { Arrow->SetPickupState((a_NBT.GetByte(PlayerIdx) == 0) ? cArrowEntity::psNoPickup : cArrowEntity::psInSurvivalOrCreative); } } // Load damage: int DamageIdx = a_NBT.FindChildByName(a_TagIdx, "damage"); if (DamageIdx > 0) { Arrow->SetDamageCoeff(a_NBT.GetDouble(DamageIdx)); } // Store the new arrow in the entities list: a_Entities.push_back(Arrow.release()); }
void cWSSAnvil::LoadMinecartCFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { 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 } std::auto_ptr<cMinecartWithChest> Minecart(new cMinecartWithChest(0, 0, 0)); 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()); }
void cWSSAnvil::LoadNoteFromNBT(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<cNoteEntity> Note(new cNoteEntity(x, y, z, m_World)); int note = a_NBT.FindChildByName(a_TagIdx, "note"); if (note >= 0) { Note->SetPitch(a_NBT.GetByte(note)); } a_BlockEntities.push_back(Note.release()); }
bool cWSSAnvil::LoadProjectileBaseFromNBT(cProjectileEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx) { if (!LoadEntityBaseFromNBT(a_Entity, a_NBT, a_TagIdx)) { return false; } bool IsInGround = false; int InGroundIdx = a_NBT.FindChildByName(a_TagIdx, "inGround"); if (InGroundIdx > 0) { IsInGround = (a_NBT.GetByte(InGroundIdx) != 0); } a_Entity.SetIsInGround(IsInGround); // TODO: Load inTile, TileCoords return true; }
bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_TagIdx) { int ID = a_NBT.FindChildByName(a_TagIdx, "id"); if ((ID < 0) || (a_NBT.GetType(ID) != TAG_Short)) { return false; } a_Item.m_ItemType = (ENUM_ITEM_ID)(a_NBT.GetShort(ID)); int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage"); if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short)) { return false; } a_Item.m_ItemDamage = a_NBT.GetShort(Damage); int Count = a_NBT.FindChildByName(a_TagIdx, "Count"); if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte)) { return false; } a_Item.m_ItemCount = a_NBT.GetByte(Count); // 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; } // Load enchantments: const char * EnchName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; int EnchTag = a_NBT.FindChildByName(TagTag, EnchName); if (EnchTag > 0) { a_Item.m_Enchantments.ParseFromNBT(a_NBT, EnchTag); } return true; }
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; } int SlotNum = (int)(a_NBT.GetByte(SlotTag)) - a_SlotOffset; 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[] }
bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT) { int Data = a_NBT.FindChildByName(0, "data"); if (Data < 0) { return false; } int CurrLine = a_NBT.FindChildByName(Data, "scale"); if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Byte)) { unsigned int Scale = (unsigned int)a_NBT.GetByte(CurrLine); m_Map->SetScale(Scale); } CurrLine = a_NBT.FindChildByName(Data, "dimension"); if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Byte)) { eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine); if (Dimension != m_Map->m_World->GetDimension()) { // TODO 2014-03-20 xdot: We should store nether maps in nether worlds, e.t.c. return false; } } CurrLine = a_NBT.FindChildByName(Data, "width"); if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Short)) { unsigned int Width = (unsigned int)a_NBT.GetShort(CurrLine); if (Width != 128) { return false; } m_Map->m_Width = Width; } CurrLine = a_NBT.FindChildByName(Data, "height"); if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Short)) { unsigned int Height = (unsigned int)a_NBT.GetShort(CurrLine); if (Height >= 256) { return false; } m_Map->m_Height = Height; } CurrLine = a_NBT.FindChildByName(Data, "xCenter"); if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Int)) { int CenterX = a_NBT.GetInt(CurrLine); m_Map->m_CenterX = CenterX; } CurrLine = a_NBT.FindChildByName(Data, "zCenter"); if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_Int)) { int CenterZ = a_NBT.GetInt(CurrLine); m_Map->m_CenterZ = CenterZ; } unsigned int NumPixels = m_Map->GetNumPixels(); m_Map->m_Data.resize(NumPixels); CurrLine = a_NBT.FindChildByName(Data, "colors"); if ((CurrLine >= 0) && (a_NBT.GetType(CurrLine) == TAG_ByteArray)) { memcpy(m_Map->m_Data.data(), a_NBT.GetData(CurrLine), NumPixels); } return true; }
void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type) { if (a_TagIdx < 0) { return; } switch (a_Type) { case E_ITEM_FIREWORK_STAR: { for (int explosiontag = a_NBT.GetFirstChild(a_TagIdx); explosiontag >= 0; explosiontag = a_NBT.GetNextSibling(explosiontag)) { eTagType TagType = a_NBT.GetType(explosiontag); if (TagType == TAG_Byte) // Custon name tag { AString ExplosionName = a_NBT.GetName(explosiontag); if (ExplosionName == "Flicker") { a_FireworkItem.m_HasFlicker = (a_NBT.GetByte(explosiontag) == 1); } else if (ExplosionName == "Trail") { a_FireworkItem.m_HasTrail = (a_NBT.GetByte(explosiontag) == 1); } else if (ExplosionName == "Type") { a_FireworkItem.m_Type = a_NBT.GetByte(explosiontag); } } else if (TagType == TAG_IntArray) { AString ExplosionName = a_NBT.GetName(explosiontag); if (ExplosionName == "Colors") { // Divide by four as data length returned in bytes int DataLength = a_NBT.GetDataLength(explosiontag); // round to the next highest multiple of four DataLength -= DataLength % 4; if (DataLength == 0) { continue; } const char * ColourData = (a_NBT.GetData(explosiontag)); for (int i = 0; i < DataLength; i += 4 /* Size of network int*/) { a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i)); } } else if (ExplosionName == "FadeColors") { int DataLength = a_NBT.GetDataLength(explosiontag) / 4; // round to the next highest multiple of four DataLength -= DataLength % 4; if (DataLength == 0) { continue; } const char * FadeColourData = (a_NBT.GetData(explosiontag)); for (int i = 0; i < DataLength; i += 4 /* Size of network int*/) { a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i)); } } } } break; } case E_ITEM_FIREWORK_ROCKET: { for (int fireworkstag = a_NBT.GetFirstChild(a_TagIdx); fireworkstag >= 0; fireworkstag = a_NBT.GetNextSibling(fireworkstag)) { eTagType TagType = a_NBT.GetType(fireworkstag); if (TagType == TAG_Byte) // Custon name tag { if (a_NBT.GetName(fireworkstag) == "Flight") { a_FireworkItem.m_FlightTimeInTicks = a_NBT.GetByte(fireworkstag) * 20; } } else if ((TagType == TAG_List) && (a_NBT.GetName(fireworkstag) == "Explosions")) { int ExplosionsChild = a_NBT.GetFirstChild(fireworkstag); if ((a_NBT.GetType(ExplosionsChild) == TAG_Compound) && (a_NBT.GetName(ExplosionsChild).empty())) { ParseFromNBT(a_FireworkItem, a_NBT, ExplosionsChild, E_ITEM_FIREWORK_STAR); } } } break; } default: ASSERT(!"Unhandled firework item!"); break; } }
void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas) { ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); int x, y, z; if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) { return; } 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 } // 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)); // 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)) { Furnace->SetSlot(a_NBT.GetByte(Slot), Item); } } // for itr - ItemDefs[] // Load burn time: 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% Furnace->SetBurnTimes(bt, 0); } // Load cook time: int CookTime = a_NBT.FindChildByName(a_TagIdx, "CookTime"); if (CookTime >= 0) { Int16 ct = a_NBT.GetShort(CookTime); // 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); } // Restart cooking: Furnace->ContinueCooking(); a_BlockEntities.push_back(Furnace.release()); }
bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT) { // The data arrays, in MCA-native y/z/x ordering (will be reordered for the final chunk data) cChunkDef::BlockTypes BlockTypes; cChunkDef::BlockNibbles MetaData; cChunkDef::BlockNibbles BlockLight; cChunkDef::BlockNibbles SkyLight; memset(BlockTypes, E_BLOCK_AIR, sizeof(BlockTypes)); memset(MetaData, 0, sizeof(MetaData)); memset(SkyLight, 0xff, sizeof(SkyLight)); // By default, data not present in the NBT means air, which means full skylight memset(BlockLight, 0x00, sizeof(BlockLight)); // Load the blockdata, blocklight and skylight: int Level = a_NBT.FindChildByName(0, "Level"); if (Level < 0) { return false; } int Sections = a_NBT.FindChildByName(Level, "Sections"); if ((Sections < 0) || (a_NBT.GetType(Sections) != TAG_List) || (a_NBT.GetChildrenType(Sections) != TAG_Compound)) { 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; } CopyNBTData(a_NBT, Child, "Blocks", (char *)&(BlockTypes[y * 4096]), 4096); CopyNBTData(a_NBT, Child, "Data", (char *)&(MetaData[y * 2048]), 2048); CopyNBTData(a_NBT, Child, "SkyLight", (char *)&(SkyLight[y * 2048]), 2048); CopyNBTData(a_NBT, Child, "BlockLight", (char *)&(BlockLight[y * 2048]), 2048); } // for itr - LevelSections[] // Load the biomes from NBT, if present and valid. First try MCS-style, then Vanilla-style: cChunkDef::BiomeMap BiomeMap; cChunkDef::BiomeMap * Biomes = LoadBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "MCSBiomes")); if (Biomes == NULL) { // MCS-style biomes not available, load vanilla-style: Biomes = LoadVanillaBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes")); } // Load the entities from NBT: cEntityList Entities; cBlockEntityList BlockEntities; LoadEntitiesFromNBT (Entities, a_NBT, a_NBT.FindChildByName(Level, "Entities")); LoadBlockEntitiesFromNBT(BlockEntities, a_NBT, a_NBT.FindChildByName(Level, "TileEntities"), BlockTypes, MetaData); bool IsLightValid = (a_NBT.FindChildByName(Level, "MCSIsLightValid") > 0); /* // Uncomment this block for really cool stuff :) // DEBUG magic: Invert the underground, so that we can see the MC generator in action :) bool ShouldInvert[cChunkDef::Width * cChunkDef::Width]; memset(ShouldInvert, 0, sizeof(ShouldInvert)); for (int y = cChunkDef::Height - 1; y >= 0; y--) { for (int x = 0; x < cChunkDef::Width; x++) for (int z = 0; z < cChunkDef::Width; z++) { int Index = cChunkDef::MakeIndexNoCheck(x, y, z); if (ShouldInvert[x + cChunkDef::Width * z]) { BlockTypes[Index] = (BlockTypes[Index] == E_BLOCK_AIR) ? E_BLOCK_STONE : E_BLOCK_AIR; } else { switch (BlockTypes[Index]) { case E_BLOCK_AIR: case E_BLOCK_LEAVES: { // nothing needed break; } default: { ShouldInvert[x + cChunkDef::Width * z] = true; } } BlockTypes[Index] = E_BLOCK_AIR; } } } // for y //*/ m_World->SetChunkData( a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, BlockTypes, MetaData, IsLightValid ? BlockLight : NULL, IsLightValid ? SkyLight : NULL, NULL, Biomes, Entities, BlockEntities, false ); return true; }