def STORAGE(cls): from Core.Storage import Storage assert hasattr(cls, 'base') or error("Storage has no 'base'", depth=2, do_exit=True) assert isinstance(cls.base, type) and issubclass(cls.base, StructBase) or error("Storage base must be USTRUCT", depth=2, do_exit=True) storage = Storage(cls.__name__, cls.base) storage.name, storage.type = cls.__name__, cls.base storage_list.append(storage) return storage
def __getitem__(self, item): item = complicate_type(item[0], "TMap"), complicate_type(item[1], "TMap") assert isinstance(item, tuple) and len(item) == 2 base_key, base_value = item assert issubclass(base_key, TypeBase) or error("Invalid map type key base '%s'" % base_key, depth=2, do_exit=True) assert issubclass(base_value, TypeBase) or error("Invalid map type value base '%s'" % base_value, depth=2, do_exit=True) new_type = type("TMap<%s, %s>" % (base_key.__name__, base_value.__name__), (MapBase,), {}) new_type.init_typedata(base_key, base_value) return new_type
def __new__(mcs, cls_name, bases, dictionary): assert not (not _isbase(dictionary) and '__init__' in dictionary) or \ error("You can't overload __init__ in your AsyncObj subclass %s! Just use __ainit__ instead" % cls_name, depth=2, do_exit=True) assert not (not _isbase(dictionary) and '__await__' in dictionary) or \ error("You can't overload __await__ in your AsyncObj subclass %s! Not supported" % cls_name, depth=2, do_exit=True) cls = super().__new__(mcs, cls_name, bases, dictionary) return cls
def serialize(self): int64_type = self.find_type('int64') assert int64_type is not None or error("int64 type missing", do_exit=True, depth=2) days, seconds, microseconds, milliseconds, minutes, hours, weeks = self.get_decayed(self) days += weeks * 7 ticks = _timespan.TicksPerMicrosecond * (1000 * (1000 * (60 * 60 * 24 * days + 60 * 60 * hours + 60 * minutes + seconds) + milliseconds) + microseconds) return int64_type(ticks).serialize()
def decorator(cls) -> EnumBase: assert cls.__name__.startswith("E") or error("UENUMS should starts with 'E'", depth=2, do_exit=True) values = None new_type = declare_enum(cls.__name__, cls, specifiers, kwspecifiers) frame_info = sys._getframe(1) new_type.inspect_info = get_file_line(frame_info) new_type.__doc__ = cls.__doc__ return new_type
async def __initobj(self): """ Crutch used for __await__ after spawning """ assert not self.async_initialized or error( "Unable to initialize twice!") self.async_initialized = True await self.__ainit__(*self.__storedargs[0], **self.__storedargs[1]) await self.__apostinit__() return self
def __init__(self, *vars): assert len(vars) > 0 or error("To start replication context one or more variables must be passed", depth=1) self.vars = [(var.owner, var.property_name) for var in vars] if None in self.vars: ERROR_MSG("None property name passed into Replication") for var in vars: if isinstance(var, MapBase): # todo: temporary for valid buffer var.replication_buffer.append((SliceReplicationKind.Nop, None))
def __init__(self, *vars, name="Undefined"): super().__init__(*vars) assert len(vars) > 0 or error( "To start transaction one or more variables must be passed", depth=1) self.serialized_variables = dict() self.old_variables = TArray[FPropertyInfo]() self.name = name self.id = self.new_id()
def complicate_type(T, outer): """ If passed python type, the Type ancestor will be returned. Else 'T' will be""" if T in pythonic_types_mapping: out_T = pythonic_types_mapping[T] WARN_MSG(f"Pythonic type has been used in {outer} ({T}), {out_T} will be substituted", once="complication", depth=2, warning_id="TYPE_NEGLECT") return out_T assert issubclass(T, TypeBase) or error("Invalid type %s for %s" % (T, outer), depth=3, do_exit=True) return T
def deserialize(cls, serialized_value): int64_type = cls.find_type('int64') assert int64_type is not None or error("int64 type missing", do_exit=True, depth=2) ticks = int64_type.deserialize(serialized_value) days = ticks // _timespan.TicksPerDay hours = (ticks // _timespan.TicksPerHour) % 24 microseconds = (ticks // _timespan.TicksPerMicrosecond) % 1000 milliseconds = (ticks // _timespan.TicksPerMillisecond) % 1000 minutes = (ticks // _timespan.TicksPerMinute) % 60 seconds = (ticks // _timespan.TicksPerSecond) % 60 result = cls(days, seconds, microseconds, milliseconds, minutes, hours) return result
def __init__(self, generate_only_config=False): target_dir = ConfigGlobals.UE4GeneratorSourcePath # ConfigurationCommon().get_globals()['ue4_src_gen_path'] game_editor_module_path = ConfigGlobals.UE4GeneratorSourceEditorPath # ConfigurationCommon().get_globals()['ue4_src_editor_gen_path'] self.latent_functions_supported = ConfigGlobals.LatentFunctionsSupported # ConfigurationCommon().get_globals()['latent_functions_supported'] if self.latent_functions_supported and not game_editor_module_path: error( "Failed to use latent functions. There are no game editor module specified", do_exit=True) self.target_dir = target_dir + "/Generated" self.target_editor_module_dir = ( game_editor_module_path + "/Generated") if game_editor_module_path else None self.game_editor_module_name = ConfigGlobals.UE4EditorGameModuleName # ConfigurationCommon().get_globals()['ue4_game_editor_module_name'] self.classes_info = dict() self.types_info = dict() self.enums_info = dict() self.storage_info = dict() wn_imported = Globals.HaloNet_imported Globals.HaloNet_imported = True self.generate_config() Globals.HaloNet_imported = wn_imported if not generate_only_config: if os.path.exists(self.target_dir): shutil.rmtree(self.target_dir) os.makedirs(self.target_dir) self.generate_entities_listings() self.generate_types_listing()
def render_template(self, src, dst, **kwargs): """ Рендер темплейта из src в dst @param src путь к шаблону @param dst путь сохранения @param kwargs параметры шаблонизатору """ assert ConfigGlobals.ProjectName is not None or \ error("ProjectName not specified in config file. Go to your config file to resolve this error") with open(src, 'r', encoding='utf-8') as f: text = Template(f.read()).render( PROJECT_NAME=ConfigGlobals.ProjectName, PROJECT_API=ConfigGlobals.ProjectName.upper(), **kwargs) path = os.path.abspath(dst) with open(path, "xb") as f: f.write(text.encode())
def decorator(cls) -> StructBase: assert cls.__name__.startswith("F") or error("USTRUCTS should starts with 'F'", depth=2, do_exit=True) defaults = dict() items = list() for key, in_T in cls.__annotations__.items(): default_value = getattr(cls, key, None) T = complicate_type(in_T, cls.__name__) if default_value is not None: defaults[key] = T items.append((key, T)) # for name, T in cls.__annotations__.items(): # assert isinstance(T, type) and issubclass(T, TypeBase) or error("Invalid type %s for %s" % (T, name), depth=2, do_exit=True) new_type = declare_struct(cls, cls.__name__, items, defaults, specifiers, kwspecifiers) frame_info = sys._getframe(1) new_type.inspect_info = get_file_line(frame_info) new_type.__doc__ = cls.__doc__ new_type.__gencode__ = getattr(cls, '__gencode__', None) return new_type
def get_by_name(self, name) -> EntityInfo: # print(self.entities) entity_info = self.entities.get(name, None) assert entity_info is not None or error( 'Failed to get entity with name %s' % name) return entity_info
def __enter__(self): error("Transaction is async action. Use 'async with' instead", NotImplementedError, depth=2)
def decorator(method): nonlocal specifiers frame_info = sys._getframe(1) # assert iscoroutinefunction(method) or error("rmi must be coroutine! Mark method as 'async'") assert Native not in specifiers or error( "'Native' not supported", depth=2, do_exit=True) if Latent in specifiers and BlueprintCallable not in specifiers: error("'Latent' functions must be 'BlueprintCallable'", depth=2, do_exit=True) if BlueprintCallable in specifiers and ( BlueprintNativeEvent in specifiers or BlueprintImplementableEvent in specifiers): error( "BlueprintCallable can't be BlueprintNativeEvent or BlueprintImplementableEvent" ) if BlueprintCallable in specifiers and Exposed not in specifiers: error("'BlueprintCallable' functions must be 'Exposed'", depth=2, do_exit=True) if Exec in specifiers and Exposed not in specifiers: error("'Exec' functions must be 'Exposed'", depth=2, do_exit=True) if timeout is not None and WithTimeout not in specifiers: specifiers += (WithTimeout, ) if WithTimeout in specifiers and timeout is None: error( "'WithTimeout' should be accompanied with 'timeout=secs' keyword argument", depth=2, do_exit=True) if WithTimeout in specifiers and not iscoroutinefunction(method): error("Timeout methods must be 'async'") outer_class_dict = frame_info.f_locals context_name = outer_class_dict.get('context_name', "Unknown") var_list, return_list, vars_defaults = extract_rmi_signature(method) reduce_classes_pairs(var_list, context_name) reduce_classes_list(return_list, context_name) new_method = method if WithTimeout in specifiers: raise NotImplementedError() # async def timeout_method(*args, **kwargs): # return await asyncio.wait_for(method(*args, **kwargs), timeout) # new_method = lambda *args, **kwargs: # new_method.__name__ = method.__name__ for _, var in var_list: assert var.is_validated() or error( f"{var} is not validated. Please make validate_container for this type in Types.py", do_exit=True, depth=2) for ret in return_list: assert ret.is_validated() or error( f"{ret} is not validated. Please make validate_container for this type in Types.py", do_exit=True, depth=2) if (outer_class_dict.get('is_client_side', False) or outer_class_dict.get('base_entity_class', None) ) and method.__code__.co_code not in acceptable_pure_code: error( "Code not allowed. Use \"\"\"docstrings\"\"\", \"pass\" or \"...\" instead ", depth=2, do_exit=True) assert (len(method.__annotations__) - ('return' in method.__annotations__)) == \ (method.__code__.co_argcount - 1 - int(CaptureConnection in specifiers) - int(CaptureAccessToken in specifiers)) \ or error("Invalid signature!", depth=2, do_exit=True) if not iscoroutinefunction(method) and ('return' in method.__annotations__): error( "rmi with return values must be coroutines! Mark method as 'async'", depth=2, do_exit=True) new_method.is_rmi = True kwspecs = dict() if category is not None: kwspecs['Category'] = category if access is not None: kwspecs['access'] = access new_method.rmi_specifiers = dict( specifiers=specifiers, kwspecifiers=kwspecs, isasyncmethod=iscoroutinefunction(method), meta=meta) new_method.rmi_signature = var_list, return_list, vars_defaults new_method.get_meta = lambda: meta new_method.inspect_info = get_file_line(frame_info) if 'methods_to_register' not in outer_class_dict: outer_class_dict['methods_to_register'] = list() outer_class_dict['methods_to_register'].append(new_method) return new_method
def __init_subclass__(cls, **kwargs): assert asyncio.iscoroutinefunction(cls.__ainit__) or error( "'__ainit__' must be async", do_exit=True, depth=3)
def __register_main(self, obj): assert self.main is None or error( "Cannot dispatch more than one main entities per executable!") self.main = obj self.entities[0] = obj obj.set_internal_id(0)
def __call__(self, *args, **kwargs): error("Cannot instantiate TSubclassOf directly", depth=2, do_exit=True)
def generate_entities_listings(self): """ Генерация листингов для сущностей """ delegate_postfixes = [ "", "_OneParam", "_TwoParams", "_ThreeParams", "_FourParams", "_FiveParams", "_SixParams", "_SevenParams", "_EightParams", "_NineParams" ] latent_functions = list() exposed_context_name = None for context_name, context_data in AppConfig.by_context.items(): if context_data.IsExposed: exposed_context_name = context_name os.makedirs(self.target_dir + "/Entities/") ue4_exec_capable_classes = list() for entity_name, entity_data in self.classes_info.items(): for context_name, entity_info in entity_data.items(): if entity_info.get('IsExecCapable', False): ue4_exec_capable_classes.append(entity_name + context_name.capitalize()) ue4_classes_mapping = dict() global_includes = list() for entity_name, entity_data in self.classes_info.items(): for context_name, entity_info in entity_data.items(): context_info = AppConfig.by_context[context_name] is_exposed_context = context_info.IsExposed or context_info.IsExposedApp is_client_context = context_info.IsClient has_exposed_context = exposed_context_name in entity_data is_app = entity_info.get("IsApplication", False) is_basic_class = entity_info.get("IsBasicServiceClass", False) base_cls = entity_info.get("BaseClass", "INVALID") is_available_context = (is_exposed_context or is_client_context) if is_available_context and not is_basic_class: context_path = self.target_dir + "/Entities/" + context_name if not os.path.exists(context_path): os.makedirs(context_path) entity_fullname = (entity_name + context_name.capitalize() ) if not is_app else entity_name exec_capable = entity_info.get('IsExecCapable', False) methods = dict() properties = dict() forwarded_types = list() forwarded_includes = list() for method_info in entity_info["Methods"]: if method_info["Exposed"]: name = method_info["Name"] id = method_info["ID"] exposed = method_info["Exposed"] doc = method_info["Docstring"] args = { argname: TypeBase.find_type( argtype).get_type_signature() for argname, argtype in method_info["Args"].items() } defaults = method_info.get("Defaults_generator", {}) signed_args = { argname: TypeBase.find_type( argtype).get_full_type_signature() for argname, argtype in method_info["Args"].items() } returns = [ TypeBase.find_type(ret).get_type_signature() for ret in method_info["Returns"] ] returns_sig = [ TypeBase.find_type( ret).get_full_type_signature() for ret in method_info["Returns"] ] for argtype in list(method_info["Args"].values() ) + method_info["Returns"]: if issubclass(TypeBase.find_type(argtype), MailboxProxyDatatype): T = TypeBase.find_type(argtype) forwarded_types.append("U" + T.simple_name) # forwarded_types += ["U" + argtype for argtype in # list(method_info["Args"].values()) + method_info["Returns"] # if issubclass(TypeBase.find_type(argtype), MailboxProxyDatatype)] for argtypename in list(method_info["Args"].values( )) + method_info["Returns"]: argtype = TypeBase.find_type(argtypename) if issubclass(argtype, MailboxProxyDatatype): forwarded_includes.append(( argtype.meta_context_name, argtype.meta_class_name + argtype.meta_context_name.capitalize() )) # forwarded_includes = list() # print(forwarded_types) # print([(TypeBase.find_type(ret).get_type_signature(), ret) for i, ret in enumerate(returns)]) # print(TypeBase.all_types) if exposed or is_client_context: methods[name] = { "ID": id, "Name": name, "BlueprintCallable": method_info['BlueprintCallable'], "Latent": method_info['Latent'], "SystemInternal": method_info['SystemInternal'], "BlueprintNativeEvent": method_info['BlueprintNativeEvent'], "BlueprintImplementableEvent": method_info['BlueprintImplementableEvent'], "Category": method_info['Category'], "Exec": method_info['Exec'], "Native": method_info['Native'], "Docstring": None if not doc else [s.strip() for s in doc.split('\n')], "params_list": [ typename + " " + argname for argname, typename in args.items() ], "params_list_with_defaults": [ typename + " " + argname + (" = " + defaults[argname] if argname in defaults else "") for argname, typename in args.items() ], "signature_params_list_with_defaults": [ typename + " " + argname + (" = " + defaults[argname] if argname in defaults else "") for argname, typename in signed_args.items() ], "signature_params_list": [ typename + " " + argname for argname, typename in signed_args.items() ], "params_names": [argname for argname in args.keys()], "delegate_postfix": delegate_postfixes[len(returns)], "delegate_retvals": [ret for ret in returns], "dynamic_delegate_retvals": [ ret + ", " + "RetVal%i" % (i + 1) for i, ret in enumerate(returns) ], "dynamic_delegate_retvals_decl": [ ret + ", " + "RetVal%i" % (i + 1) for i, ret in enumerate(returns_sig) ], "returns_list": [ ret + " " + "RetVal%i" % (i + 1) for i, ret in enumerate(returns) ], "ret_names": [ "RetVal%i" % (i + 1) for i, ret in enumerate(returns) ], "params_commas": [ ", " + typename + ", " + argname for argname, typename in args.items() ], "is_async": method_info['Async'], "DeferredReturn": method_info['DeferredReturn'], "returns_list_result_def": [ ret + " " + "InRetVal%i" % (i + 1) for i, ret in enumerate(returns) ], "returns_list_result_decl": [ "RetVal{0} = InRetVal{0}".format(i + 1) for i, ret in enumerate(returns) ], "returns_list_result_call": [ "result.RetVal%i" % (i + 1) for i, ret in enumerate(returns) ], "owner_name": entity_name, "owner_fullname": entity_fullname, "latent_info": method_info['LatentInfo'] if 'LatentInfo' in method_info else None } if method_info['Latent']: latent_functions.append(methods[name]) if has_exposed_context: for property_info in entity_data[exposed_context_name][ 'Properties']: if property_info["Replicated"]: properties[ property_info['Name']] = property_info dest = context_path + "/" + entity_name + context_name.capitalize( ) + "Mailbox.h" self.render_template( "../System/Core/CodeGen_templates/Mailbox.h", dest, FORWARDED_TYPES=set(forwarded_types), FORWARDED_INCLUDES=set(forwarded_includes), ENTITY_NAME=entity_name, ENTITY_FULLNAME=entity_fullname, EXEC_CAPABLE=exec_capable, CONTEXT_NAME=context_name.capitalize(), METHODS=methods, LATENT_SUPPORTED=self.latent_functions_supported) global_includes.append("Entities/" + context_name + "/" + entity_name + context_name.capitalize() + "Mailbox.h") dest = context_path + "/" + entity_name + context_name.capitalize( ) + "Mailbox.cpp" self.render_template( "../System/Core/CodeGen_templates/Mailbox.cpp", dest, FORWARDED_TYPES=set(forwarded_types), FORWARDED_INCLUDES=set(forwarded_includes), ENTITY_NAME=entity_name, ENTITY_FULLNAME=entity_fullname, EXEC_CAPABLE=exec_capable, CONTEXT_NAME=context_name.capitalize(), METHODS=methods, LATENT_SUPPORTED=self.latent_functions_supported) if is_client_context: dest = context_path + "/" + entity_name + context_name.capitalize( ) + "Interface.h" self.render_template( "../System/Core/CodeGen_templates/Interface.h", dest, FORWARDED_TYPES=forwarded_types, FORWARDED_INCLUDES=forwarded_includes, ENTITY_NAME=entity_name, ENTITY_FULLNAME=entity_fullname, CONTEXT_NAME=context_name.capitalize(), METHODS=methods, PROPERTIES=properties) global_includes.append("Entities/" + context_name + "/" + entity_name + context_name.capitalize() + "Interface.h") dest = context_path + "/" + entity_name + context_name.capitalize( ) + "Interface.cpp" self.render_template( "../System/Core/CodeGen_templates/Interface.cpp", dest, ENTITY_NAME=entity_name, FORWARDED_TYPES=set(forwarded_types), FORWARDED_INCLUDES=forwarded_includes, ENTITY_FULLNAME=entity_fullname, CONTEXT_NAME=context_name.capitalize(), METHODS=methods, PROPERTIES=properties) generate_entity = False generate_entity_file = (is_app or is_client_context and has_exposed_context) # if is_app and not is_client_context and is_basic_class: # generate_entity_file = False ent_data = dict() # has_exposed_context = (exposed_context_name in entity_data) if is_client_context and has_exposed_context and not is_app: generate_entity = True assert entity_info["BaseClass"] is not None ent_data['is_actor_entity'] = False if entity_info["BaseClass"].startswith("A"): ent_data['is_actor_entity'] = True elif entity_info["BaseClass"].startswith("U"): ent_data['is_actor_entity'] = False else: raise AssertionError("Must starts with A or U") assert entity_info["UsingClass"] is not None or error( "there is no UsingClass for %s" % entity_name) ent_data['using_class'] = entity_info["UsingClass"] ue4_classes_mapping[entity_name] = entity_info[ "UsingClass"] if generate_entity_file: dest = context_path + "/" + entity_name + context_name.capitalize( ) + "Entity.h" self.render_template( "../System/Core/CodeGen_templates/Entity.h", dest, ENTITY_NAME=entity_name, BASE_CLASS=base_cls, FORWARDED_TYPES=set(forwarded_types), FORWARDED_INCLUDES=set(forwarded_includes), ENTITY_FULLNAME=entity_fullname, GENERATE_ENTITY=generate_entity, CONTEXT_NAME=context_name.capitalize(), EXPOSED_CONTEXT_NAME=exposed_context_name. capitalize(), ENTITY=ent_data, METHODS=methods, PROPERTIES=properties) global_includes.append("Entities/" + context_name + "/" + entity_name + context_name.capitalize() + "Entity.h") dest = context_path + "/" + entity_name + context_name.capitalize( ) + "Entity.cpp" self.render_template( "../System/Core/CodeGen_templates/Entity.cpp", dest, ENTITY_NAME=entity_name, FORWARDED_TYPES=set(forwarded_types), FORWARDED_INCLUDES=set(forwarded_includes), ENTITY_FULLNAME=entity_fullname, GENERATE_ENTITY=generate_entity, EXPOSED_CONTEXT_NAME=exposed_context_name. capitalize(), CONTEXT_NAME=context_name.capitalize(), ENTITY=ent_data, METHODS=methods, PROPERTIES=properties) storages = list() for storage in storage_list: storage_keys = dict() for key, value in storage.type.fields: if value.blueprint_atomic: storage_keys[key] = value print(storage_keys) storages.append( (storage.name, storage.type.__name__, AvailableEverywhere in storage.specifiers, storage_keys)) self.render_template( "../System/Core/CodeGen_templates/HaloNetCommon.h", self.target_dir + "/HaloNetCommon.h", CLIENT_CLASSES_MAPPING=ue4_classes_mapping, EXEC_CAPABLE_CLASSES=ue4_exec_capable_classes, GENERATOR_SIGNATURE=self.generator_signature, STORAGES=storages) self.render_template( "../System/Core/CodeGen_templates/HaloNetCommon.cpp", self.target_dir + "/HaloNetCommon.cpp", CLIENT_CLASSES_MAPPING=ue4_classes_mapping, EXEC_CAPABLE_CLASSES=ue4_exec_capable_classes, GENERATOR_SIGNATURE=self.generator_signature, STORAGES=storages) self.render_template( "../System/Core/CodeGen_templates/HaloNetClasses.h", self.target_dir + "/HaloNetClasses.h", INCLUDES=[inc.replace('/', '/') for inc in global_includes])
def __getitem__(self, base): base = complicate_type(base, "TSet") assert issubclass(base, TypeBase) or error("Invalid set type base '%s'" % base, depth=2, do_exit=True) new_type = type("TSet<%s>" % base.__name__, (SetBase,), {}) new_type.init_typedata(base) return new_type
def __call__(self, *args, **kwargs): error("Cannot instantiate TSet directly", depth=2)