public override byte[] GetBytes(Stream instream) { if (_cache != null) { instream.Write(_cache); return(_cache); } using (var stream = new MemoryStream()) { stream.WriteByte(8); // version int numberOfStores = 1; stream.WriteByte((byte)numberOfStores); // storage size List <uint> palette = new List <uint>(10); byte[] indexes = new byte[_blocks.Length]; for (int i = 0; i < numberOfStores; i++) { palette.Clear(); stream.WriteByte((8 << 1) | 1); // version int index = 0; uint prevHash = uint.MaxValue; for (int b = 0; b < _blocks.Length; b++) { byte bid = (byte)_blocks[b]; byte data = _metadata[b]; uint hash = BlockFactory.GetRuntimeId(bid, data); if (hash != prevHash) { index = palette.IndexOf(hash); if (index == -1) { palette.Add(hash); } index = palette.IndexOf(hash); } indexes[b] = (byte)index; prevHash = hash; } stream.Write(indexes, 0, indexes.Length); VarInt.WriteSInt32(stream, palette.Count); // count foreach (var val in palette) { VarInt.WriteSInt32(stream, (int)val); } } var bytes = stream.ToArray(); instream.Write(bytes); _cache = bytes; } return(_cache); }
public static Item GetItem(short id, short metadata = 0, int count = 1) { Item item = null; if (CustomItemFactory != null) { item = CustomItemFactory.GetItem(id, metadata, count); } if (item != null) { return(item); } if (id == 0) { item = new ItemAir(); } else if (id == 256) { item = new ItemIronShovel(); } else if (id == 257) { item = new ItemIronPickaxe(); } else if (id == 258) { item = new ItemIronAxe(); } else if (id == 259) { item = new ItemFlintAndSteel(); } else if (id == 260) { item = new ItemApple(); } else if (id == 261) { item = new ItemBow(); } else if (id == 262) { item = new ItemArrow(); } else if (id == 263) { item = new ItemCoal(); } else if (id == 264) { item = new ItemDiamond(); } else if (id == 265) { item = new ItemIronIngot(); } else if (id == 266) { item = new ItemGoldIngot(); } else if (id == 267) { item = new ItemIronSword(); } else if (id == 268) { item = new ItemWoodenSword(); } else if (id == 269) { item = new ItemWoodenShovel(); } else if (id == 270) { item = new ItemWoodenPickaxe(); } else if (id == 271) { item = new ItemWoodenAxe(); } else if (id == 272) { item = new ItemStoneSword(); } else if (id == 273) { item = new ItemStoneShovel(); } else if (id == 274) { item = new ItemStonePickaxe(); } else if (id == 275) { item = new ItemStoneAxe(); } else if (id == 276) { item = new ItemDiamondSword(); } else if (id == 277) { item = new ItemDiamondShovel(); } else if (id == 278) { item = new ItemDiamondPickaxe(); } else if (id == 279) { item = new ItemDiamondAxe(); } else if (id == 280) { item = new ItemStick(); } else if (id == 283) { item = new ItemGoldenSword(); } else if (id == 284) { item = new ItemGoldenShovel(); } else if (id == 285) { item = new ItemGoldenPickaxe(); } else if (id == 286) { item = new ItemGoldenAxe(); } else if (id == 290) { item = new ItemWoodenHoe(); } else if (id == 291) { item = new ItemStoneHoe(); } else if (id == 292) { item = new ItemIronHoe(); } else if (id == 293) { item = new ItemDiamondHoe(); } else if (id == 294) { item = new ItemGoldenHoe(); } else if (id == 295) { item = new ItemWheatSeeds(); } else if (id == 296) { item = new ItemWheat(); } else if (id == 297) { item = new ItemBread(); } else if (id == 298) { item = new ItemLeatherHelmet(); } else if (id == 299) { item = new ItemLeatherChestplate(); } else if (id == 300) { item = new ItemLeatherLeggings(); } else if (id == 301) { item = new ItemLeatherBoots(); } else if (id == 302) { item = new ItemChainmailHelmet(); } else if (id == 303) { item = new ItemChainmailChestplate(); } else if (id == 304) { item = new ItemChainmailLeggings(); } else if (id == 305) { item = new ItemChainmailBoots(); } else if (id == 309) { item = new ItemIronBoots(); } else if (id == 308) { item = new ItemIronLeggings(); } else if (id == 307) { item = new ItemIronChestplate(); } else if (id == 306) { item = new ItemIronHelmet(); } else if (id == 310) { item = new ItemDiamondHelmet(); } else if (id == 311) { item = new ItemDiamondChestplate(); } else if (id == 312) { item = new ItemDiamondLeggings(); } else if (id == 313) { item = new ItemDiamondBoots(); } else if (id == 314) { item = new ItemGoldHelmet(); } else if (id == 315) { item = new ItemGoldChestplate(); } else if (id == 316) { item = new ItemGoldLeggings(); } else if (id == 317) { item = new ItemGoldBoots(); } else if (id == 319) { item = new ItemRawPorkchop(); } else if (id == 320) { item = new ItemCookedPorkshop(); } else if (id == 321) { item = new ItemPainting(); } else if (id == 322) { item = new ItemGoldenApple(); } else if (id == 323) { item = new ItemSign(); } else if (id == 324) { item = new ItemWoodenDoor(); } else if (id == 325) { item = new ItemBucket(metadata); } else if (id == 329) { item = new ItemSaddle(); } else if (id == 331) { item = new ItemRedstone(); } else if (id == 332) { item = new ItemSnowball(); } else if (id == 333) { item = new ItemBoat(metadata); } else if (id == 340) { item = new ItemBook(); } else if (id == 344) { item = new ItemEgg(); } else if (id == 345) { item = new ItemCompass(); } else if (id == 351) { item = new ItemDye(); } else if (id == 352) { item = new ItemBone(); } else if (id == 352) { item = new ItemSugar(); } else if (id == 355) { item = new ItemBed(); } else if (id == 357) { item = new ItemCookie(); } else if (id == 358) { item = new ItemMap(); } else if (id == 359) { item = new ItemShears(); } else if (id == 360) { item = new ItemMelonSlice(); } else if (id == 363) { item = new ItemBeef(); } else if (id == 364) { item = new ItemCookedBeef(); } else if (id == 365) { item = new ItemRawChicken(); } else if (id == 366) { item = new ItemCookedChicken(); } else if (id == 369) { item = new ItemBlazeRod(); } else if (id == 371) { item = new ItemGoldNugget(); } else if (id == 373) { item = new ItemPotion(metadata); } else if (id == 377) { item = new ItemBlazePowder(); } else if (id == 380) { item = new ItemCauldron(); } else if (id == 383) { item = new ItemMonsterEgg(metadata); } else if (id == 389) { item = new ItemFrame(); } else if (id == 391) { item = new ItemCarrot(); } else if (id == 392) { item = new ItemPotato(); } else if (id == 393) { item = new ItemBakedPotato(); } else if (id == 395) { item = new ItemEmptyMap(); } else if (id == 395) { item = new ItemGoldenCarrot(); } else if (id == 397) { item = new ItemMobHead(metadata); } else if (id == 400) { item = new ItemPumpkinPie(); } else if (id == 401) { item = new ItemFireworks(); } else if (id == 403) { item = new ItemEnchantedBook(); } else if (id == 416) { item = new ItemHorseArmorLeather(); } else if (id == 417) { item = new ItemHorseArmorIron(); } else if (id == 418) { item = new ItemHorseArmorGold(); } else if (id == 419) { item = new ItemHorseArmorDiamond(); } else if (id == 423) { item = new ItemMuttonRaw(); } else if (id == 424) { item = new ItemMuttonCooked(); } else if (id == 427) { item = new ItemSpruceDoor(); } else if (id == 428) { item = new ItemBirchDoor(); } else if (id == 429) { item = new ItemJungleDoor(); } else if (id == 430) { item = new ItemAcaciaDoor(); } else if (id == 431) { item = new ItemDarkOakDoor(); } else if (id == 444) { item = new ItemElytra(); } else if (id == 446) { item = new ItemBanner(); } else if (id == 452) { item = new ItemIronNugget(); } else if (id == 454 && metadata == 0) { item = new ItemSlate(); } else if (id == 454 && metadata == 1) { item = new ItemPoster(); } else if (id == 454 && metadata == 2) { item = new ItemBoard(); } else if (id == 458) { item = new ItemBeetrootSeeds(); } else if (id == 498) { item = new ItemCamera(metadata); } else if (id <= 255) { int blockId = id; if (blockId < 0) { blockId = (short)(Math.Abs(id) + 255); // hehe } Block block = BlockFactory.GetBlockById(blockId); var runtimeId = BlockFactory.GetRuntimeId(blockId, (byte)metadata); if (runtimeId < BlockFactory.BlockPalette.Count) { var blockState = BlockFactory.BlockPalette[(int)runtimeId]; block.SetState(blockState); } if (CustomBlockItemFactory == null) { item = new ItemBlock(block, metadata); } else { item = CustomBlockItemFactory.GetBlockItem(block, metadata, count); } } else { item = new Item(id, metadata, count); } // This might now be a good idea if the constructor changes these // properties for custom items. item.Metadata = metadata; item.Count = (byte)count; return(item); }
private void ParseSection(SubChunk section, ReadOnlySpan <byte> data) { var reader = new SpanReader(); var version = reader.ReadByte(data); if (version != 8) { throw new Exception("Wrong chunk version"); } var storageSize = reader.ReadByte(data); for (int storage = 0; storage < storageSize; storage++) { byte paletteAndFlag = reader.ReadByte(data); bool isRuntime = (paletteAndFlag & 1) != 0; if (isRuntime) { throw new Exception("Can't use runtime for persistent storage."); } int bitsPerBlock = paletteAndFlag >> 1; int blocksPerWord = (int)Math.Floor(32d / bitsPerBlock); int wordCount = (int)Math.Ceiling(4096d / blocksPerWord); int blockIndex = reader.Position; reader.Position += wordCount * 4; int paletteSize = reader.ReadInt32(data); var palette = new Dictionary <int, (short, byte)>(); for (int j = 0; j < paletteSize; j++) { var file = new NbtFile { BigEndian = false, UseVarInt = false }; var buffer = data.Slice(reader.Position).ToArray(); int numberOfBytesRead = (int)file.LoadFromStream(new MemoryStream(buffer), NbtCompression.None); reader.Position += numberOfBytesRead; var tag = file.RootTag; string blockName = tag["name"].StringValue; Block block = BlockFactory.GetBlockByName(blockName); short blockId = 0; if (block != null) { blockId = (short)block.Id; } else { Log.Warn($"Missing block={blockName}"); } short blockMeta = tag["val"].ShortValue; palette.Add(j, (blockId, (byte)blockMeta)); } int nextStore = reader.Position; reader.Position = blockIndex; int position = 0; for (int wordIdx = 0; wordIdx < wordCount; wordIdx++) { uint word = reader.ReadUInt32(data); for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { continue; // padding bytes } int state = (int)((word >> ((position % blocksPerWord) * bitsPerBlock)) & ((1 << bitsPerBlock) - 1)); int x = (position >> 8) & 0xF; int y = position & 0xF; int z = (position >> 4) & 0xF; if (state > palette.Count) { Log.Error($"Got wrong state={state} from word. bitsPerBlock={bitsPerBlock}, blocksPerWord={blocksPerWord}, Word={word}"); } short bid = palette[state].Item1; byte metadata = palette[state].Item2; int runtimeId = (int)BlockFactory.GetRuntimeId(bid, metadata); if (storage == 0) { section.SetBlockByRuntimeId(x, y, z, runtimeId); } else { section.SetLoggedBlockByRuntimeId(x, y, z, runtimeId); } position++; } } reader.Position = nextStore; } }
public void EncodePalettedChunk() { //PaletteChunk chunk = new PaletteChunk(); //chunk.GetBytes() uint waste = BlockFactory.GetRuntimeId(0, 0); int[] legacyToRuntimeId = BlockFactory.LegacyToRuntimeId; short[] blocks = new short[4096]; Random random = new Random(); for (int i = 0; i < blocks.Length; i++) { blocks[i] = (short)random.Next(8); } //blocks[0] = 0b000; //blocks[1] = 0b111; //blocks[2] = 0b111; //blocks[3] = 0b111; //blocks[4] = 0b111; //blocks[5] = 0b111; //blocks[6] = 0b111; //blocks[7] = 0b001; //blocks[8] = 0b010; //blocks[9] = 0b011; //blocks[10] = 0b100; //blocks[11] = 0b101; byte[] metas = new byte[4096]; int count = 10_000; var sw = Stopwatch.StartNew(); for (int c = 0; c < count; c++) { for (int sc = 0; sc < 8; sc++) { var palette = new Dictionary <uint, byte>(); uint prevHash = uint.MaxValue; for (int i = 0; i < 4096; i++) { uint hash = (uint)blocks[i] << 4 | metas[i]; if (hash == prevHash) { continue; } prevHash = hash; palette[hash] = 0; } // log2(number of entries) => bits needed to store them //Assert.AreEqual(0, Math.Ceiling(Math.Log(1, 2))); //Assert.AreEqual(1, Math.Ceiling(Math.Log(2, 2))); //Assert.AreEqual(2, Math.Ceiling(Math.Log(3, 2))); //Assert.AreEqual(2, Math.Ceiling(Math.Log(4, 2))); //Assert.AreEqual(3, Math.Ceiling(Math.Log(5, 2))); //Assert.AreEqual(3, Math.Ceiling(Math.Log(palette.Count, 2))); //Assert.AreEqual(3, Math.Ceiling(Math.Log(8, 2))); //Assert.AreEqual(4, Math.Ceiling(Math.Log(9, 2))); //Assert.AreEqual(4, Math.Ceiling(Math.Log(16, 2))); //Assert.AreEqual(5, Math.Ceiling(Math.Log(17, 2))); //Assert.AreEqual(5, Math.Ceiling(Math.Log(32, 2))); //Assert.AreEqual(6, Math.Ceiling(Math.Log(33, 2))); //Assert.AreEqual(6, Math.Ceiling(Math.Log(64, 2))); //Assert.AreEqual(7, Math.Ceiling(Math.Log(65, 2))); //Assert.AreEqual(7, Math.Ceiling(Math.Log(128, 2))); //Assert.AreEqual(8, Math.Ceiling(Math.Log(129, 2))); //Assert.AreEqual(8, Math.Ceiling(Math.Log(256, 2))); //Assert.AreEqual(16, Math.Ceiling(Math.Log(ushort.MaxValue, 2))); int bitsPerBlock = (int)Math.Ceiling(Math.Log(palette.Count, 2)); switch (bitsPerBlock) { case 1: case 2: case 3: case 4: case 5: case 6: //Paletted1 = 1, // 32 blocks per word //Paletted2 = 2, // 16 blocks per word //Paletted3 = 3, // 10 blocks and 2 bits of padding per word //Paletted4 = 4, // 8 blocks per word //Paletted5 = 5, // 6 blocks and 2 bits of padding per word //Paletted6 = 6, // 5 blocks and 2 bits of padding per word break; case 7: case 8: //Paletted8 = 8, // 4 blocks per word bitsPerBlock = 8; break; case int i when i > 8: //Paletted16 = 16, // 2 blocks per word bitsPerBlock = 16; break; default: break; } int blocksPerWord = (int)Math.Floor(32f / bitsPerBlock); // Floor to remove padding bits int wordsPerChunk = (int)Math.Ceiling(4096f / blocksPerWord); Assert.AreEqual(10, blocksPerWord); byte t = 0; foreach (var b in palette.ToArray()) { palette[b.Key] = t++; } uint[] indexes = new uint[wordsPerChunk]; int position = 0; for (int w = 0; w < wordsPerChunk; w++) { uint word = 0; for (int block = 0; block < blocksPerWord; block++) { if (position >= 4096) { continue; } uint state = palette[(uint)blocks[position] << 4 | metas[position]]; word |= state << (bitsPerBlock * block); //string bin = Convert.ToString(word, 2); //bin = new string('0', 32 - bin.Length) + bin; //Console.WriteLine($"{bin}"); position++; } indexes[w] = word; } } } Console.WriteLine($"time={sw.ElapsedMilliseconds}"); }