def create_put_down_in_slot_type_constraint(sim, target, slot_types_and_costs):
    constraints = []
    for (slot_type, cost) in slot_types_and_costs:
        if cost is None:
            pass
        slot_manifest_entry = SlotManifestEntry(target,
                                                PostureSpecVariable.ANYTHING,
                                                slot_type)
        slot_manifest = SlotManifest((slot_manifest_entry, ))
        posture_state_spec_stand = PostureStateSpec(
            STAND_POSTURE_MANIFEST, slot_manifest,
            PostureSpecVariable.ANYTHING)
        posture_constraint_stand = Constraint(
            debug_name='PutDownInSlotTypeConstraint_Stand',
            posture_state_spec=posture_state_spec_stand,
            cost=cost)
        constraints.append(posture_constraint_stand)
        posture_state_spec_sit = PostureStateSpec(SIT_POSTURE_MANIFEST,
                                                  slot_manifest,
                                                  PostureSpecVariable.ANYTHING)
        posture_constraint_sit = Constraint(
            debug_name='PutDownInSlotTypeConstraint_Sit',
            posture_state_spec=posture_state_spec_sit,
            cost=cost)
        constraints.append(posture_constraint_sit)
    if not constraints:
        return Nowhere()
    final_constraint = create_constraint_set(constraints)
    return final_constraint
 def generate_constraint(self, build_convex=DEFAULT):
     self._distance_map = [None] * self._map_divisions
     self._connection_map = [None] * self._map_divisions
     self._connection_index = 0
     self._collect_segments()
     vertices = self._render_vertices()
     segments = self._simplify_geometry(vertices)
     if build_convex is DEFAULT:
         build_convex = self.build_convex
     if build_convex:
         try:
             convex_segments = list(self.maximal_convex(vertices))
         except RuntimeError as ex:
             logger.error('{}: {}'.format(
                 ex, ','.join(str(v) for v in vertices)))
             self._constraint_convex = Nowhere()
             return
         simple_convex = self._simplify_geometry(convex_segments)
         maximal_convex_polygon = self._make_compound_polygon(
             [simple_convex])
         self._constraint_convex = Constraint(
             debug_name='LineOfSightConvex',
             routing_surface=self._routing_surface,
             geometry=sims4.geometry.RestrictedPolygon(
                 maximal_convex_polygon, []))
     else:
         maximal_convex_polygon = None
         self._constraint_convex = Nowhere()
     convex_polygons = self._concave_to_convex(segments)
     cp = self._make_compound_polygon(convex_polygons)
     self._constraint = Constraint(
         debug_name='LineOfSight',
         routing_surface=self._routing_surface,
         geometry=sims4.geometry.RestrictedPolygon(cp, []))
Ejemplo n.º 3
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')
Ejemplo n.º 4
0
 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
Ejemplo n.º 5
0
 def _cache_mobile_posture_constraint(cls):
     if cls._posture_at_none_constraint is None:
         cls._posture_at_none_posture_state_spec = create_body_posture_state_spec(
             cls.get_provided_postures(), body_target=None)
         cls._posture_at_none_constraint = Constraint(
             debug_name='{}@None'.format(cls.name),
             posture_state_spec=cls._posture_at_none_posture_state_spec)
Ejemplo n.º 6
0
def routing_debug_generate_routing_goals_from_geometry(
        *args, obj: OptionalTargetParam = None, _connection=None):
    output = sims4.commands.Output(_connection)
    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
    total_string = ''.join(args)
    polygon_strs = find_substring_in_repr(total_string, POLYGON_STR,
                                          POLYGON_END_PARAM)
    if not polygon_strs:
        output('No valid polygons. must start with {} and end with {}'.format(
            POLYGON_STR, POLYGON_END_PARAM))
        return
    constraints = []
    routing_surface = routing.SurfaceIdentifier(
        services.current_zone_id(), 0, routing.SurfaceType.SURFACETYPE_OBJECT)
    for poly_str in polygon_strs:
        point_list = extract_floats(poly_str)
        if not point_list or len(point_list) % 2 != 0:
            output('Point list is not valid length. Too few or one too many.')
            return
        vertices = []
        for index in range(0, len(point_list), 2):
            vertices.append(
                sims4.math.Vector3(point_list[index], 0.0,
                                   point_list[index + 1]))
        polygon = sims4.geometry.Polygon(vertices)
        geometry = RestrictedPolygon(polygon, [])
        constraints.append(
            Constraint(geometry=geometry, routing_surface=routing_surface))
    constraint_set = create_constraint_set(constraints)
    if not postures.posture_graph.enable_debug_goals_visualization:
        sims4.commands.execute('debugvis.goals.enable', _connection)
    handles = constraint_set.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:
        for constraint in constraints:
            with debugvis.Context(
                    'goal_scoring',
                    routing_surface=constraint.routing_surface) as layer:
                for polygon in constraint.geometry.polygon:
                    layer.add_polygon(
                        polygon, routing_surface=constraint.routing_surface)
                for goal in all_goals:
                    position = goal.location.transform.translation
                    layer.add_point(position,
                                    routing_surface=constraint.routing_surface)
Ejemplo n.º 7
0
 def _create_drive_posture_constraint(self, posture_type):
     posture_manifest = PostureManifest()
     entry = PostureManifestEntry(AnimationParticipant.ACTOR,
                                  posture_type.name,
                                  posture_type.family_name, MATCH_ANY,
                                  MATCH_NONE, MATCH_NONE, MATCH_ANY, None)
     posture_manifest.add(entry)
     posture_manifest = posture_manifest.intern()
     posture_state_spec = PostureStateSpec(posture_manifest, SlotManifest(),
                                           PostureSpecVariable.ANYTHING)
     return Constraint(posture_state_spec=posture_state_spec,
                       debug_name='VehiclePostureConstraint')
Ejemplo n.º 8
0
class GoHereSuperInteraction(TerrainSuperInteraction):
    __qualname__ = 'GoHereSuperInteraction'
    POSTURE_MANIFEST = PostureManifest(
        (PostureManifestEntry(None, 'stand', '', 'FullBody', MATCH_ANY,
                              MATCH_ANY, MATCH_NONE), )).intern()
    POSTURE_STATE_SPEC = PostureStateSpec(POSTURE_MANIFEST,
                                          SlotManifest().intern(), None)
    CONSTRAINT = Constraint(debug_name='GoHere',
                            posture_state_spec=POSTURE_STATE_SPEC,
                            allow_small_intersections=True)
    _ignores_spawn_point_footprints = True

    @classmethod
    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.')
        routing_location = routing.Location(position,
                                            sims4.math.Quaternion.IDENTITY(),
                                            surface)
        if not routing.test_connectivity_permissions_for_handle(
                routing.connectivity.Handle(routing_location),
                context.sim.routing_context):
            return TestResult(False, 'Cannot GoHere! Unroutable area.')
        return TestResult.TRUE

    @classmethod
    def potential_interactions(cls, target, context, **kwargs):
        (position, surface) = cls._get_position_and_surface(target, context)
        if position is not None and context is not None and context.sim is not None:
            main_group = context.sim.get_visible_group()
            if main_group is not None and not main_group.is_solo:
                group_constraint = next(
                    iter(main_group.get_constraint(context.sim)))
                if group_constraint is not None and group_constraint.routing_surface == surface:
                    while True:
                        for constraint in group_constraint:
                            group_geometry = constraint.geometry
                            while group_geometry is not None and group_geometry.contains_point(
                                    position):
                                yield AffordanceObjectPair(cls,
                                                           target,
                                                           cls,
                                                           None,
                                                           ignore_party=True,
                                                           **kwargs)
                                return
        if cls._can_rally(context):
            for aop in cls.get_rallyable_aops_gen(target, context, **kwargs):
                yield aop
        yield cls.generate_aop(target, context, **kwargs)
Ejemplo n.º 9
0
def create_put_down_in_slot_type_constraint(sim,
                                            carry_target,
                                            slot_types_and_costs,
                                            target=None):
    constraints = []
    for (slot_type, cost) in slot_types_and_costs:
        if cost is None:
            continue
        if target is not None and target is not carry_target:
            slot_manifest_entry = SlotManifestEntry(
                carry_target, PostureSpecVariable.INTERACTION_TARGET,
                slot_type)
        else:
            slot_manifest_entry = SlotManifestEntry(
                carry_target, PostureSpecVariable.ANYTHING, slot_type)
        slot_manifest = SlotManifest((slot_manifest_entry, ))
        posture_state_spec_stand = PostureStateSpec(
            STAND_POSTURE_MANIFEST, slot_manifest,
            PostureSpecVariable.ANYTHING)
        posture_constraint_stand = Constraint(
            debug_name='PutDownInSlotTypeConstraint_Stand',
            posture_state_spec=posture_state_spec_stand,
            cost=cost)
        constraints.append(posture_constraint_stand)
        posture_state_spec_sit = PostureStateSpec(SIT_POSTURE_MANIFEST,
                                                  slot_manifest,
                                                  PostureSpecVariable.ANYTHING)
        posture_constraint_sit = Constraint(
            debug_name='PutDownInSlotTypeConstraint_Sit',
            posture_state_spec=posture_state_spec_sit,
            cost=cost)
        constraints.append(posture_constraint_sit)
    if not constraints:
        return Nowhere(
            'Carry Target has no slot types or costs tuned for put down: {} Sim:{}',
            carry_target, sim)
    final_constraint = create_constraint_set(constraints)
    return final_constraint
Ejemplo n.º 10
0
 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
Ejemplo n.º 11
0
 def get_edge_constraint(self, constraint_width=1.0, inward_dir=False, return_constraint_list=False, los_reference_point=DEFAULT, sim=None):
     edges = self.get_edges()
     polygons = []
     for (start, stop) in edges:
         along = sims4.math.vector_normalize(stop - start)
         inward = sims4.math.vector3_rotate_axis_angle(along, sims4.math.PI/2, sims4.math.Vector3.Y_AXIS())
         if inward_dir:
             polygon = sims4.geometry.Polygon([start, start + constraint_width*inward, stop + constraint_width*inward, stop])
         else:
             polygon = sims4.geometry.Polygon([start, stop, stop - constraint_width*inward, start - constraint_width*inward])
         polygons.append(polygon)
     routing_surface = self.routing_surface
     if return_constraint_list:
         constraint_list = []
         for polygon in polygons:
             restricted_polygon = sims4.geometry.RestrictedPolygon(polygon, ())
             constraint = Constraint(routing_surface=routing_surface, geometry=restricted_polygon, los_reference_point=los_reference_point, posture_state_spec=STAND_AT_NONE_POSTURE_STATE_SPEC)
             constraint_list.append(constraint)
         return constraint_list
     else:
         geometry = sims4.geometry.RestrictedPolygon(sims4.geometry.CompoundPolygon(polygons), ())
         constraint = Constraint(routing_surface=routing_surface, geometry=geometry, posture_state_spec=STAND_AT_NONE_POSTURE_STATE_SPEC)
         return constraint
