From 303766878b6cb95e1e70c4555ecd815faf99a7c8 Mon Sep 17 00:00:00 2001 From: heinezen Date: Wed, 4 Sep 2019 04:46:35 +0200 Subject: [PATCH] convert: Load nyan API. --- doc/nyan/api_reference/reference_aux.md | 8 +- openage/convert/nyan/api_loader.py | 37 ++++++ openage/convert/texture.py | 5 +- openage/nyan/CMakeLists.txt | 1 + openage/nyan/nyan_file.py | 60 +++++++++ openage/nyan/nyan_structs.py | 154 +++++++++++++++--------- 6 files changed, 203 insertions(+), 62 deletions(-) create mode 100644 openage/convert/nyan/api_loader.py create mode 100644 openage/nyan/nyan_file.py diff --git a/doc/nyan/api_reference/reference_aux.md b/doc/nyan/api_reference/reference_aux.md index b634c3af879..cbb244fe5ad 100644 --- a/doc/nyan/api_reference/reference_aux.md +++ b/doc/nyan/api_reference/reference_aux.md @@ -6,10 +6,10 @@ Reference documentation of the `engine.aux` module of the openage modding API. ```python Accuracy(Entity): - accuracy : float - accuracy_dispersion : float - dispersion_dropoff : DropOffType - target_types : set(GameEntityType) + accuracy : float + accuracy_dispersion : float + dispersion_dropoff : DropOffType + target_types : set(GameEntityType) blacklisted_entities : set(GameEntity) ``` diff --git a/openage/convert/nyan/api_loader.py b/openage/convert/nyan/api_loader.py new file mode 100644 index 00000000000..0075919eb08 --- /dev/null +++ b/openage/convert/nyan/api_loader.py @@ -0,0 +1,37 @@ +# Copyright 2019-2019 the openage authors. See copying.md for legal info. + +""" +Loads the API into the converter. + +TODO: Implement a parser instead of hardcoded +object creation. +""" + +from ...nyan.nyan_structs import NyanObject, NyanMember + + +def load_api(): + """ + Returns a dict with the API object's fqon as keys + and the API objects as values. + """ + api_objects = dict() + + # Object creation + + # engine.root + # engine.root.Entity + nyan_object = NyanObject("Entity") + fqon = "engine.root.Entity" + nyan_object.set_fqon(fqon) + + api_objects.update({fqon: nyan_object}) + + # engine.aux + # engine.aux.accuracy.Accuracy + parents = [api_objects["engine.root.Entity"]] + nyan_object = NyanObject("Accuracy", parents) + fqon = "engine.aux.accuracy.Accuracy" + nyan_object.set_fqon(fqon) + + api_objects.update({fqon: nyan_object}) diff --git a/openage/convert/texture.py b/openage/convert/texture.py index 98330aa6d18..9ecaaf405c5 100644 --- a/openage/convert/texture.py +++ b/openage/convert/texture.py @@ -132,7 +132,7 @@ def __init__(self, input_data, palette=None, custom_cutter=None): "from unknown source type: %s" % (type(input_data))) self.image_data, (self.width, self.height), self.image_metadata\ - = merge_frames(frames) + = merge_frames(frames) def _slp_to_subtextures(self, frame, palette=None, custom_cutter=None): """ @@ -186,6 +186,9 @@ def save(self, targetdir, filename, meta_formats=None): formatter.export(targetdir, meta_formats) def dump(self, filename): + """ + Creates a DataDefinition object for the texture metadata. + """ return [data_definition.DataDefinition(self, self.image_metadata, filename)] diff --git a/openage/nyan/CMakeLists.txt b/openage/nyan/CMakeLists.txt index a6e90fef566..e012dbea65c 100644 --- a/openage/nyan/CMakeLists.txt +++ b/openage/nyan/CMakeLists.txt @@ -1,3 +1,4 @@ add_py_modules( + nyan_file.py nyan_structs.py ) diff --git a/openage/nyan/nyan_file.py b/openage/nyan/nyan_file.py new file mode 100644 index 00000000000..b5244a11047 --- /dev/null +++ b/openage/nyan/nyan_file.py @@ -0,0 +1,60 @@ +# Copyright 2019-2019 the openage authors. See copying.md for legal info. + +""" +Nyan file struct that stores a bunch of objects and +manages imports. +""" + +from .nyan_structs import NyanObject + +FILE_VERSION = "NYAN FILE version 0.1.0" + + +class NyanFile: + """ + Superclass for nyan files. + """ + + def __init__(self, targetdir, filename, nyan_objects=None): + + self.targetdir = targetdir + if not isinstance(filename, str): + raise ValueError("str expected as filename, not %s" % + type(filename)) + + self.filename = filename + + self.nyan_objects = set() + if nyan_objects: + self.nyan_objects = nyan_objects + + def add_nyan_object(self, new_object): + """ + Adds a nyan object to the file. + """ + if isinstance(new_object, NyanObject): + self.nyan_objects.add(new_object) + + else: + raise Exception("nyan file cannot contain %s", + new_object) + + def save(self): + """ + Creates a .nyan file from the data. + """ + with self.targetdir[self.filename].open("wb") as nyan_file: + nyan_file.write(self.dump()) + + def dump(self): + """ + Returns the string that represents the nyan file. + """ + output_str = "# %s" % (FILE_VERSION) + + # TODO: imports + + for nyan_object in self.nyan_objects: + output_str += nyan_object.dump() + + return output_str diff --git a/openage/nyan/nyan_structs.py b/openage/nyan/nyan_structs.py index c96f64a573a..425b9e2124f 100644 --- a/openage/nyan/nyan_structs.py +++ b/openage/nyan/nyan_structs.py @@ -31,7 +31,9 @@ def __init__(self, name: str, parents=None, members=None, checks, for your convenience. """ self.name = name # object name - self._fqon = self.name # unique identifier (in modpack) + + # unique identifier (in modpack) + self._fqon = self.name self._parents = set() # parent objects self._inherited_members = set() # members inherited from parents @@ -50,25 +52,50 @@ def __init__(self, name: str, parents=None, members=None, nested_object.set_fqon("%s.%s" % (self._fqon, nested_object.get_name())) + # Set of children + self._children = set() + self._sanity_check() if len(self._parents) > 0: self._process_inheritance() - def add_nested_object(self, nested_object): + def add_nested_object(self, new_nested_object): """ Adds a nested object to the nyan object. """ - if not isinstance(nested_object, NyanObject): + if not isinstance(new_nested_object, NyanObject): raise Exception("nested object must have type") - if nested_object is self: - raise Exception("nyan object must not contain itself as nested object") + if new_nested_object is self: + raise Exception( + "nyan object must not contain itself as nested object") + + self._nested_objects.add(new_nested_object) + + new_nested_object.set_fqon("%s.%s" % (self._fqon, + new_nested_object.get_name())) + + def add_member(self, new_member): + """ + Adds a member to the nyan object. + """ + if self.is_inherited(): + raise Exception("added member cannot be inherited") + + if not isinstance(new_member, NyanMember): + raise Exception("added member must have type") - self._nested_objects.add(nested_object) + self._members.add(new_member) + + def add_child(self, new_child): + """ + Registers another object as a child. + """ + if not isinstance(new_child, NyanObject): + raise Exception("children must have type") - nested_object.set_fqon("%s.%s" % (self._fqon, - nested_object.get_name())) + self._children.add(new_child) def get_fqon(self) -> str: """ @@ -86,7 +113,7 @@ def get_member_by_name(self, member_name): """ Returns the NyanMember with the specified name or None if there is no member with that name. - + For inherited members, the notation 'origin_name.member' must be used. """ @@ -155,13 +182,25 @@ def set_fqon(self, new_fqon): nested_object.set_fqon("%s.%s" % (new_fqon, nested_object.get_name())) + def update_inheritance(self): + """ + Update the set of inherited members. + """ + # Reinitialize set + self._inherited_members = set() + self._process_inheritance() + + # Update child objects + for child in self._children: + child.update_inheritance() + def dump(self, indent_depth=0): """ Returns the string representation of the object. """ # Header output_str = "%s%s" % (indent_depth * INDENT, - self.get_name()) + self.get_name()) output_str += self._prepare_inheritance_content() @@ -207,9 +246,9 @@ def _prepare_object_content(self, indent_depth) -> str: empty = False for nested_object in self._nested_objects: output_str += "%s%s" % (indent_depth * INDENT, - nested_object.dump( - indent_depth + 1 - )) + nested_object.dump( + indent_depth + 1 + )) output_str += "\n" @@ -250,29 +289,29 @@ def _process_inheritance(self): if parent_member.is_inherited(): member_name = parent_member.get_name().split(".")[-1] inherited_member = InheritedNyanMember( - member_name, - parent_member.get_member_type(), - parent, - parent_member.get_origin(), - None, - parent_member.get_set_type(), - None, - None, - parent_member.is_optional() - ) + member_name, + parent_member.get_member_type(), + parent, + parent_member.get_origin(), + None, + parent_member.get_set_type(), + None, + None, + parent_member.is_optional() + ) else: inherited_member = InheritedNyanMember( - parent_member.get_name(), - parent_member.get_member_type(), - parent, - parent, - None, - parent_member.get_set_type(), - None, - None, - parent_member.is_optional() - ) + parent_member.get_name(), + parent_member.get_member_type(), + parent, + parent, + None, + parent_member.get_set_type(), + None, + None, + parent_member.is_optional() + ) self._inherited_members.add(inherited_member) @@ -287,7 +326,8 @@ def _sanity_check(self): # self.name must conform to nyan grammar rules if not re.fullmatch(r"[a-zA-Z_][a-zA-Z_]*", self.name): - raise Exception("%s: 'name' is not well-formed" % (self.__repr__())) + raise Exception("%s: 'name' is not well-formed" % + (self.__repr__())) # self._parents must be NyanObjects for parent in self._parents: @@ -420,8 +460,8 @@ class NyanMember: Superclass for all nyan members. """ - def __init__(self, name: str, member_type, value=None, operator:str=None, - override_depth:int=0, set_type=None, optional:bool=False): + def __init__(self, name: str, member_type, value=None, operator: str=None, + override_depth: int=0, set_type=None, optional: bool=False): """ Initializes the member and does some correctness checks, for your convenience. @@ -441,7 +481,7 @@ def __init__(self, name: str, member_type, value=None, operator:str=None, self._set_type = MemberType(set_type) self._optional = optional # whether the value is allowed - # to be NYAN_NONE + # to be NYAN_NONE self._operator = None if operator: @@ -502,7 +542,7 @@ def is_initialized(self) -> bool: """ Returns True if the member has a value. """ - return self.value != None + return self.value is not None def is_inherited(self) -> bool: """ @@ -527,7 +567,7 @@ def set_value(self, value): self.value.has_ancestor((self._member_type))): raise Exception(("%s: 'value' with type NyanObject must " "have their member type as ancestor") - % (self.__repr__())) + % (self.__repr__())) self._type_conversion() def dump(self) -> str: @@ -569,7 +609,7 @@ def dump_short(self): without the type definition. """ return "%s %s%s %s" % (self.get_name(), "@" * self._override_depth, - self._operator.value, self.__str__()) + self._operator.value, self.__str__()) def _sanity_check(self): """ @@ -679,7 +719,7 @@ def _sanity_check(self): self.value.has_ancestor((self._member_type))): raise Exception(("%s: 'value' with type NyanObject must " "have their member type as ancestor") - % (self.__repr__())) + % (self.__repr__())) def _type_conversion(self): """ @@ -713,7 +753,7 @@ def _type_conversion(self): def _get_primitive_value_str(self, member_type, value) -> str: """ Returns the nyan string representation of primitive values. - + Subroutine of __str__() """ if member_type is MemberType.FLOAT: @@ -732,7 +772,7 @@ def __str__(self): return "UNINITIALIZED VALUE %s" % self.__repr__() if self._optional and self.value is MemberSpecialValue.NYAN_NONE: - return MemberSpecialValue.NYAN_NONE.value + return MemberSpecialValue.NYAN_NONE.value if self._member_type in (MemberType.INT, MemberType.FLOAT, MemberType.TEXT, MemberType.FILE, @@ -751,9 +791,9 @@ def __str__(self): if len(self.value) > 0: for val in self.value: output_str += "%s, " % self._get_primitive_value_str( - self._set_type, - val - ) + self._set_type, + val + ) return output_str[:-2] + "}" @@ -773,18 +813,18 @@ class InheritedNyanMember(NyanMember): """ def __init__(self, name: str, member_type, parent, origin, value=None, - set_type=None, operator=None, override_depth=None, optional=False): + set_type=None, operator=None, override_depth=None, optional=False): """ Initializes the member and does some correctness checks, for your convenience. """ self._parent = parent # the direct parent of the - # object which contains the - # member + # object which contains the + # member self._origin = origin # nyan object which originally - # defines the member + # defines the member super().__init__(name, member_type, value, operator, override_depth, set_type, optional) @@ -882,10 +922,10 @@ class MemberOperator(Enum): Symbols for nyan member operators. """ - ASSIGN = "=" # assignment - ADD = "+=" # addition, append, insertion, union - SUBTRACT = "-=" # subtraction, remove - MULTIPLY = "*=" # multiplication - DIVIDE = "/=" # division - AND = "&=" # logical AND, intersect - OR = "|=" # logical OR, union + ASSIGN = "=" # assignment + ADD = "+=" # addition, append, insertion, union + SUBTRACT = "-=" # subtraction, remove + MULTIPLY = "*=" # multiplication + DIVIDE = "/=" # division + AND = "&=" # logical AND, intersect + OR = "|=" # logical OR, union