using System; using System.Runtime.CompilerServices; using MinecraftClient.Mapping.BlockPalettes; namespace MinecraftClient.Mapping { /// /// Represents a Minecraft Block /// public struct Block { public static readonly Block Air = new(0); /// /// Get or set global block ID to Material mapping /// The global Palette is a concept introduced with Minecraft 1.13 /// public static BlockPalette Palette { get; set; } = new Palette112(); /// /// Storage for block ID and metadata, as ushort for compatibility, performance and lower memory footprint /// For Minecraft 1.12 and lower, first 12 bits contain block ID (0-4095), last 4 bits contain metadata (0-15) /// For Minecraft 1.13 and greater, all 16 bits are used to store block state ID (0-65535) /// private ushort blockIdAndMeta; /// /// Id of the block /// public int BlockId { get { if (Palette.IdHasMetadata) { return blockIdAndMeta >> 4; } return blockIdAndMeta; } set { if (Palette.IdHasMetadata) { if (value > (ushort.MaxValue >> 4) || value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Invalid block ID. Accepted range: 0-4095"); blockIdAndMeta = (ushort)(value << 4 | BlockMeta); } else { if (value > ushort.MaxValue || value < 0) throw new ArgumentOutOfRangeException(nameof(value), "Invalid block ID. Accepted range: 0-65535"); blockIdAndMeta = (ushort)value; } } } /// /// Metadata of the block. /// This field has no effect starting with Minecraft 1.13. /// public byte BlockMeta { get { if (Palette.IdHasMetadata) { return (byte)(blockIdAndMeta & 0x0F); } return 0; } set { if (Palette.IdHasMetadata) { blockIdAndMeta = (ushort)((blockIdAndMeta & ~0x0F) | (value & 0x0F)); } } } /// /// Material of the block /// public Material Type { get { return Palette.FromId(BlockId); } } /// /// Get a block of the specified type and metadata /// /// Block type /// Block metadata public Block(short type, byte metadata) { if (!Palette.IdHasMetadata) throw new InvalidOperationException("Current global Palette does not support block Metadata"); blockIdAndMeta = 0; BlockId = type; BlockMeta = metadata; } /// /// Get a block of the specified type and metadata OR block state /// /// Type and metadata packed in the same value OR block state [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public Block(ushort typeAndMeta) { blockIdAndMeta = typeAndMeta; } public string GetTypeString() { string typeStr = Type.ToString(); string? trans = Protocol.ChatParser.TranslateString("block.minecraft." + typeStr.ToUnderscoreCase()); return string.IsNullOrEmpty(trans) ? typeStr : trans; } /// /// String representation of the block /// public override string ToString() { return BlockId.ToString() + (BlockMeta != 0 ? ":" + BlockMeta.ToString() : ""); } } }