Ejemplo n.º 12
0
 def _generate_cluster(self, position, objects):
     radius = self._get_cluster_radius(position, objects)
     los = LineOfSight(radius, self.line_of_sight_constraint.map_divisions,
                       self.line_of_sight_constraint.simplification_ratio,
                       self.line_of_sight_constraint.boundary_epsilon)
     routing_surface = next(iter(objects)).routing_surface
     los.generate(position, routing_surface, build_convex=True)
     valid_objects = []
     rejects = []
     if los.constraint_convex.geometry is not None:
         for obj in objects:
             for polygon in los.constraint_convex.geometry.polygon:
                 while test_point_in_polygon(
                         obj.lineofsight_component.default_position,
                         polygon):
                     valid_objects.append(obj)
                     break
             rejects.append(obj)
     else:
         rejects = objects
     if not valid_objects:
         (rejected_ne, rejected_nw, rejected_se, rejected_sw) = ([], [], [],
                                                                 [])
         for reject in rejects:
             reject_position = reject.lineofsight_component.default_position
             if reject_position.x >= position.x and reject_position.z >= position.z:
                 rejected_ne.append(reject)
             elif reject_position.z >= position.z:
                 rejected_nw.append(reject)
             elif reject_position.x < position.x and reject_position.z < position.z:
                 rejected_sw.append(reject)
             else:
                 rejected_se.append(reject)
         return (rejected_ne, rejected_nw, rejected_se, rejected_sw)
     convex_hull_poly = self._get_cluster_polygon(position, valid_objects)
     convex_hull_constraint = Constraint(
         debug_name='ClusterConvexHull',
         routing_surface=routing_surface,
         allow_small_intersections=True,
         geometry=sims4.geometry.RestrictedPolygon(convex_hull_poly, []))
     cluster_constraint = los.constraint_convex.intersect(
         convex_hull_constraint)
     if cluster_constraint.valid:
         cluster = ObjectCluster(position, cluster_constraint,
                                 valid_objects, routing_surface)
         self._clusters.append(cluster)
     return [rejects]
Ejemplo n.º 13
0
def polygon_intersection(*args, _connection=None):
    output = sims4.commands.Output(_connection)
    total_string = ''.join(args)
    polygon_strs = find_substring_in_repr(total_string, POLYGON_STR,
                                          POLYGON_END_PARAM)
    if not polygon_strs:
        output('No valid polygons. must start with {} and end with {}'.format(
            POLYGON_STR, POLYGON_END_PARAM))
        return
    constraints = []
    for poly_str in polygon_strs:
        point_list = extract_floats(poly_str)
        if not point_list or len(point_list) % 2 != 0:
            output('Point list is not valid length. Too few or one too many.')
            return
        vertices = []
        for index in range(0, len(point_list), 2):
            vertices.append(
                sims4.math.Vector3(point_list[index], 0.0,
                                   point_list[index + 1]))
        polygon = sims4.geometry.Polygon(vertices)
        geometry = sims4.geometry.RestrictedPolygon(polygon, [])
        constraint = Constraint(geometry=geometry,
                                routing_surface=routing.SurfaceIdentifier(
                                    services.current_zone_id(), 0,
                                    routing.SurfaceType.SURFACETYPE_WORLD))
        constraints.append(constraint)
    intersection = ANYWHERE
    for constraint in constraints:
        new_intersection = intersection.intersect(constraint)
        if not new_intersection.valid:
            output(
                'Constraint intersection failed. Drawing incompatible geometry. {}'
                .format(new_intersection))
            if intersection.geometry is not None:
                draw_geometry_in_string(str(intersection.geometry),
                                        _connection=_connection)
            draw_geometry_in_string(str(constraint.geometry),
                                    _connection=_connection)
            return
        intersection = new_intersection
    if intersection.valid:
        draw_geometry_in_string(str(intersection.geometry),
                                _connection=_connection)
        output('Intersection valid. Drawing Polygon.')
Ejemplo n.º 14
0
 def get_water_constraint(self, min_water_depth=None, max_water_depth=None):
     water_constraint_key = (min_water_depth, max_water_depth)
     if water_constraint_key in self._water_constraint:
         return self._water_constraint[water_constraint_key]
     if self._context.sim is not None:
         (min_water_depth, max_water_depth) = OceanTuning.make_depth_bounds_safe_for_surface_and_sim(self._routing_surface, self._context.sim, min_water_depth, max_water_depth)
     if self._target is not None:
         if self._target is not self._context.sim:
             (min_water_depth, max_water_depth) = OceanTuning.make_depth_bounds_safe_for_surface_and_sim(self._routing_surface, self._target, min_water_depth, max_water_depth)
     if self.is_for_vehicle:
         wading_interval = TunedInterval(0.1, 0.1)
         (min_water_depth, max_water_depth) = OceanTuning.make_depth_bounds_safe_for_surface(self._routing_surface, wading_interval, min_water_depth, max_water_depth)
     if min_water_depth is None and max_water_depth is None:
         constraint = ANYWHERE
     else:
         constraint = Constraint(min_water_depth=min_water_depth, max_water_depth=max_water_depth)
     self._water_constraint[water_constraint_key] = constraint
     return constraint
 def get_inventory_access_constraint(
         self,
         sim,
         is_put,
         carry_target,
         use_owner_as_target_for_resolver=False):
     carry_posture = self.owner.posture_state.get_carry_posture(
         carry_target)
     if carry_posture is not None:
         posture_manifest = carry_posture.get_provided_postures(
             species=sim.species)
         if sim.species != Species.DOG:
             posture_manifest = posture_manifest.__class__(
                 e for e in posture_manifest if e.specific != 'swim')
         posture_manifest = posture_manifest.replace_actor(
             for_actor=self.owner)
         posture_state_spec = create_body_posture_state_spec(
             posture_manifest)
         return Constraint(posture_state_spec=posture_state_spec)
     return STAND_OR_SIT_CONSTRAINT
Ejemplo n.º 16
0
 def get_start_constraint(self):
     constraint = self.get_water_constraint()
     sim = self._context.sim
     supported_postures = self._target.provided_mobile_posture_types
     if self._target.footprint_polygon.contains(
             sim.position
     ) and sim.posture.posture_type in supported_postures and sim.level == self._target.level:
         return constraint
     transform = self._target.transform
     corners = [
         transform.transform_point(sims4.math.Vector3(
             corner.x, 0, corner.z)) for corner in self.get_corners()
     ]
     corners.reverse()
     geometry = sims4.geometry.RestrictedPolygon(
         sims4.geometry.CompoundPolygon(sims4.geometry.Polygon(corners)),
         ())
     return constraint.intersect(
         Constraint(geometry=geometry,
                    debug_name='FootprintConstraint',
                    routing_surface=self._routing_surface))
Ejemplo n.º 17
0
 def _constraint_gen(cls, *args, **kwargs):
     yield Constraint(debug_name='PickUpObjectSuperInteraction({})'.format(cls.si_to_push), posture_state_spec=CARRY_TARGET_POSTURE_STATE_SPEC)
Ejemplo n.º 18
0
 def _create_constraint_set(self, sim, timeline):
     orient = sims4.math.Quaternion.IDENTITY()
     positions = services.current_zone().lot.corners
     position = positions[0]
     routing_surface = self._privacy.constraint.get_world_routing_surface(
         force_world=True)
     if self._privacy._routing_surface_only:
         routing_surfaces = (routing_surface, )
     else:
         routing_surfaces = self._privacy.constraint.get_all_valid_routing_surfaces(
         )
     goals = []
     center_pos = services.current_zone().lot.position
     for pos in positions:
         plex_service = services.get_plex_service()
         if plex_service.is_active_zone_a_plex():
             towards_center_vec = sims4.math.vector_normalize(center_pos -
                                                              pos)
             pos = pos + towards_center_vec * self.PLEX_LOT_CORNER_ADJUSTMENT
             pos.y = services.terrain_service.terrain_object(
             ).get_routing_surface_height_at(pos.x, pos.z, routing_surface)
         if not sims4.geometry.test_point_in_compound_polygon(
                 pos, self._privacy.constraint.geometry.polygon):
             for surface in routing_surfaces:
                 goals.append(
                     routing.Goal(routing.Location(pos, orient, surface)))
     obj_pos = self._privacy.central_object.position
     for offset in self._privacy.additional_exit_offsets:
         goals.append(
             routing.Goal(
                 routing.Location(obj_pos + Vector3(offset.x, 0, offset.y),
                                  orient, surface)))
     if not goals:
         return Nowhere(
             'BuildAndForceSatisfyShooConstraintInteraction, Could not generate goals to exit a privacy region, Sim: {} Privacy Region: {}',
             sim, self._privacy.constraint.geometry.polygon)
         yield
     route = routing.Route(sim.routing_location,
                           goals,
                           routing_context=sim.routing_context)
     plan_primitive = PlanRoute(route,
                                sim,
                                reserve_final_location=False,
                                interaction=self)
     yield from element_utils.run_child(timeline, plan_primitive)
     max_distance = self._privacy._max_line_of_sight_radius * self._privacy._max_line_of_sight_radius * 4
     nodes = []
     path = plan_primitive.path
     while path is not None:
         nodes.extend(path.nodes)
         path = path.next_path
     if nodes:
         previous_node = nodes[0]
         for node in nodes:
             node_vector = sims4.math.Vector3(node.position[0],
                                              node.position[1],
                                              node.position[2])
             if not sims4.geometry.test_point_in_compound_polygon(
                     node_vector,
                     self._privacy.constraint.geometry.polygon):
                 position = node_vector
                 if node.portal_id != 0:
                     continue
                 circle_constraint = interactions.constraints.Circle(
                     position, self.TRIVIAL_SHOO_RADIUS,
                     node.routing_surface_id)
                 if circle_constraint.intersect(
                         self._privacy.constraint).valid:
                     continue
                 break
             previous_node = node
         position2 = sims4.math.Vector3(previous_node.position[0],
                                        previous_node.position[1],
                                        previous_node.position[2])
         if (position - position2).magnitude_2d_squared() > max_distance:
             position = self._find_close_position(position, position2)
     elif (position - sim.position).magnitude_2d_squared() > max_distance:
         position = self._find_close_position(position, sim.position)
     p1 = position
     p2 = self._privacy.central_object.position
     forward = sims4.math.vector_normalize(p1 - p2)
     radius_min = 0
     radius_max = self._privacy.shoo_constraint_radius
     angle = sims4.math.PI
     (cone_geometry,
      cost_functions) = build_weighted_cone(position,
                                            forward,
                                            radius_min,
                                            radius_max,
                                            angle,
                                            ideal_radius_min=0,
                                            ideal_radius_max=0,
                                            ideal_angle=1)
     subtracted_cone_polygon_list = []
     for cone_polygon in cone_geometry.polygon:
         for privacy_polygon in self._privacy.constraint.geometry.polygon:
             subtracted_cone_polygons = cone_polygon.subtract(
                 privacy_polygon)
             if subtracted_cone_polygons:
                 subtracted_cone_polygon_list.extend(
                     subtracted_cone_polygons)
     compound_subtracted_cone_polygon = sims4.geometry.CompoundPolygon(
         subtracted_cone_polygon_list)
     subtracted_cone_geometry = sims4.geometry.RestrictedPolygon(
         compound_subtracted_cone_polygon, [])
     subtracted_cone_constraint = Constraint(
         geometry=subtracted_cone_geometry,
         scoring_functions=cost_functions,
         routing_surface=routing_surface,
         debug_name='ShooedSimsCone',
         multi_surface=True,
         los_reference_point=position)
     point_cost = 5
     point_constraint = interactions.constraints.Position(
         position, routing_surface=routing_surface, multi_surface=True)
     point_constraint = point_constraint.generate_constraint_with_cost(
         point_cost)
     constraints = (subtracted_cone_constraint, point_constraint)
     return interactions.constraints.create_constraint_set(
         constraints, debug_name='ShooPositions')
     yield
 def _constraint_gen(cls, inst, sim, target, participant_type=ParticipantType.Actor):
     inst_or_cls = inst if inst is not None else cls
     if participant_type == ParticipantType.Actor and cls.relocate_main_group and (inst is None or inst.pipeline_progress < PipelineProgress.RUNNING):
         for constraint in super(SuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type):
             yield constraint
         return
     if inst is None or inst.social_group is None or not inst.social_group.constraint_initialized:
         for constraint in super(SuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type):
             yield constraint
         if inst is not None and inst.is_finishing:
             return
         actor = None
         if inst is not None:
             actor = inst.sim
             target = inst.target_sim
         if participant_type == ParticipantType.Actor:
             actor = sim
         if sim is not None and participant_type == ParticipantType.TargetSim:
             target = sim
         if target is None or not target.is_sim:
             return
         if actor is not None and actor is not target:
             (fallback_position, fallback_routing_surface) = get_fallback_social_constraint_position(actor, target, inst)
         else:
             fallback_position = None
         if fallback_position is None:
             if inst is not None:
                 yield Constraint(allow_geometry_intersections=False)
             return
         if inst is not None:
             picked_object = inst.picked_object
         else:
             picked_object = None
         fallback_constraint = cls._social_group_type.make_constraint_default(actor, target, fallback_position, fallback_routing_surface, participant_type=participant_type, picked_object=picked_object, participant_slot_overrides=inst_or_cls._social_group_participant_slot_overrides)
         priority = inst.priority if inst is not None else None
         if sim.si_state.is_compatible_constraint(fallback_constraint, priority=priority, to_exclude=inst) and target.is_sim and target.si_state.is_compatible_constraint(fallback_constraint, priority=priority, to_exclude=inst):
             yield fallback_constraint
         else:
             yield Constraint(allow_geometry_intersections=False)
         return
     if participant_type == ParticipantType.TargetSim:
         if not cls.acquire_targets_as_resource:
             yield Anywhere()
             return
         if inst is not None:
             (target_si, test_result) = inst.get_target_si()
             if not test_result:
                 yield Nowhere()
                 return
             if target_si is not None:
                 target_si_target = target_si.get_participant(ParticipantType.TargetSim)
                 for constraint in target_si.constraint_gen(sim, target_si_target, participant_type=ParticipantType.Actor):
                     yield constraint
                 return
         for constraint in super(SuperInteraction, cls)._constraint_gen(sim, target, participant_type=participant_type):
             yield constraint
         if inst is not None:
             if inst.social_group is not None:
                 yield inst.social_group.get_constraint(sim)
             else:
                 logger.error('Attempt to get constraint from Social interaction and no constraint exists: {}', inst, owner='maxr')
                 yield Anywhere()
                 return
     elif participant_type == ParticipantType.Actor:
         for constraint in super(SuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type):
             yield constraint
         if inst is not None:
             if inst.social_group is not None and participant_type == ParticipantType.Actor:
                 yield inst.social_group.get_constraint(sim)
Ejemplo n.º 20
0
    def __init__(self,
                 sim,
                 current_posture_state,
                 posture_spec,
                 var_map,
                 invalid_expected=False,
                 body_state_spec_only=False,
                 carry_posture_overrides=frozendict(),
                 is_throwaway=False):
        def _get_default_carry_aspect(track):
            if track in carry_posture_overrides:
                return carry_posture_overrides[track]
            return postures.create_posture(
                CarryPostureStaticTuning.POSTURE_CARRY_NOTHING,
                sim,
                None,
                track=track)

        self._constraint_intersection = None
        self._constraint_intersection_dirty = True
        self._spec = posture_spec
        self._sim_ref = sim.ref()
        self._linked_posture_state = None
        self._valid = True
        self._constraints = {}
        self._invalid_expected = invalid_expected
        self.body_state_spec_only = body_state_spec_only
        self._posture_constraint = None
        self._posture_constraint_strict = None
        body_index = BODY_INDEX
        body_posture_type_index = BODY_POSTURE_TYPE_INDEX
        body_target_index = BODY_TARGET_INDEX
        spec_body = posture_spec[body_index]
        self.body_target = spec_body[body_target_index]
        if current_posture_state is None or spec_body[
                body_posture_type_index] != current_posture_state.body.posture_type or spec_body[
                    body_target_index] != current_posture_state.body.target:
            animation_context = None
            if current_posture_state is not None:
                if not current_posture_state.body.mobile:
                    if not spec_body[body_posture_type_index].mobile:
                        animation_context = current_posture_state.body.animation_context
            self._aspect_body = postures.create_posture(
                spec_body[body_posture_type_index],
                self.sim,
                self.body_target,
                animation_context=animation_context,
                is_throwaway=is_throwaway)
        else:
            self._aspect_body = current_posture_state.body
        posture_manifest = self._aspect_body.get_provided_postures(
            surface_target=self.surface_target, concrete=True)
        posture_manifest = posture_manifest.get_constraint_version(self.sim)
        posture_state_spec = PostureStateSpec(
            posture_manifest, SlotManifest(), self._aspect_body.target
            or PostureSpecVariable.ANYTHING)
        self.body_posture_state_constraint = Constraint(
            debug_name='PostureStateManifestConstraint',
            posture_state_spec=posture_state_spec)
        if body_state_spec_only:
            self._constraints[None] = self.body_posture_state_constraint
            return
        body_slot_constraint = self._aspect_body.slot_constraint
        if not (body_slot_constraint is not None and
                (self._aspect_body.is_vehicle and current_posture_state
                 is not None) and current_posture_state.body.is_vehicle):
            body_posture_constraint = self.body_posture_state_constraint.intersect(
                body_slot_constraint)
        else:
            body_posture_constraint = self.body_posture_state_constraint
        self._constraints[None] = body_posture_constraint
        if current_posture_state is not None:
            curr_spec_carry_target = current_posture_state.get_posture_spec(
                var_map)[CARRY_INDEX][CARRY_TARGET_INDEX]
        spec_carry = posture_spec[CARRY_INDEX]
        spec_carry_target = spec_carry[CARRY_TARGET_INDEX]
        if current_posture_state is not None and spec_carry_target != curr_spec_carry_target:
            if spec_carry_target is None:
                current_carry_target = var_map.get(curr_spec_carry_target)
                current_carry_track = current_posture_state.get_carry_track(
                    current_carry_target)
                if current_carry_track == PostureTrack.RIGHT:
                    self._aspect_carry_right = _get_default_carry_aspect(
                        PostureTrack.RIGHT)
                    self._aspect_carry_left = current_posture_state.left
                else:
                    self._aspect_carry_left = _get_default_carry_aspect(
                        PostureTrack.LEFT)
                    self._aspect_carry_right = current_posture_state.right
            else:
                spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
                if spec_carry_target not in var_map:
                    raise KeyError(
                        'spec_carry_target {} not in var_map:{}. Sim posture state {} and carry aspects {}, '
                        .format(spec_carry_target, var_map,
                                current_posture_state,
                                current_posture_state.carry_aspects))
                if spec_carry_posture_type not in var_map:
                    carry_target = var_map[spec_carry_target]
                    aop = posture_specs.get_carry_posture_aop(
                        sim, carry_target)
                    if aop is None:
                        raise RuntimeError(
                            'Sim {} failed to find carry posture aop for carry target {}.'
                            .format(sim, carry_target))
                    carry_posture_type = aop.affordance._carry_posture_type
                    if carry_posture_type is None:
                        raise KeyError
                    var_map += {
                        PostureSpecVariable.POSTURE_TYPE_CARRY_OBJECT:
                        carry_posture_type
                    }
                carry_target = var_map[spec_carry_target]
                carry_posture_type = var_map[spec_carry_posture_type]
                if spec_carry[CARRY_HAND_INDEX] in var_map:
                    hand = var_map[spec_carry[CARRY_HAND_INDEX]]
                else:
                    for hand in sim.posture_state.get_free_hands():
                        if hand in carry_target.get_allowed_hands(sim):
                            break
                    else:
                        raise RuntimeError('No allowable free hand was empty.')
                new_carry_aspect = postures.create_posture(
                    carry_posture_type,
                    self.sim,
                    carry_target,
                    track=hand_to_track(hand),
                    is_throwaway=is_throwaway)
                if hand == Hand.LEFT:
                    self._aspect_carry_left = new_carry_aspect
                    if current_posture_state is not None:
                        self._aspect_carry_right = current_posture_state.right
                    else:
                        self._aspect_carry_right = _get_default_carry_aspect(
                            PostureTrack.RIGHT)
                elif hand == Hand.RIGHT:
                    self._aspect_carry_right = new_carry_aspect
                    if current_posture_state is not None:
                        self._aspect_carry_left = current_posture_state.left
                    else:
                        self._aspect_carry_right = _get_default_carry_aspect(
                            PostureTrack.LEFT)
                else:
                    raise RuntimeError(
                        'Invalid value specified for hand: {}'.format(hand))
        elif current_posture_state is not None:
            self._aspect_carry_left = current_posture_state.left
            self._aspect_carry_right = current_posture_state.right
        elif spec_carry_target is not None:
            carry_target = var_map[spec_carry_target]
            spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
            carry_posture_type = var_map.get(spec_carry_posture_type)
            if carry_posture_type is None:
                aop = get_carry_posture_aop(sim, carry_target)
                if aop is None and invalid_expected:
                    return
                carry_posture_type = aop.affordance._carry_posture_type
            if spec_carry[CARRY_HAND_INDEX] in var_map:
                hand = var_map[spec_carry[CARRY_HAND_INDEX]]
            else:
                allowed_hands = carry_target.get_allowed_hands(sim)
                hand = allowed_hands[0]
            new_carry_aspect = postures.create_posture(
                carry_posture_type,
                self.sim,
                carry_target,
                track=hand_to_track(hand),
                is_throwaway=is_throwaway)
            if hand == Hand.LEFT:
                self._aspect_carry_left = new_carry_aspect
                self._aspect_carry_right = _get_default_carry_aspect(
                    PostureTrack.RIGHT)
            else:
                self._aspect_carry_right = new_carry_aspect
                self._aspect_carry_left = _get_default_carry_aspect(
                    PostureTrack.LEFT)
        else:
            self._aspect_carry_left = _get_default_carry_aspect(
                PostureTrack.LEFT)
            self._aspect_carry_right = _get_default_carry_aspect(
                PostureTrack.RIGHT)
Ejemplo n.º 21
0
 def get_spawn_point_ignore_constraint(self):
     objects_to_ignore = set()
     for spawn_point in self._spawner_data.values():
         objects_to_ignore.add(spawn_point.spawn_point_id)
     return Constraint(objects_to_ignore=objects_to_ignore)
