Beispiel #1
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self._sim = self._context.sim
     self._valid_objects = []
     for obj in services.object_manager().get_objects_matching_tags(
             self.object_tags, match_any=True):
         if self.placement_restriction is not None and self.placement_restriction == obj.is_outside:
             continue
         distance_from_sim = obj.position - self._sim.position
         if distance_from_sim.magnitude_squared(
         ) <= self.object_max_distance:
             if obj.is_connected(self._sim):
                 self._valid_objects.append(obj)
     self._valid_objects = self.object_search_strategy.get_waypoint_objects(
         self._valid_objects)
     if not self._valid_objects:
         self._start_constraint = Circle(
             self._sim.position,
             self.constrain_radius,
             routing_surface=self._sim.routing_surface,
             los_reference_point=None)
         return
     if self.randomize_order:
         random.shuffle(self._valid_objects)
     starting_object = self._valid_objects.pop(0)
     self._start_constraint = Circle(
         starting_object.position,
         self.constrain_radius,
         routing_surface=self._sim.routing_surface,
         los_reference_point=None)
     self._start_constraint = self._start_constraint.intersect(
         self.get_water_constraint())
Beispiel #2
0
 def get_start_constraint(self):
     if self._start_constraint is not None:
         return self._start_constraint
     sim = self._context.sim
     position = self._target.position if self._target is not None else sim.position
     relative_offset_vector = Vector3(
         0, 0, self.ocean_constraint_distance_past_swim_portal)
     if self._target is not None and self._target.routing_surface is not None:
         routing_surface = self._target.routing_surface
     else:
         routing_surface = sim.routing_surface
     if routing_surface.type != routing.SurfaceType.SURFACETYPE_POOL:
         self._start_constraint = OceanStartLocationConstraint.create_simple_constraint(
             WaterDepthIntervals.SWIM,
             self.ocean_constraint_radius,
             sim,
             self._target,
             position,
             ideal_radius=self.constraint_width,
             ideal_radius_width=self.constraint_width,
             relative_offset_vector=relative_offset_vector)
     else:
         self._start_constraint = Circle(
             position,
             self.ocean_constraint_radius,
             routing_surface=self._routing_surface)
     self._master_depth_constraint = WaterDepthIntervalConstraint.create_water_depth_interval_constraint(
         sim, WaterDepthIntervals.SWIM)
     self._start_constraint = self._start_constraint.intersect(
         self._master_depth_constraint)
     return self._start_constraint
Beispiel #3
0
 def _get_starting_constraint(self, *args, **kwargs):
     constraint = ANYWHERE
     target = self.target
     if self._waypoint_generator.is_for_vehicle and (target is not None and target.vehicle_component is not None) and not target.is_in_inventory():
         constraint = Circle(target.position, target.vehicle_component.minimum_route_distance, routing_surface=target.routing_surface)
         constraint = constraint.intersect(self._waypoint_generator.get_water_constraint())
     else:
         constraint = self._waypoint_generator.get_start_constraint()
     posture_constraint = self._waypoint_generator.get_posture_constraint()
     if posture_constraint is not None:
         constraint = constraint.intersect(posture_constraint)
     return constraint
Beispiel #4
0
 def push_dismount_affordance(self, sim, final_location, depend_on_si=None):
     if sim.posture.is_vehicle:
         constraint = sim.posture_state.posture_constraint
     else:
         constraint = self._create_drive_posture_constraint(
             self.drive_affordance.provided_posture_type)
     radius = max(
         self.owner.routing_component.object_radius *
         self.object_radius_dismount_multiplier, self.ideal_route_radius)
     circle_constraint = None
     wading_interval = TunedInterval(0.1, 0.1)
     (min_water_depth,
      max_water_depth) = OceanTuning.make_depth_bounds_safe_for_surface(
          sim.routing_surface, wading_interval)
     if not (min_water_depth is None and max_water_depth is None):
         water_constraint = Constraint(min_water_depth=min_water_depth,
                                       max_water_depth=max_water_depth)
         if water_constraint.is_location_water_depth_valid(final_location):
             constraint = constraint.intersect(water_constraint)
         else:
             large_radius = max(self.minimum_route_distance, radius)
             circle_constraint = Circle(
                 final_location.transform.translation,
                 large_radius,
                 sim.routing_surface,
                 ideal_radius=self.ideal_route_radius,
                 los_reference_point=DEFAULT)
             water_constraint = water_constraint.intersect(
                 circle_constraint)
             if water_constraint.is_any_geometry_water_depth_valid():
                 constraint = constraint.intersect(water_constraint)
             else:
                 constraint = constraint.intersect(circle_constraint)
                 circle_constraint = None
     if circle_constraint is None:
         circle_constraint = Circle(final_location.transform.translation,
                                    radius,
                                    sim.routing_surface,
                                    ideal_radius=self.ideal_route_radius,
                                    los_reference_point=DEFAULT)
         constraint = constraint.intersect(circle_constraint)
     proxy_obj = services.terrain_service.TerrainService.create_surface_proxy_from_location(
         final_location)
     constraint = constraint.intersect(circle_constraint)
     return self._push_affordance(
         sim,
         interactions.utils.satisfy_constraint_interaction.
         SatisfyConstraintSuperInteraction,
         proxy_obj,
         depend_on_si=depend_on_si,
         constraint_to_satisfy=constraint,
         name_override='DismountVehicle')
Beispiel #5
0
 def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
     water_constraint = self.get_water_constraint()
     for _ in range(waypoint_count - 1):
         if not self._valid_objects:
             return
         obj = self._valid_objects.pop(0)
         next_constraint_circle = Circle(
             obj.position,
             self.constrain_radius,
             los_reference_point=None,
             routing_surface=obj.routing_surface)
         next_constraint_circle = next_constraint_circle.intersect(
             water_constraint)
         yield next_constraint_circle
Beispiel #6
0
 def get_center_of_mass_constraint(self):
     if not self:
         logger.warn('No Sims in ensemble when trying to construct constraint.')
         return ANYWHERE
     (level, position) = self.calculate_level_and_center_of_mass()
     routing_surface = routing.SurfaceIdentifier(services.current_zone_id(), level, routing.SurfaceType.SURFACETYPE_WORLD)
     return Circle(position, sqrt(self.max_ensemble_radius), routing_surface)
