Skip to content

Instantly share code, notes, and snippets.

@Podshot
Created December 21, 2020 16:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Podshot/6b423009c101599125b03fba5d333072 to your computer and use it in GitHub Desktop.
Save Podshot/6b423009c101599125b03fba5d333072 to your computer and use it in GitHub Desktop.
from __future__ import annotations
from enum import IntFlag
from typing import List
from collections.abc import Mapping, MutableSequence
from pprint import pprint
from dataclasses import dataclass
from uuid import UUID
def flatten_nbt(data):
def walk(path, node, store=None):
if not store:
store = {}
for key, item in node.items():
entry_key = f"{path}{'.' if path else ''}{key}".lower()
if isinstance(item, Mapping):
walk(entry_key, item, store)
elif isinstance(item, MutableSequence):
ls = []
for element in item:
if isinstance(element, Mapping):
ls.append(walk("", element))
else:
ls.append(element)
store[entry_key] = ls
else:
store[entry_key] = item
return store
return walk("item", data)
class ItemFactory:
def __init__(self):
pass
def load(self, item_nbt) -> Item:
raise NotImplementedError()
def save(self, item: Item):
raise NotImplementedError()
class ItemStructures:
class HideFlags(IntFlag):
ENCHANTMENTS = 1
ATTRIBUTE_MODIFIERS = 2
UNBREAKABLE = 4
CAN_DESTROY = 8
CAN_PLACE_ON = 16
MISC = 32
DYED = 64
@dataclass
class Enchantment:
id: str = None
lvl: int = None
@dataclass
class Display:
name: str = None
color: int = None
lore: List[str] = None
@staticmethod
def parse_color(red, green, blue) -> int:
return (red << 16) + (green << 8) + blue
@staticmethod
def from_color(color):
blue = color & 0xFF
green = (color >> 8) & 0xFF
red = (color >> 16) & 0xFF
return red, green, blue
@dataclass
class AttributeModifier:
attribute_name: str = None
name: str = None
slot: str = None
operation: int = None
amount: float = None
uuid: UUID = None
class ItemValue:
def __init__(self, value=None, children=None, func_pointer=None):
if value is None and children is None:
raise Exception("ItemValue must have a value or children")
if value and children:
raise Exception("ItemValue cannot have both a value and children")
self._value = value
self._children = children
self._func_pointer = func_pointer
@property
def value(self):
return self._value
@value.setter
def value(self, val):
self._func_pointer(val)
@property
def children(self):
return self._children
class Item:
def __init__(self, item_data):
self._item_data = item_data
def _set_data(self, path, value):
self._item_data[path] = value
def __getitem__(self, item):
if item in self._item_data:
return ItemValue(
value=self._item_data[item],
func_pointer=lambda v: self._set_data(item, v),
)
return ItemValue(
children=list(filter(lambda k: k.startswith(item), self._item_data.keys())),
func_pointer=lambda v: self._set_data(item, v),
)
if __name__ == "__main__":
i1 = {
"id": "minecraft:stick",
"tag": {
"Damage": 10,
"Unbreakable": 0,
"Enchantments": [
{"id": "aqua_affinity", "lvl": 1},
{"id": "enchant", "lvl": 100},
],
"test": [0, 1, 2],
"test_nested": [
{
"id": "test1",
"values": [3, 4, 5],
"nested": {"foo": "bar", "vals": [6, 7, 8]},
},
{
"id": "test2",
"values": [3.5, 4.5, 5.5],
"nested": {"foo": "var", "vals": [6.5, 7.5, 8.5]},
},
],
},
}
pprint(flatten_nbt(i1))
from __future__ import annotations
from common import ItemFactory, flatten_nbt, Item, ItemStructures
class Anvil2ItemFactory(ItemFactory):
def load(self, item_nbt) -> Item:
flattened = flatten_nbt(item_nbt)
if "item.tag.enchantments" in flattened:
flattened["item.tag.enchantments"] = [
ItemStructures.Enchantment(id=enchant["id"], lvl=enchant["lvl"])
for enchant in flattened["item.tag.enchantments"]
]
if "item.tag.display" in flattened:
flattened["item.tag.display"] = ItemStructures.Display(
color=flattened.get("item.tag.display.color", None),
name=flattened.get("item.tag.display.Name", None),
lore=flattened.get("item.tag.display.Lore", None)
)
return Item(flattened)
def save(self, item: Item):
raise NotImplementedError
if __name__ == "__main__":
factory = Anvil2ItemFactory()
item = factory.load(
{
"id": "minecraft:stick",
"tag": {
"Damage": 10,
"Unbreakable": 0,
"Enchantments": [
{"id": "aqua_affinity", "lvl": 1},
{"id": "enchant", "lvl": 100},
],
"test": [0, 1, 2],
"test_nested": [
{
"id": "test1",
"values": [3, 4, 5],
"nested": {"foo": "bar", "vals": [6, 7, 8]},
},
{
"id": "test2",
"values": [3.5, 4.5, 5.5],
"nested": {"foo": "var", "vals": [6.5, 7.5, 8.5]},
},
],
},
}
)
print(item._item_data)
print(item['item.tag.doesnt_exist1.doesnt_exist2'].value)
item['item.tag.doesnt_exist1.doesnt_exist2'].value = 4
print(item['item.tag.doesnt_exist1.doesnt_exist2'].children)
print(item['item.tag.doesnt_exist1.doesnt_exist2'].value)
print(item['item.tag'].children)
print()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment