mcdreforged.minecraft.rtext.hover_event 源代码

import dataclasses
import json
from abc import ABC, abstractmethod
from typing import Optional, TYPE_CHECKING, Type, Dict, Any, Union, TypeVar, Generic, ClassVar
from uuid import UUID

from typing_extensions import override, Self, final

from mcdreforged.minecraft.rtext._registry import RRegistry, NamedObject
from mcdreforged.minecraft.rtext.schema import RTextJsonFormat
from mcdreforged.utils import class_utils

if TYPE_CHECKING:
	from mcdreforged.minecraft.rtext.text import RTextBase


class __RHoverMeta(RRegistry['RHoverAction']):
	pass


_RHE_co = TypeVar('_RHE_co', bound='RHoverEvent', covariant=True)


[文档] class RHoverAction(NamedObject, ABC, Generic[_RHE_co], metaclass=__RHoverMeta): """ Minecraft text hover event actions .. versionadded:: v2.15.0 """ show_text: ClassVar['RHoverAction[RHoverText]'] """Show hover text""" show_entity: ClassVar['RHoverAction[RHoverEntity]'] """Show entity information""" show_item: ClassVar['RHoverAction[RHoverItem]'] """Show item information""" @property @abstractmethod def event_class(self) -> Type[_RHE_co]: raise NotImplementedError()
class _RHoverActionImpl(RHoverAction): def __init__(self, name: str, event_class: Type['RHoverEvent']): self.__name = name self.__event_class = event_class @property @override def name(self) -> str: return self.__name @property @override def event_class(self) -> Type['RHoverEvent']: return self.__event_class def __repr__(self) -> str: return class_utils.represent(self, {'action': self.name, 'class': self.__event_class})
[文档] @dataclasses.dataclass(frozen=True) class RHoverEvent(ABC): """ An abstract base class of Minecraft hover event component .. versionadded:: v2.15.0 """ @property @abstractmethod def action(self) -> RHoverAction: """ Return the hover action type of this component """ raise NotImplementedError()
[文档] @final def to_json_object(self, json_format: RTextJsonFormat) -> dict: """ Serialize itself into a json dict :param json_format: The target json format """ data = self._to_json_object(json_format) data.pop('action', None) return {'action': self.action.name, **data}
@abstractmethod def _to_json_object(self, json_format: RTextJsonFormat) -> dict: raise NotImplementedError()
[文档] @classmethod @final def from_json_object(cls, hover_event: dict, json_format: RTextJsonFormat) -> 'RHoverEvent': """ Deserialize a json dict to a hover event component :param hover_event: The json dict to deserialize from :param json_format: The json format of the provided data """ action: str = class_utils.check_type(hover_event['action'], str) for rha in RHoverAction: if rha.name == action: event_class: Type[RHoverEvent] = rha.event_class return event_class._from_json_object(hover_event, json_format) raise ValueError(f'Unknown hover event action {action!r}')
@classmethod @abstractmethod def _from_json_object(cls, click_event: dict, json_format: RTextJsonFormat) -> Self: raise NotImplementedError()
_K = TypeVar('_K') _V = TypeVar('_V') def _get_by_any_key(dt: Dict[_K, _V], *keys: _K) -> _V: for key in keys: if key in dt: return dt[key] raise KeyError(keys)
[文档] @dataclasses.dataclass(frozen=True) class RHoverText(RHoverEvent): """ The hover event component for :attr:`RHoverAction.show_text` action .. versionadded:: v2.15.0 """ text: 'RTextBase' """The text to be displayed""" @property @override def action(self) -> RHoverAction: return RHoverAction.show_text @override def _to_json_object(self, json_format: RTextJsonFormat) -> dict: text_obj = self.text.to_json_object(json_format=json_format) if json_format == RTextJsonFormat.V_1_7: return {'value': text_obj} elif json_format == RTextJsonFormat.V_1_21_5: return {'value': text_obj} else: raise ValueError(json_format) @classmethod @override def _from_json_object(cls, click_event: dict, json_format: RTextJsonFormat) -> Self: if json_format == RTextJsonFormat.V_1_7: text_obj = _get_by_any_key(click_event, 'value', 'contents') elif json_format == RTextJsonFormat.V_1_21_5: text_obj = click_event['value'] else: raise ValueError(json_format) from mcdreforged.minecraft.rtext.text import RTextBase return cls(text=RTextBase.from_json_object(text_obj))
[文档] @dataclasses.dataclass(frozen=True) class RHoverEntity(RHoverEvent): """ The hover event component for :attr:`RHoverAction.show_entity` action .. versionadded:: v2.15.0 """ id: str """ The entity type identifier, e.g. ``minecraft:creeper`` """ uuid: UUID """ The UUID of the entity """ name: Optional[Union[str, 'RTextBase']] = None """ (Optional) The custom name of the entity """ @property @override def action(self) -> RHoverAction: return RHoverAction.show_entity @override def _to_json_object(self, json_format: RTextJsonFormat) -> dict: from mcdreforged.minecraft.rtext.text import RTextBase name_value: Union[str, dict, list, None] if isinstance(self.name, str): name_value = self.name elif isinstance(self.name, RTextBase): name_value = self.name.to_json_object(json_format=json_format) else: name_value = None if json_format == RTextJsonFormat.V_1_7: return { 'value': json.dumps({ 'type': self.id, 'id': str(self.uuid), **({'name': json.dumps(name_value, ensure_ascii=False)} if name_value is not None else {}), }, ensure_ascii=False) } elif json_format == RTextJsonFormat.V_1_21_5: return { 'id': self.id, 'uuid': str(self.uuid), **({'name': name_value} if name_value is not None else {}), } else: raise ValueError(json_format) @classmethod @override def _from_json_object(cls, click_event: dict, json_format: RTextJsonFormat) -> Self: from mcdreforged.minecraft.rtext.text import RTextBase def deserialize_name(value: Any) -> Optional[Union[str, RTextBase]]: if value is None or isinstance(value, str): return value else: return RTextBase.from_json_object(value) def deserialize_uuid(value: Any) -> UUID: if isinstance(value, str): return UUID(value) elif isinstance(value, list): if len(value) != 4: raise ValueError('list-like UUID should have exactly 4 elements, got {}'.format(len(value))) return UUID(int=(int(value[0]) << 96) | (int(value[1]) << 64) | (int(value[2]) << 32) | int(value[3])) else: raise TypeError(type(value)) if json_format == RTextJsonFormat.V_1_7: data: dict if 'contents' in click_event: data = click_event['contents'] else: data = json.loads(click_event['value']) if 'name' in data: data['name'] = json.loads(data['name']) return cls( id=class_utils.check_type(data['type'], str), uuid=deserialize_uuid(data['id']), name=deserialize_name(data.get('name')), ) elif json_format == RTextJsonFormat.V_1_21_5: return cls( id=class_utils.check_type(click_event['id'], str), uuid=deserialize_uuid(click_event['uuid']), name=deserialize_name(click_event.get('name')), ) else: raise ValueError(json_format)
[文档] @dataclasses.dataclass(frozen=True) class RHoverItem(RHoverEvent): """ The hover event component for :attr:`RHoverAction.show_item` action .. versionadded:: v2.15.0 """ id: str """ The item type identifier, e.g. ``minecraft:stone`` """ count: Optional[int] = None """ (Optional) Item count. Although it's optional, it's still suggested provide a value (e.g. 1) """ components: Optional[dict] = None """ (Optional) Extra NBT tag / item components information of the item stack """ @property @override def action(self) -> RHoverAction: return RHoverAction.show_item @override def _to_json_object(self, json_format: RTextJsonFormat) -> dict: if json_format == RTextJsonFormat.V_1_7: return { 'value': json.dumps({ 'id': self.id, **({'Count': self.count} if self.count is not None else {}), **({'tag': self.components} if self.components is not None else {}), }, ensure_ascii=False) } elif json_format == RTextJsonFormat.V_1_21_5: return { 'id': self.id, **({'count': self.count} if self.count is not None else {}), **({'components': self.components} if self.components is not None else {}), } else: raise ValueError(json_format) @classmethod @override def _from_json_object(cls, click_event: dict, json_format: RTextJsonFormat) -> Self: if json_format == RTextJsonFormat.V_1_7: data: dict if 'contents' in click_event: data = click_event['contents'] else: data = json.loads(click_event['value']) return cls( id=class_utils.check_type(data['id'], str), count=class_utils.check_type(data.get('Count'), (int, None)), components=class_utils.check_type(data.get('tag'), (dict, None)), ) elif json_format == RTextJsonFormat.V_1_21_5: return cls( id=class_utils.check_type(click_event['id'], str), count=class_utils.check_type(click_event.get('count'), (int, None)), components=class_utils.check_type(click_event.get('components'), (dict, None)), ) else: raise ValueError(json_format)
def __register_hover_events(): def register(name: str, event_class: Type[RHoverEvent]): # noinspection PyProtectedMember RHoverAction._register_item(name, _RHoverActionImpl(name, event_class)) register('show_text', RHoverText) register('show_entity', RHoverEntity) register('show_item', RHoverItem) # noinspection PyProtectedMember RHoverAction._ensure_registration_done() __register_hover_events()