Beispiel #7
0
 def _get_waypoint_constraints_from_polygons(self, polygons, object_constraints, waypoint_count):
     object_constraints = dict(object_constraints)
     total_area = sum(p.area() for (p, _) in itertools.chain.from_iterable(polygons.values()))
     sim_location = self._sim.routing_location
     sim_routing_context = self._sim.get_routing_context()
     restriction = None
     if self.object_tag_generator is not None:
         restriction = self.object_tag_generator.placement_restriction
     final_constraints = []
     for (block_id, block_data) in polygons.items():
         block_object_constraints = object_constraints.pop(block_id, ())
         if restriction is not None:
             if restriction and block_id == 0:
                 continue
         else:
             for (polygon, routing_surface) in block_data:
                 polygon_waypoint_count = math.ceil(waypoint_count*(polygon.area()/total_area))
                 for position in random_uniform_points_in_compound_polygon(polygon, num=int(polygon_waypoint_count)):
                     if not routing.test_connectivity_pt_pt(sim_location, routing.Location(position, routing_surface=self._routing_surface), sim_routing_context, ignore_objects=self._sim):
                         continue
                     position_constraint = Circle(position, self.constraint_radius, routing_surface=routing_surface)
                     for block_object_constraint in tuple(block_object_constraints):
                         intersection = block_object_constraint.intersect(position_constraint)
                         if intersection.valid:
                             block_object_constraints.remove(block_object_constraint)
                     final_constraints.append(position_constraint)
             final_constraints.extend(block_object_constraints)
     final_constraints.extend(itertools.chain.from_iterable(object_constraints.values()))
     return final_constraints
Beispiel #8
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     if self._target is None:
         self._start_constraint = Nowhere(
             'Trying to generate a waypoint constraint without a target.')
         self._los_reference_point = None
     else:
         self._los_reference_point = self._target.position
         if self._target.is_terrain:
             self._los_reference_point = None
         self._start_constraint = Circle(
             self._target.position,
             self.object_constraint_radius,
             routing_surface=self._routing_surface,
             los_reference_point=self._los_reference_point)
         self._start_constraint = self._start_constraint.intersect(
             self.get_water_constraint())