Ejemplo n.º 22
0
class PostureState:
    __qualname__ = 'PostureState'

    def _get_default_carry_aspect(self, track):
        return postures.create_posture(HoldNothing.CARRY_NOTHING_POSTURE_TYPE, self.sim, None, track=track)

    def __init__(self, sim, current_posture_state, posture_spec, var_map, invalid_expected=False, body_state_spec_only=False):
        self._constraint_intersection = None
        self._constraint_intersection_dirty = True
        self._spec = posture_spec
        self._sim_ref = sim.ref()
        self._linked_posture_state = None
        self._valid = True
        self._constraints = {}
        self._invalid_expected = invalid_expected
        self.body_state_spec_only = body_state_spec_only
        self._posture_constraint = None
        self._posture_constraint_strict = None
        body_index = BODY_INDEX
        body_posture_type_index = BODY_POSTURE_TYPE_INDEX
        body_target_index = BODY_TARGET_INDEX
        spec_body = posture_spec[body_index]
        self.body_target = spec_body[body_target_index]
        if current_posture_state is None or spec_body[body_posture_type_index] != current_posture_state.body.posture_type or spec_body[body_target_index] != current_posture_state.body.target:
            animation_context = None
            if current_posture_state is not None and not current_posture_state.body.mobile and not spec_body[body_posture_type_index].mobile:
                animation_context = current_posture_state.body.animation_context
            self._aspect_body = postures.create_posture(spec_body[body_posture_type_index], self.sim, self.body_target, animation_context=animation_context)
        else:
            self._aspect_body = current_posture_state.body
        posture_manifest = self._aspect_body.get_provided_postures(surface_target=self.surface_target, concrete=True)
        posture_manifest = posture_manifest.get_constraint_version(self.sim)
        posture_state_spec = PostureStateSpec(posture_manifest, SlotManifest(), self._aspect_body.target or PostureSpecVariable.ANYTHING)
        self.body_posture_state_constraint = Constraint(debug_name='PostureStateManifestConstraint', posture_state_spec=posture_state_spec)
        if body_state_spec_only:
            self._constraints[self] = self.body_posture_state_constraint
            return
        body_slot_constraint = self._aspect_body.slot_constraint
        if body_slot_constraint is not None:
            body_posture_constraint = self.body_posture_state_constraint.intersect(body_slot_constraint)
        else:
            body_posture_constraint = self.body_posture_state_constraint
        self._constraints[self] = body_posture_constraint
        if current_posture_state is not None:
            curr_spec_carry_target = current_posture_state.get_posture_spec(var_map)[CARRY_INDEX][CARRY_TARGET_INDEX]
        spec_carry = posture_spec[CARRY_INDEX]
        spec_carry_target = spec_carry[CARRY_TARGET_INDEX]
        if current_posture_state is not None and spec_carry_target != curr_spec_carry_target:
            if spec_carry_target is None:
                current_carry_target = var_map.get(curr_spec_carry_target)
                current_carry_track = current_posture_state.get_carry_track(current_carry_target)
                if current_carry_track == PostureTrack.RIGHT:
                    self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
                    self._aspect_carry_left = current_posture_state.left
                else:
                    self._aspect_carry_left = self._get_default_carry_aspect(PostureTrack.LEFT)
                    self._aspect_carry_right = current_posture_state.right
                    spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
                    if spec_carry_target not in var_map:
                        raise KeyError
                    if spec_carry_posture_type not in var_map:
                        aop = posture_specs.get_carry_posture_aop(sim, var_map[spec_carry_target])
                        carry_posture_type = aop.affordance._carry_posture_type
                        if carry_posture_type is None:
                            raise KeyError
                        var_map += {PostureSpecVariable.POSTURE_TYPE_CARRY_OBJECT: carry_posture_type}
                    carry_target = var_map[spec_carry_target]
                    carry_posture_type = var_map[spec_carry_posture_type]
                    if spec_carry[CARRY_HAND_INDEX] in var_map:
                        hand = var_map[spec_carry[CARRY_HAND_INDEX]]
                    else:
                        for hand in sim.posture_state.get_free_hands():
                            while hand in carry_target.allowed_hands:
                                break
                        raise RuntimeError('No allowable free hand was empty.')
                    new_carry_aspect = postures.create_posture(carry_posture_type, self.sim, carry_target, track=self.hand_to_track(hand))
                    if hand == Hand.LEFT:
                        self._aspect_carry_left = new_carry_aspect
                        if current_posture_state is not None:
                            self._aspect_carry_right = current_posture_state.right
                        else:
                            self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
                            if hand == Hand.RIGHT:
                                self._aspect_carry_right = new_carry_aspect
                                if current_posture_state is not None:
                                    self._aspect_carry_left = current_posture_state.left
                                else:
                                    self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.LEFT)
                                    raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                            else:
                                raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                    elif hand == Hand.RIGHT:
                        self._aspect_carry_right = new_carry_aspect
                        if current_posture_state is not None:
                            self._aspect_carry_left = current_posture_state.left
                        else:
                            self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.LEFT)
                            raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                    else:
                        raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
            else:
                spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
                if spec_carry_target not in var_map:
                    raise KeyError
                if spec_carry_posture_type not in var_map:
                    aop = posture_specs.get_carry_posture_aop(sim, var_map[spec_carry_target])
                    carry_posture_type = aop.affordance._carry_posture_type
                    if carry_posture_type is None:
                        raise KeyError
                    var_map += {PostureSpecVariable.POSTURE_TYPE_CARRY_OBJECT: carry_posture_type}
                carry_target = var_map[spec_carry_target]
                carry_posture_type = var_map[spec_carry_posture_type]
                if spec_carry[CARRY_HAND_INDEX] in var_map:
                    hand = var_map[spec_carry[CARRY_HAND_INDEX]]
                else:
                    for hand in sim.posture_state.get_free_hands():
                        while hand in carry_target.allowed_hands:
                            break
                    raise RuntimeError('No allowable free hand was empty.')
                new_carry_aspect = postures.create_posture(carry_posture_type, self.sim, carry_target, track=self.hand_to_track(hand))
                if hand == Hand.LEFT:
                    self._aspect_carry_left = new_carry_aspect
                    if current_posture_state is not None:
                        self._aspect_carry_right = current_posture_state.right
                    else:
                        self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
                        if hand == Hand.RIGHT:
                            self._aspect_carry_right = new_carry_aspect
                            if current_posture_state is not None:
                                self._aspect_carry_left = current_posture_state.left
                            else:
                                self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.LEFT)
                                raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                        else:
                            raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                elif hand == Hand.RIGHT:
                    self._aspect_carry_right = new_carry_aspect
                    if current_posture_state is not None:
                        self._aspect_carry_left = current_posture_state.left
                    else:
                        self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.LEFT)
                        raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                else:
                    raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
        elif current_posture_state is not None:
            self._aspect_carry_left = current_posture_state.left
            self._aspect_carry_right = current_posture_state.right
        elif spec_carry_target is not None:
            carry_target = var_map[spec_carry_target]
            spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
            carry_posture_type = var_map.get(spec_carry_posture_type)
            if carry_posture_type is None:
                aop = get_carry_posture_aop(sim, carry_target)
                if aop is None and invalid_expected:
                    return
                carry_posture_type = aop.affordance._carry_posture_type
            if spec_carry[CARRY_HAND_INDEX] in var_map:
                hand = var_map[spec_carry[CARRY_HAND_INDEX]]
            else:
                hand = carry_target.allowed_hands[0]
            new_carry_aspect = postures.create_posture(carry_posture_type, self.sim, carry_target, track=self.hand_to_track(hand))
            if hand == Hand.LEFT:
                self._aspect_carry_left = new_carry_aspect
                self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
            else:
                self._aspect_carry_right = new_carry_aspect
                self._aspect_carry_left = self._get_default_carry_aspect(PostureTrack.LEFT)
        else:
            self._aspect_carry_left = self._get_default_carry_aspect(PostureTrack.LEFT)
            self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)

    def __repr__(self):
        return standard_repr(self, *self.aspects)

    @property
    def valid(self):
        return self._valid and bool(self.constraint_intersection)

    @property
    def spec(self):
        return self._spec

    def get_posture_spec(self, var_map):
        if not var_map:
            return self._spec.clone()
        carry_target = var_map.get(PostureSpecVariable.CARRY_TARGET) or var_map.get(PostureSpecVariable.INTERACTION_TARGET)
        if carry_target is not None and carry_target.definition is not carry_target and carry_target.carryable_component is not None:
            carry_posture = self.get_carry_posture(carry_target)
        else:
            carry_posture = None
        if carry_posture is not None:
            if PostureSpecVariable.HAND in var_map:
                required_hand = PostureState.track_to_hand(carry_posture.track)
                if required_hand != var_map[PostureSpecVariable.HAND]:
                    return
            source_carry = PostureAspectCarry((PostureSpecVariable.POSTURE_TYPE_CARRY_OBJECT, PostureSpecVariable.CARRY_TARGET, PostureSpecVariable.HAND))
        else:
            source_carry = PostureAspectCarry((PostureSpecVariable.POSTURE_TYPE_CARRY_NOTHING, None, PostureSpecVariable.HAND))
        surface_spec = self._spec[SURFACE_INDEX]
        surface_target = surface_spec[SURFACE_TARGET_INDEX]
        if surface_target is not None:
            var_map_surface_target = var_map.get(PostureSpecVariable.SURFACE_TARGET, None)
            if var_map_surface_target is None or surface_target == var_map_surface_target:
                var_map_carry_target = var_map.get(PostureSpecVariable.CARRY_TARGET, PostureSpecVariable.CARRY_TARGET)
                if carry_target is not None and (carry_posture is None and carry_target.definition is not carry_target) and not carry_target.is_surface(include_parts=True):
                    surface_spec = PostureAspectSurface((surface_target, PostureSpecVariable.SLOT, PostureSpecVariable.CARRY_TARGET))
                    spec = self._spec.clone(carry=source_carry, surface=surface_spec)
                    if spec._validate_surface(var_map) and (var_map_carry_target is None or var_map_carry_target.parent is surface_target):
                        return spec
                surface_spec = PostureAspectSurface((surface_target, PostureSpecVariable.SLOT, None))
                spec = self._spec.clone(carry=source_carry, surface=surface_spec)
                if spec._validate_surface(var_map):
                    return spec
            surface_spec = PostureAspectSurface((surface_target, None, None))
            spec = self._spec.clone(carry=source_carry, surface=surface_spec)
            if spec._validate_surface(var_map):
                return spec
        surface_spec = PostureAspectSurface((None, None, None))
        spec = self._spec.clone(carry=source_carry, surface=surface_spec)
        if spec._validate_surface(var_map):
            return spec

    def _get_posture_constraint(self, strict=False):
        posture_state_constraint = self.body_posture_state_constraint
        posture_state_constraint = posture_state_constraint.get_holster_version()
        if posture_state_constraint.valid and not self.body_state_spec_only:
            carry_left_constraint = carry.create_carry_constraint(self.left.target, Hand.LEFT, strict=strict)
            posture_state_constraint = posture_state_constraint.intersect(carry_left_constraint)
            if posture_state_constraint.valid:
                carry_right_constraint = carry.create_carry_constraint(self.right.target, Hand.RIGHT, strict=strict)
                posture_state_constraint = posture_state_constraint.intersect(carry_right_constraint)
        return posture_state_constraint

    @property
    def posture_constraint(self):
        if self._posture_constraint is None:
            self._posture_constraint = self._get_posture_constraint()
        return self._posture_constraint

    @property
    def posture_constraint_strict(self):
        if self._posture_constraint_strict is None:
            self._posture_constraint_strict = self._get_posture_constraint(strict=True)
        return self._posture_constraint_strict

    @property
    def sim(self):
        if self._sim_ref is not None:
            return self._sim_ref()

    @property
    def linked_posture_state(self):
        return self._linked_posture_state

    @linked_posture_state.setter
    def linked_posture_state(self, posture_state):
        self._set_linked_posture_state(posture_state)
        posture_state._set_linked_posture_state(self)
        self.body.linked_posture = posture_state.body

    def _set_linked_posture_state(self, posture_state):
        self._linked_posture_state = posture_state

    @property
    def body(self):
        return self._aspect_body

    @property
    def left(self):
        return self._aspect_carry_left

    @property
    def right(self):
        return self._aspect_carry_right

    @property
    def aspects(self):
        if self.body_state_spec_only:
            return ()
        return (self.body, self.left, self.right)

    @property
    def carry_aspects(self):
        return (self.left, self.right)

    @property
    def surface_target(self):
        surface = self._spec[SURFACE_INDEX][SURFACE_TARGET_INDEX]
        if (surface is None or self.body.mobile) and self.body.target is not None and self.body.target.is_surface():
            return self.body.target
        return surface

    @property
    def carry_targets(self):
        return (self.left.target, self.right.target)

    def get_aspect(self, track):
        if track == PostureTrack.BODY:
            return self.body
        if track == PostureTrack.LEFT:
            return self.left
        if track == PostureTrack.RIGHT:
            return self.right

    @property
    def has_geometry(self):
        raise RuntimeError('[bhill] This function is believed to be dead code and is scheduled for pruning. If this exception has been raised, the code is not dead and this exception should be removed.')
        constraint_insteraction = self.constraint_intersection
        if constraint_insteraction is not None:
            for constraint in constraint_insteraction:
                while constraint.geometry is not None:
                    return True
        return False

    def add_constraint(self, handle, constraint):
        if not constraint.valid:
            logger.error('Attempt to add an invalid constraint {} to posture_state {}.', constraint, self, owner='bhill', trigger_breakpoint=True)
        test_constraint = self.constraint_intersection.intersect(constraint)
        if not (self._invalid_expected or test_constraint.valid):
            logger.warn('Attempt to add a constraint to {} which is incompatible with already-registered constraints: {} + {}.', self, constraint, self.constraint_intersection)
        self._constraints[handle] = constraint
        self._constraint_intersection_dirty = True

    def remove_constraint(self, handle):
        if handle in self._constraints:
            del self._constraints[handle]
            self._constraint_intersection_dirty = True
            self._constraint_intersection = None

    @property
    def constraint_intersection(self):
        if self._constraint_intersection_dirty:
            intersection = Anywhere()
            for constraint in set(self._constraints.values()):
                new_intersection = intersection.intersect(constraint)
                if not self._invalid_expected and not new_intersection.valid:
                    logger.error('Invalid constraint intersection for PostureState:{}', self)
                    intersection = new_intersection
                    break
                intersection = new_intersection
            self._constraint_intersection_dirty = False
            self._constraint_intersection = intersection
        return self._constraint_intersection

    def compatible_with(self, constraint):
        intersection = self.constraint_intersection
        if not intersection.valid:
            return False
        intersection = constraint.intersect(intersection)
        if not intersection.valid:
            return False
        return True

    def compatible_with_pre_resolve(self, constraint):
        for constraint_existing in self._constraints.values():
            while constraint_existing is constraint:
                return True
        return self.compatible_with(constraint)

    def get_slot_info(self):
        surface = self._spec[SURFACE_INDEX]
        return (surface[SURFACE_TARGET_INDEX], surface[SURFACE_SLOT_TYPE_INDEX])

    def is_source_interaction(self, si):
        if si is not None:
            for aspect in self.aspects:
                while aspect.source_interaction is si:
                    return True
        return False

    def is_source_or_owning_interaction(self, si):
        return self.get_source_or_owned_posture_for_si(si) is not None

    def is_carry_source_or_owning_interaction(self, si):
        return self.get_source_or_owned_posture_for_si(si, carry_only=True) is not None

    def get_source_or_owned_posture_for_si(self, si, carry_only=False):
        if self.left.source_interaction is si or si in self.left.owning_interactions:
            return self.left
        if self.right.source_interaction is si or si in self.right.owning_interactions:
            return self.right
        if carry_only:
            return
        if self.body.source_interaction is si or si in self.body.owning_interactions:
            return self.body

    def _hand_to_track(self, hand) -> PostureTrack:
        raise RuntimeError('[bhill] This function is believed to be dead code and is scheduled for pruning. If this exception has been raised, the code is not dead and this exception should be removed.')
        if hand == Hand.LEFT:
            return PostureTrack.LEFT
        return PostureTrack.RIGHT

    def _track_to_hand(self, track) -> Hand:
        raise RuntimeError('[bhill] This function is believed to be dead code and is scheduled for pruning. If this exception has been raised, the code is not dead and this exception should be removed.')
        if track == PostureTrack.LEFT:
            return Hand.LEFT
        return Hand.RIGHT

    @property
    def connectivity_handles(self):
        if self.body.target is not None:
            return self.body.target.connectivity_handles

    def kickstart_gen(self, timeline):
        for aspect in self.aspects:
            yield aspect.kickstart_gen(timeline, self)
        self._valid = True

    def on_reset(self, reset_reason):
        for aspect in self.aspects:
            aspect.reset()
        self._valid = False

    def _carrying(self, track, **kwargs):
        posture = self.left if track == PostureTrack.LEFT else self.right
        return self._carrying_posture(posture, **kwargs)

    def _carrying_posture(self, posture, ignore_target=None, only_target=None):
        if posture is not None and posture.is_active_carry:
            if ignore_target is None and only_target is None:
                return True
            target = posture.target

            def target_is(other):
                if target is None:
                    return False
                if isinstance(other, int):
                    return target.definition.id == other
                if isinstance(other, Definition):
                    return target.definition == other
                return target is other

            if ignore_target is None or not target_is(ignore_target):
                if only_target is None or target_is(only_target):
                    return True
        return False

    def get_carry_state(self, target=None, override_posture=None):
        if override_posture is not None:
            if override_posture.track == PostureTrack.LEFT:
                carry_state = (self._carrying_posture(override_posture, ignore_target=target), self._carrying(PostureTrack.RIGHT, ignore_target=target))
            else:
                carry_state = (self._carrying(PostureTrack.LEFT, ignore_target=target), self._carrying_posture(override_posture, ignore_target=target))
        else:
            carry_state = (self._carrying(PostureTrack.LEFT, ignore_target=target), self._carrying(PostureTrack.RIGHT, ignore_target=target))
        return carry_state

    def get_carry_track(self, target):
        if target is None:
            return
        if self._carrying(PostureTrack.LEFT, only_target=target):
            return PostureTrack.LEFT
        if self._carrying(PostureTrack.RIGHT, only_target=target):
            return PostureTrack.RIGHT

    def is_carrying(self, target):
        if self.get_carry_track(target) is not None:
            return True
        return False

    def get_carry_posture(self, target):
        if self.left.target is target:
            return self.left
        if self.right.target is target:
            return self.right

    def get_posture_for_si(self, si):
        for posture in self.aspects:
            while posture is not None and posture.source_interaction == si:
                return posture

    def get_other_carry_posture(self, target):
        track = self.get_carry_track(target)
        if track is None:
            return
        if track is PostureTrack.LEFT:
            result = self.get_aspect(PostureTrack.RIGHT)
        else:
            result = self.get_aspect(PostureTrack.LEFT)
        if result is not None and result.target is not None:
            return result

    def get_free_carry_track(self, obj=None) -> PostureTrack:
        if obj is not None and obj.carryable_component is None:
            logger.error('Obj {} has no carryable component.', obj, owner='tastle')
            return
        allowed_hands = obj.carryable_component.allowed_hands if obj is not None else (Hand.RIGHT, Hand.LEFT)
        if self.sim.handedness == Hand.RIGHT:
            preferred_track = PostureTrack.RIGHT
            unpreferred_track = PostureTrack.LEFT
        else:
            preferred_track = PostureTrack.LEFT
            unpreferred_track = PostureTrack.RIGHT
        if self.track_to_hand(preferred_track) in allowed_hands and not self._carrying(preferred_track):
            return preferred_track
        if self.track_to_hand(unpreferred_track) in allowed_hands and not self._carrying(unpreferred_track):
            return unpreferred_track

    def get_free_hands(self):
        if not self._carrying(PostureTrack.RIGHT):
            if not self._carrying(PostureTrack.LEFT):
                return (Hand.RIGHT, Hand.LEFT)
            return (Hand.RIGHT,)
        if not self._carrying(PostureTrack.LEFT):
            return (Hand.LEFT,)
        return ()

    @staticmethod
    def hand_to_track(hand) -> PostureTrack:
        if hand == Hand.LEFT:
            return PostureTrack.LEFT
        return PostureTrack.RIGHT

    @staticmethod
    def track_to_hand(track) -> Hand:
        if track == PostureTrack.LEFT:
            return Hand.LEFT
        return Hand.RIGHT
 def _create_constraint_set(self, sim, timeline):
     orient = sims4.math.Quaternion.IDENTITY()
     positions = services.current_zone().lot.corners
     position = positions[0]
     goals = []
     for pos in positions:
         while not sims4.geometry.test_point_in_compound_polygon(
                 pos, self._privacy.constraint.geometry.polygon):
             goals.append(
                 routing.Goal(
                     routing.Location(pos, orient, sim.routing_surface)))
     if not goals:
         return Nowhere()
     route = routing.Route(sim.routing_location,
                           goals,
                           routing_context=sim.routing_context)
     plan_primitive = PlanRoute(route, sim, reserve_final_location=False)
     yield element_utils.run_child(timeline, plan_primitive)
     max_distance = self._privacy._max_line_of_sight_radius * self._privacy._max_line_of_sight_radius * 4
     nodes = plan_primitive.path.nodes
     if nodes:
         previous_node = nodes[0]
         for node in nodes:
             node_vector = sims4.math.Vector3(node.position[0],
                                              node.position[1],
                                              node.position[2])
             if not sims4.geometry.test_point_in_compound_polygon(
                     node_vector,
                     self._privacy.constraint.geometry.polygon):
                 position = node_vector
                 if node.portal_id != 0:
                     pass
                 circle_constraint = interactions.constraints.Circle(
                     position, self.TRIVIAL_SHOO_RADIUS,
                     node.routing_surface_id)
                 if circle_constraint.intersect(
                         self._privacy.constraint).valid:
                     pass
                 break
             previous_node = node
         position2 = sims4.math.Vector3(previous_node.position[0],
                                        previous_node.position[1],
                                        previous_node.position[2])
         if (position - position2).magnitude_2d_squared() > max_distance:
             position = self._find_close_position(position, position2)
     elif (position - sim.position).magnitude_2d_squared() > max_distance:
         position = self._find_close_position(position, sim.position)
     p1 = position
     p2 = self._privacy.central_object.position
     forward = sims4.math.vector_normalize(p1 - p2)
     radius_min = 0
     radius_max = self._privacy._SHOO_CONSTRAINT_RADIUS
     angle = sims4.math.PI
     (cone_geometry,
      scoring_functions) = build_weighted_cone(position,
                                               forward,
                                               radius_min,
                                               radius_max,
                                               angle,
                                               ideal_radius_min=0,
                                               ideal_radius_max=0,
                                               ideal_angle=1)
     subtracted_cone_polygon_list = []
     for cone_polygon in cone_geometry.polygon:
         for privacy_polygon in self._privacy.constraint.geometry.polygon:
             subtracted_cone_polygons = cone_polygon.subtract(
                 privacy_polygon)
             while subtracted_cone_polygons:
                 subtracted_cone_polygon_list.extend(
                     subtracted_cone_polygons)
     compound_subtracted_cone_polygon = sims4.geometry.CompoundPolygon(
         subtracted_cone_polygon_list)
     subtracted_cone_geometry = sims4.geometry.RestrictedPolygon(
         compound_subtracted_cone_polygon, [])
     subtracted_cone_constraint = Constraint(
         geometry=subtracted_cone_geometry,
         scoring_functions=scoring_functions,
         routing_surface=sim.routing_surface,
         debug_name='ShooedSimsCone',
         los_reference_point=position)
     point_cost = 5
     point_constraint = interactions.constraints.Position(
         position, routing_surface=sim.routing_surface)
     point_constraint = point_constraint.generate_constraint_with_cost(
         point_cost)
     constraints = (subtracted_cone_constraint, point_constraint)
     return interactions.constraints.create_constraint_set(
         constraints, debug_name='ShooPositions')
 def __init__(self, sim, current_posture_state, posture_spec, var_map, invalid_expected=False, body_state_spec_only=False):
     self._constraint_intersection = None
     self._constraint_intersection_dirty = True
     self._spec = posture_spec
     self._sim_ref = sim.ref()
     self._linked_posture_state = None
     self._valid = True
     self._constraints = {}
     self._invalid_expected = invalid_expected
     self.body_state_spec_only = body_state_spec_only
     self._posture_constraint = None
     self._posture_constraint_strict = None
     body_index = BODY_INDEX
     body_posture_type_index = BODY_POSTURE_TYPE_INDEX
     body_target_index = BODY_TARGET_INDEX
     spec_body = posture_spec[body_index]
     self.body_target = spec_body[body_target_index]
     if current_posture_state is None or spec_body[body_posture_type_index] != current_posture_state.body.posture_type or spec_body[body_target_index] != current_posture_state.body.target:
         animation_context = None
         if current_posture_state is not None and not current_posture_state.body.mobile and not spec_body[body_posture_type_index].mobile:
             animation_context = current_posture_state.body.animation_context
         self._aspect_body = postures.create_posture(spec_body[body_posture_type_index], self.sim, self.body_target, animation_context=animation_context)
     else:
         self._aspect_body = current_posture_state.body
     posture_manifest = self._aspect_body.get_provided_postures(surface_target=self.surface_target, concrete=True)
     posture_manifest = posture_manifest.get_constraint_version(self.sim)
     posture_state_spec = PostureStateSpec(posture_manifest, SlotManifest(), self._aspect_body.target or PostureSpecVariable.ANYTHING)
     self.body_posture_state_constraint = Constraint(debug_name='PostureStateManifestConstraint', posture_state_spec=posture_state_spec)
     if body_state_spec_only:
         self._constraints[self] = self.body_posture_state_constraint
         return
     body_slot_constraint = self._aspect_body.slot_constraint
     if body_slot_constraint is not None:
         body_posture_constraint = self.body_posture_state_constraint.intersect(body_slot_constraint)
     else:
         body_posture_constraint = self.body_posture_state_constraint
     self._constraints[self] = body_posture_constraint
     if current_posture_state is not None:
         curr_spec_carry_target = current_posture_state.get_posture_spec(var_map)[CARRY_INDEX][CARRY_TARGET_INDEX]
     spec_carry = posture_spec[CARRY_INDEX]
     spec_carry_target = spec_carry[CARRY_TARGET_INDEX]
     if current_posture_state is not None and spec_carry_target != curr_spec_carry_target:
         if spec_carry_target is None:
             current_carry_target = var_map.get(curr_spec_carry_target)
             current_carry_track = current_posture_state.get_carry_track(current_carry_target)
             if current_carry_track == PostureTrack.RIGHT:
                 self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
                 self._aspect_carry_left = current_posture_state.left
             else:
                 self._aspect_carry_left = self._get_default_carry_aspect(PostureTrack.LEFT)
                 self._aspect_carry_right = current_posture_state.right
                 spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
                 if spec_carry_target not in var_map:
                     raise KeyError
                 if spec_carry_posture_type not in var_map:
                     aop = posture_specs.get_carry_posture_aop(sim, var_map[spec_carry_target])
                     carry_posture_type = aop.affordance._carry_posture_type
                     if carry_posture_type is None:
                         raise KeyError
                     var_map += {PostureSpecVariable.POSTURE_TYPE_CARRY_OBJECT: carry_posture_type}
                 carry_target = var_map[spec_carry_target]
                 carry_posture_type = var_map[spec_carry_posture_type]
                 if spec_carry[CARRY_HAND_INDEX] in var_map:
                     hand = var_map[spec_carry[CARRY_HAND_INDEX]]
                 else:
                     for hand in sim.posture_state.get_free_hands():
                         while hand in carry_target.allowed_hands:
                             break
                     raise RuntimeError('No allowable free hand was empty.')
                 new_carry_aspect = postures.create_posture(carry_posture_type, self.sim, carry_target, track=self.hand_to_track(hand))
                 if hand == Hand.LEFT:
                     self._aspect_carry_left = new_carry_aspect
                     if current_posture_state is not None:
                         self._aspect_carry_right = current_posture_state.right
                     else:
                         self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
                         if hand == Hand.RIGHT:
                             self._aspect_carry_right = new_carry_aspect
                             if current_posture_state is not None:
                                 self._aspect_carry_left = current_posture_state.left
                             else:
                                 self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.LEFT)
                                 raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                         else:
                             raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                 elif hand == Hand.RIGHT:
                     self._aspect_carry_right = new_carry_aspect
                     if current_posture_state is not None:
                         self._aspect_carry_left = current_posture_state.left
                     else:
                         self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.LEFT)
                         raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                 else:
                     raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
         else:
             spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
             if spec_carry_target not in var_map:
                 raise KeyError
             if spec_carry_posture_type not in var_map:
                 aop = posture_specs.get_carry_posture_aop(sim, var_map[spec_carry_target])
                 carry_posture_type = aop.affordance._carry_posture_type
                 if carry_posture_type is None:
                     raise KeyError
                 var_map += {PostureSpecVariable.POSTURE_TYPE_CARRY_OBJECT: carry_posture_type}
             carry_target = var_map[spec_carry_target]
             carry_posture_type = var_map[spec_carry_posture_type]
             if spec_carry[CARRY_HAND_INDEX] in var_map:
                 hand = var_map[spec_carry[CARRY_HAND_INDEX]]
             else:
                 for hand in sim.posture_state.get_free_hands():
                     while hand in carry_target.allowed_hands:
                         break
                 raise RuntimeError('No allowable free hand was empty.')
             new_carry_aspect = postures.create_posture(carry_posture_type, self.sim, carry_target, track=self.hand_to_track(hand))
             if hand == Hand.LEFT:
                 self._aspect_carry_left = new_carry_aspect
                 if current_posture_state is not None:
                     self._aspect_carry_right = current_posture_state.right
                 else:
                     self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
                     if hand == Hand.RIGHT:
                         self._aspect_carry_right = new_carry_aspect
                         if current_posture_state is not None:
                             self._aspect_carry_left = current_posture_state.left
                         else:
                             self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.LEFT)
                             raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
                     else:
                         raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
             elif hand == Hand.RIGHT:
                 self._aspect_carry_right = new_carry_aspect
                 if current_posture_state is not None:
                     self._aspect_carry_left = current_posture_state.left
                 else:
                     self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.LEFT)
                     raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
             else:
                 raise RuntimeError('Invalid value specified for hand: {}'.format(hand))
     elif current_posture_state is not None:
         self._aspect_carry_left = current_posture_state.left
         self._aspect_carry_right = current_posture_state.right
     elif spec_carry_target is not None:
         carry_target = var_map[spec_carry_target]
         spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
         carry_posture_type = var_map.get(spec_carry_posture_type)
         if carry_posture_type is None:
             aop = get_carry_posture_aop(sim, carry_target)
             if aop is None and invalid_expected:
                 return
             carry_posture_type = aop.affordance._carry_posture_type
         if spec_carry[CARRY_HAND_INDEX] in var_map:
             hand = var_map[spec_carry[CARRY_HAND_INDEX]]
         else:
             hand = carry_target.allowed_hands[0]
         new_carry_aspect = postures.create_posture(carry_posture_type, self.sim, carry_target, track=self.hand_to_track(hand))
         if hand == Hand.LEFT:
             self._aspect_carry_left = new_carry_aspect
             self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
         else:
             self._aspect_carry_right = new_carry_aspect
             self._aspect_carry_left = self._get_default_carry_aspect(PostureTrack.LEFT)
     else:
         self._aspect_carry_left = self._get_default_carry_aspect(PostureTrack.LEFT)
         self._aspect_carry_right = self._get_default_carry_aspect(PostureTrack.RIGHT)
