Source code for gd.api.struct

from gd.utils.text_tools import make_repr
from gd.errors import EditorError

from gd.utils import search_utils as search

from gd.api.parser import (
    _dump,
    _convert,
    _collect,
    _process_level,
    _level_dump,
    _object_dump,
    _object_convert,
    _object_collect,
    _color_dump,
    _color_convert,
    _color_collect,
    _header_dump,
    _header_convert,
    _header_collect,
)

from gd.api.utils import _make_color, _get_dir, _define_color, get_id, get_default
from gd.api._property import (
    _object_code,
    _color_code,
    _header_code,
    _level_code,
)

from gd.typing import (
    Any,
    Color,
    ColorChannel,
    ColorCollection,
    Dict,
    Editor,
    Header,
    Iterable,
    LevelAPI,
    Object,
    Optional,
    Struct,
    Tuple,
    Union,
)

__all__ = ("Object", "ColorChannel", "Header", "LevelAPI", "ColorCollection", "DEFAULT_COLORS")

Number = Union[float, int]


class Struct:
    _dump = _dump
    _convert = _convert
    _convert = _collect
    _base_data = {}
    _container = {}

    def __init__(self, **properties) -> None:
        self.data = self._base_data.copy()

        for name, value in properties.items():
            setattr(self, name, value)

    def __repr__(self) -> str:
        info = {key: repr(value) for key, value in self.to_dict().items()}
        return make_repr(self, info)

    def __json__(self) -> Dict[str, Any]:
        return self.to_dict()

    def to_dict(self) -> Dict[str, Any]:
        final = {}
        for key, value in self.data.items():
            key = self._container.get(key)

            if key is not None:
                final[key] = value

        return final

    def dump(self) -> str:
        return self.__class__._collect(self.to_map())

    def to_map(self) -> Dict[str, Any]:
        return self.__class__._dump(self.data)

    def copy(self) -> Struct:
        self_copy = self.__class__()
        self_copy.data = self.data.copy()
        return self_copy

    def delete(self, *attrs) -> Struct:
        for attr in attrs:
            delattr(self, attr)
        return self

    def edit(self, **fields) -> Struct:
        for field, value in fields.items():
            setattr(self, field, value)
        return self

    @classmethod
    def from_mapping(cls, mapping: dict) -> Struct:
        self = cls()
        self.data = mapping
        return self

    @classmethod
    def from_string(cls, string: str) -> Struct:
        try:
            return cls.from_mapping(cls._convert(string))

        except Exception as exc:
            raise EditorError("Failed to process string.") from exc