Beispiel #9
0
class _WaypointGeneratorObjectPoints(_WaypointGeneratorBase):
    FACTORY_TUNABLES = {
        'object_constraint_radius':
        TunableRange(
            description=
            '\n            The radius, in meters, of the generated constraint around the \n            target object where the waypoints will be generated.\n            ',
            tunable_type=float,
            default=3,
            minimum=0),
        'waypoint_constraint_radius':
        TunableRange(
            description=
            '\n            The radius, in meters, for each generated waypoint inside the \n            object constraint radius for the Sim to route to.\n            ',
            tunable_type=float,
            default=1,
            minimum=1)
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self._target is None:
            self._start_constraint = Nowhere(
                'Trying to generate a waypoint constraint without a target.')
            self._los_reference_point = None
        else:
            self._los_reference_point = self._target.position
            if self._target.is_terrain:
                self._los_reference_point = None
            self._start_constraint = Circle(
                self._target.position,
                self.object_constraint_radius,
                routing_surface=self._routing_surface,
                los_reference_point=self._los_reference_point)
            self._start_constraint = self._start_constraint.intersect(
                self.get_water_constraint())

    def get_start_constraint(self):
        return self._start_constraint

    def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
        polygon = self._start_constraint.geometry.polygon
        object_waypoint_constraints = []
        object_waypoint = Circle(self._target.position,
                                 self.waypoint_constraint_radius,
                                 routing_surface=self._target.routing_surface,
                                 los_reference_point=self._los_reference_point)
        object_waypoint_constraints.append(object_waypoint)
        for position in random_uniform_points_in_compound_polygon(
                polygon, num=waypoint_count):
            object_waypoint_constraints.append(
                Circle(position,
                       self.waypoint_constraint_radius,
                       routing_surface=self._start_constraint.routing_surface,
                       los_reference_point=self._los_reference_point))
            object_waypoint_constraints.append(object_waypoint)
        object_waypoint_constraints = self.apply_water_constraint(
            object_waypoint_constraints)
        yield from object_waypoint_constraints
Beispiel #10
0
 def _constraint_gen(cls, inst, sim, target, **kwargs):
     for constraint in super(SuperInteraction,
                             cls)._constraint_gen(sim, target, **kwargs):
         yield constraint
     obj = cls.object_to_put_down(inst, sim=sim, target=target)
     yield create_carry_constraint(obj, debug_name='CarryForPutDown')
     yield Circle(sim.position,
                  PUT_DOWN_GEOMETRY_RADIUS,
                  routing_surface=sim.routing_surface)
 def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
     zone = services.current_zone()
     constraint_set = zone.get_spawn_points_constraint(except_lot_id=self._except_lot_id, sim_spawner_tags=self.spawn_point_tags, generalize=True)
     routing_context = routing_agent.routing_component.pathplan_context
     source_handle = routing.connectivity.Handle(routing_agent.position, routing_agent.routing_surface)
     dest_handles = set()
     for constraint in constraint_set:
         handles = constraint.get_connectivity_handles(routing_agent)
         dest_handles.update(handles)
     connectivity = routing.test_connectivity_batch((source_handle,), dest_handles, routing_context=routing_context, compute_cost=True)
     vehicle_dest_handles = {dest for (_, dest, cost) in connectivity if sims4.math.almost_equal(cost, 0.0)}
     constraint_set = create_constraint_set([handle.constraint for handle in vehicle_dest_handles])
     constraints_weighted = []
     min_score = sims4.math.MAX_FLOAT
     for constraint in constraint_set:
         spawn_point_vector = constraint.average_position - self._sim.position
         score = sims4.math.vector_dot_2d(self._pick_vector, spawn_point_vector)
         min_score = score
         constraints_weighted.append((score, constraint))
     constraints_weighted = [(score - min_score, constraint) for (score, constraint) in constraints_weighted]
     constraints_weighted = sorted(constraints_weighted, key=lambda i: i[0])
     first_constraint = constraints_weighted[-1][1]
     del constraints_weighted[-1]
     first_constraint_circle = Circle(first_constraint.average_position, self.constraint_radius, routing_surface=first_constraint.routing_surface)
     jog_waypoint_constraints = []
     jog_waypoint_constraints.append(first_constraint_circle)
     last_waypoint_position = first_constraint.average_position
     for _ in range(waypoint_count - 1):
         constraints_weighted_next = []
         for (_, constraint) in constraints_weighted:
             average_position = constraint.average_position
             distance_last = (average_position - last_waypoint_position).magnitude_2d()
             distance_home = (average_position - self._origin_position).magnitude_2d()
             constraints_weighted_next.append((distance_last + distance_home, constraint))
         break
         next_constraint = pop_weighted(constraints_weighted_next)
         next_constraint_circle = Circle(next_constraint.average_position, self.constraint_radius, routing_surface=next_constraint.routing_surface)
         jog_waypoint_constraints.append(next_constraint_circle)
         constraints_weighted = constraints_weighted_next
         break
         last_waypoint_position = next_constraint.average_position
     jog_waypoint_constraints = self.apply_water_constraint(jog_waypoint_constraints)
     yield from jog_waypoint_constraints
     yield self._start_constraint
Beispiel #12
0
 def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
     polygon = self._start_constraint.geometry.polygon
     object_waypoint_constraints = []
     object_waypoint = Circle(self._target.position,
                              self.waypoint_constraint_radius,
                              routing_surface=self._target.routing_surface,
                              los_reference_point=self._los_reference_point)
     object_waypoint_constraints.append(object_waypoint)
     for position in random_uniform_points_in_compound_polygon(
             polygon, num=waypoint_count):
         object_waypoint_constraints.append(
             Circle(position,
                    self.waypoint_constraint_radius,
                    routing_surface=self._start_constraint.routing_surface,
                    los_reference_point=self._los_reference_point))
         object_waypoint_constraints.append(object_waypoint)
     object_waypoint_constraints = self.apply_water_constraint(
         object_waypoint_constraints)
     yield from object_waypoint_constraints
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     if self._target is None:
         self._start_constraint = Nowhere(
             'No target for _WaypointGeneratorPacing')
         self._los_reference_point = None
         return
     self._los_reference_point = self._target.position
     if self._target.is_terrain:
         self._los_reference_point = None
     water_constraint = self.get_water_constraint(
         self.constraint_parameters.min_water_depth,
         self.constraint_parameters.max_water_depth)
     if self.outside_only:
         self._routing_surface = routing.SurfaceIdentifier(
             services.current_zone_id(), 0,
             routing.SurfaceType.SURFACETYPE_WORLD)
         starting_location = Location(position=self._target.position,
                                      routing_surface=self._routing_surface)
         search_flags = FGLSearchFlagsDefaultForSim | FGLSearchFlag.STAY_OUTSIDE
         fgl_context = placement.FindGoodLocationContext(
             starting_location,
             routing_context=self._context.sim.routing_context,
             additional_avoid_sim_radius=routing.get_default_agent_radius(),
             max_results=1,
             max_steps=10,
             search_flags=search_flags,
             min_water_depth=water_constraint.get_min_water_depth(),
             max_water_depth=water_constraint.get_max_water_depth())
         (trans, _) = placement.find_good_location(fgl_context)
         if trans is not None:
             geometry = sims4.geometry.RestrictedPolygon(
                 sims4.geometry.CompoundPolygon(
                     sims4.geometry.Polygon((trans, ))), ())
             self._start_constraint = SmallAreaConstraint(
                 geometry=geometry,
                 debug_name='WaypointPacingStartingConstraint',
                 routing_surface=self._routing_surface,
                 min_water_depth=water_constraint.get_min_water_depth(),
                 max_water_depth=water_constraint.get_max_water_depth())
         else:
             self._start_constraint = Nowhere(
                 'WaypointGeneratorPacing requires outside, but we failed to find a good location.'
             )
     else:
         self._start_constraint = Circle(
             self._target.position,
             self.constraint_parameters.object_constraint_radius,
             routing_surface=self._routing_surface,
             los_reference_point=self._los_reference_point,
             min_water_depth=water_constraint.get_min_water_depth(),
             max_water_depth=water_constraint.get_max_water_depth())
def routing_debug_generate_routing_goals(x: float = None,
                                         y: float = None,
                                         z: float = None,
                                         radius: int = None,
                                         obj: OptionalTargetParam = None,
                                         _connection=None):
    if x is None or (y is None or z is None) or radius is None:
        sims4.commands.output('Please enter 4 floats for x,y,z and radius',
                              _connection)
        return False
    obj = get_optional_target(obj, _connection=_connection)
    if obj is None:
        return False
    routing_component = obj.get_component(ROUTING_COMPONENT)
    if routing_component is None:
        return False
    if not postures.posture_graph.enable_debug_goals_visualization:
        sims4.commands.execute('debugvis.goals.enable', _connection)
    position = Vector3(x, y, z)
    routing_surface = routing.SurfaceIdentifier(
        services.current_zone_id(), 0, routing.SurfaceType.SURFACETYPE_WORLD)
    constraint = Circle(position, radius, routing_surface)
    handles = constraint.get_connectivity_handles(obj)
    handles_str = 'Handles: {}'.format(len(handles))
    sims4.commands.output(handles_str, _connection)
    all_goals = []
    for handle in handles:
        goal_list = handle.get_goals()
        goals_str = '\tGoals: {}'.format(len(goal_list))
        sims4.commands.output(goals_str, _connection)
        all_goals.extend(goal_list)
    if postures.posture_graph.enable_debug_goals_visualization:
        with debugvis.Context('goal_scoring',
                              routing_surface=routing_surface) as layer:
            for polygon in constraint.geometry.polygon:
                layer.add_polygon(polygon, routing_surface=routing_surface)
            for goal in all_goals:
                position = goal.location.transform.translation
                layer.add_point(position, routing_surface=routing_surface)
Beispiel #15
0
 def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
     if self._start_constraint is None:
         self.get_start_constraint()
     goals = []
     handles = self._start_constraint.get_connectivity_handles(
         routing_agent)
     for handle in handles:
         goals.extend(handle.get_goals(always_reject_invalid_goals=True))
     agent_radius = routing_agent.routing_component.pathplan_context.agent_radius
     ocean_goal_count = min(len(goals), self.ocean_unique_goal_count)
     for _ in range(ocean_goal_count):
         goal = random.choice(goals)
         break
         goals.remove(goal)
         constraint = Circle(goal.position,
                             agent_radius,
                             routing_surface=self._routing_surface)
         self._waypoint_constraints.append(
             constraint.intersect(self._master_depth_constraint))
     available_waypoint_count = len(self._waypoint_constraints)
     if not self._start_constraint is not None or (
             self._waypoint_constraints
             or not goals) or available_waypoint_count == 0:
         return
     use_pool_debug_visualizer = False and (
         routing.waypoints.waypoint_generator.enable_waypoint_visualization
         and self._location_is_pool)
     polygon_metadata = {}
     for i in range(waypoint_count):
         if not not i % available_waypoint_count == 0 and self.shuffle_waypoints:
             random.shuffle(self._waypoint_constraints)
         yield self._waypoint_constraints[i % available_waypoint_count]
         if use_pool_debug_visualizer:
             self._build_polygon_metadata_dictionary(
                 polygon_metadata,
                 self._waypoint_constraints[i % available_waypoint_count],
                 i)
     if not use_pool_debug_visualizer or use_pool_debug_visualizer:
         self._draw_pool_debugvis(polygon_metadata)
Beispiel #16
0
def put_down_geometry_constraint_gen(sim, target):
    if target.is_in_inventory():
        yield Circle(sim.position,
                     PUT_DOWN_GEOMETRY_RADIUS,
                     routing_surface=sim.routing_surface)
    elif hasattr(target, 'get_carry_transition_constraint'):
        yield target.get_carry_transition_constraint(sim, target.position,
                                                     target.routing_surface)
    else:
        logger.error(
            'Trying to call get_carry_transition_constraint on Object {} that has no such attribute.\n                            Definition: {}\n                            Sim: {}\n                            ',
            target,
            target.definition,
            sim,
            owner='trevor')
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self._sim = self._context.sim
     if self._context.pick is not None:
         pick_position = self._context.pick.location
         self._pick_vector = pick_position - self._sim.position
         self._pick_vector /= self._pick_vector.magnitude()
     else:
         self._pick_vector = self._sim.forward
     if self._sim.is_on_active_lot():
         plex_service = services.get_plex_service()
         if plex_service.is_active_zone_a_plex():
             tags = (SpawnPoint.VISITOR_ARRIVAL_SPAWN_POINT_TAG,)
         else:
             tags = (SpawnPoint.ARRIVAL_SPAWN_POINT_TAG,)
         spawn_point = services.current_zone().get_spawn_point(lot_id=services.active_lot_id(), sim_spawner_tags=tags)
         self._origin_position = spawn_point.get_approximate_center()
         self._except_lot_id = services.active_lot_id()
     else:
         self._origin_position = self._sim.position
         self._except_lot_id = None
     self._routing_surface = routing.SurfaceIdentifier(services.current_zone_id(), 0, routing.SurfaceType.SURFACETYPE_WORLD)
     self._start_constraint = Circle(self._origin_position, self.constraint_radius, routing_surface=self._routing_surface, los_reference_point=None)
     self._start_constraint = self._start_constraint.intersect(self.get_water_constraint())
Beispiel #18
0
def create_put_down_in_self_inventory_constraint(inst, sim, target, cost=0):
    if cost is None:
        return Nowhere('No Cost({}). Sim: {} Target: {}', cost, sim, target)
    carry_constraint = create_carry_constraint(
        target, debug_name='CarryForPutDownInSimInventory')
    carry_constraint = carry_constraint.generate_constraint_with_cost(cost)
    constraint = sim.get_inventory_access_constraint(sim, True, target)
    constraint = constraint.apply_posture_state(
        None, inst.get_constraint_resolver(None))
    posture_slot_constraint = sim.posture.slot_constraint
    if posture_slot_constraint:
        if not sim.parent_may_move:
            constraint = constraint.intersect(posture_slot_constraint)
    else:
        constraint = constraint.intersect(
            Circle(sim.position, PUT_DOWN_GEOMETRY_RADIUS,
                   sim.routing_surface))
    final_constraint = carry_constraint.intersect(constraint)
    return final_constraint
 def get_routes_gen(self):
     waypoint_generator = self.waypoint_generator(
         WaypointContext(self._obj), None)
     waypoints = []
     constraints = itertools.chain(
         (waypoint_generator.get_start_constraint(), ),
         waypoint_generator.get_waypoint_constraints_gen(
             self._obj, self.waypoint_count))
     obj_start_constraint = Circle(
         self._obj.position,
         self.return_to_starting_point,
         routing_surface=self._obj.routing_surface,
         los_reference_point=None)
     constraints = itertools.chain(constraints, obj_start_constraint)
     for constraint in constraints:
         goals = list(
             itertools.chain.from_iterable(
                 h.get_goals()
                 for h in constraint.get_connectivity_handles(self._obj)))
         if not goals:
             continue
         for goal in goals:
             goal.orientation = sims4.math.angle_to_yaw_quaternion(
                 random.uniform(0.0, sims4.math.TWO_PI))
         waypoints.append(goals)
     if not (self.return_to_starting_point is not None and waypoints):
         return False
         yield
     routing_context = self._obj.get_routing_context()
     for route_waypoints in self.waypoint_stitching(
             waypoints, waypoint_generator.loops):
         route = routing.Route(self._obj.routing_location,
                               route_waypoints[-1],
                               waypoints=route_waypoints[:-1],
                               routing_context=routing_context)
         yield route
     return True
     yield
    def _get_close_to_deploy(self, timeline, vehicle):
        sim = self._interaction.sim
        constraint = self._get_deployment_constraint()
        if not constraint.valid:
            return InteractionQueuePreparationStatus.FAILURE
            yield
        handles = constraint.get_connectivity_handles(sim)
        goals = []
        for handle in handles:
            goals.extend(handle.get_goals(single_goal_only=True))
        if not goals:
            return InteractionQueuePreparationStatus.FAILURE
            yield
        if sim.posture.unconstrained:
            source_constraint = Position(sim.position, routing_surface=sim.routing_surface)
        else:
            source_constraint = Circle(sim.position, self.SOURCE_CONNECTIVITY_HANDLE_RADIUS, sim.routing_surface)
        source_handles = source_constraint.get_connectivity_handles(sim)
        if not source_handles:
            return InteractionQueuePreparationStatus.FAILURE
            yield
        source_goals = source_handles[0].get_goals(single_goal_only=True)
        if not source_goals:
            return InteractionQueuePreparationStatus.FAILURE
            yield
        source_goal = source_goals[0]
        if source_goal.position == goals[0].position and source_goal.routing_surface_id == goals[0].routing_surface_id:
            return InteractionQueuePreparationStatus.SUCCESS
            yield
        route = routing.Route(source_goal.location, goals, routing_context=sim.routing_context)
        plan_primitive = PlanRoute(route, sim, interaction=self._interaction)
        result = yield from element_utils.run_child(timeline, plan_primitive)
        if not result and not (not plan_primitive.path.nodes and not plan_primitive.path.nodes.plan_success):
            return InteractionQueuePreparationStatus.FAILURE
            yield
        cur_path = plan_primitive.path
        if not cur_path.nodes:
            return InteractionQueuePreparationStatus.FAILURE
            yield

        def get_start_node_index_for_path(vehicle, path):
            nodes = list(path.nodes)
            object_manager = services.object_manager()
            prev_node = None
            for node in nodes[::-1]:
                portal_obj_id = node.portal_object_id
                portal_obj = object_manager.get(portal_obj_id) if portal_obj_id else None
                if node.portal_id:
                    if portal_obj:
                        if not vehicle.vehicle_component.can_transition_through_portal(portal_obj, node.portal_id):
                            break
                prev_node = node
            else:
                return 0
            return prev_node.index

        split_paths = False
        while cur_path.next_path is not None:
            split_paths = True
            cur_path = cur_path.next_path
            if not cur_path.nodes:
                return InteractionQueuePreparationStatus.FAILURE
                yield
        start_node_index = get_start_node_index_for_path(vehicle, cur_path)
        start_node = cur_path.nodes[start_node_index]
        start_location = sims4.math.Location(Transform(Vector3(*start_node.position), Quaternion(*start_node.orientation)), start_node.routing_surface_id)
        if not split_paths and start_node_index == 0 and (start_location.transform.translation - source_goal.location.position).magnitude_squared() < vehicle.vehicle_component.minimum_route_distance:
            return InteractionQueuePreparationStatus.SUCCESS
            yield
        deploy_constraint = Position(start_location.transform.translation, routing_surface=start_location.routing_surface)
        depended_on_si = self._interaction
        affordance = self.get_close_affordance if self.get_close_affordance is not None else VehicleLiability.GET_CLOSE_AFFORDANCE
        aop = AffordanceObjectPair(affordance, None, affordance, None, route_fail_on_transition_fail=False, constraint_to_satisfy=deploy_constraint, allow_posture_changes=True, depended_on_si=depended_on_si)
        context = InteractionContext(sim, InteractionContext.SOURCE_SCRIPT, Priority.High, insert_strategy=QueueInsertStrategy.FIRST, must_run_next=True, group_id=depended_on_si.group_id)
        if not aop.test_and_execute(context):
            return InteractionQueuePreparationStatus.FAILURE
            yield
        return InteractionQueuePreparationStatus.NEEDS_DERAIL
        yield
class _WaypointGeneratorSpawnPoints(_WaypointGeneratorBase):
    FACTORY_TUNABLES = {'constraint_radius': TunableRange(description='\n            The radius, in meters, for each of the generated waypoint\n            constraints.\n            ', tunable_type=float, default=6, minimum=0), 'spawn_point_tags': OptionalTunable(description='\n            Controls which spawn points can be used as waypoints.\n            ', tunable=TunableSet(tunable=TunableEnumWithFilter(tunable_type=Tag, default=Tag.INVALID, filter_prefixes=SPAWN_PREFIX)))}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._sim = self._context.sim
        if self._context.pick is not None:
            pick_position = self._context.pick.location
            self._pick_vector = pick_position - self._sim.position
            self._pick_vector /= self._pick_vector.magnitude()
        else:
            self._pick_vector = self._sim.forward
        if self._sim.is_on_active_lot():
            plex_service = services.get_plex_service()
            if plex_service.is_active_zone_a_plex():
                tags = (SpawnPoint.VISITOR_ARRIVAL_SPAWN_POINT_TAG,)
            else:
                tags = (SpawnPoint.ARRIVAL_SPAWN_POINT_TAG,)
            spawn_point = services.current_zone().get_spawn_point(lot_id=services.active_lot_id(), sim_spawner_tags=tags)
            self._origin_position = spawn_point.get_approximate_center()
            self._except_lot_id = services.active_lot_id()
        else:
            self._origin_position = self._sim.position
            self._except_lot_id = None
        self._routing_surface = routing.SurfaceIdentifier(services.current_zone_id(), 0, routing.SurfaceType.SURFACETYPE_WORLD)
        self._start_constraint = Circle(self._origin_position, self.constraint_radius, routing_surface=self._routing_surface, los_reference_point=None)
        self._start_constraint = self._start_constraint.intersect(self.get_water_constraint())

    def get_start_constraint(self):
        return self._start_constraint

    def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
        zone = services.current_zone()
        constraint_set = zone.get_spawn_points_constraint(except_lot_id=self._except_lot_id, sim_spawner_tags=self.spawn_point_tags, generalize=True)
        routing_context = routing_agent.routing_component.pathplan_context
        source_handle = routing.connectivity.Handle(routing_agent.position, routing_agent.routing_surface)
        dest_handles = set()
        for constraint in constraint_set:
            handles = constraint.get_connectivity_handles(routing_agent)
            dest_handles.update(handles)
        connectivity = routing.test_connectivity_batch((source_handle,), dest_handles, routing_context=routing_context, compute_cost=True)
        vehicle_dest_handles = {dest for (_, dest, cost) in connectivity if sims4.math.almost_equal(cost, 0.0)}
        constraint_set = create_constraint_set([handle.constraint for handle in vehicle_dest_handles])
        constraints_weighted = []
        min_score = sims4.math.MAX_FLOAT
        for constraint in constraint_set:
            spawn_point_vector = constraint.average_position - self._sim.position
            score = sims4.math.vector_dot_2d(self._pick_vector, spawn_point_vector)
            min_score = score
            constraints_weighted.append((score, constraint))
        constraints_weighted = [(score - min_score, constraint) for (score, constraint) in constraints_weighted]
        constraints_weighted = sorted(constraints_weighted, key=lambda i: i[0])
        first_constraint = constraints_weighted[-1][1]
        del constraints_weighted[-1]
        first_constraint_circle = Circle(first_constraint.average_position, self.constraint_radius, routing_surface=first_constraint.routing_surface)
        jog_waypoint_constraints = []
        jog_waypoint_constraints.append(first_constraint_circle)
        last_waypoint_position = first_constraint.average_position
        for _ in range(waypoint_count - 1):
            constraints_weighted_next = []
            for (_, constraint) in constraints_weighted:
                average_position = constraint.average_position
                distance_last = (average_position - last_waypoint_position).magnitude_2d()
                distance_home = (average_position - self._origin_position).magnitude_2d()
                constraints_weighted_next.append((distance_last + distance_home, constraint))
            break
            next_constraint = pop_weighted(constraints_weighted_next)
            next_constraint_circle = Circle(next_constraint.average_position, self.constraint_radius, routing_surface=next_constraint.routing_surface)
            jog_waypoint_constraints.append(next_constraint_circle)
            constraints_weighted = constraints_weighted_next
            break
            last_waypoint_position = next_constraint.average_position
        jog_waypoint_constraints = self.apply_water_constraint(jog_waypoint_constraints)
        yield from jog_waypoint_constraints
        yield self._start_constraint
 def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
     water_constraint = self.get_water_constraint(
         self.constraint_parameters.min_water_depth,
         self.constraint_parameters.max_water_depth)
     debugvis_constraints = []
     target_position = self._target.position
     object_radius_constraint = Circle(
         target_position,
         self.constraint_parameters.object_constraint_radius,
         routing_surface=self._start_constraint.routing_surface,
         los_reference_point=self._los_reference_point,
         min_water_depth=water_constraint.get_min_water_depth(),
         max_water_depth=water_constraint.get_max_water_depth())
     debugvis_constraints.append(
         (target_position,
          self.constraint_parameters.object_constraint_radius))
     area_goals = []
     handles = object_radius_constraint.get_connectivity_handles(
         routing_agent)
     for handle in handles:
         area_goals.extend(
             handle.get_goals(relative_object=self._target,
                              always_reject_invalid_goals=True))
     area_goals = [
         goal for goal in area_goals if is_location_outside(
             goal.position, goal.location.routing_surface.secondary_id)
     ]
     if not (self.outside_only and area_goals):
         yield Circle(
             target_position,
             self.constraint_parameters.object_constraint_radius,
             routing_surface=self._start_constraint.routing_surface,
             los_reference_point=self._los_reference_point,
             min_water_depth=water_constraint.get_min_water_depth(),
             max_water_depth=water_constraint.get_max_water_depth())
         return
     min_dist_sq = self.waypoint_min_distance
     current_point = None
     for _ in range(waypoint_count):
         if current_point is None:
             current_point = random.choice(area_goals)
             debugvis_constraints.append(
                 (current_point.position,
                  self.constraint_parameters.waypoint_constraint_radius))
             yield Circle(
                 current_point.position,
                 self.constraint_parameters.waypoint_constraint_radius,
                 routing_surface=self._start_constraint.routing_surface,
                 los_reference_point=self._los_reference_point,
                 min_water_depth=water_constraint.get_min_water_depth(),
                 max_water_depth=water_constraint.get_max_water_depth())
         farthest_point = None
         farthest_dist = 0
         for _ in range(self.MAX_WAYPOINT_RANDOM_TRIES):
             try_point = random.choice(area_goals)
             try_dist = (try_point.position -
                         current_point.position).magnitude_squared()
             farthest_point = try_point
             break
             if not (try_dist > min_dist_sq and
                     (farthest_point is None or not farthest_point
                      is not None)) and try_dist > farthest_dist:
                 farthest_point = try_point
                 farthest_dist = try_dist
         current_point = farthest_point
         debugvis_constraints.append(
             (current_point.position,
              self.constraint_parameters.waypoint_constraint_radius))
         yield Circle(
             current_point.position,
             self.constraint_parameters.waypoint_constraint_radius,
             routing_surface=self._start_constraint.routing_surface,
             los_reference_point=self._los_reference_point,
             min_water_depth=water_constraint.get_min_water_depth(),
             max_water_depth=water_constraint.get_max_water_depth())
Beispiel #23
0
class _WaypointGeneratorMultipleObjectByTag(_WaypointGeneratorBase):
    FACTORY_TUNABLES = {
        'object_max_distance':
        TunableDistanceSquared(
            description=
            '\n            The maximum distance to check for an object as the next target\n            of our waypoint interaction.\n            ',
            default=5),
        'constrain_radius':
        TunableRange(
            description=
            '\n            The radius of the circle that will be generated around the objects\n            where the waypoints will be generated.\n            ',
            tunable_type=float,
            default=5,
            minimum=0),
        'object_tags':
        TunableTags(
            description=
            '\n            Find all of the objects based on these tags.\n            ',
            filter_prefixes=('func', )),
        'object_search_strategy':
        TunableVariant(
            description=
            '\n            Search strategies to find and soft the possible objects where the\n            waypoints will be generated.\n            ',
            default_waypoints=_WaypointObjectDefaultStrategy.TunableFactory(),
            sorted_by_distance=_WaypointObjectSortedDistanceStrategy.
            TunableFactory(),
            default='default_waypoints'),
        'placement_restriction':
        OptionalTunable(
            description=
            '\n            If enabled the objects where the waypoints will be generated will\n            be restricted to either the inside of outside.\n            ',
            tunable=Tunable(
                description=
                '\n                If checked objects will be restricted to the inside the \n                house, otherwise only objects outside will be considered.\n                ',
                tunable_type=bool,
                default=True),
            enabled_name='inside_only',
            disabled_name='no_restrictions'),
        'randomize_order':
        Tunable(
            description=
            '\n            If checked, the waypoints will be shuffled into a random order each\n            time the route is generated. If not they will be the same (but\n            still non-deterministic) order each time, for a given run.\n            ',
            tunable_type=bool,
            default=False)
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._sim = self._context.sim
        self._valid_objects = []
        for obj in services.object_manager().get_objects_matching_tags(
                self.object_tags, match_any=True):
            if self.placement_restriction is not None and self.placement_restriction == obj.is_outside:
                continue
            distance_from_sim = obj.position - self._sim.position
            if distance_from_sim.magnitude_squared(
            ) <= self.object_max_distance:
                if obj.is_connected(self._sim):
                    self._valid_objects.append(obj)
        self._valid_objects = self.object_search_strategy.get_waypoint_objects(
            self._valid_objects)
        if not self._valid_objects:
            self._start_constraint = Circle(
                self._sim.position,
                self.constrain_radius,
                routing_surface=self._sim.routing_surface,
                los_reference_point=None)
            return
        if self.randomize_order:
            random.shuffle(self._valid_objects)
        starting_object = self._valid_objects.pop(0)
        self._start_constraint = Circle(
            starting_object.position,
            self.constrain_radius,
            routing_surface=self._sim.routing_surface,
            los_reference_point=None)
        self._start_constraint = self._start_constraint.intersect(
            self.get_water_constraint())

    def get_start_constraint(self):
        return self._start_constraint

    def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
        water_constraint = self.get_water_constraint()
        for _ in range(waypoint_count - 1):
            if not self._valid_objects:
                return
            obj = self._valid_objects.pop(0)
            next_constraint_circle = Circle(
                obj.position,
                self.constrain_radius,
                los_reference_point=None,
                routing_surface=obj.routing_surface)
            next_constraint_circle = next_constraint_circle.intersect(
                water_constraint)
            yield next_constraint_circle
Beispiel #24
0
class _WaypointGeneratorPool(_WaypointGeneratorBase):
    FACTORY_TUNABLES = {
        'constraint_width':
        TunableRange(
            description=
            '\n            The width of the constraint created around the edge of the pool.\n            ',
            tunable_type=float,
            default=1.5,
            minimum=0),
        'ocean_constraint_radius':
        TunableRange(
            description=
            '\n            When in the ocean, the radius of the area around the nearest swim\n            portal to generate waypoints.\n            ',
            tunable_type=float,
            default=30,
            minimum=0,
            maximum=1000),
        'ocean_constraint_distance_past_swim_portal':
        TunableRange(
            description=
            '\n            When in the ocean, an offset away from the nearest swim portal to\n            center the area to generate waypoints.\n            ',
            tunable_type=float,
            default=0,
            minimum=0),
        'ocean_unique_goal_count':
        TunableRange(
            description=
            '\n            When in the ocean, the number of unique waypoints to generate.\n            ',
            tunable_type=int,
            default=10,
            minimum=0),
        'shuffle_waypoints':
        Tunable(
            description=
            '\n            If true, pool edge waypoint constraints will be shuffled and traversed in a random order.\n            If false, pool edge waypoint constraints will be traversed in counter-clockwise order.        \n            ',
            tunable_type=bool,
            default=True),
        'keep_away_from_edges':
        OptionalTunable(
            description=
            '\n            If enabled, turns on a constraint that forces sims away from the pool edges by a tuned distance.\n            ',
            tunable=Tunable(
                description=
                '\n                The distance from the pool edge.\n                ',
                tunable_type=float,
                default=0.25))
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        sim = self._context.sim
        self._routing_surface = routing.SurfaceIdentifier(
            self._routing_surface.primary_id,
            self._routing_surface.secondary_id,
            routing.SurfaceType.SURFACETYPE_POOL)
        position = self._target.position if self._target is not None else sim.position
        level = self._routing_surface.secondary_id
        self._start_constraint = None
        self._master_depth_constraint = None
        self._waypoint_constraints = []
        self.keep_away_constraint = None
        self._location_is_pool = build_buy.is_location_pool(position, level)
        if self._location_is_pool:
            pool_block_id = build_buy.get_block_id(sim.zone_id, position,
                                                   level - 1)
            pool = pool_utils.get_pool_by_block_id(pool_block_id)
            if pool is not None:
                pool_edge_constraints = pool.get_edge_constraint(
                    constraint_width=self.constraint_width,
                    inward_dir=True,
                    return_constraint_list=True)
                pool_edge_constraints = [
                    constraint.generate_geometry_only_constraint()
                    for constraint in pool_edge_constraints
                ]
                if self.keep_away_from_edges is not None:
                    bb_polys = build_buy.get_pool_polys(
                        pool_block_id, level - 1)
                    if len(bb_polys) > 0:
                        bb_poly = bb_polys[0]
                        _WaypointGeneratorPool._push_poly_inward(
                            bb_poly, self.keep_away_from_edges)
                        bb_poly.reverse()
                        keep_away_geom = sims4.geometry.RestrictedPolygon(
                            sims4.geometry.Polygon(bb_poly), ())
                        self.keep_away_constraint = Constraint(
                            routing_surface=pool.provided_routing_surface,
                            geometry=keep_away_geom)
                    else:
                        logger.error(
                            f'Pool Waypoint Generator: Pool polygon data unexpectedly empty while ${sim} was routing on a pool with id ${pool_block_id}.',
                            owner='jmorrow')
                    for i in range(len(pool_edge_constraints)):
                        pool_edge_constraints[i] = pool_edge_constraints[
                            i].intersect(self.keep_away_constraint)
                self._start_constraint = create_constraint_set(
                    pool_edge_constraints)
                self._waypoint_constraints = pool_edge_constraints

    def get_start_constraint(self):
        if self._start_constraint is not None:
            return self._start_constraint
        sim = self._context.sim
        position = self._target.position if self._target is not None else sim.position
        relative_offset_vector = Vector3(
            0, 0, self.ocean_constraint_distance_past_swim_portal)
        if self._target is not None and self._target.routing_surface is not None:
            routing_surface = self._target.routing_surface
        else:
            routing_surface = sim.routing_surface
        if routing_surface.type != routing.SurfaceType.SURFACETYPE_POOL:
            self._start_constraint = OceanStartLocationConstraint.create_simple_constraint(
                WaterDepthIntervals.SWIM,
                self.ocean_constraint_radius,
                sim,
                self._target,
                position,
                ideal_radius=self.constraint_width,
                ideal_radius_width=self.constraint_width,
                relative_offset_vector=relative_offset_vector)
        else:
            self._start_constraint = Circle(
                position,
                self.ocean_constraint_radius,
                routing_surface=self._routing_surface)
        self._master_depth_constraint = WaterDepthIntervalConstraint.create_water_depth_interval_constraint(
            sim, WaterDepthIntervals.SWIM)
        self._start_constraint = self._start_constraint.intersect(
            self._master_depth_constraint)
        return self._start_constraint

    def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
        if self._start_constraint is None:
            self.get_start_constraint()
        goals = []
        handles = self._start_constraint.get_connectivity_handles(
            routing_agent)
        for handle in handles:
            goals.extend(handle.get_goals(always_reject_invalid_goals=True))
        agent_radius = routing_agent.routing_component.pathplan_context.agent_radius
        ocean_goal_count = min(len(goals), self.ocean_unique_goal_count)
        for _ in range(ocean_goal_count):
            goal = random.choice(goals)
            break
            goals.remove(goal)
            constraint = Circle(goal.position,
                                agent_radius,
                                routing_surface=self._routing_surface)
            self._waypoint_constraints.append(
                constraint.intersect(self._master_depth_constraint))
        available_waypoint_count = len(self._waypoint_constraints)
        if not self._start_constraint is not None or (
                self._waypoint_constraints
                or not goals) or available_waypoint_count == 0:
            return
        use_pool_debug_visualizer = False and (
            routing.waypoints.waypoint_generator.enable_waypoint_visualization
            and self._location_is_pool)
        polygon_metadata = {}
        for i in range(waypoint_count):
            if not not i % available_waypoint_count == 0 and self.shuffle_waypoints:
                random.shuffle(self._waypoint_constraints)
            yield self._waypoint_constraints[i % available_waypoint_count]
            if use_pool_debug_visualizer:
                self._build_polygon_metadata_dictionary(
                    polygon_metadata,
                    self._waypoint_constraints[i % available_waypoint_count],
                    i)
        if not use_pool_debug_visualizer or use_pool_debug_visualizer:
            self._draw_pool_debugvis(polygon_metadata)

    def _draw_pool_debugvis(self, polygon_metadata):
        color_palette = [Color.WHITE, Color.BLUE, Color.GREEN, Color.MAGENTA]
        if routing.waypoints.waypoint_generator.enable_waypoint_visualization:
            with debugvis.Context(routing.waypoints.waypoint_generator.
                                  DEBUGVIS_WAYPOINT_LAYER_NAME) as layer:
                for entry in polygon_metadata.values():
                    position = entry[0]
                    waypoint_indices = entry[1]
                    layer.add_text_world(position, f'{waypoint_indices}')
                for (index,
                     constraint) in enumerate(self._waypoint_constraints):
                    polygon = constraint.geometry.polygon
                    layer.add_polygon(polygon,
                                      color=color_palette[index % 4],
                                      altitude=0.1)
                if self.keep_away_from_edges is not None:
                    polygon = self.keep_away_constraint.geometry.polygon
                    layer.add_polygon(polygon, color=Color.BLACK, altitude=0.1)

    def _build_polygon_metadata_dictionary(self, polygon_metadata, constraint,
                                           waypoint_index):
        compound_polygon = constraint.geometry.polygon
        if isinstance(compound_polygon, CompoundPolygon):
            for polygon in compound_polygon:
                if len(polygon) > 0:
                    key = polygon
                    if key not in polygon_metadata:
                        center = sum(polygon, Vector3.ZERO()) / len(polygon)
                        polygon_metadata[key] = (center, [])
                    waypoint_indices = polygon_metadata[key][1]
                    waypoint_indices.append(waypoint_index)
                else:
                    sim = self._context.sim
                    logger.error(
                        f'Pool Waypoint Generator: Polygon unexpectedly contains no vertices while drawing debug visuals of ${sim}"s route"',
                        owner='jmorrow')
        else:
            sim = self._context.sim
            logger.error(
                f'Pool Waypoint Generator: Constraint geometry in unexpected format while drawing debug visuals of ${sim}"s route."',
                owner='jmorrow')

    @staticmethod
    def _push_poly_inward(verts, amt):
        for i in range(1, len(verts)):
            _WaypointGeneratorPool._push_edge_inward(verts, i - 1, i, amt)
        _WaypointGeneratorPool._push_edge_inward(verts, i, 0, amt)

    @staticmethod
    def _push_edge_inward(verts, start, stop, amt):
        along = amt * sims4.math.vector_normalize(verts[stop] - verts[start])
        inward = sims4.math.vector3_rotate_axis_angle(
            along, sims4.math.PI / 2, sims4.math.Vector3.Y_AXIS())
        verts[start] += inward
        verts[stop] += inward
 def get_circle_constraint(cls, origin_position, radius, routing_surface, ideal_radius=None, ideal_radius_width=0):
     return Circle(origin_position, radius, routing_surface, ideal_radius=ideal_radius, ideal_radius_width=ideal_radius_width)