using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.IO.Compression; using fNbt; using fNbt.Serialization; using TrueCraft.API.Networking; namespace TrueCraft.API { /// /// Represents a stack of items. /// public struct ItemStack : ICloneable, IEquatable { /// /// Returns the hash code for this item stack. /// /// public override int GetHashCode() { unchecked { int hashCode = _Id.GetHashCode(); hashCode = (hashCode * 397) ^ _Count.GetHashCode(); hashCode = (hashCode * 397) ^ _Metadata.GetHashCode(); hashCode = (hashCode * 397) ^ Index; hashCode = (hashCode * 397) ^ (Nbt != null ? Nbt.GetHashCode() : 0); return hashCode; } } public static bool operator ==(ItemStack left, ItemStack right) { return left.Equals(right); } public static bool operator !=(ItemStack left, ItemStack right) { return !left.Equals(right); } /// /// Creates a new item stack with the specified values. /// /// The item ID for the item stack. public ItemStack(short id) : this() { _Id = id; _Count = 1; Metadata = 0; Nbt = null; Index = 0; } /// /// Creates a new item stack with the specified values. /// /// The item ID for the item stack. /// The item count for the item stack. public ItemStack(short id, sbyte count) : this(id) { Count = count; } /// /// Creates a new item stack with the specified values. /// /// The item ID for the item stack. /// The item count for the item stack. /// The metadata for the item stack. public ItemStack(short id, sbyte count, short metadata) : this(id, count) { Metadata = metadata; } /// /// Creates a new item stack with the specified values. /// /// The item ID for the item stack. /// The item count for the item stack. /// The metadata for the item stack. /// The NBT compound tag for the item stack. public ItemStack(short id, sbyte count, short metadata, NbtCompound nbt) : this(id, count, metadata) { Nbt = nbt; if (Count == 0) { ID = -1; Metadata = 0; Nbt = null; } } /// /// Creates and returns a new item stack read from a Minecraft stream. /// /// The stream to read from. /// public static ItemStack FromStream(IMinecraftStream stream) { var slot = ItemStack.EmptyStack; slot.ID = stream.ReadInt16(); if (slot.Empty) return slot; slot.Count = stream.ReadInt8(); slot.Metadata = stream.ReadInt16(); var length = stream.ReadInt16(); if (length == -1) return slot; slot.Nbt = new NbtCompound(); var buffer = stream.ReadUInt8Array(length); var nbt = new NbtFile(); nbt.LoadFromBuffer(buffer, 0, length, NbtCompression.GZip, null); slot.Nbt = nbt.RootTag; return slot; } /// /// Writes this item stack to a Minecraft stream. /// /// The stream to write to. public void WriteTo(IMinecraftStream stream) { stream.WriteInt16(ID); if (Empty) return; stream.WriteInt8(Count); stream.WriteInt16(Metadata); if (Nbt == null) { stream.WriteInt16(-1); return; } var mStream = new MemoryStream(); var file = new NbtFile(Nbt); file.SaveToStream(mStream, NbtCompression.GZip); stream.WriteInt16((short)mStream.Position); stream.WriteUInt8Array(mStream.GetBuffer()); } /// /// Creates and returns a new item stack created from an NBT compound tag. /// /// The compound tag to create the item stack from. /// public static ItemStack FromNbt(NbtCompound compound) { var s = ItemStack.EmptyStack; s.ID = compound.Get("id").Value; s.Metadata = compound.Get("Damage").Value; s.Count = (sbyte)compound.Get("Count").Value; s.Index = compound.Get("Slot").Value; if (compound.Get("tag") != null) s.Nbt = compound.Get("tag"); return s; } /// /// Creates and returns a new NBT compound tag containing this item stack. /// /// public NbtCompound ToNbt() { var c = new NbtCompound(); c.Add(new NbtShort("id", ID)); c.Add(new NbtShort("Damage", Metadata)); c.Add(new NbtByte("Count", (byte)Count)); c.Add(new NbtByte("Slot", (byte)Index)); if (Nbt != null) c.Add(new NbtCompound("tag")); return c; } /// /// Gets whether this item stack is empty. /// [NbtIgnore] public bool Empty { get { return ID == -1; } } /// /// Gets or sets the item ID for this item stack. /// public short ID { get { return _Id; } set { _Id = value; if (_Id == -1) { _Count = 0; Metadata = 0; Nbt = null; } } } /// /// Gets or sets the item count for this item stack. /// public sbyte Count { get { return _Count; } set { _Count = value; if (_Count == 0) { _Id = -1; Metadata = 0; Nbt = null; } } } /// /// Gets or sets the metadata for this item stack. /// public short Metadata { get { return _Metadata; } set { _Metadata = value; } } private short _Id; private sbyte _Count; private short _Metadata; /// /// The NBT compound tag for this item stack, if any. /// [IgnoreOnNull] public NbtCompound Nbt { get; set; } /// /// The index (slot) of this item stack in an inventory. /// [NbtIgnore] public int Index; /// /// Returns the string representation of this item stack. /// /// public override string ToString() { if (Empty) return "(Empty)"; StringBuilder resultBuilder = new StringBuilder("ID: " + ID); if (Count != 1) resultBuilder.Append("; Count: " + Count); if (Metadata != 0) resultBuilder.Append("; Metadata: " + Metadata); if (Nbt != null) resultBuilder.Append(Environment.NewLine + Nbt.ToString()); return "(" + resultBuilder.ToString() + ")"; } /// /// Returns a clone of this item stack. /// /// public object Clone() { return new ItemStack(ID, Count, Metadata, Nbt); } /// /// Gets an empty item stack. /// [NbtIgnore] public static ItemStack EmptyStack { get { return new ItemStack(-1); } } /// /// Determines whether this item stack can merge with another. /// /// The other item stack. /// public bool CanMerge(ItemStack other) { if (this.Empty || other.Empty) return true; return _Id == other._Id && _Metadata == other._Metadata && Equals(Nbt, other.Nbt); } /// /// Determines whether this item stack and another object are equal. /// /// The other object. /// public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; return obj is ItemStack && Equals((ItemStack)obj); } /// /// Determines whether this item stack and another are equal. /// /// The other item stack. /// public bool Equals(ItemStack other) { return _Id == other._Id && _Count == other._Count && _Metadata == other._Metadata && Index == other.Index && Equals(Nbt, other.Nbt); } } }