Source code for bacommon.bs._displayitem

# Released under the MIT License. See LICENSE for details.
#
"""DisplayItem related functionality."""

from __future__ import annotations

from enum import Enum
from dataclasses import dataclass
from typing import Annotated, override, assert_never

from efro.util import pairs_to_flat
from efro.dataclassio import ioprepped, IOAttrs, IOMultiType

from bacommon.bs._chest import ClassicChestAppearance


[docs] class DisplayItemTypeID(Enum): """Type ID for each of our subclasses.""" UNKNOWN = 'u' TICKETS = 't' TOKENS = 'k' TEST = 's' CHEST = 'c'
[docs] class DisplayItem(IOMultiType[DisplayItemTypeID]): """Some amount of something that can be shown or described. Used to depict chest contents, inventory, rewards, etc. """
[docs] @override @classmethod def get_type_id(cls) -> DisplayItemTypeID: # Require child classes to supply this themselves. If we did a # full type registry/lookup here it would require us to import # everything and would prevent lazy loading. raise NotImplementedError()
[docs] @override @classmethod def get_type(cls, type_id: DisplayItemTypeID) -> type[DisplayItem]: """Return the subclass for each of our type-ids.""" # pylint: disable=cyclic-import t = DisplayItemTypeID if type_id is t.UNKNOWN: return UnknownDisplayItem if type_id is t.TICKETS: return TicketsDisplayItem if type_id is t.TOKENS: return TokensDisplayItem if type_id is t.TEST: return TestDisplayItem if type_id is t.CHEST: return ChestDisplayItem # Important to make sure we provide all types. assert_never(type_id)
[docs] def get_description(self) -> tuple[str, list[tuple[str, str]]]: """Return a string description and subs for the item. These decriptions are baked into the DisplayItemWrapper and should be accessed from there when available. This allows clients to give descriptions even for newer display items they don't recognize. """ raise NotImplementedError()
# Implement fallbacks so client can digest item lists even if they # contain unrecognized stuff. DisplayItemWrapper contains basic # baked down info that they can still use in such cases.
[docs] @override @classmethod def get_unknown_type_fallback(cls) -> DisplayItem: return UnknownDisplayItem()
[docs] @ioprepped @dataclass class UnknownDisplayItem(DisplayItem): """Something we don't know how to display."""
[docs] @override @classmethod def get_type_id(cls) -> DisplayItemTypeID: return DisplayItemTypeID.UNKNOWN
[docs] @override def get_description(self) -> tuple[str, list[tuple[str, str]]]: import logging # Make noise but don't break. logging.exception( 'UnknownDisplayItem.get_description() should never be called.' ' Always access descriptions on the DisplayItemWrapper.' ) return 'Unknown', []
[docs] @ioprepped @dataclass class TicketsDisplayItem(DisplayItem): """Some amount of tickets.""" count: int
[docs] @override @classmethod def get_type_id(cls) -> DisplayItemTypeID: return DisplayItemTypeID.TICKETS
[docs] @override def get_description(self) -> tuple[str, list[tuple[str, str]]]: return '${C} Tickets', [('${C}', str(self.count))]
[docs] @ioprepped @dataclass class TokensDisplayItem(DisplayItem): """Some amount of tokens.""" count: int
[docs] @override @classmethod def get_type_id(cls) -> DisplayItemTypeID: return DisplayItemTypeID.TOKENS
[docs] @override def get_description(self) -> tuple[str, list[tuple[str, str]]]: return '${C} Tokens', [('${C}', str(self.count))]
[docs] @ioprepped @dataclass class TestDisplayItem(DisplayItem): """Fills usable space for a display-item - good for calibration."""
[docs] @override @classmethod def get_type_id(cls) -> DisplayItemTypeID: return DisplayItemTypeID.TEST
[docs] @override def get_description(self) -> tuple[str, list[tuple[str, str]]]: return 'Test Display Item Here', []
[docs] @ioprepped @dataclass class ChestDisplayItem(DisplayItem): """Display a chest.""" appearance: ClassicChestAppearance
[docs] @override @classmethod def get_type_id(cls) -> DisplayItemTypeID: return DisplayItemTypeID.CHEST
[docs] @override def get_description(self) -> tuple[str, list[tuple[str, str]]]: return self.appearance.pretty_name, []
[docs] @ioprepped @dataclass class DisplayItemWrapper: """Wraps a DisplayItem and common info.""" item: DisplayItem description: str description_subs: list[str] | None
[docs] @classmethod def for_display_item(cls, item: DisplayItem) -> DisplayItemWrapper: """Convenience method to wrap a DisplayItem.""" desc, subs = item.get_description() return DisplayItemWrapper(item, desc, pairs_to_flat(subs))
# Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum