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')
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 ()
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