def _ScanForAllSnippets() -> None: if services.snippet_manager is None: raise Exception("Cannot look for snippets, the manager is None.") if len(_scanningSnippets) == 0: return operationStartTime = time.time() # type: float snippetsByType = dict( ) # type: typing.Dict[str, typing.List[snippets.SnippetInstanceMetaclass]] for snippetID, snippet in services.snippet_manager().types.items( ): # type: typing.Any, snippets.SnippetInstanceMetaclass if isinstance(snippet, snippets.SnippetInstanceMetaclass): snippetList = snippetsByType.get( snippet.snippet_type, None) # type: typing.List[snippets.SnippetInstanceMetaclass] if snippetList is None: snippetList = list() snippetsByType[snippet.snippet_type] = snippetList snippetList.append(snippet) for snippetType, snippetCallbacks in _scanningSnippets.items( ): # type: str, typing.List[typing.Callable] snippetList = snippetsByType.get(snippetType, None) if snippetList is None: snippetList = list() for snippetCallback in snippetCallbacks: # type: typing.Callable try: snippetCallback(snippetList) except: Debug.Log("Failed to trigger snippet scan callback at '%s'." % Types.GetFullName(snippetCallback), This.Mod.Namespace, Debug.LogLevels.Exception, group=This.Mod.Namespace, owner=__name__) operationTime = time.time() - operationStartTime Debug.Log( "Finished scanning for %s types of snippet in %s seconds with %s snippets existing." % (len(_scanningSnippets), operationTime, len(services.snippet_manager().types)), This.Mod.Namespace, Debug.LogLevels.Info, group=This.Mod.Namespace, owner=__name__)
def generate_scholarship_view_data(sim_id:int=None): sim_info = services.sim_info_manager().get(sim_id) snippet_manager = services.snippet_manager() if snippet_manager is None: return degree_tracker = sim_info.degree_tracker if degree_tracker is None: return scholarships_view_data = [] def _process_scholarship_view_data(scholarships, status): scholarship_entries = [] for scholarship_id in scholarships: scholarship_entry_data = {} scholarship = snippet_manager.get(scholarship_id) scholarship_entry_data['scholarship'] = str(scholarship) scholarship_entry_data['status'] = status scholarship_entry_data['value'] = str(scholarship.get_value(sim_info)) scholarship_entries.append(scholarship_entry_data) return scholarship_entries accepted_scholarships_data = _process_scholarship_view_data(degree_tracker.get_accepted_scholarships(), str(ScholarshipStatus.ACCEPTED)) if accepted_scholarships_data: scholarships_view_data.extend(accepted_scholarships_data) rejected_scholarships_data = _process_scholarship_view_data(degree_tracker.get_rejected_scholarships(), str(ScholarshipStatus.REJECTED)) if rejected_scholarships_data: scholarships_view_data.extend(rejected_scholarships_data) pending_scholarships_data = _process_scholarship_view_data(degree_tracker.get_pending_scholarships(), str(ScholarshipStatus.PENDING)) if pending_scholarships_data: scholarships_view_data.extend(pending_scholarships_data) active_scholarships_data = _process_scholarship_view_data(degree_tracker.get_active_scholarships(), str(ScholarshipStatus.ACTIVE)) if active_scholarships_data: scholarships_view_data.extend(active_scholarships_data) return scholarships_view_data
def get_scholarship_description(self): if self._scholarship_id is None: logger.error( "Scholarship ID is None and cannot be in order to get the scholarships's description for object with scholarship letter component ({}).", self.owner) return scholarship = services.snippet_manager().get(self._scholarship_id) return scholarship.display_description()
def ALL_ORGANIZATION_IDS(): if OrganizationTracker._ALL_ORGANIZATION_IDS is None: OrganizationTracker._ALL_ORGANIZATION_IDS = [ org.guid64 for org in services.snippet_manager().get_ordered_types( only_subclasses_of=Organization) ] return OrganizationTracker._ALL_ORGANIZATION_IDS
def _assign_organizations_tasks_for_all_enrolled_orgs(self): snippet_manager = services.snippet_manager() for org_id in self.get_enrolled_organizations(enrolled_status=ACTIVE): org = snippet_manager.get(org_id) if org is None: continue self._add_assignments_to_aspiration_tracker(org) self.send_organization_update_message( DistributorOps_pb2.OrganizationUpdate.ADD, org.guid64)
def join_organization(self, organization_id): if self._organization_status.get(organization_id) == ACTIVE: return snippet_manager = services.snippet_manager() if snippet_manager is None: return organization_instance = snippet_manager.get(organization_id) progress_stat_type = organization_instance.progress_statistic tracker = self._sim_info.get_tracker(progress_stat_type) tracker.add_statistic(progress_stat_type) self._set_organization_status(organization_id, OrganizationStatusEnum.ACTIVE) if not self._sim_info.is_npc: self._assign_organization_tasks(organization_instance)
def _LoadEntries() -> None: for snippetID, snippet in services.snippet_manager().types.items( ): # type: typing.Any, snippets.SnippetInstanceMetaclass if isinstance(snippet, snippets.SnippetInstanceMetaclass): if snippet.snippet_type == IdentifiersSnippetName: for identifier, key in snippet.value.items(): # type: str, int identifierSegments = _SplitIdentifier( identifier) # type: typing.List[str] targetIdentifierObject = _GetIdentifierObject( identifierSegments) # type: _Identifier if targetIdentifierObject.Key is None: targetIdentifierObject.Key = key _loadedEntries = True
def get_scholarship_amount(self): if self._scholarship_id is None: logger.error( "Scholarship ID is None and cannot be in order to get the scholarships's amount for object with scholarship letter component ({}).", self.owner) return if self._applicant_sim_id is None: logger.error( "Applicant Sim ID is None and cannot be in order to get the scholarships's amount for object with scholarship letter component ({}).", self.owner) return sim = services.sim_info_manager().get(self._applicant_sim_id) if sim is None: logger.error( "Applicant Sim is None and cannot be in order to get the scholarships's amount for object with scholarship letter component ({}).", self.owner) return scholarship = services.snippet_manager().get(self._scholarship_id) return scholarship.get_value(sim.sim_info)
def get_definition_notebook_data(self, ingredient_cache=[]): definition_manager = services.definition_manager() snippet_manager = services.snippet_manager() fish_definition = definition_manager.get( self.entry_object_definition_id) sublist = [] for (sub_entry_id, new_sub_entry) in reversed(self.sub_entries): bait_data = snippet_manager.get(sub_entry_id) if fish_definition is None or bait_data is None: return sublist.append( SubListData( None, 0, 0, True, new_sub_entry, bait_data.bait_name(), IconInfoData(obj_def_id=bait_data.bait_icon_definition.id), bait_data.bait_description())) return EntryData( LocalizationHelperTuning.get_object_name(fish_definition), IconInfoData(obj_def_id=fish_definition.id), self._get_entry_tooltip(fish_definition), sublist, self.entry_sublist_is_sortable)
def update_organization_task(self, task_data_org_info, timed_out=False): if timed_out: if self._organization_active_tasks.get( task_data_org_info.org_id) is None: return if self._organization_active_tasks.get( task_data_org_info.org_id).get( task_data_org_info.task) is None: return del self._organization_active_tasks[task_data_org_info.org_id][ task_data_org_info.task] else: self.update_stored_task(task_data_org_info) if not self._organization_active_tasks.get( task_data_org_info.org_id) and timed_out: snippet_manager = services.snippet_manager() if snippet_manager is None: return org = snippet_manager.get(task_data_org_info.org_id) self._assign_organization_tasks(org, from_update=True)
def get_organization_members(org_id, status_enum): organization_member_data = [] organization_service = services.organization_service() if organization_service is None: return organization_member_data sim_info_manager = services.sim_info_manager() if sim_info_manager is None: return snippet_manager = services.snippet_manager() if snippet_manager is None: return progress_stat_type = snippet_manager.get(org_id).progress_statistic members_list = organization_service.get_organization_members(org_id) for member_id in members_list: sim_info = sim_info_manager.get(member_id) organization_tracker = sim_info.organization_tracker if organization_tracker is None: continue if organization_tracker.get_organization_status(org_id) != status_enum: continue tracker = sim_info.get_tracker(progress_stat_type) progress_stat = tracker.get_statistic(progress_stat_type) organization_member_data.append({'sim': sim_info.full_name, 'progress': progress_stat.get_value(), 'rank': progress_stat.rank_level}) return organization_member_data
def generate_aspiration_view_data(sim_id:int=None): sim_info = services.sim_info_manager().get(sim_id) snippet_manager = services.snippet_manager() if snippet_manager is None: return all_orgs = [] if sim_info.organization_tracker is None: return all_orgs enrolled_orgs = sim_info.organization_tracker.get_enrolled_organizations(OrganizationStatusEnum.ACTIVE) for org_id in enrolled_orgs: org_data = {} organization_instance = snippet_manager.get(org_id) org_data['organization'] = str(organization_instance) active_tasks = sim_info.organization_tracker.get_active_tasks(org_id) tasks = [] for task_data_org_info in active_tasks.values(): task_data = {} task_data['task'] = str(task_data_org_info.task) task_data['completed'] = str(task_data_org_info.completed) task_data['end_time'] = str(task_data_org_info.end_time) tasks.append(task_data) org_data['active_tasks'] = tasks all_orgs.append(org_data) return all_orgs
def leave_organization(self, organization_id): if self.get_organization_status(organization_id) != ACTIVE: return snippet_manager = services.snippet_manager() if snippet_manager is None: return progress_stat_type = snippet_manager.get( organization_id).progress_statistic tracker = self._sim_info.get_tracker(progress_stat_type) progress_stat = tracker.get_statistic(progress_stat_type) tracker.set_value(progress_stat_type, progress_stat.points_to_current_rank()) self._set_organization_status(organization_id, OrganizationStatusEnum.INACTIVE) aspiration_tracker = self._sim_info.aspiration_tracker if aspiration_tracker: for (task, task_data_org_info ) in self.get_active_tasks(organization_id).items(): if not task_data_org_info.completed: aspiration_tracker.deactivate_timed_aspiration(task) if self._organization_active_tasks.get(organization_id): del self._organization_active_tasks[organization_id] self.send_organization_update_message( DistributorOps_pb2.OrganizationUpdate.REMOVE, organization_id)
def __init__(self, snippet_class, **kwargs): super().__init__(services.snippet_manager(), class_restrictions=snippet_class, **kwargs)
class RoutingFormation(HasTunableReference, metaclass=HashedTunedInstanceMetaclass, manager=services.snippet_manager()): INSTANCE_TUNABLES = { 'formation_behavior': RoutingFormationBehavior.TunableFactory(), 'formation_routing_type': TunableVariant( description= '\n The purpose of the routing formation which governs how the slave\n behaves on routes.\n ', follow=FormationTypeFollow.TunableFactory(), paired=FormationTypePaired.TunableFactory(), default='follow'), 'formation_compatibility': TunableWhiteBlackList( description= '\n This routing formation is able to coexist with any other formation\n listed here. For example, "Walk Dog" on the right side of a Sim is\n compatible with "Walk Dog" on their left side (and vice-versa).\n ', tunable=TunableReference(manager=services.get_instance_manager( sims4.resources.Types.SNIPPET), class_restrictions=('RoutingFormation', ), pack_safe=True)), 'formation_tests': TunableTestSet( description= '\n A test set to determine whether or not the master and slave can be\n in a formation together.\n \n Master: Participant Actor\n Slave: Participant Slave\n ' ), 'walkstyle_mapping': TunableMapping( description= '\n Mapping of Master walkstyles to Slave walkstyles. This is how we\n ensure that slaves use a walkstyle to keep pace with their masters.\n \n Note you do not need to worry about combo replacement walkstyles\n like GhostRun or GhostWalk. We get the first non-combo from the\n master and apply the walkstyle to get any combos from the slave.\n ', key_type=TunableWalkstyle( description= '\n The walkstyle that the master must be in to apply the value\n walkstyle to the slave.\n ' ), value_type=WalkStyleRequest.TunableFactory(), key_name='Master Walkstyle', value_name='Slave Walkstyle Request'), 'should_increase_master_agent_radius': Tunable( description= "\n If enabled, we combine the slave's agent radius with the master's.\n ", tunable_type=bool, default=True), 'allow_slave_to_teleport_with_master': Tunable( description= '\n If enabled, when the master teleports using a teleport style, the \n slave will also be teleported nearby. If this is false, the master\n cannot use teleport styles at all while they have a routing slave\n using this data.\n ', tunable_type=bool, default=False) } def __init__(self, master, slave, *args, interaction=None, **kwargs): super().__init__(*args, **kwargs) self._master = master self._slave = slave self._interaction = interaction self._routing_type = self.formation_routing_type( self._master, self._slave, self.formation_type) self._formation_behavior = self.formation_behavior(master, slave) master.routing_component.add_routing_slave(self) if interaction is not None: formation_liability = RoutingFormationLiability(self) interaction.add_liability(formation_liability.LIABILITY_TOKEN, formation_liability) else: logger.callstack( 'Routing Formation created without an interaction, this should not happen. Slave: {} Master: {} Formation: {}', slave, master, self) self.release_formation_data() @classmethod def test_formation(cls, master, slave): resolver = DoubleObjectResolver(master, slave) return cls.formation_tests.run_tests(resolver) @classproperty def formation_type(cls): return cls @property def master(self): return self._master @property def slave(self): return self._slave @classproperty def max_slave_count(cls): return cls.formation_routing_type.factory.get_max_slave_count( cls.formation_routing_type) @property def offset(self): return self._routing_type.offset @property def route_length_minimum(self): return self._routing_type.route_length_minimum def on_add(self): self.master.register_routing_stage_event(RoutingStageEvent.ROUTE_START, self._on_master_route_start) self.master.register_routing_stage_event(RoutingStageEvent.ROUTE_END, self._on_master_route_end) self._formation_behavior.on_add() def on_release(self): self._routing_type.on_release() self._formation_behavior.on_release() self.master.unregister_routing_stage_event( RoutingStageEvent.ROUTE_START, self._on_master_route_start) self.master.unregister_routing_stage_event(RoutingStageEvent.ROUTE_END, self._on_master_route_end) def attachment_info_gen(self): yield from self._routing_type.attachment_info_gen() def _on_master_route_start(self, *_, **__): self._routing_type.on_master_route_start() def _on_master_route_end(self, *_, **__): self._routing_type.on_master_route_end() def get_routing_slave_constraint(self): return self._routing_type.get_routing_slave_constraint() def get_walkstyle_override(self): walkstyle_request = self.walkstyle_mapping.get( self.master.get_walkstyle()) slaved_walkstyle = self._slave.get_walkstyle() if walkstyle_request is not None: with self._slave.routing_component.temporary_walkstyle_request( walkstyle_request): slaved_walkstyle = self._slave.get_walkstyle() return slaved_walkstyle def find_good_location_for_slave(self, master_location): return self._routing_type.find_good_location_for_slave(master_location) def add_routing_slave_to_pb(self, route_pb, path=None): slave_pb = route_pb.slaves.add() slave_pb.id = self._slave.id slave_pb.type = self._routing_type.slave_attachment_type walkstyle_override_msg = slave_pb.walkstyle_overrides.add() walkstyle_override_msg.from_walkstyle = 0 walkstyle_override_msg.to_walkstyle = self.get_walkstyle_override() for (from_walkstyle, to_walkstyle_request) in self.walkstyle_mapping.items(): walkstyle_override_msg = slave_pb.walkstyle_overrides.add() walkstyle_override_msg.from_walkstyle = from_walkstyle with self._slave.routing_component.temporary_walkstyle_request( to_walkstyle_request): walkstyle_override_msg.to_walkstyle = self._slave.get_walkstyle( ) for attachment_node in self.attachment_info_gen(): with ProtocolBufferRollback(slave_pb.offset) as attachment_pb: attachment_node.populate_attachment_pb(attachment_pb) self._routing_type.build_routing_slave_pb(slave_pb, path=path) return (self._slave, slave_pb) def release_formation_data(self): self._routing_type.on_release() self._master.routing_component.clear_slave(self._slave) def should_slave_for_path(self, path): return self._routing_type.should_slave_for_path(path) def update_slave_position(self, master_transform, master_orientation, routing_surface, distribute=True, path=None, canceled=False): self._routing_type.update_slave_position(master_transform, master_orientation, routing_surface, distribute=distribute, path=path, canceled=canceled)
class OceanTuning: BEACH_LOCATOR_TAG = TunableTag( description= '\n The tag we can use to get the beach locator definition.\n ' ) OCEAN_DATA = TunableMapping( description= '\n The species-age mapping to ocean data. This defines what\n ages and species can wade in the water and what the water level\n restrictions are as well as beach portal access objects.\n ', key_name='species', key_type=TunableEnumEntry( description= '\n The extended species that this data is for.\n ', tunable_type=SpeciesExtended, default=SpeciesExtended.HUMAN), value_name='age_data', value_type=TunableList( description='\n The ages and their data.\n ', tunable=TunableTuple( description= '\n The ages and their ocean data.\n ', ages=TunableEnumSet( description= '\n The age of the actor.\n ', enum_type=Age), ocean_data=TunableTuple( description= '\n The ocean data for this Age.\n ', wading_interval=TunableInterval( description= '\n The wading interval for Sims at this age and species. The lower\n bound indicates the minimum water height required to apply the\n wading walkstyle, and the upper bound indicates the maximum\n height we can walk into the water until we can potentially\n swim.\n ', tunable_type=float, default_lower=0.1, default_upper=1.0, minimum=0.01), beach_portal_data=OptionalTunable( description= '\n An optional portal definition to allow sims to swim in\n the ocean. Without this, Sims at this age and species\n cannot swim in the ocean.\n ', tunable=TunableReference( description= '\n The portals this age/species will use to swim in the ocean.\n ', manager=services.snippet_manager(), class_restrictions=('PortalData', ), pack_safe=True)), water_depth_error=TunableRange( description= '\n The error, in meters, that we allow for the swimming beach\n portals.\n ', tunable_type=float, default=0.05, minimum=0.01), swimwear_change_water_depth=TunableRange( description= "\n If a Sim's path includes water where the depth is at\n least the tuned value, in meters, they will switch into\n the outfit based on the outfit change reasonat the \n start of the path.\n ", tunable_type=float, default=0.1, minimum=0), swimwear_change_outfit_reason=OptionalTunable( description= '\n If enabled, the outfit change reason that determines which outfit\n category a Sim automatically changes into when \n entering water.\n ', tunable=TunableEnumEntry( tunable_type=OutfitChangeReason, default=OutfitChangeReason.Invalid, invalid_enums=(OutfitChangeReason.Invalid, ))))))) beach_locator_definition = None @staticmethod def get_beach_locator_definition(): if OceanTuning.beach_locator_definition is None: for definition in services.definition_manager( ).get_definitions_for_tags_gen((OceanTuning.BEACH_LOCATOR_TAG, )): OceanTuning.beach_locator_definition = definition break return OceanTuning.beach_locator_definition @staticmethod def get_actor_ocean_data(actor): if not actor.is_sim and not isinstance(actor, StubActor): return species_data = OceanTuning.OCEAN_DATA.get(actor.extended_species, None) if species_data is None: return actor_age = actor.age for age_data in species_data: if actor_age in age_data.ages: return age_data.ocean_data @staticmethod def get_actor_wading_interval(actor): ocean_data = OceanTuning.get_actor_ocean_data(actor) if ocean_data is not None: return ocean_data.wading_interval else: interval_actor = actor if not isinstance(actor, StubActor): if actor.vehicle_component is not None: drivers = actor.get_users(sims_only=True) for driver in drivers: if driver.posture.is_vehicle: if driver.posture.target is actor: interval_actor = driver break ocean_data = OceanTuning.get_actor_ocean_data(interval_actor) if ocean_data is not None: return ocean_data.wading_interval @staticmethod def get_actor_swimwear_change_info(actor): ocean_data = OceanTuning.get_actor_ocean_data(actor) if ocean_data is not None: return (ocean_data.swimwear_change_water_depth, ocean_data.swimwear_change_outfit_reason) return (None, None) @staticmethod def make_depth_bounds_safe_for_surface_and_sim(routing_surface, sim, min_water_depth=None, max_water_depth=None): interval = OceanTuning.get_actor_wading_interval(sim) return OceanTuning.make_depth_bounds_safe_for_surface( routing_surface, wading_interval=interval, min_water_depth=min_water_depth, max_water_depth=max_water_depth) @staticmethod def make_depth_bounds_safe_for_surface(routing_surface, wading_interval=None, min_water_depth=None, max_water_depth=None): if routing_surface.type == SurfaceType.SURFACETYPE_WORLD: surface_min_water_depth = min_water_depth if wading_interval is not None: if max_water_depth is None: surface_max_water_depth = wading_interval.upper_bound else: surface_max_water_depth = min(wading_interval.upper_bound, max_water_depth) surface_max_water_depth = 0 else: surface_max_water_depth = 0 elif routing_surface.type == SurfaceType.SURFACETYPE_POOL: if wading_interval is not None: if min_water_depth is None: surface_min_water_depth = wading_interval.upper_bound else: surface_min_water_depth = max(wading_interval.upper_bound, min_water_depth) else: surface_min_water_depth = min_water_depth surface_max_water_depth = max_water_depth else: surface_min_water_depth = min_water_depth surface_max_water_depth = max_water_depth return (surface_min_water_depth, surface_max_water_depth)
def generate_organization_view(): organizations = [] for org in services.snippet_manager().get_ordered_types(only_subclasses_of=Organization): organizations.append({'organization': str(org), 'active_members': get_organization_members(org.guid64, OrganizationStatusEnum.ACTIVE), 'inactive_members': get_organization_members(org.guid64, OrganizationStatusEnum.INACTIVE)}) return organizations
def __init__(self, snippet_variant_list_instance, **kwargs): super().__init__(services.snippet_manager(), class_restrictions=snippet_variant_list_instance, **kwargs)
def define_snippet(snippet_type, snippet, use_list_reference=False): module_dict = globals() name = snippet_type.title().replace('_', '') SNIPPET_CLASS_NAMES[snippet_type] = name module_name = module_dict['__name__'] snippet_manager = services.snippet_manager() bases = () class_dict = {'__module__': module_name, 'snippet_type': snippet_type} SnippetInstance = SnippetInstanceMetaclass.__new__( SnippetInstanceMetaclass, name, bases, class_dict, manager=snippet_manager) class SnippetReference(TunableSnippetReference): __qualname__ = 'define_snippet.<locals>.SnippetReference' def __init__(self, description=DEFAULT, **kwargs): if description is DEFAULT: description = 'A reference to a {} tuning snippet.'.format( name) super().__init__(SnippetInstance, description=description, **kwargs) SnippetReference.__name__ = 'Tunable{}Reference'.format(name) SNIPPET_REFERENCES[snippet_type] = SnippetReference class SnippetVariant(TunableSnippet): __qualname__ = 'define_snippet.<locals>.SnippetVariant' def __init__(self, allow_list_reference=use_list_reference, **kwargs): super().__init__(snippet_type, allow_list_reference=allow_list_reference, **kwargs) SnippetVariant.__name__ = 'Tunable{}Snippet'.format(name) SNIPPET_VARIANTS[snippet_type] = SnippetVariant backup_dict = module_dict.copy() with sims4.reload.protected(module_dict): module_dict[name] = SnippetInstance module_dict[SnippetVariant.__name__] = SnippetVariant module_dict[SnippetReference.__name__] = SnippetReference sims4.reload.update_module_dict(backup_dict, module_dict) if isinstance(snippet, type): snippet = snippet() SnippetInstance.add_tunable_to_instance('value', snippet) SNIPPETS[snippet_type] = snippet if use_list_reference: list_name = '{}List'.format(name) SNIPPET_VARIANT_LIST_NAMES[snippet_type] = list_name SnippetVariantListInstance = SnippetInstanceMetaclass.__new__( SnippetInstanceMetaclass, list_name, bases, class_dict, manager=snippet_manager) SnippetVariantListInstance.is_list = True class SnippetVariantList(TunableSnippetVariantList): __qualname__ = 'define_snippet.<locals>.SnippetVariantList' def __init__(self, **kwargs): super().__init__(SnippetVariant, **kwargs) SnippetVariantList.__name__ = '{}SnippetVariantList'.format(name) SNIPPET_VARIANT_LISTS[snippet_type] = SnippetVariantList class SnippetVariantListReference(TunableSnippetVariantListReference): __qualname__ = 'define_snippet.<locals>.SnippetVariantListReference' def __init__(self, **kwargs): super().__init__(SnippetVariantListInstance, **kwargs) SnippetVariantListReference.__name__ = '{}SnippetVariantListReference'.format( name) SNIPPET_VARIANT_LIST_REFERENCES[ snippet_type] = SnippetVariantListReference backup_dict = module_dict.copy() with sims4.reload.protected(module_dict): module_dict[list_name] = SnippetVariantListInstance module_dict[SnippetVariantList.__name__] = SnippetVariantList module_dict[SnippetVariantListReference. __name__] = SnippetVariantListReference sims4.reload.update_module_dict(backup_dict, module_dict) SnippetVariantListInstance.add_tunable_to_instance( 'value', SnippetVariantList(allow_list_reference=False)) return (SnippetReference, SnippetVariant)
def define_snippet(snippet_type, snippet, use_list_reference=False): module_dict = globals() name = snippet_type.title().replace('_', '') SNIPPET_CLASS_NAMES[snippet_type] = name module_name = module_dict['__name__'] snippet_manager = services.snippet_manager() bases = () class_dict = {'__module__': module_name, 'snippet_type': snippet_type} SnippetInstance = SnippetInstanceMetaclass.__new__(SnippetInstanceMetaclass, name, bases, class_dict, manager=snippet_manager) class SnippetReference(TunableSnippetReference): def __init__(self, description=DEFAULT, **kwargs): if description is DEFAULT: description = 'A reference to a {} tuning snippet.'.format(name) super().__init__(SnippetInstance, description=description, **kwargs) SnippetReference.__name__ = 'Tunable{}Reference'.format(name) SNIPPET_REFERENCES[snippet_type] = SnippetReference class SnippetVariant(TunableSnippet): def __init__(self, allow_list_reference=use_list_reference, **kwargs): super().__init__(snippet_type, allow_list_reference=allow_list_reference, **kwargs) SnippetVariant.__name__ = 'Tunable{}Snippet'.format(name) SNIPPET_VARIANTS[snippet_type] = SnippetVariant backup_dict = module_dict.copy() with sims4.reload.protected(module_dict): module_dict[name] = SnippetInstance module_dict[SnippetVariant.__name__] = SnippetVariant module_dict[SnippetReference.__name__] = SnippetReference sims4.reload.update_module_dict(backup_dict, module_dict) if isinstance(snippet, type): snippet = snippet() SnippetInstance.add_tunable_to_instance('value', snippet) SNIPPETS[snippet_type] = snippet if use_list_reference: list_name = '{}List'.format(name) SNIPPET_VARIANT_LIST_NAMES[snippet_type] = list_name SnippetVariantListInstance = SnippetInstanceMetaclass.__new__(SnippetInstanceMetaclass, list_name, bases, class_dict, manager=snippet_manager) SnippetVariantListInstance.is_list = True class SnippetVariantList(TunableSnippetVariantList): def __init__(self, **kwargs): super().__init__(SnippetVariant, **kwargs) SnippetVariantList.__name__ = '{}SnippetVariantList'.format(name) SNIPPET_VARIANT_LISTS[snippet_type] = SnippetVariantList class SnippetVariantListReference(TunableSnippetVariantListReference): def __init__(self, **kwargs): super().__init__(SnippetVariantListInstance, **kwargs) SnippetVariantListReference.__name__ = '{}SnippetVariantListReference'.format(name) SNIPPET_VARIANT_LIST_REFERENCES[snippet_type] = SnippetVariantListReference backup_dict = module_dict.copy() with sims4.reload.protected(module_dict): module_dict[list_name] = SnippetVariantListInstance module_dict[SnippetVariantList.__name__] = SnippetVariantList module_dict[SnippetVariantListReference.__name__] = SnippetVariantListReference sims4.reload.update_module_dict(backup_dict, module_dict) SnippetVariantListInstance.add_tunable_to_instance('value', SnippetVariantList(allow_list_reference=False)) return (SnippetReference, SnippetVariant)
class ObjectRoutingBehavior(HasTunableReference, SubclassableGeneratorElement, metaclass=HashedTunedInstanceMetaclass, manager=services.snippet_manager()): INSTANCE_TUNABLES = { 'route': TunableVariant( description= '\n Define how this object routes when this behavior is active.\n ', from_waypoints=ObjectRoutingBehaviorFromWaypointGenerator. TunableFactory(), from_slot_constraint=ObjectRoutingBehaviorFromRoutingSlotConstraint .TunableFactory(), from_routing_formation=ObjectRouteFromRoutingFormation. TunableFactory(), from_fgl=ObjectRouteFromFGL.TunableFactory(), from_target_object=ObjectRouteFromTargetObject.TunableFactory( locked_args={'route_fail': None}), default='from_waypoints'), 'pre_route_animation': OptionalTunable( description= '\n If enabled, the routing object will play this animation before any\n route planning/following happens.\n ', tunable=ObjectAnimationElement.TunableReference()), 'actions': TunableList( description= '\n A list of things the routing object can do once they have reached a\n routing destination.\n ', tunable=TunableVariant( play_animation=ObjectRoutingBehaviorActionAnimation. TunableFactory(), destroy_objects=ObjectRoutingBehaviorActionDestroyObjects. TunableFactory(), apply_loot=ObjectRoutingBehaviorActionApplyLoot.TunableFactory( ), default='play_animation')), 'completion_loot': TunableSet( description= '\n Upon completion, this loot is applied to the routing object. This\n loot is not executed if the behavior was canceled.\n ', tunable=LootActions.TunableReference()), 'walkstyle_override': OptionalTunable( description= '\n If enabled, we will override the default walkstyle for any routes\n in this routing behavior.\n ', tunable=WalkStyleRequest.TunableFactory( description= '\n The walkstyle request we want to make.\n ' )), 'clear_locomotion_mask': Tunable( description= '\n If enabled, override the locomotion queue mask. This mask controls\n which Animation Requests and XEvents get blocked during locomotion.\n By default, the mask blocks everything. If cleared, it blocks\n nothing. It also lowers the animation track used by locomotion to \n 9,999 from the default of 10,000. Use with care, ask your GPE.\n ', tunable_type=bool, default=False) } def __init__(self, obj, *args, **kwargs): super().__init__(*args, **kwargs) self._obj = obj self._route_data = self.route(obj) self._canceled = False self._element = None def _do_single_route_gen(self, timeline, route): if not route: yield from self._route_data.do_route_fail_gen(timeline) return True yield self._element = plan_primitive = PlanRoute(route, self._obj) result = yield from element_utils.run_child(timeline, plan_primitive) if not result: return result yield nodes = plan_primitive.path.nodes if not (nodes and nodes.plan_success): yield from self._route_data.do_route_fail_gen(timeline) return True yield if self._canceled: return False yield plan_primitive.path.blended_orientation = self._route_data.get_randomize_orientation( ) mask_override = None track_override = None if self.clear_locomotion_mask: mask_override = 0 track_override = 9999 self._element = follow_path_element = FollowPath( self._obj, plan_primitive.path, track_override=track_override, mask_override=mask_override) result = yield from element_utils.run_child(timeline, follow_path_element) if not result: return result yield if self._canceled: return False yield for action in self.actions: result = yield from action.run_action_gen( timeline, self._obj, self._route_data.get_target()) if not result: return result yield return True yield def _run_gen(self, timeline): if self.pre_route_animation is not None: animation_element = self.pre_route_animation(self._obj) self._element = build_element( (animation_element, flush_all_animations)) result = yield from element_utils.run_child( timeline, self._element) if not result: return result yield def do_routes(timeline): result = False for route in self._route_data.get_routes_gen(): result = yield from self._do_single_route_gen(timeline, route) if not result: break if not result: yield from element_utils.run_child( timeline, element_utils.sleep_until_next_tick_element()) return result yield if self.walkstyle_override is None: yield from do_routes(timeline) else: walkstyle_request = self.walkstyle_override(self._obj) yield from element_utils.run_child( timeline, walkstyle_request(sequence=do_routes)) target = self._route_data.get_target() if target: if target.is_sim: yield from self._route_data.do_target_action_rules_gen( timeline) else: reservation_handler = target.get_reservation_handler(self._obj) if reservation_handler and reservation_handler.may_reserve(): reservation_handler.begin_reservation() try: yield from self._route_data.do_target_action_rules_gen( timeline) finally: reservation_handler.end_reservation() else: self._route_data.on_no_target() resolver = SingleObjectResolver(self._obj) for loot_action in self.completion_loot: loot_action.apply_to_resolver(resolver) return True yield def _soft_stop(self): self._canceled = True if self._element is not None: self._element.trigger_soft_stop() return super()._soft_stop() def get_target(self): if self._route_data is not None: return self._route_data.get_target() else: return