Ejemplo n.º 25
0
from animation.posture_manifest
import MATCH_ANY, MATCH_NONE, PostureManifestEntry, PostureManifest
from interactions.constraints
import Constraint, create_constraint_set
from postures.posture_state_spec
import create_body_posture_state_spec
STAND_POSTURE_MANIFEST = PostureManifest((PostureManifestEntry(None, '', 'stand', 'FullBody', MATCH_ANY, MATCH_ANY, MATCH_ANY), PostureManifestEntry(None, '', 'stand', 'UpperBody', MATCH_ANY, MATCH_ANY, MATCH_ANY))).intern()
STAND_NO_SURFACE_POSTURE_MANIFEST = PostureManifest((PostureManifestEntry(None, '', 'stand', 'FullBody', MATCH_ANY, MATCH_ANY, MATCH_NONE), PostureManifestEntry(None, '', 'stand', 'UpperBody', MATCH_ANY, MATCH_ANY, MATCH_NONE))).intern()
STAND_NO_CARRY_NO_SURFACE_POSTURE_MANIFEST = PostureManifest((PostureManifestEntry(None, '', 'stand', 'FullBody', MATCH_NONE, MATCH_NONE, MATCH_NONE), PostureManifestEntry(None, '', 'stand', 'UpperBody', MATCH_NONE, MATCH_NONE, MATCH_NONE))).intern()
STAND_POSTURE_STATE_SPEC = create_body_posture_state_spec(STAND_POSTURE_MANIFEST)
STAND_NO_SURFACE_STATE_SPEC = create_body_posture_state_spec(STAND_NO_SURFACE_POSTURE_MANIFEST)
STAND_NO_CARRY_NO_SURFACE_STATE_SPEC = create_body_posture_state_spec(STAND_NO_CARRY_NO_SURFACE_POSTURE_MANIFEST)
STAND_CONSTRAINT = Constraint(debug_name = 'Stand', posture_state_spec = STAND_POSTURE_STATE_SPEC)
STAND_NO_SURFACE_CONSTRAINT = Constraint(debug_name = 'Stand-NoSurface', posture_state_spec = STAND_NO_SURFACE_STATE_SPEC)
STAND_NO_CARRY_NO_SURFACE_CONSTRAINT = Constraint(debug_name = 'Stand-NoCarryNoSurface', posture_state_spec = STAND_NO_CARRY_NO_SURFACE_STATE_SPEC)
STAND_CONSTRAINT_OUTER_PENALTY = Constraint(debug_name = 'Stand', posture_state_spec = STAND_POSTURE_STATE_SPEC, ignore_outer_penalty_threshold = 1.0)
STAND_AT_NONE_POSTURE_STATE_SPEC = create_body_posture_state_spec(STAND_POSTURE_MANIFEST, body_target = None)
STAND_AT_NONE_CONSTRAINT = Constraint(debug_name = 'Stand@None', posture_state_spec = STAND_AT_NONE_POSTURE_STATE_SPEC)
SIT_POSTURE_MANIFEST = PostureManifest((PostureManifestEntry(None, '', 'sit', 'FullBody', MATCH_ANY, MATCH_ANY, MATCH_ANY), PostureManifestEntry(None, '', 'sit', 'UpperBody', MATCH_ANY, MATCH_ANY, MATCH_ANY))).intern()
SIT_NO_CARRY_NO_SURFACE_MANIFEST = PostureManifest((PostureManifestEntry(None, '', 'sit', 'FullBody', MATCH_NONE, MATCH_NONE, MATCH_NONE), PostureManifestEntry(None, '', 'sit', 'UpperBody', MATCH_NONE, MATCH_NONE, MATCH_NONE))).intern()
SIT_POSTURE_STATE_SPEC = create_body_posture_state_spec(SIT_POSTURE_MANIFEST)
SIT_NO_CARRY_NO_SURFACE_STATE_SPEC = create_body_posture_state_spec(SIT_NO_CARRY_NO_SURFACE_MANIFEST)
SIT_CONSTRAINT = Constraint(debug_name = 'Sit', posture_state_spec = SIT_POSTURE_STATE_SPEC)
SIT_NO_CARRY_NO_SURFACE_CONSTRAINT = Constraint(debug_name = 'SitNoCarryNoSurface', posture_state_spec = SIT_NO_CARRY_NO_SURFACE_STATE_SPEC)
SIT_INTIMATE_POSTURE_MANIFEST = PostureManifest((PostureManifestEntry(None, 'sitIntimate', '', 'FullBody', MATCH_NONE, MATCH_NONE, MATCH_NONE), PostureManifestEntry(None, 'sitIntimate', '', 'UpperBody', MATCH_NONE, MATCH_NONE, MATCH_NONE))).intern()
SIT_INTIMATE_POSTURE_STATE_SPEC = create_body_posture_state_spec(SIT_INTIMATE_POSTURE_MANIFEST)
SIT_INTIMATE_CONSTRAINT = Constraint(debug_name = 'SitIntimate', posture_state_spec = SIT_INTIMATE_POSTURE_STATE_SPEC)
STAND_OR_SIT_POSTURE_MANIFEST = PostureManifest(list(STAND_POSTURE_MANIFEST) + list(SIT_POSTURE_MANIFEST)).intern()
STAND_OR_SIT_CONSTRAINT = create_constraint_set((STAND_CONSTRAINT, SIT_CONSTRAINT), debug_name = 'Stand-or-Sit')
STAND_OR_SIT_CONSTRAINT_OUTER_PENALTY = create_constraint_set((STAND_CONSTRAINT_OUTER_PENALTY, SIT_CONSTRAINT), debug_name = 'Stand-or-Sit-Outer-Penalty')
Ejemplo n.º 26
0
class PostureState:
    def __init__(self,
                 sim,
                 current_posture_state,
                 posture_spec,
                 var_map,
                 invalid_expected=False,
                 body_state_spec_only=False,
                 carry_posture_overrides=frozendict(),
                 is_throwaway=False):
        def _get_default_carry_aspect(track):
            if track in carry_posture_overrides:
                return carry_posture_overrides[track]
            return postures.create_posture(
                CarryPostureStaticTuning.POSTURE_CARRY_NOTHING,
                sim,
                None,
                track=track)

        self._constraint_intersection = None
        self._constraint_intersection_dirty = True
        self._spec = posture_spec
        self._sim_ref = sim.ref()
        self._linked_posture_state = None
        self._valid = True
        self._constraints = {}
        self._invalid_expected = invalid_expected
        self.body_state_spec_only = body_state_spec_only
        self._posture_constraint = None
        self._posture_constraint_strict = None
        body_index = BODY_INDEX
        body_posture_type_index = BODY_POSTURE_TYPE_INDEX
        body_target_index = BODY_TARGET_INDEX
        spec_body = posture_spec[body_index]
        self.body_target = spec_body[body_target_index]
        if current_posture_state is None or spec_body[
                body_posture_type_index] != current_posture_state.body.posture_type or spec_body[
                    body_target_index] != current_posture_state.body.target:
            animation_context = None
            if current_posture_state is not None:
                if not current_posture_state.body.mobile:
                    if not spec_body[body_posture_type_index].mobile:
                        animation_context = current_posture_state.body.animation_context
            self._aspect_body = postures.create_posture(
                spec_body[body_posture_type_index],
                self.sim,
                self.body_target,
                animation_context=animation_context,
                is_throwaway=is_throwaway)
        else:
            self._aspect_body = current_posture_state.body
        posture_manifest = self._aspect_body.get_provided_postures(
            surface_target=self.surface_target, concrete=True)
        posture_manifest = posture_manifest.get_constraint_version(self.sim)
        posture_state_spec = PostureStateSpec(
            posture_manifest, SlotManifest(), self._aspect_body.target
            or PostureSpecVariable.ANYTHING)
        self.body_posture_state_constraint = Constraint(
            debug_name='PostureStateManifestConstraint',
            posture_state_spec=posture_state_spec)
        if body_state_spec_only:
            self._constraints[None] = self.body_posture_state_constraint
            return
        body_slot_constraint = self._aspect_body.slot_constraint
        if not (body_slot_constraint is not None and
                (self._aspect_body.is_vehicle and current_posture_state
                 is not None) and current_posture_state.body.is_vehicle):
            body_posture_constraint = self.body_posture_state_constraint.intersect(
                body_slot_constraint)
        else:
            body_posture_constraint = self.body_posture_state_constraint
        self._constraints[None] = body_posture_constraint
        if current_posture_state is not None:
            curr_spec_carry_target = current_posture_state.get_posture_spec(
                var_map)[CARRY_INDEX][CARRY_TARGET_INDEX]
        spec_carry = posture_spec[CARRY_INDEX]
        spec_carry_target = spec_carry[CARRY_TARGET_INDEX]
        if current_posture_state is not None and spec_carry_target != curr_spec_carry_target:
            if spec_carry_target is None:
                current_carry_target = var_map.get(curr_spec_carry_target)
                current_carry_track = current_posture_state.get_carry_track(
                    current_carry_target)
                if current_carry_track == PostureTrack.RIGHT:
                    self._aspect_carry_right = _get_default_carry_aspect(
                        PostureTrack.RIGHT)
                    self._aspect_carry_left = current_posture_state.left
                else:
                    self._aspect_carry_left = _get_default_carry_aspect(
                        PostureTrack.LEFT)
                    self._aspect_carry_right = current_posture_state.right
            else:
                spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
                if spec_carry_target not in var_map:
                    raise KeyError(
                        'spec_carry_target {} not in var_map:{}. Sim posture state {} and carry aspects {}, '
                        .format(spec_carry_target, var_map,
                                current_posture_state,
                                current_posture_state.carry_aspects))
                if spec_carry_posture_type not in var_map:
                    carry_target = var_map[spec_carry_target]
                    aop = posture_specs.get_carry_posture_aop(
                        sim, carry_target)
                    if aop is None:
                        raise RuntimeError(
                            'Sim {} failed to find carry posture aop for carry target {}.'
                            .format(sim, carry_target))
                    carry_posture_type = aop.affordance._carry_posture_type
                    if carry_posture_type is None:
                        raise KeyError
                    var_map += {
                        PostureSpecVariable.POSTURE_TYPE_CARRY_OBJECT:
                        carry_posture_type
                    }
                carry_target = var_map[spec_carry_target]
                carry_posture_type = var_map[spec_carry_posture_type]
                if spec_carry[CARRY_HAND_INDEX] in var_map:
                    hand = var_map[spec_carry[CARRY_HAND_INDEX]]
                else:
                    for hand in sim.posture_state.get_free_hands():
                        if hand in carry_target.get_allowed_hands(sim):
                            break
                    else:
                        raise RuntimeError('No allowable free hand was empty.')
                new_carry_aspect = postures.create_posture(
                    carry_posture_type,
                    self.sim,
                    carry_target,
                    track=hand_to_track(hand),
                    is_throwaway=is_throwaway)
                if hand == Hand.LEFT:
                    self._aspect_carry_left = new_carry_aspect
                    if current_posture_state is not None:
                        self._aspect_carry_right = current_posture_state.right
                    else:
                        self._aspect_carry_right = _get_default_carry_aspect(
                            PostureTrack.RIGHT)
                elif hand == Hand.RIGHT:
                    self._aspect_carry_right = new_carry_aspect
                    if current_posture_state is not None:
                        self._aspect_carry_left = current_posture_state.left
                    else:
                        self._aspect_carry_right = _get_default_carry_aspect(
                            PostureTrack.LEFT)
                else:
                    raise RuntimeError(
                        'Invalid value specified for hand: {}'.format(hand))
        elif current_posture_state is not None:
            self._aspect_carry_left = current_posture_state.left
            self._aspect_carry_right = current_posture_state.right
        elif spec_carry_target is not None:
            carry_target = var_map[spec_carry_target]
            spec_carry_posture_type = spec_carry[CARRY_POSTURE_TYPE_INDEX]
            carry_posture_type = var_map.get(spec_carry_posture_type)
            if carry_posture_type is None:
                aop = get_carry_posture_aop(sim, carry_target)
                if aop is None and invalid_expected:
                    return
                carry_posture_type = aop.affordance._carry_posture_type
            if spec_carry[CARRY_HAND_INDEX] in var_map:
                hand = var_map[spec_carry[CARRY_HAND_INDEX]]
            else:
                allowed_hands = carry_target.get_allowed_hands(sim)
                hand = allowed_hands[0]
            new_carry_aspect = postures.create_posture(
                carry_posture_type,
                self.sim,
                carry_target,
                track=hand_to_track(hand),
                is_throwaway=is_throwaway)
            if hand == Hand.LEFT:
                self._aspect_carry_left = new_carry_aspect
                self._aspect_carry_right = _get_default_carry_aspect(
                    PostureTrack.RIGHT)
            else:
                self._aspect_carry_right = new_carry_aspect
                self._aspect_carry_left = _get_default_carry_aspect(
                    PostureTrack.LEFT)
        else:
            self._aspect_carry_left = _get_default_carry_aspect(
                PostureTrack.LEFT)
            self._aspect_carry_right = _get_default_carry_aspect(
                PostureTrack.RIGHT)

    def __repr__(self):
        return standard_repr(self, *self.aspects)

    @property
    def valid(self):
        return self._valid and bool(self.constraint_intersection)

    @property
    def spec(self):
        return self._spec

    def get_posture_spec(self, var_map):
        if not var_map:
            return self._spec.clone()
        carry_target = var_map.get(PostureSpecVariable.CARRY_TARGET)
        if carry_target is not None and carry_target.definition is not carry_target:
            carry_posture = self.get_carry_posture(carry_target)
        else:
            carry_posture = None
        if carry_posture is not None:
            if PostureSpecVariable.HAND in var_map:
                required_hand = track_to_hand(carry_posture.track)
                if required_hand != var_map[PostureSpecVariable.HAND]:
                    return
            source_carry = PostureAspectCarry(
                (PostureSpecVariable.POSTURE_TYPE_CARRY_OBJECT,
                 PostureSpecVariable.CARRY_TARGET, PostureSpecVariable.HAND))
        else:
            source_carry = PostureAspectCarry(
                (PostureSpecVariable.POSTURE_TYPE_CARRY_NOTHING, None,
                 PostureSpecVariable.HAND))
        surface_spec = self._spec[SURFACE_INDEX]
        surface_target = surface_spec[SURFACE_TARGET_INDEX]
        if surface_target is not None:
            var_map_surface_target = var_map.get(
                PostureSpecVariable.SURFACE_TARGET, None)
            if var_map_surface_target is None or surface_target == var_map_surface_target:
                if carry_target is not None and carry_posture is None and carry_target.definition is not carry_target:
                    surface_spec = PostureAspectSurface(
                        (surface_target, PostureSpecVariable.SLOT,
                         PostureSpecVariable.CARRY_TARGET))
                    spec = self._spec.clone(carry=source_carry,
                                            surface=surface_spec)
                    if spec._validate_surface(
                            var_map) and carry_target.parent is surface_target:
                        return spec
                interaction_target = var_map.get(
                    PostureSpecVariable.INTERACTION_TARGET,
                    PostureSpecVariable.INTERACTION_TARGET)
                if interaction_target is not None:
                    surface_spec = PostureAspectSurface(
                        (surface_target, PostureSpecVariable.SLOT,
                         PostureSpecVariable.SLOT_TARGET))
                    spec = self._spec.clone(carry=source_carry,
                                            surface=surface_spec)
                    if spec._validate_surface(var_map) and not isinstance(
                            interaction_target, PostureSpecVariable
                    ) and interaction_target.parent is surface_target:
                        return spec
                surface_spec = PostureAspectSurface(
                    (surface_target, PostureSpecVariable.SLOT, None))
                spec = self._spec.clone(carry=source_carry,
                                        surface=surface_spec)
                if spec._validate_surface(var_map):
                    return spec
            surface_spec = PostureAspectSurface((surface_target, None, None))
            spec = self._spec.clone(carry=source_carry, surface=surface_spec)
            if spec._validate_surface(var_map):
                return spec
            else:
                surface_spec = PostureAspectSurface((None, None, None))
                spec = self._spec.clone(carry=source_carry,
                                        surface=surface_spec)
                if spec._validate_surface(var_map):
                    return spec
        else:
            surface_spec = PostureAspectSurface((None, None, None))
            spec = self._spec.clone(carry=source_carry, surface=surface_spec)
            if spec._validate_surface(var_map):
                return spec

    def _get_posture_constraint(self, strict=False):
        posture_state_constraint = self.body_posture_state_constraint
        posture_state_constraint = posture_state_constraint.get_holster_version(
        )
        if posture_state_constraint.valid:
            if not self.body_state_spec_only:
                carry_left_constraint = create_carry_constraint(
                    self.left.target, Hand.LEFT, strict=strict)
                posture_state_constraint = posture_state_constraint.intersect(
                    carry_left_constraint)
                if posture_state_constraint.valid:
                    carry_right_constraint = create_carry_constraint(
                        self.right.target, Hand.RIGHT, strict=strict)
                    posture_state_constraint = posture_state_constraint.intersect(
                        carry_right_constraint)
        return posture_state_constraint

    @property
    def posture_constraint(self):
        if self._posture_constraint is None:
            self._posture_constraint = self._get_posture_constraint()
        return self._posture_constraint

    @property
    def posture_constraint_strict(self):
        if self._posture_constraint_strict is None:
            self._posture_constraint_strict = self._get_posture_constraint(
                strict=True)
        return self._posture_constraint_strict

    @property
    def sim(self):
        if self._sim_ref is not None:
            return self._sim_ref()

    @property
    def linked_posture_state(self):
        return self._linked_posture_state

    @linked_posture_state.setter
    def linked_posture_state(self, posture_state):
        self._set_linked_posture_state(posture_state)
        posture_state._set_linked_posture_state(self)
        self.body.linked_posture = posture_state.body

    def _set_linked_posture_state(self, posture_state):
        self._linked_posture_state = posture_state

    @property
    def body(self):
        return self._aspect_body

    @property
    def left(self):
        return self._aspect_carry_left

    @property
    def right(self):
        return self._aspect_carry_right

    @property
    def aspects(self):
        if self.body_state_spec_only:
            return ()
        return (self.body, self.left, self.right)

    @property
    def carry_aspects(self):
        return (self.left, self.right)

    @property
    def surface_target(self):
        surface = self._spec[SURFACE_INDEX][SURFACE_TARGET_INDEX]
        if (
                surface is None or self.body.mobile
        ) and self.body.target is not None and self.body.target.is_surface():
            return self.body.target
        return surface

    @property
    def carry_targets(self):
        return (self.left.target, self.right.target)

    def get_aspect(self, track):
        if track == PostureTrack.BODY:
            return self.body
        if track == PostureTrack.LEFT:
            return self.left
        elif track == PostureTrack.RIGHT:
            return self.right

    def add_constraint(self, handle, constraint):
        if not self._invalid_expected:
            if not constraint.valid:
                logger.warn(
                    'Attempt to add an invalid constraint {} to posture_state {}.',
                    constraint,
                    self,
                    owner='bhill',
                    trigger_breakpoint=True)
            test_constraint = self.constraint_intersection.intersect(
                constraint)
            if not test_constraint.valid:
                logger.warn(
                    'Attempt to add a constraint to {} which is incompatible with already-registered constraints: {} + {}.',
                    self, constraint, self.constraint_intersection)
        self._constraints[handle] = constraint
        self._constraint_intersection_dirty = True

    def remove_constraint(self, handle):
        if handle in self._constraints:
            del self._constraints[handle]
            self._constraint_intersection_dirty = True
            self._constraint_intersection = None

    @property
    def constraint_intersection(self):
        if self._constraint_intersection_dirty or self._constraint_intersection is None:
            intersection = Anywhere()
            for constraint in set(self._constraints.values()):
                new_intersection = intersection.intersect(constraint)
                if not self._invalid_expected:
                    if not new_intersection.valid:
                        indent_text = '                '
                        logger.error(
                            'Invalid constraint intersection for PostureState: {}.\n    A: {} \n    A Geometry: {}    B: {} \n    B Geometry: {}',
                            self, intersection,
                            intersection.get_geometry_text(indent_text),
                            constraint,
                            constraint.get_geometry_text(indent_text))
                        intersection = new_intersection
                        break
                intersection = new_intersection
            self._constraint_intersection_dirty = False
            self._constraint_intersection = intersection
        return self._constraint_intersection

    def compatible_with(self, constraint):
        intersection = self.constraint_intersection
        if not intersection.valid:
            return False
        else:
            intersection = constraint.intersect(intersection)
            if not intersection.valid:
                return False
        return True

    def compatible_with_pre_resolve(self, constraint):
        for constraint_existing in self._constraints.values():
            if constraint_existing is constraint:
                return True
        return self.compatible_with(constraint)

    def get_slot_info(self):
        surface = self._spec[SURFACE_INDEX]
        return (surface[SURFACE_TARGET_INDEX],
                surface[SURFACE_SLOT_TYPE_INDEX])

    def is_source_interaction(self, si):
        if si is not None:
            for aspect in self.aspects:
                if aspect.source_interaction is si:
                    return True
        return False

    def is_source_or_owning_interaction(self, si):
        return self.get_source_or_owned_posture_for_si(si) is not None

    def is_carry_source_or_owning_interaction(self, si):
        return self.get_source_or_owned_posture_for_si(
            si, carry_only=True) is not None

    def get_source_or_owned_posture_for_si(self, si, carry_only=False):
        if self.left.source_interaction is si or si in self.left.owning_interactions:
            return self.left
        if self.right.source_interaction is si or si in self.right.owning_interactions:
            return self.right
        if carry_only:
            return
        elif self.body.source_interaction is si or si in self.body.owning_interactions:
            return self.body

    @property
    def connectivity_handles(self):
        if self.body.target is not None:
            return self.body.target.connectivity_handles

    def kickstart_gen(self, timeline, routing_surface, target_override=None):
        for aspect in self.aspects:
            yield from aspect.kickstart_gen(timeline,
                                            self,
                                            routing_surface,
                                            target_override=target_override)
        self._valid = True

    def on_reset(self, reset_reason):
        for aspect in self.aspects:
            aspect.reset()
        self._valid = False

    def _carrying(self, track, **kwargs):
        posture = self.left if track == PostureTrack.LEFT else self.right
        return self._carrying_posture(posture, **kwargs)

    def _carrying_posture(self, posture, ignore_target=None, only_target=None):
        if posture.is_active_carry:
            if ignore_target is None and only_target is None:
                return True
            else:
                target = posture.target

                def target_is(other):
                    if target is None:
                        return False
                    if isinstance(other, Tag):
                        return target.has_tag(other)
                    if isinstance(other, int):
                        return target.definition.id == other
                    if isinstance(other, Definition):
                        return target.definition is other
                    return target is other

                if not (ignore_target is None or not target_is(ignore_target)
                        ) and (only_target is None or target_is(only_target)):
                    return True
        return False

    def get_carry_state(self, target=None, override_posture=None):
        if override_posture is not None:
            if override_posture.track == PostureTrack.LEFT:
                carry_state = (self._carrying_posture(override_posture,
                                                      ignore_target=target),
                               self._carrying(PostureTrack.RIGHT,
                                              ignore_target=target))
            else:
                carry_state = (self._carrying(PostureTrack.LEFT,
                                              ignore_target=target),
                               self._carrying_posture(override_posture,
                                                      ignore_target=target))
        else:
            carry_state = (self._carrying(PostureTrack.LEFT,
                                          ignore_target=target),
                           self._carrying(PostureTrack.RIGHT,
                                          ignore_target=target))
        return carry_state

    def get_carry_track(self, target):
        if target is None:
            return
        if self._carrying(PostureTrack.LEFT, only_target=target):
            return PostureTrack.LEFT
        elif self._carrying(PostureTrack.RIGHT, only_target=target):
            return PostureTrack.RIGHT

    def is_carrying(self, target):
        if self.get_carry_track(target) is not None:
            return True
        return False

    def get_carry_posture(self, target):
        if self.left.target is target:
            return self.left
        elif self.right.target is target:
            return self.right

    def get_posture_for_si(self, si):
        for posture in self.aspects:
            if posture is not None:
                if posture.source_interaction == si:
                    return posture

    def get_other_carry_posture(self, target):
        track = self.get_carry_track(target)
        if track is None:
            return
        else:
            if track is PostureTrack.LEFT:
                result = self.get_aspect(PostureTrack.RIGHT)
            else:
                result = self.get_aspect(PostureTrack.LEFT)
            if result is not None and result.target is not None:
                return result

    def get_free_carry_track(self, obj=None) -> PostureTrack:
        if obj is not None and obj.carryable_component is None:
            logger.error('Obj {} has no carryable component.',
                         obj,
                         owner='tastle')
            return
        if obj is None:
            allowed_hands = (Hand.RIGHT, Hand.LEFT)
        else:
            allowed_hands = obj.get_allowed_hands(self.sim)
        preferred_hand = self.sim.get_preferred_hand()
        if preferred_hand == Hand.RIGHT:
            preferred_track = PostureTrack.RIGHT
            unpreferred_track = PostureTrack.LEFT
        else:
            preferred_track = PostureTrack.LEFT
            unpreferred_track = PostureTrack.RIGHT
        if track_to_hand(
                preferred_track
        ) in allowed_hands and not self._carrying(preferred_track):
            return preferred_track
        elif track_to_hand(
                unpreferred_track
        ) in allowed_hands and not self._carrying(unpreferred_track):
            return unpreferred_track

    def get_free_hands(self):
        if not self._carrying(PostureTrack.RIGHT):
            if not self._carrying(PostureTrack.LEFT):
                return (Hand.RIGHT, Hand.LEFT)
            return (Hand.RIGHT, )
        elif not self._carrying(PostureTrack.LEFT):
            return (Hand.LEFT, )
        return ()