def get_waypoint_constraints_gen(self, routing_agent, waypoint_count): zone_id = services.current_zone_id() object_constraints = defaultdict(list) if self.object_tag_generator is not None: object_tag_generator = self.object_tag_generator(WaypointContext(self._sim), None) for constraint in itertools.chain((object_tag_generator.get_start_constraint(),), object_tag_generator.get_waypoint_constraints_gen(routing_agent, MAX_INT32)): level = constraint.routing_surface.secondary_id block_id = get_block_id(zone_id, constraint.average_position, level) object_constraints[block_id].append(constraint) plex_id = services.get_plex_service().get_active_zone_plex_id() or plex_enums.INVALID_PLEX_ID block_data = get_all_block_polygons(plex_id) polygons = defaultdict(list) if self._routing_surface.secondary_id == 0: polygons[0] = self._get_polygons_for_lot() for (block_id, (polys, level)) in block_data.items(): if level != self._routing_surface.secondary_id: continue polygon = CompoundPolygon([Polygon(list(reversed(p))) for p in polys]) if not polygon.area(): continue polygons[block_id].append((polygon, self._routing_surface)) if not polygons: return False yield final_constraints = self._get_waypoint_constraints_from_polygons(polygons, object_constraints, waypoint_count) final_constraints = self.apply_water_constraint(final_constraints) yield from final_constraints
def create_constraint(self, sim, target=None, target_position=DEFAULT, routing_surface=DEFAULT, **kwargs): if target is None: target = sim if routing_surface is DEFAULT: routing_surface = target.intended_routing_surface plex_service = services.get_plex_service() zone_id = services.current_zone_id() if not plex_service.is_zone_a_plex(zone_id): return self.non_plex_constraint.constraint level = routing_surface.secondary_id polygons = plex_service.get_plex_polygons(level) if not polygons: return Nowhere('PlexConstraint: plex {} not on level {}', zone_id, level) compound_polygon = CompoundPolygon(polygons) restricted_polygon = RestrictedPolygon(compound_polygon, []) constraint = Constraint( geometry=restricted_polygon, routing_surface=routing_surface, debug_name='Plex zone id: {}, level: {}'.format(zone_id, level)) return constraint
def _test_zone_id(cls, zone_id): if zone_id is None: return TestResult(False, 'Could not resolve into a valid zone id.') active_household = services.active_household() if zone_id == active_household.home_zone_id: return TestResult( False, "Cannot move sim into the active household's home zone.") if zone_id == services.current_zone_id(): return TestResult(False, 'Cannot move Sim into the active zone.') plex_service = services.get_plex_service() if not plex_service.is_zone_an_apartment( zone_id, consider_penthouse_an_apartment=False): persistence_service = services.get_persistence_service() if persistence_service is None: return TestResult(False, 'Persistence service is not initialized.') zone_data = persistence_service.get_zone_proto_buff(zone_id) if zone_data is None: return TestResult(False, 'Could not resolve zone data.') lot_data = persistence_service.get_lot_data_from_zone_data( zone_data) if lot_data is None: return TestResult(False, 'Could not resolve lot data.') venue_tuning = services.get_instance_manager( sims4.resources.Types.VENUE).get(lot_data.venue_key) if not venue_tuning.is_residential: return TestResult(False, 'Only residential venues are eligible.') return TestResult.TRUE
def on_zone_load(self): zone = services.current_zone() plexes_in_group = services.get_plex_service().get_plex_zones_in_group(zone.id) for sim_info in tuple(self.values()): sim_info.on_zone_load() if sim_info.sim_id in self._sims_traveled_to_zone: sim_info._serialization_option = sims.sim_info_types.SimSerializationOption.UNDECLARED elif sim_info.serialization_option == sims.sim_info_types.SimSerializationOption.LOT: if sim_info.zone_id == zone.id: self._sim_infos_saved_in_zone.append(sim_info) elif sim_info.zone_id in plexes_in_group: self._sim_infos_saved_in_plex_group.append(sim_info) if sim_info.serialization_option == sims.sim_info_types.SimSerializationOption.UNDECLARED: if sim_info.zone_id == zone.id and (not sim_info.is_baby or sim_info.lives_here): self._sim_infos_injected_into_zone.append(sim_info) if sim_info.serialization_option == sims.sim_info_types.SimSerializationOption.OPEN_STREETS: if sim_info.world_id == zone.open_street_id: self._sim_infos_saved_in_open_street.append(sim_info) elif sim_info.serialization_option == sims.sim_info_types.SimSerializationOption.OPEN_STREETS: if sim_info.world_id == zone.open_street_id: self._sim_infos_saved_in_open_street.append(sim_info) elif sim_info.serialization_option == sims.sim_info_types.SimSerializationOption.UNDECLARED: if sim_info.zone_id == zone.id and (not sim_info.is_baby or sim_info.lives_here): self._sim_infos_injected_into_zone.append(sim_info) if sim_info.serialization_option == sims.sim_info_types.SimSerializationOption.OPEN_STREETS: if sim_info.world_id == zone.open_street_id: self._sim_infos_saved_in_open_street.append(sim_info) elif sim_info.serialization_option == sims.sim_info_types.SimSerializationOption.OPEN_STREETS: if sim_info.world_id == zone.open_street_id: self._sim_infos_saved_in_open_street.append(sim_info)
def _cache_valid_objects(self): debt_value = self.get_debt_value() if debt_value is None: self._self_destruct() return target_amount = debt_value * self.repo_amount.target_amount unsorted = [] plex_service = services.get_plex_service() check_common_area = plex_service.is_active_zone_a_plex() debtor_household_id = self.debtor_sim().household_id for obj in services.object_manager().valid_objects(): if not obj.get_household_owner_id() == debtor_household_id: continue if not obj.is_on_active_lot(): continue if check_common_area and plex_service.get_plex_zone_at_position( obj.position, obj.level) is None: continue if not obj.is_connected(self.repo_person()): continue if obj.children: continue resolver = SingleObjectResolver(obj) if self.valid_object_tests.run_tests(resolver): delta = abs(obj.depreciated_value - target_amount) unsorted.append((obj.id, delta)) self.objects_to_take = sorted(unsorted, key=operator.itemgetter(1))
def get_residential_zone_director_type(zone_id, residence_zone_director, apartment_zone_director, penthouse_zone_director, *args, **kwargs): plex_service = services.get_plex_service() if penthouse_zone_director is not None and plex_service.get_plex_building_type(zone_id) == PlexBuildingType.PENTHOUSE_PLEX: return penthouse_zone_director(*args, **kwargs) if apartment_zone_director is not None and plex_service.is_zone_a_plex(zone_id): return apartment_zone_director(*args, **kwargs) return residence_zone_director(*args, **kwargs)
def on_cleanup_zone_objects(self): super().on_cleanup_zone_objects() persistence_service = services.get_persistence_service() plex_service = services.get_plex_service() plex_zone_ids = plex_service.get_plex_zones_in_group( services.current_zone_id()) last_save_ticks = None for zone_id in plex_zone_ids: zone_data = persistence_service.get_zone_proto_buff(zone_id) gameplay_zone_data = zone_data.gameplay_zone_data if not gameplay_zone_data.HasField('game_time'): continue if not last_save_ticks is None: if last_save_ticks < gameplay_zone_data.game_time: last_save_ticks = gameplay_zone_data.game_time last_save_ticks = gameplay_zone_data.game_time if last_save_ticks is not None: last_save_time = DateAndTime(last_save_ticks) next_cleanup_time = last_save_time.time_of_next_day_time( ApartmentZoneDirectorMixin.COMMON_AREA_CLEANUP.time_of_day) if next_cleanup_time < services.time_service().sim_now: self._run_common_area_cleanup() owning_household = services.owning_household_of_active_lot() if owning_household is not None and not owning_household.has_home_zone_been_active( ): self._run_new_tenant_cleanup()
def get_default_position(self, position=None): front_door = services.get_door_service().get_front_door() if front_door is not None: default_position = front_door.position elif position is not None: default_position = min(self.corners, key=lambda p: (p - position).magnitude_squared()) else: plex_service = services.get_plex_service() if plex_service.get_plex_building_type( services.current_zone_id()) == PlexBuildingType.COASTAL: for corner_position in self.corners: if get_water_depth(corner_position.x, corner_position.z) <= 0: default_position = corner_position break else: logger.error( "Couldn't find a corner that was not below water on the current lot. This is probably an error case. We need a place to put down things like the mailbox, etc." ) default_position = self.corners[0] else: default_position = self.corners[0] delta = self.position - default_position if not sims4.math.vector3_almost_equal(delta, sims4.math.Vector3.ZERO()): default_position += vector_normalize(delta) if front_door is not None: plex_service = services.get_plex_service() if plex_service.is_active_zone_a_plex(): (front_position, back_position) = front_door.get_door_positions() if front_position is not None: front_zone_id = plex_service.get_plex_zone_at_position( front_position, front_door.level) else: front_zone_id = None if front_zone_id is not None: default_position = front_position elif back_position is not None: back_zone_id = plex_service.get_plex_zone_at_position( back_position, front_door.level) if back_zone_id is not None: default_position = back_position return default_position
def _validate_location(self): plex_service = services.get_plex_service() if not plex_service.is_active_zone_a_plex(): return if plex_service.get_plex_zone_at_position(self.position, self.level) is not None: return self.place_in_good_location()
def all_objects_gen(objects): plex_service = services.get_plex_service() for obj in objects: if not not plex_service.is_active_zone_a_plex( ) and plex_service.get_plex_zone_at_position(obj.position, obj.level) is None: continue yield obj
def fix_up_doors(self, force_refresh=False): building_type = services.get_plex_service().get_plex_building_type( services.current_zone_id()) if building_type == PlexBuildingType.DEFAULT or building_type == PlexBuildingType.PENTHOUSE_PLEX or building_type == PlexBuildingType.COASTAL: self._fix_up(force_refresh=force_refresh) elif building_type == PlexBuildingType.FULLY_CONTAINED_PLEX: self._fix_up_for_apartments() services.object_manager().on_front_door_candidates_changed()
def _run_common_area_cleanup(self): actions = ApartmentZoneDirectorMixin.COMMON_AREA_CLEANUP.actions() plex_service = services.get_plex_service() def object_criteria(obj): return plex_service.get_plex_zone_at_position( obj.position, obj.level) is None actions.modify_objects(object_criteria=object_criteria)
def print_plex_rents(_connection=None): persistence_service = services.get_persistence_service() plex_service = services.get_plex_service() for (zone_id, _) in plex_service.zone_to_master_map_gen(): house_description_id = persistence_service.get_house_description_id( zone_id) rent = services.get_rent(house_description_id) sims4.commands.output('Zone Id: {}, Rent: {}'.format(zone_id, rent), _connection)
def is_ungreeted_sim_disallowed(self): zone_id = services.current_zone_id() active_household = services.active_household() if active_household is not None and active_household.home_zone_id == zone_id: return False else: plex_service = services.get_plex_service() if plex_service.get_plex_building_type(zone_id) != PlexBuildingType.PENTHOUSE_PLEX: return False return True
def _get_shell(self): candidates = list(services.object_manager().get_objects_with_tag_gen(self.shell_tag)) if not candidates: zone_id = services.current_zone_id() if services.get_plex_service().is_zone_an_apartment(zone_id, consider_penthouse_an_apartment=True): logger.error('Failed to find shell. Tag: {}.', self.shell_tag) return if len(candidates) > 1: logger.error('Found multiple shells. Candidates: {}. Tag: {}.', candidates, self.shell_tag) return candidates[0]
def print_plex_types(_connection=None): persistence_service = services.get_persistence_service() plex_service = services.get_plex_service() for (zone_id, _) in plex_service.zone_to_master_map_gen(): house_description_id = persistence_service.get_house_description_id( zone_id) building_type = PlexBuildingType( services.get_building_type(house_description_id)) sims4.commands.output( 'Zone Id: {}, Rent: {}'.format(zone_id, building_type), _connection)
def __call__(self, *args, **kwargs): zone_id = self.zone_source.get_zone_id(**kwargs) if not zone_id: return TestResult(False, "ZoneTest couldn't find a zone to test.", tooltip=self.tooltip) if self.zone_tests.venue_type is not None: venue_service = services.venue_service() if self.zone_tests.use_source_venue: venue_tuning = type(venue_service.source_venue) else: venue_tuning = type(venue_service.active_venue) venue_tunings = (venue_tuning,) if venue_tuning is not None else () if not self.zone_tests.venue_type.test_collection(venue_tunings): return TestResult(False, 'Zone failed venue white or black list {}', venue_tuning, tooltip=self.tooltip) if self.zone_tests.venue_tier is not None: venue_tier_index = build_buy.get_venue_tier(zone_id) if self.zone_tests.venue_tier != venue_tier_index: return TestResult(False, 'Zone has tier {} but {} was required', venue_tier_index, self.zone_tests.venue_tier, tooltip=self.tooltip) if self.zone_tests.is_apartment is not None: plex_service = services.get_plex_service() if self.zone_tests.is_apartment.is_apartment != plex_service.is_zone_an_apartment(zone_id, consider_penthouse_an_apartment=self.zone_tests.is_apartment.consider_penthouse_an_apartment): return TestResult(False, 'Zone failed apartment test', tooltip=self.tooltip) if self.zone_tests.is_penthouse is not None: plex_service = services.get_plex_service() is_penthouse = plex_service.get_plex_building_type(zone_id) == PlexBuildingType.PENTHOUSE_PLEX if is_penthouse != self.zone_tests.is_penthouse: return TestResult(False, 'Zone failed penthouse test', tooltip=self.tooltip) if self.zone_tests.zone_modifiers is not None: zone_modifier_service = services.get_zone_modifier_service() zone_modifiers = zone_modifier_service.get_zone_modifiers(zone_id) if not self.zone_tests.zone_modifiers.test_collection(zone_modifiers): return TestResult(False, 'Zone failed to meet whitelist/blacklist for zone modifiers. ZoneId: {}, Mods: {}', zone_id, zone_modifiers, tooltip=self.tooltip) if self.zone_tests.world_tests is not None: world_id = services.get_persistence_service().get_world_id_from_zone(zone_id) world_desc_id = services.get_world_description_id(world_id) if world_desc_id == 0: return TestResult(False, 'Unable to determine world for Zone {}', zone_id) if not self.zone_tests.world_tests.test_item(world_desc_id): return TestResult(False, 'Zone {} failed to meet world requirements, is in {}, fails tests for {}', zone_id, world_desc_id, self.zone_tests.world_tests, tooltip=self.tooltip) if self.zone_tests.business_tests is not None: return self.zone_tests.business_tests(zone_id) return TestResult.TRUE
def _exec_on_objects_with_component(self, component_type, func): object_manager = services.object_manager() plex_service = services.get_plex_service() for obj in object_manager.get_all_objects_with_component_gen( component_type): if not self.is_affected_object(obj): continue if plex_service.is_active_zone_a_plex( ) and plex_service.get_plex_zone_at_position( obj.position, obj.level) is None: continue func(obj.get_component(component_type))
def get_current_zone_plex_id() -> int: """get_current_zone_plex_id() Retrieve the plex id of the current zone. .. note:: A plex id is basically a Room location. :return: The decimal identifier of the current zone or 0 if the current zone does not have a plex id. :rtype: int """ from services import get_plex_service return get_plex_service().get_active_zone_plex_id() or 0
def all_lights_gen(target): plex_service = services.get_plex_service() for obj in services.object_manager().get_all_objects_with_component_gen( LIGHTING_COMPONENT): if get_object_has_tag(obj.definition.id, LightingComponent.MANUAL_LIGHT_TAG): continue if not not plex_service.is_active_zone_a_plex( ) and plex_service.get_plex_zone_at_position(obj.position, obj.level) is None: continue yield obj
def is_shared_between_objects(inventory_type): tuning = InventoryTypeTuning.get_inventory_type_data_tuning( inventory_type) if tuning is None or tuning.shared_between_objects == ObjectShareability.SHARED: return True if tuning.shared_between_objects == ObjectShareability.NOT_SHARED: return False elif tuning.shared_between_objects == ObjectShareability.SHARED_IF_NOT_IN_APARTMENT: return not services.get_plex_service().is_zone_an_apartment( services.current_zone_id(), consider_penthouse_an_apartment=False) return True
def get_zone_id_from_pick_location(self): lot_id = self.lot_id if lot_id is None: return plex_service = services.get_plex_service() if services.active_lot_id( ) == lot_id and plex_service.is_active_zone_a_plex(): return plex_service.get_plex_zone_at_position( self.location, self.level) persistence_service = services.get_persistence_service() return persistence_service.resolve_lot_id_into_zone_id( lot_id, ignore_neighborhood_id=self._ignore_neighborhood_id)
def place_in_good_location(self, position=None, routing_surface=None): plex_service = services.get_plex_service() is_active_zone_a_plex = plex_service.is_active_zone_a_plex() def try_to_place_bassinet(position, routing_surface=None, **kwargs): starting_location = placement.create_starting_location( position=position, routing_surface=routing_surface) fgl_context = placement.create_fgl_context_for_object( starting_location, self, **kwargs) (translation, orientation) = placement.find_good_location(fgl_context) if translation is not None and orientation is not None: if is_active_zone_a_plex and ( routing_surface is None or plex_service.get_plex_zone_at_position( translation, routing_surface.secondary_id) is None): return False else: self.move_to(translation=translation, orientation=orientation) if routing_surface is not None: self.move_to(routing_surface=routing_surface) return True return False if position is not None and try_to_place_bassinet( position, routing_surface=routing_surface): return True lot = services.active_lot() for tag in Baby.BABY_PLACEMENT_TAGS: for (attempt, obj) in enumerate( services.object_manager().get_objects_with_tag_gen(tag)): position = obj.position routing_surface = obj.routing_surface if lot.is_position_on_lot(position) and try_to_place_bassinet( position, routing_surface=routing_surface, max_distance=10): return if attempt >= Baby.MAX_PLACEMENT_ATTEMPTS: break position = lot.get_default_position() if not try_to_place_bassinet(position): self.update_ownership(self.sim_info, make_sim_owner=False) if not build_buy.move_object_to_household_inventory(self): logger.error( 'Failed to place bassinet in household inventory.', owner='rmccord') if self.is_selectable: failed_placement_notification = Baby.FAILED_PLACEMENT_NOTIFICATION( self.sim_info, SingleSimResolver(self.sim_info)) failed_placement_notification.show_dialog()
def get_plex_id(zone_id: int) -> int: """get_plex_id(zone_id) Retrieve the plex id of a Zone. :return: The Plex Id of the specified zone or -1 if it was not found. :rtype: int """ plex_service = services.get_plex_service() if zone_id not in plex_service._zone_to_master_map: return 0 (_, plex_id) = plex_service._zone_to_master_map[zone_id] return plex_id
def on_loading_screen_animation_finished(self): household = services.active_household() plex_service = services.get_plex_service() if household is not None and not household.has_home_zone_been_active( ) and plex_service.is_zone_an_apartment( household.home_zone_id, consider_penthouse_an_apartment=False): active_sim = services.get_active_sim() landlord_sim_info = self.get_landlord_sim_info() if active_sim is not None and landlord_sim_info is not None: dialog = LandlordTuning.LANDLORD_FIRST_PLAY_RENT_REMINDER_NOTIFICATION( active_sim) dialog.show_dialog(icon_override=IconInfoData( obj_instance=landlord_sim_info))
def assign_mailbox_owners(self): plex_service = services.get_plex_service() door_service = services.get_door_service() if not plex_service.is_active_zone_a_plex(): return if plex_service.get_plex_building_type( services.current_zone_id()) == PlexBuildingType.PENTHOUSE_PLEX: return plex_door_infos = door_service.get_plex_door_infos() if not plex_door_infos: return object_manager = services.object_manager() unclaimed_mailboxes = [] for mailbox in object_manager.get_objects_with_tags_gen( *self.MAILBOX_TAGS): mailbox.set_household_owner_id(None) unclaimed_mailboxes.append(mailbox) mailbox_handles = [ self._create_mailbox_handle(mailbox) for mailbox in unclaimed_mailboxes ] door_handles = self._create_plexdoor_handles(plex_door_infos) path_plan_context = routing.PathPlanContext() path_plan_context.set_key_mask(routing.FOOTPRINT_KEY_ON_LOT | routing.FOOTPRINT_KEY_OFF_LOT) routes = routing_utils.sorted_estimated_distances_between_multiple_handles( mailbox_handles, door_handles, path_plan_context) for estimated_distance in routes: mbox_handle = estimated_distance[0] door_handle = estimated_distance[1] mailbox = mbox_handle.obj door = door_handle.obj if mbox_handle.assigned: continue if door_handle.assigned: continue mapped_household_ids = set() household_id = door.household_owner_id if household_id != 0 and household_id not in mapped_household_ids: mapped_household_ids.add(household_id) self._apply_ownership(mailbox, household_id) door_handle.assigned = True mbox_handle.assigned = True logger.debug( 'mailbox {} paired with a door {} owned by household {}', mailbox, door, household_id) if not [dh for dh in door_handles if not dh.assigned]: break if not [mbh for mbh in mailbox_handles if not mbh.assigned]: break
def on_lot_check(test_sim): if not test_sim.is_on_active_lot(): return False plex_service = services.get_plex_service() zone_id = services.current_zone_id() if plex_service.is_zone_a_plex(zone_id): level = test_sim.level if plex_service.get_plex_zone_at_position( test_sim.position, level) != zone_id: return False if plex_service.get_plex_zone_at_position( test_sim.intended_position, level) != zone_id: return False return not services.get_zone_situation_manager( ).is_sim_ss3_safe(test_sim)
def _get_zone_ids_from_context(cls, context): to_zone_id = context.pick.get_zone_id_from_pick_location() if to_zone_id is None: return (0, ()) plex_service = services.get_plex_service() if not plex_service.is_zone_an_apartment( to_zone_id, consider_penthouse_an_apartment=False): return (to_zone_id, ()) zone_ids = list(plex_service.get_plex_zones_in_group(to_zone_id)) if services.current_zone_id() in zone_ids: return (to_zone_id, ()) active_household_home_zone_id = services.active_household( ).home_zone_id if active_household_home_zone_id in zone_ids: zone_ids.remove(active_household_home_zone_id) return (0, zone_ids)
def _get_valid_lot_choices(cls, inst, target, context, target_list=None): to_zone_id = context.pick.get_zone_id_from_pick_location() if to_zone_id is None: logger.error( 'Could not resolve lot id: {} into a valid zone id when traveling to an apartment lot.', context.pick.lot_id, owner='rmccord') return [] plex_service = services.get_plex_service() if not plex_service.is_zone_a_plex(to_zone_id): return [] valid_zone_ids = plex_service.get_plex_zones_in_group(to_zone_id) persistence_service = services.get_persistence_service() results = list( persistence_service.get_zone_proto_buff(zone_id) for zone_id in valid_zone_ids) return results
def _test(cls, target, context, **kwargs): (position, surface) = cls._get_position_and_surface(target, context) if position is None: return TestResult(False, 'Cannot go here without a pick or target.') if context.pick is not None and context.pick.pick_type == PickType.PICK_POOL_EDGE: return TestResult.TRUE plex_service = services.get_plex_service() if plex_service.is_active_zone_a_plex(): plex_zone_id_at_pick = plex_service.get_plex_zone_at_position( position, surface.secondary_id) if plex_zone_id_at_pick is not None and plex_zone_id_at_pick != services.current_zone_id( ): return TestResult(False, 'Pick point in inactive plex') routing_location = routing.Location(position, sims4.math.Quaternion.IDENTITY(), surface) routing_context = context.sim.get_routing_context() objects_to_ignore = set() if target is not None and target.is_sim: posture_target = target.posture_target if posture_target is not None: objects_to_ignore.update( posture_target.parenting_hierarchy_gen()) if context.sim is not None: posture_target = context.sim.posture_target if posture_target.vehicle_component is not None: posture_target = posture_target.part_owner if posture_target.is_part else posture_target objects_to_ignore.add(posture_target) try: for obj in objects_to_ignore: footprint_component = obj.footprint_component if footprint_component is not None: routing_context.ignore_footprint_contour( footprint_component.get_footprint_id()) if not routing.test_connectivity_permissions_for_handle( routing.connectivity.Handle(routing_location), routing_context): return TestResult(False, 'Cannot GoHere! Unroutable area.') finally: for obj in objects_to_ignore: footprint_component = obj.footprint_component if footprint_component is not None: routing_context.remove_footprint_contour_override( footprint_component.get_footprint_id()) return TestResult.TRUE