///<summary>Reads all Entities and TileEntities from the given chunk NBT</summary> public void ReadEntitiesAndTileEntitiesFromNBT(CompoundContainer chunkLevelCompound) { if (chunkLevelCompound.Contains("Entities")) { var entList = chunkLevelCompound.GetAsList("Entities"); if (entList != null && entList.contentsType == NBTTag.TAG_Compound) { for (int i = 0; i < entList.Length; i++) { entities.Add(new Entity(entList.Get <CompoundContainer>(i))); } } } if (chunkLevelCompound.Contains("TileEntities")) { var tileEntList = chunkLevelCompound.GetAsList("TileEntities"); if (tileEntList != null && tileEntList.contentsType == NBTTag.TAG_Compound) { for (int i = 0; i < tileEntList.Length; i++) { var te = new TileEntity(tileEntList.Get <CompoundContainer>(i)); tileEntities.Add(new BlockCoord(te.BlockPosX, te.BlockPosY, te.BlockPosZ), te); } } } }
public TileEntity(CompoundContainer compound) { NBTCompound = compound; BlockPosX = compound.Get <int>("x"); BlockPosY = compound.Get <int>("y"); BlockPosZ = compound.Get <int>("z"); }
static void LoadBlocksMCRFormat(ChunkData chunk, CompoundContainer nbtCompound) { byte[] blocks = nbtCompound.Get <byte[]>("Blocks"); byte[] add; //TODO: include "Add" bits in ID (from modded worlds) if (nbtCompound.Contains("Add")) { add = nbtCompound.Get <byte[]>("Add"); } byte[] meta = nbtCompound.Get <byte[]>("Data"); //TODO: also include meta in block lookup for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 128; y++) { byte id = blocks[(x * 16 + z) * 128 + y]; var block = BlockList.FindByNumeric(new NumericID(id, 0)); if (block != null) { chunk.SetBlockAt(x, y, z, new BlockState(block)); } } } } }
public Entity(CompoundContainer compound) { NBTCompound = compound; ListContainer pos = compound.GetAsList("Pos"); BlockPosX = (int)Math.Floor(pos.Get <double>(0)); BlockPosY = (int)Math.Floor(pos.Get <double>(1)); BlockPosZ = (int)Math.Floor(pos.Get <double>(2)); }
public bool Compare(BlockState other, bool compareProperties = true) { if (compareProperties) { if (!CompoundContainer.AreEqual(properties, other.properties)) { return(false); } } return(block == other.block); }
///<summary>Generates the full NBT data of a chunk</summary> public void WriteToNBT(CompoundContainer level, Version version) { ListContainer sectionsList = level.GetAsList("Sections"); foreach (sbyte secY in sections.Keys) { var section = sections[secY]; //if(IsSectionEmpty(secY)) continue; var comp = GetSectionCompound(sectionsList, secY); if (comp == null) { bool use_1_16_format = version >= Version.Release_1(16); comp = section.CreateCompound(secY, use_1_16_format); } sectionsList.Add(null, comp); } //Make the biomes var finalBiomeArray = MakeBiomeArray(); List <int> biomes = new List <int>(); for (int y = 0; y < 64; y++) { for (int z = 0; z < 4; z++) { for (int x = 0; x < 4; x++) { var b = finalBiomeArray != null ? finalBiomeArray[x, y, z] : 1; biomes.Add(b); } } } level.Add("Biomes", biomes.ToArray()); //Add TileEntities var teList = level.GetAsList("TileEntities"); foreach (var te in tileEntities) { teList.Add(te.Value.NBTCompound); } //Add Entities var entitiyList = level.GetAsList("Entities"); foreach (var e in entities) { entitiyList.Add(e.NBTCompound); } //Add "post processing" positions (i.e. block positions that need an update) var ppList = level.GetAsList("PostProcessing"); foreach (var t in blockTicks) { //TODO: section index and coordinate packing is being guessed, trying to find out how to do it. int listIndex = t.y / 16; var x = t.x % 16; var y = t.y % 16; var z = t.z % 16; var list = ppList.Get <ListContainer>(listIndex); short packed = (short)((z << 8) + (y << 4) + x); list.Add(packed); } //Add liquid / tile ticks /* * var tileTickList = level.GetAsList("TileTicks"); * var liquidTickList = level.GetAsList("LiquidTicks"); * foreach (var t in blockTicks) * { * var block = GetBlockAt(t.x, t.y, t.z).block; * bool isLiquid = block.IsLiquid; * var comp = new CompoundContainer(); * string i; * if(isLiquid) * { * //i = block.IsWater ? "minecraft:flowing_water" : "minecraft:flowing_lava"; * //flowing_water and flowing_lava only applies to non-source blocks. * i = block.ID; * } * else * { * i = block.ID; * } * var worldCoord = coords.BlockCoord + t; * comp.Add("i", i); * comp.Add("t", 20); * comp.Add("p", 0); * comp.Add("x", worldCoord.x); * comp.Add("y", worldCoord.y); * comp.Add("z", worldCoord.z); * if(isLiquid) * { * liquidTickList.Add(comp); * } * else * { * tileTickList.Add(comp); * } * }*/ }
private CompoundContainer CreatePlayerCompound(int posX, int posY, int posZ, bool creativeModeWithCheats) { var player = new CompoundContainer(); var abilities = player.AddCompound("abilities"); abilities.Add <byte>("flying", 0); abilities.Add <float>("flySpeed", 0.05f); abilities.Add <byte>("instabuild", (byte)(creativeModeWithCheats ? 1 : 0)); abilities.Add <byte>("invulnerable", (byte)(creativeModeWithCheats ? 1 : 0)); abilities.Add <byte>("mayBuild", 0); abilities.Add <byte>("mayfly", (byte)(creativeModeWithCheats ? 1 : 0)); abilities.Add <float>("walkSpeed", 0.1f); player.AddCompound("Brain").AddCompound("memories"); player.AddCompound("recipeBook"); player.Add("Attributes", new ListContainer(NBTTag.TAG_Compound)); player.Add("EnderItems", new ListContainer(NBTTag.TAG_Compound)); player.Add("Inventory", new ListContainer(NBTTag.TAG_Compound)); player.AddList("Motion", NBTTag.TAG_Double).AddRange(0d, 0d, 0d); var pos = player.AddList("Pos", NBTTag.TAG_Double); pos.Add <double>(posX); pos.Add <double>(posY); pos.Add <double>(posZ); player.AddList("Rotation", NBTTag.TAG_Float).AddRange(0f, 0f); player.Add("AbsorptionAmount", 0f); player.Add <short>("Air", 300); player.Add <short>("DeathTime", 0); player.Add <string>("Dimension", "minecraft:overworld"); player.Add <float>("FallDistance", 0); player.Add <byte>("FallFlying", 0); player.Add <short>("Fire", -20); player.Add <float>("foodExhaustionLevel", 0); player.Add <int>("foodLevel", 20); player.Add <float>("foodSaturationLevel", 5); player.Add <int>("foodTickTimer", 0); player.Add <float>("Health", 20); player.Add <int>("HurtByTimestamp", 0); player.Add <short>("HurtTime", 0); player.Add <byte>("Invulnerable", 0); player.Add <byte>("OnGround", 0); player.Add <int>("playerGameType", creativeModeWithCheats ? 1 : 0); player.Add <int>("Score", 0); player.Add <byte>("seenCredits", 0); player.Add <int>("SelectedItemSlot", 0); player.Add <short>("SleepTimer", 0); player.Add <int>("XpLevel", 0); player.Add <float>("XpP", 0); player.Add <int>("XpSeed", 0); player.Add <int>("XpTotal", 0); player.Add <int>("DataVersion", 2504); //UUID? player.Add <int[]>("UUID", new int[] { 0, 0, 0, 0 }); return(player); }
public CompoundContainer CreateCompound(sbyte secY, bool use_1_16_Format) { var comp = new CompoundContainer(); comp.Add("Y", (byte)secY); ListContainer paletteContainer = new ListContainer(NBTTag.TAG_Compound); foreach (var block in palette) { CompoundContainer paletteBlock = new CompoundContainer(); paletteBlock.Add("Name", block.block.ID); if (block.properties != null) { CompoundContainer properties = new CompoundContainer(); foreach (var prop in block.properties.cont.Keys) { var value = block.properties.Get(prop); if (value is bool b) { value = b.ToString().ToLower(); } properties.Add(prop, value.ToString()); } paletteBlock.Add("Properties", properties); } paletteContainer.Add("", paletteBlock); } comp.Add("Palette", paletteContainer); //Encode block indices to bits and longs, oof int indexLength = Math.Max(4, (int)Math.Log(palette.Count - 1, 2.0) + 1); //How many block indices fit inside a long? int indicesPerLong = (int)Math.Floor(64f / indexLength); long[] longs = new long[(int)Math.Ceiling(4096f / indicesPerLong)]; string[] longsBinary = new string[longs.Length]; for (int j = 0; j < longsBinary.Length; j++) { longsBinary[j] = ""; } int i = 0; for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { string bin = NumToBits(blocks[x, y, z], indexLength); bin = Converter.ReverseString(bin); if (use_1_16_Format) { if (longsBinary[i].Length + indexLength > 64) { //The full value doesn't fit, start on the next long i++; longsBinary[i] += bin; } else { for (int j = 0; j < indexLength; j++) { if (longsBinary[i].Length >= 64) { i++; } longsBinary[i] += bin[j]; } } } } } } for (int j = 0; j < longs.Length; j++) { string s = longsBinary[j]; s = s.PadRight(64, '0'); s = Converter.ReverseString(s); longs[j] = Convert.ToInt64(s, 2); } comp.Add("BlockStates", longs); return(comp); }
static void LoadBlocksAnvilFormat(ChunkData chunk, CompoundContainer nbtCompound, Version?version) { var sectionsList = nbtCompound.GetAsList("Sections"); foreach (var o in sectionsList.cont) { var section = new ChunkSection(null); var compound = (CompoundContainer)o; if (!compound.Contains("Y") || !compound.Contains("Palette")) { continue; } sbyte secY; unchecked { secY = Convert.ToSByte(compound.Get("Y")); } section.palette.Clear(); foreach (var cont in compound.GetAsList("Palette").cont) { CompoundContainer block = (CompoundContainer)cont; var proto = BlockList.Find((string)block.Get("Name")); var bs = new BlockState(proto); if (block.Contains("Properties")) { bs.properties = block.GetAsCompound("Properties"); } section.palette.Add(bs); } //1.15 uses the full range of bits where 1.16 doesn't use the last bits if they can't contain a block index int indexLength = Math.Max(4, (int)Math.Log(section.palette.Count - 1, 2.0) + 1); long[] longs = (long[])compound.Get("BlockStates"); string bits = ""; for (int i = 0; i < longs.Length; i++) { string newBits = ""; byte[] bytes = BitConverter.GetBytes(longs[i]); for (int j = 0; j < 8; j++) { newBits += Converter.ByteToBinary(bytes[j], true); } if (version == null || version.Value < Version.Release_1(16, 0)) { bits += newBits; } else { bits += newBits.Substring(0, (int)Math.Floor(newBits.Length / (double)indexLength) * indexLength); } } //TODO: needs testing for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { section.blocks[x, y, z] = Converter.BitsToValue(bits, y * 256 + z * 16 + x, indexLength); } } } chunk.sections.Add(secY, section); } }