Fix Recipe impl and create TypeTaggedUnion

This commit is contained in:
object-Object 2023-06-25 17:22:35 -04:00
parent a6cfb0e244
commit 8414154460
3 changed files with 32 additions and 68 deletions

View file

@ -1,19 +1,8 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass, field
from itertools import chain
from pathlib import Path from pathlib import Path
from typing import ( from typing import Any, ClassVar, Generic, Self, Type, TypeVar
Any,
ClassVar,
Collection,
Generic,
Iterable,
Mapping,
Self,
Type,
TypeVar,
)
from common.deserialize import ( from common.deserialize import (
TypedConfig, TypedConfig,
@ -161,17 +150,15 @@ class StatefulInternallyTaggedUnion(
} }
StatefulUnions = Mapping[ @dataclass(kw_only=True)
Type[StatefulInternallyTaggedUnion[AnyState]], class TypeTaggedUnion(StatefulInternallyTaggedUnion[AnyState], tag="type", value=None):
Collection[Type[StatefulInternallyTaggedUnion[AnyState]]], type: ResourceLocation = field(init=False)
]
def __init_subclass__(cls, type: str | None) -> None:
super().__init_subclass__("type", type)
if type is not None:
cls.type = ResourceLocation.from_str(type)
def make_stateful_union_hooks( @property
base: Type[StatefulInternallyTaggedUnion[AnyState]], def _tag_value(self) -> str:
subtypes: Iterable[Type[StatefulInternallyTaggedUnion[AnyState]]], return str(self.type)
state: AnyState,
) -> TypeHooks[StatefulInternallyTaggedUnion[AnyState]]:
return {
subtype: subtype.make_type_hook(state) for subtype in chain([base], subtypes)
}

View file

@ -1,49 +1,36 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass
from typing import Any, Self, TypeVar from typing import Any, Self
from common.deserialize import TypeHook, load_json_data from common.deserialize import TypeHook, load_json_data
from common.state import BookState, StatefulInternallyTaggedUnion from common.state import AnyState, TypeTaggedUnion
from minecraft.resource import ResourceLocation from minecraft.resource import ResourceLocation
_T_State = TypeVar("_T_State", bound=BookState)
@dataclass(kw_only=True) @dataclass(kw_only=True)
class Recipe(StatefulInternallyTaggedUnion[_T_State], tag="type", value=None): class Recipe(TypeTaggedUnion[AnyState], type=None):
id: ResourceLocation id: ResourceLocation
type: ResourceLocation = field(init=False)
group: str | None = None group: str | None = None
def __init_subclass__(cls, type: str) -> None:
super().__init_subclass__(__class__._tag_key, type)
cls.type = ResourceLocation.from_str(type)
@classmethod @classmethod
def make_type_hook(cls, state: BookState) -> TypeHook[Self]: def make_type_hook(cls, state: AnyState) -> TypeHook[Self]:
"""Creates a type hook which, given a stringified ResourceLocation, loads and """Creates a type hook which, given a stringified ResourceLocation, loads and
returns the recipe json at that location.""" returns the recipe json at that location."""
super_hook = super().make_type_hook(state)
def type_hook(raw_id: str | Any) -> Self | dict[str, Any]: def type_hook(data: str | Any) -> Self | dict[str, Any]:
# FIXME: this should use isinstance_or_raise but I'm probably redoing it if isinstance(data, str):
if isinstance(raw_id, cls): # FIXME: hack
return raw_id # the point of this is to ensure the recipe exists on all platforms
# because we've had issues with that in the past, eg. in Hexal
id = ResourceLocation.from_str(data)
data = {}
for recipe_dir in state.props.recipe_dirs:
# TODO: should this use id.namespace somewhere?
path = recipe_dir / f"{id.path}.json"
data = load_json_data(cls, path, {"id": id})
# FIXME: hack return super_hook(data)
# the point of this is to ensure the recipe exists on all platforms
# because we've had issues with that in the past, eg. in Hexal
id = ResourceLocation.from_str(raw_id)
data: dict[str, Any] = {}
for recipe_dir in state.props.recipe_dirs:
# TODO: should this use id.namespace somewhere?
data = load_json_data(cls, recipe_dir / f"{id.path}.json")
return data | {"id": id, "state": state}
return type_hook return type_hook
@property
def _tag_value(self) -> str:
return str(self.type)

View file

@ -4,29 +4,23 @@ from typing import Any, Self
from common.deserialize import TypeHook, rename from common.deserialize import TypeHook, rename
from common.formatting import FormatTree from common.formatting import FormatTree
from common.state import AnyState, StatefulInternallyTaggedUnion from common.state import AnyState, TypeTaggedUnion
from common.types import LocalizedStr from common.types import LocalizedStr
from minecraft.recipe.concrete import CraftingRecipe from minecraft.recipe.concrete import CraftingRecipe
from minecraft.resource import ResourceLocation from minecraft.resource import ResourceLocation
@dataclass(kw_only=True) @dataclass(kw_only=True)
class Page(StatefulInternallyTaggedUnion[AnyState], tag="type", value=None): class Page(TypeTaggedUnion[AnyState], type=None):
"""Base class for Patchouli page types. """Base class for Patchouli page types.
See: https://vazkiimods.github.io/Patchouli/docs/patchouli-basics/page-types See: https://vazkiimods.github.io/Patchouli/docs/patchouli-basics/page-types
""" """
type: ResourceLocation = field(init=False)
advancement: ResourceLocation | None = None advancement: ResourceLocation | None = None
flag: str | None = None flag: str | None = None
anchor: str | None = None anchor: str | None = None
def __init_subclass__(cls, type: str | None) -> None:
super().__init_subclass__("type", type)
if type is not None:
cls.type = ResourceLocation.from_str(type)
@classmethod @classmethod
def make_type_hook(cls, state: AnyState) -> TypeHook[Self]: def make_type_hook(cls, state: AnyState) -> TypeHook[Self]:
super_hook = super().make_type_hook(state) super_hook = super().make_type_hook(state)
@ -39,10 +33,6 @@ class Page(StatefulInternallyTaggedUnion[AnyState], tag="type", value=None):
return type_hook return type_hook
@property
def _tag_value(self) -> str:
return str(self.type)
@dataclass(kw_only=True) @dataclass(kw_only=True)
class PageWithText(Page[AnyState], type=None): class PageWithText(Page[AnyState], type=None):