[docs]class Object(Struct): _base_data = get_default("object") _dump = _object_dump _convert = _object_convert _collect = _object_collect
[docs] def set_id(self, directive: str) -> Object: """Set ``id`` of ``self`` according to the directive, e.g. ``trigger:move``.""" self.edit(id=get_id(directive)) return self
[docs] def set_z_layer(self, directive: str) -> Object: """Set ``z_layer`` of ``self`` according to the directive, e.g. ``layer:t1`` or ``b3``.""" self.edit(z_layer=get_id(_get_dir(directive, "layer"), ret_enum=True)) return self
[docs] def set_easing(self, directive: str) -> Object: """Set ``easing`` of ``self`` according to the directive, e.g. ``sine_in_out``.""" self.edit(easing=get_id(_get_dir(directive, "easing"), ret_enum=True)) return self
[docs] def set_color(self, color: Any) -> Object: """Set ``rgb`` of ``self`` to ``color``.""" self.edit(**zip("rgb", _define_color(color).to_rgb())) return self
[docs] def get_color(self) -> Color: """Attempt to get color of ``self``.""" return _make_color(self)
[docs] def add_groups(self, *groups: Iterable[int]) -> Object: """Add ``groups`` to ``self.groups``.""" if self.groups is None: self.groups = set(groups) else: self.groups.update(groups) return self
[docs] def get_pos(self) -> Tuple[Number, Number]: """Tuple[Union[:class:`float`, :class:`int`], Union[:class:`float`, :class:`int`]]: ``x`` and ``y`` coordinates of ``self``. """ return (self.x, self.y)
[docs] def set_pos(self, x: Number, y: Number) -> Object: """Set ``x`` and ``y`` position of ``self`` to given values.""" self.x, self.y = x, y return self
[docs] def move(self, x: Number = 0, y: Number = 0) -> Object: """Add ``x`` and ``y`` to coordinates of ``self``.""" self.x += x self.y += y return self
[docs] def rotate(self, deg: Number = 0) -> Object: """Add ``deg`` to ``rotation`` of ``self``.""" if self.rotation is None: self.rotation = deg else: self.rotation += deg return self
[docs] def is_checked(self): """:class:`bool`: indicates if ``self.portal_checked`` is true.""" return bool(self.portal_checked)
exec(_object_code)
[docs]class ColorChannel(Struct): _base_data = get_default("color_channel") _dump = _color_dump _convert = _color_convert _collect = _color_collect def __init__(self, special_directive: str = None, **properties) -> None: super().__init__(**properties) if special_directive is not None: self.set_id(special_directive) def __hash__(self) -> int: return hash(self.id) def __eq__(self, other: Struct) -> bool: if not isinstance(other, type(self)): return NotImplemented return self.data == other.data
[docs] def set_id(self, directive: str) -> ColorChannel: """Set ColorID of ``self`` according to the directive, e.g. ``BG`` or ``color:bg``.""" self.edit(id=get_id(_get_dir(directive, "color"))) return self
[docs] def set_color(self, color: Any) -> ColorChannel: """Set ``rgb`` of ``self`` to ``color``.""" self.edit(**dict(zip("rgb", _define_color(color).to_rgb()))) return self
[docs] def get_color(self) -> Color: """Attempt to get color of ``self``.""" return _make_color(self)
exec(_color_code)
def _process_color(color: Union[str, Dict[str, Any], ColorChannel]): if isinstance(color, ColorChannel): return color elif isinstance(color, dict): return ColorChannel.from_mapping(color) elif isinstance(color, str): return ColorChannel.from_string(color) class ColorCollection(set): @classmethod def create(cls, colors: Iterable[Any]) -> ColorCollection: if isinstance(colors, cls): return colors.copy() self = cls() self.update(colors) return self @classmethod def from_args(cls, *args) -> ColorCollection: return cls.create(args) def get(self, directive_or_id: Union[int, str]) -> Optional[ColorCollection]: final = directive_or_id if isinstance(final, str): final = get_id(_get_dir(final, "color")) return search.get(self, id=final) def copy(self) -> ColorCollection: return self.__class__(self) def update(self, colors: Iterable[ColorCollection]) -> None: super().update(color for color in map(_process_color, colors) if color is not None) def add(self, color: Any) -> None: color = _process_color(color) if color is not None: super().add(color) def __getitem__(self, color_id: int) -> Optional[ColorCollection]: return self.get(color_id) def dump(self) -> Iterable[Dict[str, Any]]: return [cc.data for cc in self] DEFAULT_COLORS = [ ColorChannel("BG").set_color(0x287DFF), ColorChannel("GRND").set_color(0x0066FF), ColorChannel("Line").set_color(0xFFFFFF), ColorChannel("P1").set_color(0x7DFF00), ColorChannel("P2").set_color(0x00FFFF), ColorChannel("GRND2").set_color(0x0066FF), ]
[docs]class LevelAPI(Struct): _convert = None _collect = None _dump = _level_dump _base_data = get_default("api") def __init__(self, **properties) -> None: super().__init__(**properties) def __repr__(self) -> str: info = { "id": self.id, "version": self.version, "name": self.name, } return make_repr(self, info) def dump(self) -> None: raise EditorError("Level API can not be dumped.") def open_editor(self) -> Editor: from gd.api.editor import Editor # *circular imports* return Editor.launch(self, "level_string") def is_verified(self) -> bool: return bool(self.verified) def is_uploaded(self) -> bool: return bool(self.uploaded) def is_original(self) -> bool: return bool(self.original) def is_unlisted(self) -> bool: return bool(self.unlisted) @classmethod def from_mapping(cls, mapping) -> LevelAPI: self = cls() self.data = _process_level(mapping) return self @classmethod def from_string(cls, string: str) -> None: raise EditorError("Level API can not be created from string.") exec(_level_code)