using System; using System.Collections; using System.Collections.Generic; using LibAC.NBT.API; namespace LibAC.NBT { public class CompoundTag : Tag, IDictionary { private readonly Dictionary _value = new Dictionary(); public CompoundTag() { } public override void ReadValue(ByteLayer data) { _value.Clear(); while (true) { Tag tag = Tag.ReadNamedTag(data); if (tag.GetType() == 0) { return; } tag.SetParentTagType(TagType.Compound); this[tag.GetKey()] = tag; } } public override void WriteValue(ByteLayer data) { foreach (var tag in _value.Values) { Tag.WriteNamedTag(tag, data); } data.WriteByte((byte)TagType.End); } public void Put(string name, Tag tag) { _value[name] = tag; tag.SetKey(name); tag.UpdateParent(this); } public Tag? Get(string name) { return ContainsKey(name) ? _value[name] : null; } public override TagType GetTagType() { return TagType.Compound; } public override object GetValue() { return null; } public override void SetValue(object val) { } public override void PrettyPrint(int indent, bool recurse) { Console.WriteLine($"{new string('\t', indent)}{Tag.GetCanonicalName(GetTagType())}: [{_value.Count} entries]"); Console.WriteLine($"{new string('\t', indent)}"); if (recurse) { foreach (var tag in _value.Values) { tag.PrettyPrint(indent + 1, true); } } } public void EndPrettyPrint(int indent) { Console.WriteLine($"{new string('\t', indent)}"); } public override void WriteStringifiedValue(StringBuilder builder, int indent, bool isList) { builder.Append($"{(isList ? new string('\t', indent - 1) : "")}{{\n"); bool firstEntry = true; foreach (var tag in _value.Values) { if (!firstEntry) { builder.Append(",\n"); } firstEntry = false; Tag.WriteStringifiedNamedTag(tag, builder, indent); } builder.Append($"\n{new string('\t', indent - 1)}}}"); } public bool TryGetValue(string key, out Tag value) { return _value.TryGetValue(key, out value); } public Tag? this[string key] { get => _value.ContainsKey(key) ? _value[key] : null; set { if (value != null) { _value[key] = value; value.UpdateParent(this); } } } public void Add(string key, Tag value) { _value.Add(key, value); value.UpdateParent(this); } public void Add(KeyValuePair item) { _value.Add(item.Key, item.Value); item.Value.UpdateParent(this); } public void Clear() { UnsetParent(); _value.Clear(); } public bool Contains(KeyValuePair item) { return _value.ContainsKey(item.Key); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { throw new NotImplementedException(); } public bool Remove(KeyValuePair item) { return _value.Remove(item.Key); } public void UnsetParent() { foreach (var entry in _value) { entry.Value.SetParentTagType(TagType.End); entry.Value.UpdateParent(null); } } public bool ContainsKey(string key) { return _value.ContainsKey(key); } public bool ContainsValue(Tag value) { return _value.ContainsValue(value); } public void ForEach(Action action) { foreach (var entry in _value) { action(entry.Key, entry.Value); } } public int Count => _value.Count; public bool IsReadOnly { get; } public bool IsEmpty => _value.Count == 0; public bool IsNotEmpty => _value.Count > 0; public ICollection Keys => _value.Keys; public ICollection Values => _value.Values; public override void ReadStringifiedValue(StringReader reader) { reader.Expect('{'); while (reader.Peek() != '}') { Tag tag = Tag.ReadStringifiedNamedTag(reader); Put(tag.GetKey(), tag); if (reader.Peek() == ',') reader.Next(); } reader.Expect('}'); } public void AddAll(IDictionary other) { foreach (var entry in other) { _value[entry.Key] = entry.Value; entry.Value.UpdateParent(this); } } public bool Remove(string key) { if (_value.ContainsKey(key)) { _value[key].UpdateParent(null); return _value.Remove(key); } return false; } public void RemoveWhere(Predicate> predicate) { var toRemove = new List(); foreach (var entry in _value) { if (predicate(entry)) { toRemove.Add(entry.Key); } } foreach (var key in toRemove) { _value[key].UpdateParent(null); _value.Remove(key); } } public void UpdateAll(Action update) { foreach (var entry in _value) { update(entry.Key, entry.Value); } } public Tag PutIfAbsent(string key, Func ifAbsent) { if (!_value.ContainsKey(key)) { var tag = ifAbsent(); tag.UpdateParent(this); _value[key] = tag; return tag; } return _value[key]; } public void AddEntries(IEnumerable> newEntries) { foreach (var entry in newEntries) { _value.Add(entry.Key, entry.Value); entry.Value.UpdateParent(this); } } public IEnumerator> GetEnumerator() { return _value.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return _value.GetEnumerator(); } } }