Example #1
0
 def __init__(self, sim, source, priority, run_priority=None, client=None, pick=None, insert_strategy=QueueInsertStrategy.LAST, must_run_next=False, continuation_id=None, group_id=None, shift_held=False, carry_target=None, create_target_override=None, target_sim_id=None, bucket=InteractionBucketType.BASED_ON_SOURCE, visual_continuation_id=None, restored_from_load=False, cancel_if_incompatible_in_queue=False, always_check_in_use=False, source_interaction_id=None, source_interaction_sim_id=None, preferred_objects=(), preferred_carrying_sim=None, can_derail_if_constraint_invalid=True):
     self._sim = sim.ref() if sim else None
     self.source = source
     self.priority = priority
     self.client = client
     self.pick = pick
     self.insert_strategy = insert_strategy
     self.must_run_next = must_run_next
     self.shift_held = shift_held
     self.continuation_id = continuation_id
     self.visual_continuation_id = visual_continuation_id
     self.group_id = group_id
     self.source_interaction_id = source_interaction_id
     self.source_interaction_sim_id = source_interaction_sim_id
     self.carry_target = carry_target
     self.create_target_override = create_target_override
     self.target_sim_id = target_sim_id
     self.run_priority = run_priority
     self.bucket = bucket
     self.restored_from_load = restored_from_load
     self.cancel_if_incompatible_in_queue = cancel_if_incompatible_in_queue
     self.always_check_in_use = always_check_in_use
     self.preferred_objects = WeakSet(preferred_objects)
     self._preferred_carrying_sim = preferred_carrying_sim.ref() if preferred_carrying_sim is not None else None
     self.can_derail_if_constraint_invalid = can_derail_if_constraint_invalid
Example #2
0
    class Identity(object):
        """
        Identities are abstract persons which persist throughout several sessions.
        They can be associated to several avatars.

        The `link` method adds an avatar to its available representation.

        Avatars are automatically removed when all references are lost due the
        reference's weakness.
        """

        __metaclass__ = MultitonMeta

        def __init__(self, docid):
            self.docid = docid.encode('latin-1')
            self.avatars = WeakSet()

        def link(self, avatar):
            if avatar.identity not in (None, self):
                raise ValueError("double link from %r to %r and %r" %
                        (avatar, self, avatar.identity))
            service.dispatch_event("login", self, avatar)
            self.avatars.add(avatar)
            avatar.identity = self
            return self

        def fetch(self):
            return service.davenport.openDoc(self.docid)
Example #3
0
    def __init__(self,
                 src: CodeFragment,
                 begin: int = 0,
                 end: int = 0,
                 offset: int = 0) -> None:
        """
        Generates a new code fragment-view backed by another code fragment.

        :param src: the assembly code fragment of which the new fragment will constitute a view
        :param begin: line number of the first line contained in the new fragment
        :param end: line number of the first line following the last contained in the new fragment
        :param offset: offset of the view inside the origin fragment
        :raises ValueError: when the fragment size would not fit inside the origin fragment
        """

        # Delegate consistency checks
        super().__init__(src, begin, end, offset)
        self._origin = src
        self._begin = begin
        self._end = end
        self._offset = offset

        if src not in FragmentView._sources_catalogue:
            # If this source fragment has never been seen before, add it to the shared catalogue and allocate the views
            # catalogue
            self._views_catalogue = WeakSet()
            FragmentView._sources_catalogue[src] = self._views_catalogue
        else:
            # Otherwise, set the local reference to the views catalogue associated with the provided source
            self._views_catalogue = FragmentView._sources_catalogue[src]

        # Add the new view's metadata to the catalogue
        self._views_catalogue.add(self)
Example #4
0
 def add_reservation_handler(self, reservation_handler):
     if isinstance(self._reservation_handlers, tuple):
         self._reservation_handlers = WeakSet()
     self._reservation_handlers.add(reservation_handler)
     if self._on_reservation_handlers_changed:
         self._on_reservation_handlers_changed(user=reservation_handler.sim,
                                               added=True)
Example #5
0
 def __new__(mcls, name, bases, namespace, **kwargs):
     cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace,
                                        **kwargs)
     # Compute set of abstract method names
     abstracts = {
         name
         for name, value in namespace.items()
         if getattr(value, "__isabstractmethod__", False)
     }
     samplermixins = {
         name
         for name, value in namespace.items()
         if getattr(value, "__issamplemixin__", False)
     }
     if len(samplermixins) == 3:
         abstracts.update(samplermixins)
     for base in bases:
         for name in getattr(base, "__abstractmethods__", set()):
             value = getattr(cls, name, None)
             if getattr(value, "__isabstractmethod__", False):
                 abstracts.add(name)
         samplermixins = {
             name
             for name in getattr(base, "__abstractmethods__", set()) if
             getattr(getattr(cls, name, None), "__issamplemixin__", False)
         }
         if len(samplermixins) == 3:
             abstracts.update(samplermixins)
     cls.__abstractmethods__ = frozenset(abstracts)
     # Set up inheritance registry
     cls._abc_registry = WeakSet()
     cls._abc_cache = WeakSet()
     cls._abc_negative_cache = WeakSet()
     cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
     return cls
Example #6
0
 def __init__(self, sim, target, reserver, all_parts=False):
     self._sim = sim
     self._target = target.ref()
     self._reserver = reserver
     self._registered = False
     self._all_parts = all_parts
     self._reserved_objects = WeakSet()
Example #7
0
 def __init__(self, *args, source_liability=None, **kwargs):
     super().__init__(**kwargs)
     self._released = False
     if source_liability is None:
         self._shared_liability_refs = WeakSet()
     else:
         self._shared_liability_refs = source_liability._shared_liability_refs
     self._shared_liability_refs.add(self)
 def reevaluate_all_privacy_instances():
     for privacy in services.privacy_service().privacy_instances:
         privacy._allowed_sims = WeakSet()
         privacy._disallowed_sims = WeakSet()
         privacy._violators = WeakSet()
         privacy._late_violators = WeakSet()
         for sim in TurboManagerUtil.Sim.get_all_sim_instance_gen(
                 humans=True, pets=False):
             privacy.handle_late_violator(sim)
Example #9
0
    def __init__(self, parent, loggingLevel=logging.INFO):
        super(Subject, self).__init__()

        self._logger = logging.getLogger("[OBSERVER {} ({})]".format(
            parent.__class__.__name__.upper(), id(parent)))
        self._logger.setLevel(loggingLevel)

        self.parent = parent
        self._observers_lock = RLock()
        self._observers = WeakSet()
Example #10
0
 def _get_all_objects_gen(self):
     if any(broadcaster.allow_objects
            for broadcaster in self._active_broadcasters):
         if self._object_cache is None:
             self._object_cache = WeakSet(
                 services.object_manager().valid_objects())
         yield list(self._object_cache)
     else:
         self._object_cache = None
         yield services.sim_info_manager().instanced_sims_gen()
 def __init__(self, aop, context, **kwargs):
     super().__init__(aop, context, **kwargs)
     self.from_zone_id = kwargs['from_zone_id']
     self.to_zone_id = kwargs['to_zone_id']
     self.on_complete_callback = kwargs['on_complete_callback']
     self.on_complete_context = kwargs['on_complete_context']
     self._care_dependents = WeakSet()
     self._care_dependent_required = None
     if self.travel_care_dependents:
         self._find_care_dependents(context)
Example #12
0
 def _find_hamper_and_laundry_objects(self):
     object_manager = services.object_manager()
     self._laundry_hero_objects = WeakSet(
         object_manager.get_objects_with_tags_gen(
             *LaundryTuning.LAUNDRY_HERO_OBJECT_TAGS))
     if self._affected_household is None:
         return
     self._hampers = WeakSet(
         object_manager.get_objects_with_tags_gen(
             *LaundryTuning.HAMPER_OBJECT_TAGS))
Example #13
0
 def __init__(self, type, source, destination, save_id=None):
     self.__type = type
     self.__data = type.ufl_type.build_default(None)
     self.__source = ref(source)
     self.__destination = ref(destination)
     self.__visuals = WeakSet()
     self.__cache = ModelTemporaryDataCache(None)
     if save_id is None:
         self.__save_id = uuid4()
     else:
         self.__save_id = save_id
Example #14
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self._enabled = True
     self._processing = False
     self._reset_in_progress = False
     self._last_work_timestamps = {}
     self._sims = set()
     self._active_work = {}
     self._denied_sims = OrderedDict()
     self._global_required_resources = WeakSet()
     self._gsi_entry = None
     self._gsi_log_entries = None
Example #15
0
    def __init__(self, name, poolSize=4, loggingLevel=logging.INFO):
        super(WorkerPool, self).__init__()

        self._logger = logging.getLogger("[WORKER POOL - {}]".format(
            name.upper()))
        self._logger.setLevel(loggingLevel)

        self._name = name
        self._isRunning = False

        self._tasksQueue = FIFOPriorityQueue()
        self._canceledTasks = WeakSet()
        self._workers = [PoolWorker(self) for _ in range(poolSize)]
class LightingLiability(Liability, HasTunableFactory, AutoFactoryInit):
    LIABILITY_TOKEN = 'LightingLiability'
    FACTORY_TUNABLES = {'radius_squared': TunableDistanceSquared(description='\n            The distance away from the specified participant that lights will\n            be turned off.\n            ', default=1, display_name='Radius'), 'participant': TunableEnumEntry(description='\n            The participant of the interaction that we will be used as the\n            center of the radius to turn lights off.\n            ', tunable_type=ParticipantType, default=ParticipantType.Actor)}

    def __init__(self, interaction, **kwargs):
        super().__init__(**kwargs)
        self._interaction = interaction
        self._lights = WeakSet()
        self._automated_lights = WeakSet()

    def on_run(self):
        if self._lights:
            return
        participant = self._interaction.get_participant(self.participant)
        position = participant.position
        for obj in services.object_manager().get_all_objects_with_component_gen(objects.components.types.LIGHTING_COMPONENT):
            if get_object_has_tag(obj.definition.id, LightingComponent.MANUAL_LIGHT_TAG):
                continue
            distance_from_pos = obj.position - position
            if distance_from_pos.magnitude_squared() > self.radius_squared:
                continue
            if obj.get_light_dimmer_value() == LightingComponent.LIGHT_AUTOMATION_DIMMER_VALUE:
                self._automated_lights.add(obj)
            else:
                self._lights.add(obj)
            obj.set_light_dimmer_value(LightingComponent.LIGHT_DIMMER_VALUE_OFF)

    def release(self):
        for obj in self._lights:
            obj.set_light_dimmer_value(LightingComponent.LIGHT_DIMMER_VALUE_MAX_INTENSITY)
        self._lights.clear()
        for obj in self._automated_lights:
            obj.set_light_dimmer_value(LightingComponent.LIGHT_AUTOMATION_DIMMER_VALUE)
        self._automated_lights.clear()
Example #17
0
    def __new__(mcls, name, bases, namespace):
        cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace)
        # Compute set of abstract method names
        abstracts = {
            name
            for name, value in namespace.items()
            if getattr(value, "__isabstractmethod__", False)
        }
        # old
        ##        for base in bases:
        ##            for name in getattr(base, "__abstractmethods__", set()):
        ##                value = getattr(cls, name, None)
        ##                if getattr(value, "__isabstractmethod__", False):
        ##                    abstracts.add(name)
        # begin new
        names = set().union(*(getattr(base, "__abstractmethods__", set())
                              for base in bases))
        names -= set(abstracts)
        if 0:
            d = ChainMap(*map(vars, cls.__mro__))
            for name in names:
                # get decorator first; then attr
                value = d.get(name, None)
                if not getattr(value, "__isabstractmethod__", False):
                    # get attr
                    if hasattr(value, "__get__"):
                        value = getattr(cls, name)
                if getattr(value, "__isabstractmethod__", False):
                    abstracts.add(name)
        else:
            for name in names:
                # get decorator first; then attr
                value = getattr_static(cls, name, None)
                if not getattr(value, "__isabstractmethod__", False):
                    # get attr
                    if hasattr(value, "__get__"):
                        value = getattr(cls, name)
                if getattr(value, "__isabstractmethod__", False):
                    abstracts.add(name)

        # end new

        cls.__abstractmethods__ = frozenset(abstracts)
        # Set up inheritance registry
        cls._abc_registry = WeakSet()
        cls._abc_cache = WeakSet()
        cls._abc_negative_cache = WeakSet()
        cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
        return cls
Example #18
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self._crafting_cache = CraftingObjectCache()
     self._sim_spawn_conditions = collections.defaultdict(set)
     self._water_terrain_object_cache = WaterTerrainObjectCache()
     self._client_connect_callbacks = CallableList()
     self._portal_cache = WeakSet()
     self._portal_added_callbacks = CallableList()
     self._portal_removed_callbacks = CallableList()
     self._front_door_candidates_changed_callback = CallableList()
     self._all_bed_tags = self.BED_TAGS.beds | self.BED_TAGS.double_beds | self.BED_TAGS.kid_beds | self.BED_TAGS.other_sleeping_spots
     self._tag_to_object_list = defaultdict(set)
     self._whim_set_cache = Counter()
     self._posture_providing_object_cache = None
     self._objects_to_ignore_portal_validation_cache = []
Example #19
0
    def __new__(mcls, name, bases, namespace):
        cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace)
        abstracts = set((name for name, value in namespace.items() if getattr(value, '__isabstractmethod__', False)))
        for base in bases:
            for name in getattr(base, '__abstractmethods__', set()):
                value = getattr(cls, name, None)
                if getattr(value, '__isabstractmethod__', False):
                    abstracts.add(name)

        cls.__abstractmethods__ = frozenset(abstracts)
        cls._abc_registry = WeakSet()
        cls._abc_cache = WeakSet()
        cls._abc_negative_cache = WeakSet()
        cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
        return cls
Example #20
0
 def __init__(self, interaction, tests, max_line_of_sight_radius, map_divisions, simplification_ratio, boundary_epsilon, facing_offset):
     super().__init__(max_line_of_sight_radius, map_divisions, simplification_ratio, boundary_epsilon)
     self._max_line_of_sight_radius = max_line_of_sight_radius
     self._interaction = interaction
     self._tests = tests
     self._privacy_constraints = []
     self._allowed_sims = WeakSet()
     self._disallowed_sims = WeakSet()
     self._violators = WeakSet()
     self._late_violators = WeakSet()
     self.is_active = False
     self.has_shooed = False
     self.central_object = None
     self._pushed_interactions = []
     services.privacy_service().add_instance(self)
Example #21
0
 def children(self):
     if self._children_cache is None:
         self._children_cache = WeakSet()
         for child in self.part_owner.children:
             if self.has_slot(child.location.slot_hash
                              or child.location.joint_name_hash):
                 self._children_cache.add(child)
             elif self.part_owner.has_slot(
                     child.location.slot_hash
                     or child.location.joint_name_hash):
                 if child.parts is not None:
                     for part in child.parts:
                         if part.attempt_to_remap_parent(
                                 part.location.parent) == self:
                             self._children_cache.add(part)
     return self._children_cache
Example #22
0
 def _update_season_aware_objects_gen(self, timeline):
     for season_aware_object in WeakSet(
             services.object_manager().get_all_objects_with_component_gen(
                 SEASON_AWARE_COMPONENT)):
         yield timeline.run_child(elements.SleepElement(TimeSpan.ZERO))
         season_aware_object.season_aware_component.on_season_set(
             self.season)
Example #23
0
    def __subclasscheck__(cls, subclass):
        """Override for issubclass(subclass, cls)."""
        if subclass in cls._abc_cache:
            return True
        if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
            cls._abc_negative_cache = WeakSet()
            cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
        elif subclass in cls._abc_negative_cache:
            return False
        ok = cls.__subclasshook__(subclass)
        if ok is not NotImplemented:
            if not isinstance(ok, bool):
                raise AssertionError
                if ok:
                    cls._abc_cache.add(subclass)
                else:
                    cls._abc_negative_cache.add(subclass)
                return ok
            cls in getattr(subclass, '__mro__',
                           ()) and cls._abc_cache.add(subclass)
            return True
        for rcls in cls._abc_registry:
            if issubclass(subclass, rcls):
                cls._abc_cache.add(subclass)
                return True

        for scls in cls.__subclasses__():
            if issubclass(subclass, scls):
                cls._abc_cache.add(subclass)
                return True

        cls._abc_negative_cache.add(subclass)
        return False
Example #24
0
 def __init__(self, definition, **kwargs):
     self._ui_metadata_stack = []
     self._ui_metadata_handles = {}
     self._ui_metadata_cache = {}
     super().__init__(definition, **kwargs)
     if definition is not None:
         self.apply_definition(definition, **kwargs)
     self.primitives = distributor.ops.DistributionSet(self)
     self._location = sims4.math.Location(
         sims4.math.Transform(),
         routing.SurfaceIdentifier(sims4.zone_utils.get_zone_id(), 0,
                                   routing.SURFACETYPE_WORLD))
     self._children = WeakSet()
     self._occupied_slot_dict = {}
     self._scale = 1
     self._parent_type = ObjectParentType.PARENT_NONE
     self._parent_location = 0
     self._build_buy_lockout = False
     self._build_buy_lockout_alarm_handler = None
     self._tint = None
     self._opacity = None
     self._censor_state = None
     self._geometry_state = None
     self._visibility = None
     self._material_state = None
     self._reference_arb = None
     self._audio_effects = {}
     self._video_playlist = None
     self._painting_state = None
     self._current_value = definition.price
     self._needs_post_bb_fixup = False
     self._needs_depreciation = False
     self._fade_out_alarm_handle = None
Example #25
0
    def __subclasscheck__(cls, subclass):
        if subclass in cls._abc_cache:
            return True
        if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
            cls._abc_negative_cache = WeakSet()
            cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
        elif subclass in cls._abc_negative_cache:
            return False
        ok = cls.__subclasshook__(subclass)
        if ok is not NotImplemented:
            if ok:
                cls._abc_cache.add(subclass)
            else:
                cls._abc_negative_cache.add(subclass)
            return ok
        if cls in getattr(subclass, '__mro__', ()):
            cls._abc_cache.add(subclass)
            return True
        for rcls in cls._abc_registry:
            if issubclass(subclass, rcls):
                cls._abc_cache.add(subclass)
                return True

        for scls in cls.__subclasses__():
            if issubclass(subclass, scls):
                cls._abc_cache.add(subclass)
                return True

        cls._abc_negative_cache.add(subclass)
        return False
Example #26
0
 def __init__(self,
              inventory_type,
              item_location,
              max_size=None,
              allow_compaction=True,
              allow_ui=True,
              hidden_storage=False):
     self._objects = {}
     self._owners = WeakSet()
     self._inventory_type = inventory_type
     self._item_location = item_location
     self._max_size = max_size
     self._allow_compaction = allow_compaction
     self._allow_ui = allow_ui
     self._hidden_storage = hidden_storage
     self._stacks_with_options_counter = None
Example #27
0
 def __new__(mcls, name, bases, namespace):
     cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace)
     # Compute set of abstract method names
     abstracts = set(name for name, value in list(namespace.items())
                     if getattr(value, "__isabstractmethod__", False))
     for base in bases:
         for name in getattr(base, "__abstractmethods__", set()):
             value = getattr(cls, name, None)
             if getattr(value, "__isabstractmethod__", False):
                 abstracts.add(name)
     cls.__abstractmethods__ = frozenset(abstracts)
     # Set up inheritance registry
     cls._abc_registry = WeakSet()
     cls._abc_cache = WeakSet()
     cls._abc_negative_cache = WeakSet()
     cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
     return cls
 def _get_all_objects_gen(self):
     if any(broadcaster.allow_objects for broadcaster in self._active_broadcasters):
         if self._object_cache is None:
             self._object_cache = WeakSet(services.object_manager().valid_objects())
         yield list(self._object_cache)
     else:
         self._object_cache = None
         yield services.sim_info_manager().instanced_sims_gen()
Example #29
0
 def children(self):
     if self._children_cache is None:
         self._children_cache = WeakSet({
             child
             for child in self.part_owner.children if self.has_slot(
                 child.location.slot_hash or child.location.joint_name_hash)
         })
     return self._children_cache
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     self._crafting_cache = CraftingObjectCache()
     self._sim_spawn_conditions = collections.defaultdict(set)
     self._client_connect_callbacks = CallableList()
     self._portal_cache = WeakSet()
     self._portal_added_callbacks = CallableList()
     self._portal_removed_callbacks = CallableList()
     self._front_door_candidates_changed_callback = CallableList()
     self._all_bed_tags = self.BED_TAGS.beds | self.BED_TAGS.double_beds | self.BED_TAGS.kid_beds | self.BED_TAGS.other_sleeping_spots
Example #31
0
 def __init__(self, session_id, account, household_id):
     self.id = session_id
     self.manager = None
     self._account = account
     self._household_id = household_id
     self._choice_menu = None
     self._interaction_parameters = {}
     self.active = True
     self.zone_id = services.current_zone_id()
     self._selectable_sims = SelectableSims(self)
     self._active_sim_info = None
     self._active_sim_changed = CallableList()
     self.ui_objects = weakref.WeakSet()
     self.primitives = ()
     self._live_drag_objects = []
     self._live_drag_start_system = LiveDragLocation.INVALID
     self._live_drag_is_stack = False
     self._live_drag_sell_dialog_active = False
     self.objects_moved_via_live_drag = WeakSet()
class AttractorManagerMixin:
    ATTRACTOR_OBJECT_TAGS = TunableSet(description='\n        One or more tags that indicate an object is a type of attractor point.\n        We use attractor points to push Sims near things and reference specific\n        geography in the world.\n        ', tunable=TunableEnumWithFilter(description='\n            A specific tag.\n            ', tunable_type=tag.Tag, default=tag.Tag.INVALID, invalid_enums=(tag.Tag.INVALID,), filter_prefixes=('AtPo',)))
    SPAWN_POINT_ATTRACTORS = TunableMapping(description='\n        Mapping from spawn point tags to attractor objects so we can create\n        attractor points at spawn points.\n        ', key_type=TunableEnumEntry(description='\n            The tag on the spawn point.\n            ', tunable_type=tag.Tag, default=tag.Tag.INVALID, invalid_enums=(tag.Tag.INVALID,)), key_name='spawn point tag', value_type=TunableReference(description='\n            The object we want to create on the Spawn Point.\n            ', manager=services.definition_manager(), pack_safe=True), value_name='attractor point definition')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._dynamic_attractor_ids = WeakSet()

    def create_dynamic_attractor_object(self, definition_id, location, tags_to_add=None):
        tags_to_add = set() if tags_to_add is None else tags_to_add

        def setup_obj(obj):
            obj.append_tags(tags_to_add)
            obj.location = location
            obj.persistence_group = PersistenceGroups.NONE

        created_obj = objects.system.create_object(definition_id, init=setup_obj)
        self._dynamic_attractor_ids.add(created_obj)
        if not self.ATTRACTOR_OBJECT_TAGS.intersection(created_obj.get_tags()):
            logger.warn('Attractor object does not have any tags in the ATTRACTOR OBJECT TAGS list. We need to be able to locate attractor objects and keep track of them.')
        return created_obj

    def destroy_dynamic_attractor_object(self, object_id):
        obj_to_destroy = self.get(object_id)
        if obj_to_destroy is None:
            logger.error('Object {} is not a dynamic attractor point.', object_id)
            return
        self._dynamic_attractor_ids.discard(obj_to_destroy)
        obj_to_destroy.destroy(obj_to_destroy, cause='Destroying Dynamic Attractor Point')

    def get_attractor_objects(self):
        return self.get_objects_matching_tags(AttractorManagerMixin.ATTRACTOR_OBJECT_TAGS)

    def create_spawn_point_attractor(self, spawn_point):
        obj_ids = set()
        for (spawn_point_tag, attractor_definition) in self.SPAWN_POINT_ATTRACTORS.items():
            tags = spawn_point.get_tags()
            if spawn_point_tag in tags:
                location = sims4.math.Location(transform=spawn_point.get_approximate_transform(), routing_surface=spawn_point.routing_surface)
                obj = self.create_dynamic_attractor_object(attractor_definition, location, tags_to_add={spawn_point_tag})
                obj_ids.add(obj.id)
        return frozenset(obj_ids)
class ABCMeta(type):
    """Metaclass for defining Abstract Base Classes (ABCs).

    Use this metaclass to create an ABC.  An ABC can be subclassed
    directly, and then acts as a mix-in class.  You can also register
    unrelated concrete classes (even built-in classes) and unrelated
    ABCs as 'virtual subclasses' -- these and their descendants will
    be considered subclasses of the registering ABC by the built-in
    issubclass() function, but the registering ABC won't show up in
    their MRO (Method Resolution Order) nor will method
    implementations defined by the registering ABC be callable (not
    even via super()).
    """

    # A global counter that is incremented each time a class is
    # registered as a virtual subclass of anything.  It forces the
    # negative cache to be cleared before its next use.
    # Note: this counter is private. Use `abc.get_cache_token()` for
    #       external code.
    _abc_invalidation_counter = 0

    def __new__(mcls, name, bases, namespace, /, **kwargs):
        cls = super().__new__(mcls, name, bases, namespace, **kwargs)
        # Compute set of abstract method names
        abstracts = {
            name
            for name, value in namespace.items()
            if getattr(value, "__isabstractmethod__", False)
        }
        for base in bases:
            for name in getattr(base, "__abstractmethods__", set()):
                value = getattr(cls, name, None)
                if getattr(value, "__isabstractmethod__", False):
                    abstracts.add(name)
        cls.__abstractmethods__ = frozenset(abstracts)
        # Set up inheritance registry
        cls._abc_registry = WeakSet()
        cls._abc_cache = WeakSet()
        cls._abc_negative_cache = WeakSet()
        cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
        return cls
Example #34
0
	def testWorkersDontStartRunningUntilToldTo(self):
		queue = FIFOPriorityQueue()
		canceledSet = WeakSet()
		poolWorker = PoolWorker(queue, canceledSet)

		self.assertFalse(poolWorker.isAlive())

		poolWorker.start()

		self.assertTrue(poolWorker.isAlive())

		queue.put((1, PoolWorker.STOP_TASK))
Example #35
0
 def __init__(self, sim, source, priority, run_priority=None, client=None, pick=None, insert_strategy=QueueInsertStrategy.LAST, must_run_next=False, continuation_id=None, group_id=None, shift_held=False, carry_target=None, target_sim_id=None, bucket=InteractionBucketType.BASED_ON_SOURCE, visual_continuation_id=None, restored_from_load=False, cancel_if_incompatible_in_queue=False, always_check_in_use=False, preferred_objects=()):
     self._sim = sim.ref() if sim else None
     self.source = source
     self.priority = priority
     self.client = client
     self.pick = pick
     self.insert_strategy = insert_strategy
     self.must_run_next = must_run_next
     self.shift_held = shift_held
     self.continuation_id = continuation_id
     self.visual_continuation_id = visual_continuation_id
     self.group_id = group_id
     self.carry_target = carry_target
     self.target_sim_id = target_sim_id
     self.run_priority = run_priority
     self.bucket = bucket
     self.restored_from_load = restored_from_load
     self.cancel_if_incompatible_in_queue = cancel_if_incompatible_in_queue
     self.always_check_in_use = always_check_in_use
     self.preferred_objects = WeakSet(preferred_objects)
Example #36
0
 def __init__(self, sim, target, track, animation_context=None):
     self._create_asm(animation_context=animation_context)
     self._source_interaction = None
     self._primitive = None
     self._owning_interactions = set()
     self._sim = None
     self._target = None
     self._target_part = None
     self._surface_target_ref = None
     self._track = None
     self._slot_constraint = UNSET
     self._context = None
     self._asm_registry = defaultdict(dict)
     self._asms_with_posture_info = set()
     self._failed_parts = set()
     self._bind(sim, target, track)
     self._linked_posture = None
     self._entry_anim_complete = False
     self._exit_anim_complete = False
     self.external_transition = False
     self._active_cancel_aops = WeakSet()
     self._saved_exit_clothing_change = None
    def __init__(self, crystalManager=None, framesToGrowth=None, startCrystals=20, *args, **kwargs):
        GameElementBase.__init__(self, *args, **kwargs)

        if self.owner is not None:
            self.owner.addStructure(self)

        self._graph = nx.Graph()
        self._elementMapping = {}

        self._fixElements = WeakSet()

        if __debug__:
            print "FRAMESTO GROWTH", framesToGrowth
        self.framesToGrowth = framesToGrowth
        self.growTimer = 0

        self._overDriveCounter = 0
        self._overdrive = False

        self._veil = None

        self._growLock = False
        self._depletedCallback = None
        self._gameOverCallback = None

        self.crystalManager = crystalManager
        if crystalManager is None:
            logging.warn("Structure {!s} has no valid CrystalManager".format(self))
        else:
            self.crystalManager.registerStructure(self)

        self._shadowWidth = util.CRYSTAL_SIZE * StructureElement.shapeOverflowFactor ** 2
        if self.owner is None:
            self._shadowColor = "000000"
        else:
            self._shadowColor = self.owner.color

        player = avg.Player.get()
        self._canvas = player.createCanvas(
            id=str(id(self)),
            size=(max(util.WINDOW_SIZE), max(util.WINDOW_SIZE)),
            handleevents=True,
            multisamplesamples=4,
        )

        self._blackCanvas = player.createCanvas(
            id=str(id(self)) + "Black",
            size=(max(util.WINDOW_SIZE), max(util.WINDOW_SIZE)),
            handleevents=True,
            multisamplesamples=4,
        )

        self._canvasRoot = self._canvas.getRootNode()

        self._blackBackground = self._blackCanvas.getRootNode()
        self._shadowImage = avg.ImageNode(
            href="canvas:{}Black".format(id(self)),
            parent=self._root,
            size=(max(util.WINDOW_SIZE), max(util.WINDOW_SIZE)),
            opacity=0.4,
        )
        util.centerNodeOnPosition(self._shadowImage, (0, 0))
        self._graphVisRoot = avg.DivNode(parent=self._canvasRoot)

        self._image = avg.ImageNode(
            href="canvas:{}".format(id(self)), parent=self._root, size=(max(util.WINDOW_SIZE), max(util.WINDOW_SIZE))
        )
        util.centerNodeOnPosition(self._image, (0, 0))
        self._edgeNodes = dict()
        self._shadowNodes = dict()

        self._initStructureCore()

        assert self.checkSanity()

        while len(self._graph) < startCrystals:
            self.growSimple()

        self.rotationEnabled = True
        self._tickTimer = None
        self._startTickTimer()
class ObjectManager(DistributableObjectManager):
    __qualname__ = 'ObjectManager'
    FIREMETER_DISPOSABLE_OBJECT_CAP = Tunable(int, 5, description='Number of disposable objects a lot can have at any given moment.')
    BED_TAGS = TunableTuple(description='\n        Tags to check on an object to determine what type of bed an object is.\n        ', beds=TunableSet(description='\n            Tags that consider an object as a bed other than double beds.\n            ', tunable=TunableEnumWithFilter(tunable_type=tag.Tag, default=tag.Tag.INVALID, filter_prefixes=BED_PREFIX_FILTER)), double_beds=TunableSet(description='\n            Tags that consider an object as a double bed\n            ', tunable=TunableEnumWithFilter(tunable_type=tag.Tag, default=tag.Tag.INVALID, filter_prefixes=BED_PREFIX_FILTER)), kid_beds=TunableSet(description='\n            Tags that consider an object as a kid bed\n            ', tunable=TunableEnumWithFilter(tunable_type=tag.Tag, default=tag.Tag.INVALID, filter_prefixes=BED_PREFIX_FILTER)), other_sleeping_spots=TunableSet(description='\n            Tags that considered sleeping spots.\n            ', tunable=TunableEnumWithFilter(tunable_type=tag.Tag, default=tag.Tag.INVALID, filter_prefixes=BED_PREFIX_FILTER)))

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._crafting_cache = CraftingObjectCache()
        self._sim_spawn_conditions = collections.defaultdict(set)
        self._client_connect_callbacks = CallableList()
        self._portal_cache = WeakSet()
        self._portal_added_callbacks = CallableList()
        self._portal_removed_callbacks = CallableList()
        self._front_door_candidates_changed_callback = CallableList()
        self._all_bed_tags = self.BED_TAGS.beds | self.BED_TAGS.double_beds | self.BED_TAGS.kid_beds | self.BED_TAGS.other_sleeping_spots

    @property
    def crafting_cache(self):
        return self._crafting_cache

    def portal_cache_gen(self):
        yield self._portal_cache

    def on_client_connect(self, client):
        all_objects = list(self._objects.values())
        for game_object in all_objects:
            game_object.on_client_connect(client)

    def move_to_inventory(self, obj, inventory_manager):
        del self._objects[obj.id]
        obj.manager = inventory_manager
        inventory_manager._objects[obj.id] = obj
        if hasattr(obj, 'on_added_to_inventory'):
            obj.on_added_to_inventory()

    def add(self, obj, *args, **kwargs):
        super().add(obj, *args, **kwargs)
        if obj.objectage_component is None:
            current_zone = services.current_zone()
            current_zone.increment_object_count(obj)
            current_zone.household_manager.increment_household_object_count(obj.get_household_owner_id())

    def remove(self, obj, *args, **kwargs):
        super().remove(obj, *args, **kwargs)
        if obj.objectage_component is None:
            current_zone = services.current_zone()
            current_zone.decrement_object_count(obj)
            current_zone.household_manager.decrement_household_object_count(obj.get_household_owner_id())

    def _should_save_object_on_lot(self, obj):
        parent = obj.parent
        if parent is not None and parent.is_sim:
            if obj.can_go_in_inventory_type(InventoryType.SIM):
                return False
        return True

    def pre_save(self):
        all_objects = list(self._objects.values())
        lot = services.current_zone().lot
        for (_, inventory) in lot.get_all_object_inventories_gen():
            for game_object in inventory:
                all_objects.append(game_object)
        for game_object in all_objects:
            game_object.update_all_commodities()

    def save(self, object_list=None, zone_data=None, open_street_data=None, **kwargs):
        if object_list is None:
            return
        open_street_objects = file_serialization.ObjectList()
        total_beds = 0
        double_bed_exist = False
        kid_bed_exist = False
        alternative_sleeping_spots = 0
        for game_object in self._objects.values():
            while self._should_save_object_on_lot(game_object):
                if game_object.persistence_group == objects.persistence_groups.PersistenceGroups.OBJECT:
                    save_result = game_object.save_object(object_list.objects, ItemLocation.ON_LOT, 0)
                else:
                    if game_object.item_location == ItemLocation.ON_LOT or game_object.item_location == ItemLocation.INVALID_LOCATION:
                        item_location = ItemLocation.FROM_OPEN_STREET
                    else:
                        item_location = game_object.item_location
                    save_result = game_object.save_object(open_street_objects.objects, item_location, 0)
                if not save_result:
                    pass
                if zone_data is None:
                    pass
                def_build_buy_tags = game_object.definition.build_buy_tags
                if not def_build_buy_tags & self._all_bed_tags:
                    pass
                if def_build_buy_tags & self.BED_TAGS.double_beds:
                    double_bed_exist = True
                    total_beds += 1
                elif def_build_buy_tags & self.BED_TAGS.kid_beds:
                    total_beds += 1
                    kid_bed_exist = True
                elif def_build_buy_tags & self.BED_TAGS.other_sleeping_spots:
                    alternative_sleeping_spots += 1
                elif def_build_buy_tags & self.BED_TAGS.beds:
                    total_beds += 1
        if open_street_data is not None:
            open_street_data.objects = open_street_objects
        if zone_data is not None:
            bed_info_data = gameplay_serialization.ZoneBedInfoData()
            bed_info_data.num_beds = total_beds
            bed_info_data.double_bed_exist = double_bed_exist
            bed_info_data.kid_bed_exist = kid_bed_exist
            bed_info_data.alternative_sleeping_spots = alternative_sleeping_spots
            zone_data.gameplay_zone_data.bed_info_data = bed_info_data
        lot = services.current_zone().lot
        for (inventory_type, inventory) in lot.get_all_object_inventories_gen():
            for game_object in inventory:
                game_object.save_object(object_list.objects, ItemLocation.OBJECT_INVENTORY, inventory_type)

    def valid_objects(self):
        return [obj for obj in self._objects.values() if not obj._hidden_flags]

    def get_objects_of_type_gen(self, *definitions):
        for obj in self._objects.values():
            while any(obj.definition is d for d in definitions):
                yield obj

    def get_objects_with_tag_gen(self, tag):
        for obj in self._objects.values():
            while build_buy.get_object_has_tag(obj.definition.id, tag):
                yield obj

    def add_sim_spawn_condition(self, sim_id, callback):
        for sim in services.sim_info_manager().instanced_sims_gen():
            while sim.id == sim_id:
                logger.error('Sim {} is already in the world, cannot add the spawn condition', sim)
                return
        self._sim_spawn_conditions[sim_id].add(callback)

    def remove_sim_spawn_condition(self, sim_id, callback):
        if callback not in self._sim_spawn_conditions.get(sim_id, ()):
            logger.error('Trying to remove sim spawn condition with invalid id-callback pair ({}-{}).', sim_id, callback)
            return
        self._sim_spawn_conditions[sim_id].remove(callback)

    def trigger_sim_spawn_condition(self, sim_id):
        if sim_id in self._sim_spawn_conditions:
            for callback in self._sim_spawn_conditions[sim_id]:
                callback()
            del self._sim_spawn_conditions[sim_id]

    def register_portal_added_callback(self, callback):
        if callback not in self._portal_added_callbacks:
            self._portal_added_callbacks.append(callback)

    def unregister_portal_added_callback(self, callback):
        if callback in self._portal_added_callbacks:
            self._portal_added_callbacks.remove(callback)

    def register_portal_removed_callback(self, callback):
        if callback not in self._portal_removed_callbacks:
            self._portal_removed_callbacks.append(callback)

    def unregister_portal_removed_callback(self, callback):
        if callback in self._portal_removed_callbacks:
            self._portal_removed_callbacks.remove(callback)

    def add_portal_to_cache(self, portal):
        self._portal_cache.add(portal)
        self._portal_added_callbacks(portal)

    def remove_portal_from_cache(self, portal):
        self._portal_cache.remove(portal)
        self._portal_removed_callbacks(portal)

    def register_front_door_candidates_changed_callback(self, callback):
        if callback not in self._front_door_candidates_changed_callback:
            self._front_door_candidates_changed_callback.append(callback)

    def unregister_front_door_candidates_changed_callback(self, callback):
        if callback in self._front_door_candidates_changed_callback:
            self._front_door_candidates_changed_callback.remove(callback)

    def on_front_door_candidates_changed(self):
        self._front_door_candidates_changed_callback()

    def advertising_objects_gen(self, motives:set=DEFAULT):
        if not motives:
            return
        if motives is DEFAULT:
            for obj in self.valid_objects():
                while obj.commodity_flags:
                    yield obj
            return
        for obj in self.valid_objects():
            while obj.commodity_flags & motives:
                yield obj

    def get_all_objects_with_component_gen(self, component):
        if component is None:
            return
        for obj in self.valid_objects():
            if obj.has_component(component.instance_attr):
                yield obj
            else:
                while obj.has_component(component.class_attr):
                    yield obj

    def on_location_changed(self, obj):
        self._registered_callbacks[CallbackTypes.ON_OBJECT_LOCATION_CHANGED](obj)

    @classproperty
    def supports_parenting(self):
        return True
Example #39
0
class ReserveObjectHandler:
    __qualname__ = 'ReserveObjectHandler'
    LOCKOUT_TIME = TunableSimMinute(480, description='Number of sim minutes to lockout an in use object from autonomy.')

    def __init__(self, sim, target, reserver, all_parts=False):
        self._sim = sim
        self._target = target.ref()
        self._reserver = reserver
        self._registered = False
        self._all_parts = all_parts
        self._reserved_objects = WeakSet()

    @property
    def is_multi(self):
        return False

    def _is_valid_target(self, target):
        return True

    def get_targets(self):
        if self._target is not None:
            target = self._target()
            if not target.is_sim:
                if not self._all_parts:
                    return (target,)
                if target.is_part:
                    target = target.part_owner
                if target.parts:
                    return target.parts
                return (target,)
        return ()

    def _begin(self, element):
        if self.reserve():
            return True
        return False

    def reserve(self):
        if self._registered:
            return True
        if self.may_reserve():
            for target in self.get_targets():
                target.reserve(self._sim, self._reserver, multi=self.is_multi)
                self._reserved_objects.add(target)
            self._registered = True
            return True
        return False

    def end(self, *_, **__):
        if self._registered:
            for target in self._reserved_objects:
                target.release(self._sim, self._reserver, multi=self.is_multi)
            self._registered = False

    def may_reserve(self, *args, **kwargs):
        targets = self.get_targets()
        for target in targets:
            test_result = self._is_valid_target(target)
            if not test_result:
                return test_result
            reserve_result = target.may_reserve(self._sim, multi=self.is_multi, *args, **kwargs)
            while not reserve_result:
                return reserve_result
        return TestResult.TRUE

    def do_reserve(self, sequence=None):
        return build_critical_section_with_finally(self._begin, sequence, self.end)
class BroadcasterService(Service):
    __qualname__ = 'BroadcasterService'
    INTERVAL = TunableRealSecond(description='\n        The time between broadcaster pulses. A lower number will impact\n        performance.\n        ', default=5)
    DEFAULT_QUADTREE_RADIUS = 0.1

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._alarm_handle = None
        self._processing_task = None
        self._on_update_callbacks = CallableList()
        self._pending_broadcasters = []
        self._active_broadcasters = []
        self._cluster_requests = {}
        self._object_cache = None
        self._pending_update = False
        self._quadtrees = defaultdict(sims4.geometry.QuadTree)

    def start(self):
        self._alarm_handle = add_alarm_real_time(self, interval_in_real_seconds(self.INTERVAL), self._on_update, repeating=True, use_sleep_time=False)
        object_manager = services.object_manager()
        object_manager.register_callback(CallbackTypes.ON_OBJECT_LOCATION_CHANGED, self._update_object_cache)
        object_manager.register_callback(CallbackTypes.ON_OBJECT_ADD, self._update_object_cache)
        services.current_zone().wall_contour_update_callbacks.append(self._update_object_cache)

    def stop(self):
        if self._alarm_handle is not None:
            cancel_alarm(self._alarm_handle)
            self._alarm_handle = None
        if self._processing_task is not None:
            self._processing_task.stop()
            self._processing_task = None
        object_manager = services.object_manager()
        object_manager.unregister_callback(CallbackTypes.ON_OBJECT_LOCATION_CHANGED, self._update_object_cache)
        object_manager.unregister_callback(CallbackTypes.ON_OBJECT_ADD, self._update_object_cache)
        services.current_zone().wall_contour_update_callbacks.remove(self._update_object_cache)

    def add_broadcaster(self, broadcaster):
        if broadcaster not in self._pending_broadcasters:
            self._pending_broadcasters.append(broadcaster)
            self._on_update_callbacks()

    def remove_broadcaster(self, broadcaster):
        if broadcaster in self._pending_broadcasters:
            self._pending_broadcasters.remove(broadcaster)
        if broadcaster in self._active_broadcasters:
            self._remove_from_cluster_request(broadcaster)
            self._remove_broadcaster_from_quadtree(broadcaster)
            self._active_broadcasters.remove(broadcaster)
        broadcaster.on_removed()
        self._on_update_callbacks()

    def _activate_pending_broadcasters(self):
        for broadcaster in self._pending_broadcasters:
            self._active_broadcasters.append(broadcaster)
            self.update_cluster_request(broadcaster)
            self._update_object_cache()
        self._pending_broadcasters.clear()

    def _add_broadcaster_to_quadtree(self, broadcaster):
        self._remove_broadcaster_from_quadtree(broadcaster)
        broadcaster_quadtree = self._quadtrees[broadcaster.routing_surface.secondary_id]
        broadcaster_bounds = sims4.geometry.QtCircle(sims4.math.Vector2(broadcaster.position.x, broadcaster.position.z), self.DEFAULT_QUADTREE_RADIUS)
        broadcaster_quadtree.insert(broadcaster, broadcaster_bounds)
        return broadcaster_quadtree

    def _remove_broadcaster_from_quadtree(self, broadcaster):
        broadcaster_quadtree = broadcaster.quadtree
        if broadcaster_quadtree is not None:
            broadcaster_quadtree.remove(broadcaster)

    def update_cluster_request(self, broadcaster):
        if broadcaster not in self._active_broadcasters:
            return
        clustering_request = broadcaster.get_clustering()
        if clustering_request is None:
            return
        self._remove_from_cluster_request(broadcaster)
        cluster_request_key = (type(broadcaster), broadcaster.routing_surface.secondary_id)
        if cluster_request_key in self._cluster_requests:
            cluster_request = self._cluster_requests[cluster_request_key]
            cluster_request.set_object_dirty(broadcaster)
        else:
            cluster_quadtree = self._quadtrees[broadcaster.routing_surface.secondary_id]
            cluster_request = clustering_request(lambda : self._get_broadcasters_for_cluster_request_gen(*cluster_request_key), quadtree=cluster_quadtree)
            self._cluster_requests[cluster_request_key] = cluster_request
        quadtree = self._add_broadcaster_to_quadtree(broadcaster)
        broadcaster.on_added_to_quadtree_and_cluster_request(quadtree, cluster_request)

    def _remove_from_cluster_request(self, broadcaster):
        cluster_request = broadcaster.cluster_request
        if cluster_request is not None:
            cluster_request.set_object_dirty(broadcaster)

    def _update_object_cache(self, obj=None):
        if obj is None:
            self._object_cache = None
            return
        if self._object_cache is not None:
            self._object_cache.add(obj)

    def _is_valid_broadcaster(self, broadcaster):
        broadcasting_object = broadcaster.broadcasting_object
        if broadcasting_object is None:
            return False
        if broadcasting_object.is_in_inventory():
            return False
        if broadcasting_object.parent is not None and broadcasting_object.parent.is_sim:
            return False
        return True

    def _get_broadcasters_for_cluster_request_gen(self, broadcaster_type, broadcaster_level):
        for broadcaster in self._active_broadcasters:
            while broadcaster.guid == broadcaster_type.guid:
                if broadcaster.should_cluster() and broadcaster.routing_surface.secondary_id == broadcaster_level:
                    yield broadcaster

    def get_broadcasters_gen(self, inspect_only=False):
        for (cluster_request_key, cluster_request) in self._cluster_requests.items():
            is_cluster_dirty = cluster_request.is_dirty()
            if is_cluster_dirty:
                for broadcaster in self._get_broadcasters_for_cluster_request_gen(*cluster_request_key):
                    broadcaster.regenerate_constraint()
            while not is_cluster_dirty or not inspect_only:
                while True:
                    for cluster in cluster_request.get_clusters_gen():
                        broadcaster_iter = cluster.objects_gen()
                        master_broadcaster = next(broadcaster_iter)
                        master_broadcaster.set_linked_broadcasters(list(broadcaster_iter))
                        yield master_broadcaster
        for broadcaster in self._active_broadcasters:
            while not broadcaster.should_cluster():
                if self._is_valid_broadcaster(broadcaster):
                    yield broadcaster

    def get_pending_broadcasters_gen(self):
        yield self._pending_broadcasters

    def _get_all_objects_gen(self):
        if any(broadcaster.allow_objects for broadcaster in self._active_broadcasters):
            if self._object_cache is None:
                self._object_cache = WeakSet(services.object_manager().valid_objects())
            yield list(self._object_cache)
        else:
            self._object_cache = None
            yield services.sim_info_manager().instanced_sims_gen()

    def register_callback(self, callback):
        if callback not in self._on_update_callbacks:
            self._on_update_callbacks.append(callback)

    def unregister_callback(self, callback):
        if callback in self._on_update_callbacks:
            self._on_update_callbacks.remove(callback)

    def _on_update(self, _):
        self._pending_update = True

    def update(self):
        if self._pending_update:
            self._pending_update = False
            self._update()

    def _update(self):
        try:
            self._activate_pending_broadcasters()
            current_broadcasters = set(self.get_broadcasters_gen())
            for obj in self._get_all_objects_gen():
                is_affected = False
                for broadcaster in current_broadcasters:
                    while broadcaster.can_affect(obj):
                        constraint = broadcaster.get_constraint()
                        if not constraint.valid:
                            pass
                        if constraint.geometry is None or constraint.geometry.contains_point(obj.position) and constraint.routing_surface == obj.routing_surface:
                            broadcaster.apply_broadcaster_effect(obj)
                            is_affected = True
                while not is_affected:
                    if self._object_cache is not None:
                        self._object_cache.remove(obj)
            for broadcaster in current_broadcasters:
                broadcaster.on_processed()
        finally:
            self._on_update_callbacks()
Example #41
0
 def __init__(self, docid):
     self.docid = docid.encode('latin-1')
     self.avatars = WeakSet()
     self.service = service # closure
class BaseStructure(GameElementBase):

    neighbourhoodThreshold = 2
    REACTION_THRESHOLD = util.REACTION_THRESHOLD

    class Veil(object):
        def __init__(self, structure, time, stopCallback=None, fadeOutTime=120.0, fadeInTime=120.0):
            self._structure = structure
            self._timeToVeil = time

            self._maxFadeOutTime = fadeOutTime
            self._fadeOutTime = fadeOutTime

            self._maxFadeInTime = fadeInTime
            self._fadeInTime = fadeInTime

            self._stopCallback = stopCallback

            self._action = self._veiling

        def onTick(self):
            if self._action is not None:
                self._action()

        def _veiling(self):
            if self._fadeInTime > 0:
                self._fadeInTime -= 1
                self._setVeil(self._fadeInTime / self._maxFadeInTime)
            else:
                self._action = self._veilHolding

        def _veilHolding(self):
            if self._timeToVeil > 0:
                self._timeToVeil -= 1
                self._setVeil(0)
            else:
                self._action = self._unveiling

        def _unveiling(self):
            if self._fadeOutTime > 0:
                self._fadeOutTime -= 1
                self._setVeil(1 - (self._fadeOutTime / self._maxFadeOutTime))
            else:
                self._action = self._finished

        def _finished(self):
            self._removeVeil()
            self._stopCallback()
            self._action = None

        def _setVeil(self, value):
            fxNode = avg.HueSatFXNode(0, 100 * value - 100, 100 * value - 100, False)
            self._structure._image.setEffect(fxNode)

        def _removeVeil(self):
            self._structure._image.setEffect(None)

    def __init__(self, crystalManager=None, framesToGrowth=None, startCrystals=20, *args, **kwargs):
        GameElementBase.__init__(self, *args, **kwargs)

        if self.owner is not None:
            self.owner.addStructure(self)

        self._graph = nx.Graph()
        self._elementMapping = {}

        self._fixElements = WeakSet()

        if __debug__:
            print "FRAMESTO GROWTH", framesToGrowth
        self.framesToGrowth = framesToGrowth
        self.growTimer = 0

        self._overDriveCounter = 0
        self._overdrive = False

        self._veil = None

        self._growLock = False
        self._depletedCallback = None
        self._gameOverCallback = None

        self.crystalManager = crystalManager
        if crystalManager is None:
            logging.warn("Structure {!s} has no valid CrystalManager".format(self))
        else:
            self.crystalManager.registerStructure(self)

        self._shadowWidth = util.CRYSTAL_SIZE * StructureElement.shapeOverflowFactor ** 2
        if self.owner is None:
            self._shadowColor = "000000"
        else:
            self._shadowColor = self.owner.color

        player = avg.Player.get()
        self._canvas = player.createCanvas(
            id=str(id(self)),
            size=(max(util.WINDOW_SIZE), max(util.WINDOW_SIZE)),
            handleevents=True,
            multisamplesamples=4,
        )

        self._blackCanvas = player.createCanvas(
            id=str(id(self)) + "Black",
            size=(max(util.WINDOW_SIZE), max(util.WINDOW_SIZE)),
            handleevents=True,
            multisamplesamples=4,
        )

        self._canvasRoot = self._canvas.getRootNode()

        self._blackBackground = self._blackCanvas.getRootNode()
        self._shadowImage = avg.ImageNode(
            href="canvas:{}Black".format(id(self)),
            parent=self._root,
            size=(max(util.WINDOW_SIZE), max(util.WINDOW_SIZE)),
            opacity=0.4,
        )
        util.centerNodeOnPosition(self._shadowImage, (0, 0))
        self._graphVisRoot = avg.DivNode(parent=self._canvasRoot)

        self._image = avg.ImageNode(
            href="canvas:{}".format(id(self)), parent=self._root, size=(max(util.WINDOW_SIZE), max(util.WINDOW_SIZE))
        )
        util.centerNodeOnPosition(self._image, (0, 0))
        self._edgeNodes = dict()
        self._shadowNodes = dict()

        self._initStructureCore()

        assert self.checkSanity()

        while len(self._graph) < startCrystals:
            self.growSimple()

        self.rotationEnabled = True
        self._tickTimer = None
        self._startTickTimer()

    def getOffscreenPosForElement(self, pos):
        return util.vectorAdd(pos, util.vectorMult(self._canvasRoot.size, 0.5))

    def getElementNodeParent(self):
        return self._canvasRoot

    def _startTickTimer(self):
        self._stopTickTimer()
        player = avg.Player.get()
        self._tickTimer = player.setOnFrameHandler(self.onTick)

    def _stopTickTimer(self):
        player = avg.Player.get()
        if self._tickTimer is not None:
            player.clearInterval(self._tickTimer)
            self._tickTimer = None

    def delete(self):

        if not self.alive:
            return

        self._stopTickTimer()

        if self.owner is not None:
            self.owner.removeStructure(self)

        for element in self._elementMapping.values():
            if element.node is not None:
                element.node.unlink(True)
                element.node = None

        self._elementMapping = None

        for node in self._edgeNodes.values():
            node.unlink(True)

        for node in self._shadowNodes.values():
            node.unlink(True)

        self._edgeNodes = None
        self._shadowNodes = None

        self._rootParent = None

        self._canvasRoot.unlink(True)
        self._canvasRoot = None

        self._shadowImage.unlink(True)
        self._shadowImage = None

        self._graphVisRoot.unlink(True)
        self._graphVisRoot = None

        self._image.unlink(True)
        self._image = None

        player = avg.Player.get()
        player.deleteCanvas(self._blackCanvas.getID())
        player.deleteCanvas(self._canvas.getID())

        self._blackCanvas = None
        self._canvas = None

        self._fixElements = None

        self.crystalManager.removeStructure(self)
        self.crystalManager = None

        GameElementBase.delete(self)

    def _initStructureCore(self):
        raise NotImplementedError

    def _updateElement(self, element):
        self._elementMapping[element.shape] = element
        self._elementMapping[element.node] = element
        self._elementMapping[element.id] = element

    def getElement(self, obj):
        return self._elementMapping[obj]

    def startOverdrive(self, duration):
        self._overDriveCounter += duration

    def _overdriveEnd(self):
        pass

    @property
    def size(self):
        return self._size

    def _initPhysic(self, position, angle):
        mass = pymunk.inf
        moment = pymunk.moment_for_circle(mass, 0, 1)
        self._body = physic.BaseBody(self, mass, moment)
        self._space.add(self._body)

    def _createCircleShape(self, absPos, r=util.CRYSTAL_RADIUS):
        circle = pymunk.Circle(self._body, r, self._body.world_to_local(absPos))
        circle.collision_type = physic.StructureCollisionType
        self._addShape(circle)
        return circle

    @property
    def depletedCallback(self):
        return self._depletedCallback

    @depletedCallback.setter
    def depletedCallback(self, fun):
        self._depletedCallback = fun

    def veil(self, time):
        if self._veil is None:
            self._veil = BaseStructure.Veil(self, time, self._veilEnd)

    def _veilEnd(self):
        self._veil = None

    def getAllElements(self):
        return [self.getElement(id) for id in self._graph]

    def onTick(self):

        if self._overDriveCounter > 0:
            self._overdrive = True
            self._overDriveCounter -= 1
            if self._overDriveCounter == 0:
                self._overdrive = False
                self._overdriveEnd()

        self.grow()

        if self._veil is not None:
            self._veil.onTick()

    @property
    def gameOverCallback(self):
        return self._gameOverCallback

    @gameOverCallback.setter
    def gameOverCallback(self, fun):
        self._gameOverCallback = fun

    def onWallCollision(self, other):
        if self._gameOverCallback is not None:
            self._gameOverCallback()
            self.gameOverCallback = None

    def checkSanity(self):
        return True

    def updateNeigbourhoodVisualisation(self):
        if __debug__:
            if not hasattr(self, "debugNodes"):
                self.debugNodes = []

            while len(self.debugNodes) < self._graph.number_of_edges():
                debugNode = avg.LineNode(parent=self._root)
                debugNode.color = "FF0000"
                debugNode.strokewidth = 2
                debugNode.opacity = 0.5
                debugNode.fillopacity = 0.5
                self.debugNodes.append(debugNode)

            while len(self.debugNodes) > self._graph.number_of_edges():
                self.debugNodes.pop().unlink(True)

            for edge, node in zip(self._graph.edges_iter(), self.debugNodes):
                nodeIdA, nodeIdB = edge
                node.unlink(False)
                node.pos1 = tuple(self.getElement(nodeIdA).shape.offset)
                node.pos2 = tuple(self.getElement(nodeIdB).shape.offset)
                self._root.appendChild(node)

    def removeSurplusElements(self, element):
        assert self.checkSanity()
        removeCounter = 0
        sameNeighbors = self.getSameExtendedNeighborhood(element)
        if self.REACTION_THRESHOLD > 0 and len(sameNeighbors) >= self.REACTION_THRESHOLD:
            for neighbor in sameNeighbors:
                self.removeElement(neighbor)
                removeCounter += 1
            assert self.checkSanity()

        removeCounter += self.removeNotReachableElements()
        return removeCounter

    def getGraphNeighbors(self, element):
        return [self.getElement(id) for id in self._graph.neighbors_iter(element.id)]

    def addElement(self, elementToCreate, color, relPos, rotation=0):
        assert self.checkSanity()

        if color is None:
            element = elementToCreate(relPos, rotation, self, self._helpSystem)
        else:
            element = elementToCreate(color, relPos, rotation, self, self._helpSystem)
        self._updateElement(element)
        self._addElementShadow(element)
        self._graph.add_node(element.id)

        assert self.checkSanity()
        self.updateNeigbors(element)
        assert self.checkSanity()

        return element

    def _removeEdgeNodesForElement(self, element):
        neighbors = self.getGraphNeighbors(element)
        for edge in self._graph.edges_iter([element.id] + neighbors):
            if element.id in edge:
                self._removeEdgeNodes(edge)

    def _addEdgeNodes(self, edge):
        edge = tuple(sorted(edge))

        elementA = self.getElement(edge[0])
        elementB = self.getElement(edge[1])

        shadowLine = avg.LineNode(parent=self._blackBackground)
        shadowLine.color = self._shadowColor
        shadowLine.strokewidth = self._shadowWidth
        shadowLine.opacity = 1
        shadowLine.fillopacity = 1
        shadowLine.pos1 = self.getOffscreenPosForElement(elementA.position)
        shadowLine.pos2 = self.getOffscreenPosForElement(elementB.position)
        self._shadowNodes[edge] = shadowLine
        avg.LinearAnim(shadowLine, "opacity", 700, 0, 1).start()

        edgeLine = avg.LineNode(parent=self._graphVisRoot)
        edgeLine.color = "F88017"
        edgeLine.strokewidth = util.CRYSTAL_SIZE * 0.1
        edgeLine.opacity = 1
        edgeLine.fillopacity = 1
        edgeLine.pos1 = self.getOffscreenPosForElement(elementA.position)
        edgeLine.pos2 = self.getOffscreenPosForElement(elementB.position)
        avg.LinearAnim(edgeLine, "opacity", 5000, 0, 1).start()
        self._edgeNodes[edge] = edgeLine

    def _removeEdgeNodes(self, edge):
        edge = tuple(sorted(edge))
        if edge in self._edgeNodes:
            edgeNode = self._edgeNodes[edge]
            avg.LinearAnim(
                edgeNode, "opacity", 100, edgeNode.opacity, 0, False, None, lambda: edgeNode.unlink(True)
            ).start()
            del self._edgeNodes[edge]
        if edge in self._shadowNodes:
            shadowNode = self._shadowNodes[edge]
            avg.LinearAnim(
                shadowNode, "opacity", 700, shadowNode.opacity, 0, False, None, lambda: shadowNode.unlink(True)
            ).start()
            self._shadowNodes[edge].unlink(True)
            del self._shadowNodes[edge]

    def _addElementShadow(self, element):
        roundShadow = avg.CircleNode(
            parent=self._blackBackground,
            pos=self.getOffscreenPosForElement(element.position),
            r=self._shadowWidth / 2,
            fillcolor=self._shadowColor,
            opacity=0,
            fillopacity=1,
        )
        avg.LinearAnim(roundShadow, "fillopacity", 700, 0, 1).start()
        self._shadowNodes[element.shape] = roundShadow

    def _removeElementShadow(self, element):
        self._shadowNodes[element.shape].unlink(True)
        del self._shadowNodes[element.shape]

    def onCrystalCollision(self, other, hitShape):
        try:
            element = self.getElement(hitShape)
        except KeyError:
            return

        element.onCollision(other)

    def getColorCount(self):
        return collections.Counter([e.color for e in self._elementMapping.values()])

    def removeElement(self, element):
        assert self.checkSanity()
        assert isinstance(element, StructureElement)
        assert element.parent == self

        element.onDestroyAction()
        self._removeEdgeNodesForElement(element)
        self._removeElementShadow(element)

        self._graph.remove_node(element.id)

        self._removeShape(element.shape)
        if element in self._fixElements:
            self._fixElements.remove(element)
        #            avg.LinearAnim(element.node, "opacity",1000, 1 , 0, False, None, lambda:element.node.unlink(True)).start()
        #
        if self._fixElements:
            targetPos = random.choice(list(self._fixElements)).node.pos
            avg.LinearAnim(
                element.node, "pos", 1000, element.node.pos, targetPos, False, None, lambda: element.node.unlink(True)
            ).start()
        else:
            avg.LinearAnim(element.node, "opacity", 1000, 1, 0, False, None, lambda: element.node.unlink(True)).start()

        del self._elementMapping[element.shape]
        del self._elementMapping[element.node]
        del self._elementMapping[element.id]

        assert self.checkSanity()

        self._checkDepleted()

        if __debug__:
            self.updateNeigbourhoodVisualisation()

    def updateNeigbors(self, element, reset=False):
        assert self.checkSanity()
        assert isinstance(element, StructureElement)

        if reset:
            self._removeEdgeNodesForElement(element)
            self._graph.remove_node(element.id)
            self._graph.add_node(element.id)
            assert len(self._graph.neighbors(element.id)) == 0

        for shape in self.getPhysicNeigbors(element):
            shapeId = self.getElement(shape).id
            if shapeId in self._graph:
                self._graph.add_edge(element.id, shapeId)
                self._addEdgeNodes((element.id, shapeId))

        assert self.checkSanity()

        if __debug__:
            self.updateNeigbourhoodVisualisation()

    def getPhysicNeigbors(self, element):
        shape = element.shape
        testBody = pymunk.Body()
        testBody.position = self._body.local_to_world(shape.offset)
        toTest = pymunk.Circle(testBody, self.neighbourhoodThreshold * util.CRYSTAL_SIZE / 2)
        result = self._space.shape_query(toTest)
        result = filter(lambda s: s in self._shapes, result)
        return result

    def randomizeNeighbors(self, element):
        spatialInfo = []
        for element in list(self.getGraphNeighbors(element)):
            spatialInfo.append((element.position, element.node.angle))
            self.removeElement(element)
        for pos, angle in spatialInfo:
            color, toCreate = self.crystalManager.getNextStructureElement(self)
            self.addElement(toCreate, color, pos, angle)

    def _checkDepleted(self):
        if len(self._graph) == 0 and self.depletedCallback is not None:
            self._depletedCallback()
            self._depletedCallback = None

    def removeNeighbors(self, element):
        for element in list(self.getGraphNeighbors(element)):
            self.removeElement(element)

    def _swapShapes(self, elementA, elementB):
        assert self.checkSanity()

        if (elementA in self._fixElements) ^ (elementB in self._fixElements):
            if elementA in self._fixElements:
                self._fixElements.remove(elementA)
                self._fixElements.add(elementB)
            elif elementB in self._fixElements:
                self._fixElements.remove(elementB)
                self._fixElements.add(elementA)

        elementA.shape, elementB.shape = elementB.shape, elementA.shape

        self._updateElement(elementA)
        self._updateElement(elementB)

        assert self.checkSanity()

    def getSameExtendedNeighborhood(self, element):
        assert self.checkSanity()
        neighbourFilter = filter(lambda otherId: element.isSameType(self.getElement(otherId)), self._graph)
        subGraph = self._graph.subgraph(neighbourFilter)
        for graph in nx.connected_components(subGraph):
            if element.id in graph:
                assert self.checkSanity()
                return [self.getElement(i) for i in graph]
        else:
            assert self.checkSanity()
            return []

    def removeNotReachableElements(self):
        toRemove = []
        removeCounter = 0
        for graph in nx.connected_component_subgraphs(self._graph):
            if all(element.id not in graph for element in self._fixElements):
                toRemove.append(graph)

        for graph in toRemove:
            for element in [self.getElement(i) for i in graph]:
                self.removeElement(element)
                removeCounter += 1

        return removeCounter

    #    def writeState(self):
    #            assert(self.checkSanity())
    #            nodes = []
    #            for i, node in self._idNodeMapping.items():
    #                if node is not self:
    #                    nodes.append((i,
    #                                  node.itemType,
    #                                  node.pos.x,
    #                                  node.pos.y,
    #                                  node.shape.offset[0],
    #                                  node.shape.offset[1]))
    #                else:
    #                    nodes.append((0,
    #                                  node.itemType,
    #                                  node.pos.x,
    #                                  node.pos.y,
    #                                  0,0))
    #
    #            edges= []
    #            for a,b in self._graph.edges_iter():
    #                if a == id(self): a=0
    #                if b == id(self): b=0
    #                edges.append((a,b))
    #
    #            with open("test", "w") as outFile:
    #                pickle.dump((nodes,edges), outFile)
    #            assert(self.checkSanity())
    #
    #    def loadState(self, filename):
    #        assert(self.checkSanity())
    #        nodes, edges = pickle.load(filename)
    #
    #        nodeMapping = dict()
    #
    #        for i, crystalType, posX, posY, offsetX, offsetY in nodes:
    #            if i == 0:
    #                nodeMapping[i] = self
    #                self._graph.add_node(id(self))
    #            else:
    #                nodeMapping[i]  = self.addElement(crystalType,
    #                                               (posX,posY),
    #                                               (offsetX, offsetY),
    #                                               False)
    #            self._idNodeMapping[id(nodeMapping[i])]= nodeMapping[i]
    #
    #        for a,b in edges:
    #            self._graph.add_edge(id(nodeMapping[a]), id(nodeMapping[b]) )
    #        assert(self.checkSanity())
    #
    def grow(self):
        if self._growLock:
            return

        if self._overdrive:
            pass
        elif self.framesToGrowth is None:
            return
        elif self.growTimer < self.framesToGrowth:
            self.growTimer += 1
            return
        else:
            self.growTimer = 0

        newNode = self.growOutwards()
        # self.growSimple()

    def growOutwards(self):
        newSpot, elementChain = self.getRandomDestinationPath()

        if newSpot is None:
            return

        color, crystalType = self.getElementTypeToGrow()

        newElement = self.addElement(crystalType, color, newSpot)

        for element in reversed(elementChain[1:]):
            self._swapShapes(element, newElement)

        for element in elementChain[1:]:
            self.updateNeigbors(element, True)
        self.updateNeigbors(newElement, True)

        newElement.node.pos = elementChain[0].node.pos
        newPositions = itertools.chain(
            [element.node.pos for element in elementChain[1:]], (self.getOffscreenPosForElement(newSpot),)
        )
        elementChain = itertools.chain((newElement,), elementChain[1:])

        self._growLock = True
        for element, newPosition in zip(elementChain, newPositions):
            avg.LinearAnim(element.node, "pos", 1000, element.node.pos, newPosition).start()

        avg.LinearAnim(newElement.node, "opacity", 1000, 0, 1, False, None, self._resetGrowLock).start()

        assert self.checkSanity()

    def _resetGrowLock(self):
        self._growLock = False

    def getRandomDestinationPath(self):
        newSpot, targetElement = self.searchSpot()
        if targetElement is None:
            return None, None
        assert isinstance(targetElement, StructureElement)
        paths = []
        for fixElement in self._fixElements:
            try:
                path = nx.shortest_path(self._graph, fixElement.id, targetElement.id)
                paths.append(path)
            except nx.exception.NetworkXNoPath:
                pass
        if not paths:
            return None, None
        shortestPath = min(paths, key=len)
        return newSpot, map(lambda x: self.getElement(x), shortestPath)

    def growSimple(self):
        newSpot, adjacentElement = self.searchSpot()
        if newSpot:
            color, crystalType = self.getElementTypeToGrow()
            element = self.addElement(crystalType, color, relPos=newSpot)
            return element

    def getElementTypeToGrow(self):
        return self.crystalManager.getNextStructureElement(self)

    def removeElementsInArea(self, pos, radius):
        deletedelements = 0
        for shape in self._getShapesInCircle(pos, radius):
            if shape in self._elementMapping:
                deletedelements += self.getElement(shape).delete()
        return deletedelements

    def _getShapesInCircle(self, pos, radius):
        testBody = pymunk.Body()
        testBody.position = pos
        shapeToTest = pymunk.Circle(body=testBody, radius=radius)
        intersections = self._space.shape_query(shapeToTest)
        return intersections

    def searchSpot(self):
        if self._graph.nodes():
            spots = []

            if not self._fixElements:
                return None, None

            fixelement = random.choice(list(self._fixElements))
            spots = self.checkForSpace(fixelement)
            spots = self._filterSpots(spots, fixelement)
            if spots:
                return random.choice(spots), fixelement

            node = random.choice(self._graph.nodes())
            element = self.getElement(node)
            spots = self.checkForSpace(element)
            spots = self._filterSpots(spots, element)
            if spots:
                return random.choice(spots), element

        return None, None

    def _filterSpots(self, spots, origin):
        return spots

    def checkForSpace(self, element):
        radius = element.shape.radius + util.CRYSTAL_RADIUS + 1
        availablePositions = []
        stepsize = 360 // 4
        maxNeigbors = 0
        for alpha in range(0, 360, stepsize):
            alpha += random.randint(0, stepsize - 1)
            # alpha+= random.randrange(stepsize)
            angle = (2 * math.pi) * (alpha / 360.0)
            vector = util.getVectotInDirection(angle, radius)
            posToCheck = util.vectorAdd(self.toAbsPos(element.position), vector)
            testBody = pymunk.Body()
            testBody.position = posToCheck
            shapeToTestInner = pymunk.Circle(body=testBody, radius=util.CRYSTAL_SIZE / 2)
            shapeToTestOuter = pymunk.Circle(
                body=testBody, radius=(util.CRYSTAL_SIZE / 2) * self.neighbourhoodThreshold
            )
            intersectionsInner = self._space.shape_query(shapeToTestInner)
            # dnode = avg.CircleNode(parent=self._root.getParent(), pos=posToCheck, r=util.CRYSTAL_SIZE/2,fillcolor="00FFFF", strokewidth=0)
            if len(intersectionsInner) == 0 or (len(intersectionsInner) == 1 and element.shape in intersectionsInner):
                intersectionsOuter = self._space.shape_query(shapeToTestOuter)
                neighborCount = len(intersectionsOuter)
                # dnode.fillopacity=0.5
                if neighborCount > maxNeigbors:
                    maxNeigbors = neighborCount
                    availablePositions = [self.toRelPos(posToCheck)]
                elif neighborCount == maxNeigbors:
                    availablePositions.append(self.toRelPos(posToCheck))

        return availablePositions
Example #43
0
class Posture(metaclass=TunedInstanceMetaclass, manager=services.posture_manager()):
    __qualname__ = 'Posture'
    ASM_SOURCE = '_asm_key'
    INSTANCE_TUNABLES = {'mobile': Tunable(bool, False, tuning_filter=FilterTag.EXPERT_MODE, description='If True, the Sim can route in this posture.'), 'unconstrained': Tunable(bool, False, description='If True, the Sim can stand anywhere in this posture.'), 'ownable': Tunable(bool, True, description="If True, This posture is ownable by interactions. Ex: A posture like carry_nothing should not be ownable, because it will cause strange cancelations that don't make sense."), 'social_geometry': TunableTuple(social_space=TunablePolygon(description="\n             The special geometry override for socialization in this posture. This defines\n             where the Sim's attention is focused and informs the social positioning system where\n             each Sim should stand to look most natural when interacting with this Sim. \n             Ex: we override the social geometry for a Sim who is bartending to be a wider cone \n             and be in front of the bar instead of embedded within the bar. This encourages Sims \n             to stand on the customer-side of the bar to socialize with this Sim instead of coming \n             around the back."), focal_point=TunableVector3(sims4.math.Vector3.ZERO(), description='Focal point when socializing in this posture, relative to Sim'), tuning_filter=FilterTag.EXPERT_MODE, description='The special geometry for socialization in this posture.'), ASM_SOURCE: TunableResourceKey(None, [sims4.resources.Types.STATEMACHINE], tuning_group=GroupNames.ANIMATION, description='The posture ASM.', category='asm'), '_actor_param_name': Tunable(str, 'x', source_location=ASM_SOURCE, source_query=SourceQueries.ASMActorSim, tuning_group=GroupNames.ANIMATION, description="\n             The name of the actor parameter in this posture's ASM. By default, this is x, and you should probably\n             not change it."), '_target_name': Tunable(str, None, source_location=ASM_SOURCE, source_query=SourceQueries.ASMActorAll, tuning_group=GroupNames.ANIMATION, description="\n             The actor name for the target object of this posture. Leave empty for postures with no target. \n             In the case of a posture that targets an object, it should be the name of the object actor in \n             this posture's ASM. \n             ."), '_enter_state_name': Tunable(str, None, source_location=ASM_SOURCE, source_query=SourceQueries.ASMState, tuning_group=GroupNames.ANIMATION, description='\n             The name of the entry state for the posture in the ASM. \n             All postures should have two public states, not including entry and exit.\n             This should be the first of the two states.'), '_exit_state_name': Tunable(str, 'exit', source_location=ASM_SOURCE, source_query=SourceQueries.ASMState, tuning_group=GroupNames.ANIMATION, description='\n             The name of the exit state in the ASM. By default, this is exit.'), '_state_name': Tunable(str, None, source_location=ASM_SOURCE, source_query=SourceQueries.ASMState, tuning_group=GroupNames.ANIMATION, description='\n             The main state name for the looping posture pose in the ASM.\n             All postures should have two public states, not including entry and exit.\n             This should be the second of the two states.'), '_supported_postures': TunableList(TunableTuple(posture_type=TunableReference(services.posture_manager(), description='A supported posture.'), entry=Tunable(bool, True, description=''), exit=Tunable(bool, True, description=''), transition_cost=OptionalTunable(Tunable(float, 1, description="Cost of the transition to this posture then calculating the Sim's transition sequence.")), preconditions=TunableEnumFlags(PosturePreconditions, PosturePreconditions.NONE), description='A list of postures that this posture supports entrance from and exit to. Defaults to [stand]')), '_supports_carry': Tunable(description='\n            Whether or not there should be a carry version of this posture in\n            the posture graph.\n            ', tunable_type=bool, default=True), 'censor_level': TunableEnumEntry(CensorState, None, tuning_filter=FilterTag.EXPERT_MODE, description="\n                                                                                The type of censor grid that will be applied to any Sim in this posture.  \n                                                                                A censor grid obscures different parts of a Sim's body depending on what censor level it is set at.  \n                                                                                For example, the LHAND censor level will obscure a Sim's left hand.  \n                                                                                By default, postures have no censor level association, which means no censor grid will be applied to them \n                                                                                and every part of their body will be visible when in this posture.\n                                                                                "), 'outfit_change': TunableOutfitChange(description='\n            Define what outfits the Sim is supposed to wear when entering or\n            exiting this posture.\n            '), 'cost': Tunable(float, 0, description='( >= 0 ) The distance a sim is willing to pay to avoid using this posture (higher number discourage using the posture)'), 'idle_animation': TunableAnimationReference(callback=None, tuning_group=GroupNames.ANIMATION, description='The animation for a Sim to play while in this posture and waiting for interaction behavior to start.'), 'jig': OptionalTunable(TunableReference(manager=services.definition_manager(), description='The jig to place while the Sim is in this posture.'), description='An optional Jig to place while the Sim is in this posture.'), 'allow_affinity': Tunable(bool, True, description="\n                            If True, Sims will prefer to use this posture if someone\n                            they're interacting with is using the posture.\n                            \n                            Ex: If you chat with a sitting sim, you will prefer to\n                            sit with them and chat.\n                            "), 'additional_put_down_distance': Tunable(description="\n            An additional distance in front of the Sim to start searching for\n            valid put down locations when in this posture.\n            \n            This tunable is only respected for the Sim's body posture.\n            ", tunable_type=float, default=0.5), 'additional_interaction_jig_fgl_distance': Tunable(description='\n            An additional distance (in meters) in front of the Sim to start \n            searching when using FGL to place a Jig to run an interaction.', tunable_type=float, default=0)}
    DEFAULT_POSTURE = TunableReference(services.get_instance_manager(sims4.resources.Types.POSTURE), description="The default affordance to use as the supported posture if nothing is tuned in a Posture's 'Supported Postures'")
    IS_BODY_POSTURE = True

    def test(self):
        return True

    @classproperty
    def target_name(cls):
        return cls._target_name

    def __init__(self, sim, target, track, animation_context=None):
        self._create_asm(animation_context=animation_context)
        self._source_interaction = None
        self._primitive = None
        self._owning_interactions = set()
        self._sim = None
        self._target = None
        self._target_part = None
        self._surface_target_ref = None
        self._track = None
        self._slot_constraint = UNSET
        self._context = None
        self._asm_registry = defaultdict(dict)
        self._asms_with_posture_info = set()
        self._failed_parts = set()
        self._bind(sim, target, track)
        self._linked_posture = None
        self._entry_anim_complete = False
        self._exit_anim_complete = False
        self.external_transition = False
        self._active_cancel_aops = WeakSet()
        self._saved_exit_clothing_change = None

    @classproperty
    def name(cls):
        return cls._posture_name or cls.__name__

    @property
    def posture_context(self):
        return self._context

    @property
    def animation_context(self):
        return self._animation_context

    @property
    def surface_target(self):
        return self.sim.posture_state.surface_target

    @property
    def source_interaction(self):
        return self._source_interaction

    @source_interaction.setter
    def source_interaction(self, value):
        if value is None:
            logger.error('Posture {} get a None source interaction set', self)
            return
        self._source_interaction = value

    @property
    def owning_interactions(self):
        return self._owning_interactions

    def last_owning_interaction(self, interaction):
        if interaction not in self.owning_interactions:
            return False
        for owning_interaction in self.owning_interactions:
            while owning_interaction is not interaction and not owning_interaction.is_finishing:
                return False
        return True

    def add_owning_interaction(self, interaction):
        self._owning_interactions.add(interaction)

    def remove_owning_interaction(self, interaction):
        self._owning_interactions.remove(interaction)

    def clear_owning_interactions(self):
        from interactions.base.interaction import OWNS_POSTURE_LIABILITY
        try:
            for interaction in list(self._owning_interactions):
                interaction.remove_liability((OWNS_POSTURE_LIABILITY, self.track))
        finally:
            self._owning_interactions.clear()

    def add_cancel_aop(self, cancel_aop):
        self._active_cancel_aops.add(cancel_aop)

    def kill_cancel_aops(self):
        for interaction in self._active_cancel_aops:
            interaction.cancel(FinishingType.INTERACTION_QUEUE, cancel_reason_msg='PostureOwnership. This posture wasgoing to be canceled, but another interaction took ownership over the posture. Most likely the current posture was already valid for the new interaction.')

    def get_idle_behavior(self):
        if self.idle_animation is None:
            logger.error('{} has no idle animation tuning! This tuning is required for all body postures!', self)
            return
        if self.source_interaction is None:
            logger.error('Posture({}) on sim:{} has no source interaction.', self, self.sim, owner='Maxr', trigger_breakpoint=True)
            return
        if self.owning_interactions and not self.multi_sim:
            interaction = list(self.owning_interactions)[0]
        else:
            interaction = self.source_interaction
        idle = self.idle_animation(interaction)
        auto_exit = get_auto_exit((self.sim,), asm=idle.get_asm())
        return build_critical_section(auto_exit, idle, flush_all_animations)

    def log_info(self, phase, msg=None):
        from sims.sim_log import log_posture
        log_posture(phase, self, msg=msg)

    def _create_asm(self, animation_context=None):
        self._animation_context = animation_context or AnimationContext()
        self._animation_context.add_posture_owner(self)
        self._asm = animation.asm.Asm(self._asm_key, self._animation_context)

    _provided_postures = PostureManifest().intern()
    _posture_name = None
    family_name = None

    @classproperty
    def posture_type(cls):
        return cls

    @classmethod
    def is_same_posture_or_family(cls, other_cls):
        if cls == other_cls:
            return True
        return cls.family_name is not None and cls.family_name == other_cls.family_name

    @classmethod
    def _tuning_loading_callback(cls):

        def delclassattr(name):
            if name in cls.__dict__:
                delattr(cls, name)

        delclassattr('_provided_postures')
        delclassattr('_posture_name')
        delclassattr('family_name')

    PostureTransitionData = namedtuple('PostureTransitionData', ('preconditions', 'transition_cost'))
    _posture_transitions = {}

    @staticmethod
    def _add_posture_transition(source_posture, dest_posture, transition_data):
        Posture._posture_transitions[(source_posture, dest_posture)] = transition_data

    @contextmanager
    def __reload_context__(oldobj, newobj):
        posture_transitions = dict(oldobj._posture_transitions)
        yield None
        oldobj._posture_transitions.update(posture_transitions)

    @classmethod
    def _tuning_loaded_callback(cls):
        for posture_data in cls._supported_postures:
            transition_data = cls.PostureTransitionData(posture_data.preconditions, posture_data.transition_cost)
            if posture_data.entry:
                cls._add_posture_transition(posture_data.posture_type, cls, transition_data)
            while posture_data.exit:
                cls._add_posture_transition(cls, posture_data.posture_type, transition_data)
        asm = animation.asm.Asm(cls._asm_key, get_throwaway_animation_context())
        provided_postures = asm.provided_postures
        if not provided_postures:
            return
        specific_name = None
        family_name = None
        for entry in provided_postures:
            entry_specific_name = entry.specific
            if not entry_specific_name:
                raise ValueError('{} must provide a specific posture for all posture definition rows.'.format(asm.name))
            if specific_name is None:
                specific_name = entry_specific_name
            elif entry_specific_name != specific_name:
                raise ValueError('{}: {} provides multiple specific postures: {}'.format(cls, asm.name, [specific_name, entry_specific_name]))
            entry_family_name = entry.family
            while entry_family_name:
                if family_name is None:
                    family_name = entry_family_name
                elif entry_family_name != family_name:
                    raise ValueError('{}: {} provides multiple family postures: {}'.format(cls, asm.name, [family_name, entry_family_name]))
        cls._provided_postures = provided_postures
        cls._posture_name = specific_name
        cls.family_name = family_name
        if cls.idle_animation is None:
            logger.error('{} has no idle_animation tuned. Every posture must have an idle animation suite!', cls)

    @flexmethod
    def get_provided_postures(cls, inst, surface_target=DEFAULT, concrete=False):
        if inst is None:
            return cls._provided_postures
        provided_postures = inst._provided_postures
        surface_target = inst._resolve_surface_target(surface_target)
        if surface_target is None or surface_target == MATCH_NONE:
            surface_restriction = MATCH_NONE
        elif surface_target == MATCH_ANY:
            surface_restriction = surface_target
        else:
            surface_restriction = surface_target if concrete else AnimationParticipant.SURFACE
        if surface_restriction is not None:
            filter_entry = PostureManifestEntry(MATCH_ANY, MATCH_ANY, MATCH_ANY, MATCH_ANY, MATCH_ANY, MATCH_ANY, surface_restriction, True)
            provided_postures = provided_postures.intersection_single(filter_entry)
        return provided_postures

    def _resolve_surface_target(self, surface_target):
        if surface_target is DEFAULT:
            return self.surface_target
        return surface_target

    def _bind(self, sim, target, track):
        if self.sim is sim and self.target is target and self.target_part is None or self.target_part is target and self._track == track:
            return
        if self.target is not None and track == PostureTrack.BODY:
            part_suffix = self.get_part_suffix()
            for asm in self._asms_with_posture_info:
                while not asm.remove_virtual_actor(self._target_name, self.target, suffix=part_suffix):
                    logger.error('Failed to remove previously-bound virtual posture container {} from asm {} on posture {}.', self.target, asm, self)
        if sim is not None:
            self._sim = sim.ref()
        else:
            self._sim = None
        self._intersection = None
        self._asm_registry.clear()
        self._asms_with_posture_info.clear()
        if target is not None:
            if self._target_name is not None and target is not sim:
                (route_type, _) = target.route_target
                if self._target is not None and (self._target() is not None and self._target().parts is not None) and target in self._target().parts:
                    self._target_part = target.ref()
                else:
                    self._target_part = None
                    self._target = target.ref()
            else:
                self._target = target.ref()
        else:
            self._target_part = None
            self._target = None
        if track is not None:
            self._track = track
        else:
            self._track = None
        self._slot_constraint = UNSET

    def rebind(self, target, animation_context=None):
        self._release_animation_context()
        self._create_asm(animation_context=animation_context)
        self._bind(self.sim, target, self.track)

    def reset(self):
        if self._saved_exit_clothing_change is not None:
            self.sim.sim_info.set_current_outfit(self._saved_exit_clothing_change)
            self._saved_exit_clothing_change = None
        self._entry_anim_complete = False
        self._exit_anim_complete = False
        self._release_animation_context()
        self._source_interaction = None

    def _release_animation_context(self):
        if self._animation_context is not None:
            self._animation_context.remove_posture_owner(self)
            self._animation_context = None

    def kickstart_gen(self, timeline, posture_state):
        if PostureTrack.is_carry(self.track):
            is_body = False
            self.asm.set_parameter('location', 'inventory')
        else:
            is_body = True
            self.source_interaction = self.sim.create_default_si()
        idle_arb = animation.arb.Arb()
        self.append_transition_to_arb(idle_arb, None)
        self.append_idle_to_arb(idle_arb)
        begin_element = self.get_begin(idle_arb, posture_state)
        yield element_utils.run_child(timeline, begin_element)
        if is_body:
            default_si = self.source_interaction
            yield default_si.prepare_gen(timeline)
            yield default_si.enter_si_gen(timeline)
            yield default_si.setup_gen(timeline)
            result = yield default_si.perform_gen(timeline)
            if not result:
                raise RuntimeError('Sim: {} failed to enter default si: {}'.format(self, default_si))

    def get_asm(self, animation_context, asm_key, setup_asm_func, use_cache=True, cache_key=DEFAULT, interaction=None, posture_manifest_overrides=None, **kwargs):
        dict_key = animation_context if cache_key is DEFAULT else cache_key
        if use_cache:
            asm_dict = self._asm_registry[dict_key]
            asm = asm_dict.get(asm_key)
            if asm is None:
                asm = animation.asm.Asm(asm_key, context=animation_context, posture_manifest_overrides=posture_manifest_overrides)
                if interaction is not None:
                    asm.on_state_changed_events.append(interaction.on_asm_state_changed)
                asm_dict[asm_key] = asm
        else:
            asm = animation.asm.Asm(asm_key, context=animation_context)
            if interaction is not None:
                asm.on_state_changed_events.append(interaction.on_asm_state_changed)
        if asm.current_state == 'exit':
            asm.set_current_state('entry')
        if not (setup_asm_func is not None and setup_asm_func(asm)):
            return
        return asm

    def remove_from_cache(self, cache_key):
        if cache_key in self._asm_registry:
            for asm in self._asm_registry[cache_key].values():
                del asm._on_state_changed_events[:]
            del self._asm_registry[cache_key]

    def _create_primitive(self, animate_in, dest_state):
        return PosturePrimitive(self, animate_in, dest_state, self._context)

    def _on_reset(self):
        self._primitive = None

    def __str__(self):
        return '{0}:{1}'.format(self.name, self.id)

    def __repr__(self):
        return standard_repr(self, self.id, self.target)

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

    @property
    def target(self):
        if self._target_part is not None:
            return self._target_part()
        if self._target is not None:
            return self._target()

    @property
    def target_part(self):
        if self._target_part is not None:
            return self._target_part()

    @property
    def track(self):
        return self._track

    @property
    def is_active_carry(self):
        return PostureTrack.is_carry(self.track) and self.target is not None

    def get_slot_offset_locked_params(self, anim_overrides=None):
        locked_params = self._locked_params
        if anim_overrides is not None:
            locked_params += anim_overrides.params
        locked_params += {'transitionPosture': 'stand'}
        return locked_params

    def build_slot_constraint(self, create_posture_state_spec_fn=None):
        if self.target is not None and PostureTrack.is_body(self.track):
            return interactions.constraints.RequiredSlot.create_slot_constraint(self, create_posture_state_spec_fn=create_posture_state_spec_fn)

    @property
    def slot_constraint_simple(self):
        if self._slot_constraint is UNSET:
            self._slot_constraint = self.build_slot_constraint(create_posture_state_spec_fn=lambda *_, **__: None)
        return self._slot_constraint

    @property
    def slot_constraint(self):
        if self._slot_constraint is UNSET:
            self._slot_constraint = self.build_slot_constraint()
        return self._slot_constraint

    @classproperty
    def multi_sim(cls):
        return False

    @property
    def is_puppet(self):
        return False

    @property
    def is_mirrored(self):
        if self.target is not None and self.target.is_part:
            return self.target.is_mirrored() or False
        return False

    @property
    def linked_posture(self):
        return self._linked_posture

    @linked_posture.setter
    def linked_posture(self, posture):
        self._linked_posture = posture

    @property
    def asm(self):
        return self._asm

    @property
    def _locked_params(self):
        anim_overrides_actor = self.sim.get_anim_overrides(self._actor_param_name)
        params = anim_overrides_actor.params
        if self.target is not None:
            anim_overrides_target = self.target.get_anim_overrides(self.target_name)
            if anim_overrides_target is not None:
                params += anim_overrides_target.params
            if self.target.is_part:
                part_suffix = self.target.part_suffix
                if part_suffix is not None:
                    params += {'subroot': part_suffix}
        if self.is_mirrored is not None:
            params += {'isMirrored': self.is_mirrored}
        return params

    @property
    def locked_params(self):
        if self.slot_constraint is None or self.slot_constraint.locked_params is None:
            return self._locked_params
        return self._locked_params + self.slot_constraint.locked_params

    def _setup_asm_container_parameter(self, asm, target, actor_name, part_suffix, target_name=None):
        if asm in self._asms_with_posture_info:
            return True
        if target_name is None:
            target_name = self._target_name
        result = False
        if target is not None and target_name is not None:
            result = asm.add_potentially_virtual_actor(actor_name, self.sim, target_name, target, part_suffix, target_participant=AnimationParticipant.CONTAINER)
            if not self._setup_custom_posture_target_name(asm, target):
                logger.error('Failed to set custom posture target {}', target)
                result = False
        if result:
            self._asms_with_posture_info.add(asm)
        return result

    def _setup_custom_posture_target_name(self, asm, target):
        _custom_target_name = target.custom_posture_target_name
        if _custom_target_name in asm.actors:
            (_custom_target_actor, _) = asm.get_actor_and_suffix(_custom_target_name)
            if _custom_target_actor is None:
                return asm.set_actor(target.custom_posture_target_name, target, suffix=None, actor_participant=AnimationParticipant.CONTAINER)
        return True

    def _setup_asm_carry_parameter(self, asm, target):
        pass

    def get_part_suffix(self, target=DEFAULT):
        if target is DEFAULT:
            target = self.target
        if target is not None:
            return target.part_suffix

    def setup_asm_posture(self, asm, sim, target, locked_params=frozendict(), actor_param_name=DEFAULT):
        if actor_param_name is DEFAULT:
            actor_param_name = self._actor_param_name
        if asm is None:
            logger.error('Attempt to setup an asm whose value is None.')
            return False
        if sim is None:
            logger.error('Attempt to setup an asm {0} on a sim whose value is None.', asm)
            return False
        if not asm.set_actor(actor_param_name, sim, actor_participant=AnimationParticipant.ACTOR):
            logger.error('Failed to set actor sim: {0} on asm {1}', actor_param_name, asm)
            return False
        sim.set_mood_asm_parameter(asm, actor_param_name)
        sim.set_trait_asm_parameters(asm, actor_param_name)
        if target.is_part:
            is_mirrored = target.is_mirrored()
            if is_mirrored is not None:
                locked_params += {'isMirrored': is_mirrored}
        part_suffix = self.get_part_suffix()
        if not (target is not None and self._target_name is not None and self._setup_asm_container_parameter(asm, target, actor_param_name, part_suffix)):
            logger.error('Failed to set actor target: {0} on asm {1}', self._target_name, asm)
            return False
        if not PostureTrack.is_body(self.track):
            self._update_non_body_posture_asm()
            sim.on_posture_event.append(self._update_on_posture_event)
        if locked_params:
            virtual_actor_map = {self._target_name: self.target}
            asm.update_locked_params(locked_params, virtual_actor_map)
        self._setup_asm_carry_parameter(asm, target)
        return True

    def _update_on_posture_event(self, change, dest_state, track, old_value, new_value):
        if change == PostureEvent.POSTURE_CHANGED:
            if track != self.track:
                if new_value is not None:
                    self._update_non_body_posture_asm()
                    if new_value != self:
                        self.sim.on_posture_event.remove(self._update_on_posture_event)
            elif new_value != self:
                self.sim.on_posture_event.remove(self._update_on_posture_event)

    def _update_non_body_posture_asm(self):
        if self.sim.posture.target is not None:
            (previous_target, previous_suffix) = self.asm.get_virtual_actor_and_suffix(self._actor_param_name, self.sim.posture._target_name)
            if previous_target is not None:
                self.asm.remove_virtual_actor(self.sim.posture._target_name, previous_target, previous_suffix)
        self.sim.posture.setup_asm_interaction(self.asm, self.sim, self.target, self._actor_param_name, self._target_name)

    def _setup_asm_interaction_add_posture_info(self, asm, sim, target, actor_name, target_name, carry_target, carry_target_name, surface_target=DEFAULT, carry_track=DEFAULT):

        def set_posture_param(posture_param_str, carry_param_str, carry_actor_name, surface_actor_name):
            if not asm.set_actor_parameter(actor_name, sim, 'posture', posture_param_str):
                if not asm.set_parameter('posture', posture_param_str):
                    return False
                logger.warn('Backwards compatibility with old posture parameter required by {}', asm.name)
            if not asm.set_actor_parameter(actor_name, sim, PARAM_CARRY_STATE, carry_param_str):
                asm.set_parameter('carry', carry_param_str)
            asm.set_parameter('isMirrored', self.is_mirrored)
            if target_name == carry_actor_name and target is not None:
                set_carry_track_param_if_needed(asm, sim, target_name, target, carry_track=carry_track)
            if carry_actor_name is not None and carry_target_name == carry_actor_name and carry_target is not None:
                set_carry_track_param_if_needed(asm, sim, carry_target_name, carry_target, carry_track=carry_track)
            if surface_actor_name is not None:
                _surface_target = self._resolve_surface_target(surface_target)
                if _surface_target:
                    asm.add_potentially_virtual_actor(actor_name, sim, surface_actor_name, _surface_target, target_participant=AnimationParticipant.SURFACE)
                else:
                    return False
            return True

        def build_carry_str(carry_state):
            if carry_state[0]:
                if carry_state[1]:
                    return 'both'
                return 'left'
            if carry_state[1]:
                return 'right'
            return 'none'

        def setup_asm_container_parameter(chosen_posture_type):
            container_name = chosen_posture_type.target_name
            if not container_name:
                return True
            part_suffix = self.get_part_suffix()
            if self._setup_asm_container_parameter(asm, self.target, actor_name, part_suffix, target_name=container_name):
                return True
            return False

        carry_state = sim.posture_state.get_carry_state()
        supported_postures = asm.get_supported_postures_for_actor(actor_name)
        if supported_postures is None:
            return True
        filtered_supported_postures = self.sim.filter_supported_postures(supported_postures)
        if surface_target is DEFAULT:
            surface_target = self._resolve_surface_target(surface_target)
            if surface_target is not None:
                surface_target_provided = MATCH_ANY
            else:
                surface_target_provided = MATCH_NONE
        elif surface_target is not None:
            surface_target_provided = MATCH_ANY
        else:
            surface_target_provided = MATCH_NONE
        provided_postures = self.get_provided_postures(surface_target=surface_target_provided)
        best_supported_posture = get_best_supported_posture(provided_postures, filtered_supported_postures, carry_state)
        if best_supported_posture is None:
            logger.debug('Failed to find supported posture for actor {} on {} for posture ({}) and carry ({}).  Interaction info claims this should work.', actor_name, asm, self, carry_state)
            return False
        carry_param_str = build_carry_str(carry_state)
        carry_actor_name = best_supported_posture.carry_target
        surface_actor_name = best_supported_posture.surface_target
        if not isinstance(surface_actor_name, str):
            surface_actor_name = None
        param_str_specific = best_supported_posture.posture_param_value_specific
        if best_supported_posture.is_overlay:
            return True
        if param_str_specific and set_posture_param(param_str_specific, carry_param_str, carry_actor_name, surface_actor_name) and setup_asm_container_parameter(best_supported_posture.posture_type_specific):
            return True
        param_str_family = best_supported_posture.posture_param_value_family
        if best_supported_posture.is_overlay:
            return True
        if param_str_family and set_posture_param(param_str_family, carry_param_str, carry_actor_name, surface_actor_name) and setup_asm_container_parameter(best_supported_posture.posture_type_family):
            return True
        return False

    def setup_asm_interaction(self, asm, sim, target, actor_name, target_name, carry_target=None, carry_target_name=None, create_target_name=None, surface_target=DEFAULT, carry_track=DEFAULT, actor_participant=AnimationParticipant.ACTOR, invalid_expected=False):
        if target_name is not None and (target_name == self._target_name and (target is not None and self.target is not None)) and target.id != self.target.id:
            if not invalid_expected:
                logger.error('Animation targets a different object than its posture, but both use the same actor name for the object. This is impossible to resolve. Actor name: {}, posture target: {}, interaction target: {}', target_name, target, self.target)
            return False
        if not asm.set_actor(actor_name, sim, actor_participant=actor_participant):
            logger.error('Failed to set actor: {0} on asm {1}', actor_name, asm)
            return False
        if sim.asm_auto_exit.apply_carry_interaction_mask:
            asm._set_actor_trackmask_override(actor_name, 50000, 'Trackmask_CarryInteraction')
        if target is not None and target_name is not None:
            from sims.sim import Sim
            if isinstance(target, Sim):
                if not target.posture.setup_asm_interaction(asm, target, None, target_name, None, actor_participant=AnimationParticipant.TARGET):
                    return False
            else:
                asm.add_potentially_virtual_actor(actor_name, sim, target_name, target, target_participant=AnimationParticipant.TARGET)
                anim_overrides = target.get_anim_overrides(target_name)
                if anim_overrides is not None and anim_overrides.params:
                    virtual_actor_map = {self._target_name: self.target}
                    asm.update_locked_params(anim_overrides.params, virtual_actor_map)
            if not self._setup_custom_posture_target_name(asm, target):
                logger.error('Unable to setup custom posture target name for {} on {}', target, asm)
        _carry_target_name = carry_target_name or create_target_name
        if carry_target is not None and _carry_target_name is not None:
            asm.add_potentially_virtual_actor(actor_name, sim, _carry_target_name, carry_target, target_participant=AnimationParticipant.CARRY_TARGET)
        if not self._setup_asm_interaction_add_posture_info(asm, sim, target, actor_name, target_name, carry_target, carry_target_name, surface_target, carry_track):
            return False
        return True

    def get_begin(self, animate_in, dest_state):
        if self._primitive is not None:
            raise RuntimeError('Posture Entry({}) called multiple times without a paired exit.'.format(self))
        self._primitive = self._create_primitive(animate_in, dest_state)
        return self._primitive.next_stage()

    def begin(self, animate_in, dest_state, context):
        self._context = context

        def _do_begin(timeline):
            logger.debug('{} begin Posture: {}', self.sim, self)
            begin = self.get_begin(animate_in, dest_state)
            result = yield element_utils.run_child(timeline, begin)
            return result

        return _do_begin

    def get_end(self):
        if self._primitive is None:
            raise RuntimeError('Posture Exit({}) called multiple times without a paired entry. Sim: {}'.format(self, self.sim))
        exit_behavior = self._primitive.next_stage()
        self._primitive = None
        return exit_behavior

    def end(self):

        def _do_end(timeline):
            logger.debug('{} end Posture: {}', self.sim, self)
            end = self.get_end()
            result = yield element_utils.run_child(timeline, end)
            return result

        return _do_end

    def add_transition_extras(self, sequence):
        return sequence

    def enumerate_goal_list_ids(self, goal_list):
        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 goal_list is not None:
            for (index, goal) in enumerate(goal_list):
                goal.tag = index

    def get_locked_params(self, source_posture):
        if source_posture is None:
            return self._locked_params
        updates = {TRANSITION_POSTURE_PARAM_NAME: source_posture.name}
        if source_posture.target is None:
            return self._locked_params + updates
        if source_posture.target.is_part and self.target is not None and self.target.is_part:
            if self.target.is_mirrored(source_posture.target):
                direction = 'fromSimLeft'
            else:
                direction = 'fromSimRight'
            updates['direction'] = direction
        return self._locked_params + updates

    def append_transition_to_arb(self, arb, source_posture, locked_params=frozendict(), **kwargs):
        if not self._entry_anim_complete:
            locked_params += self.get_locked_params(source_posture)
            if source_posture is not None:
                locked_params += {TRANSITION_POSTURE_PARAM_NAME: source_posture.name}
            if not self.setup_asm_posture(self.asm, self.sim, self.target, locked_params=locked_params):
                logger.error('Failed to setup the asm for the posture {}', self)
                return
            self._setup_asm_target_for_transition(source_posture)
            self.asm.request(self._enter_state_name, arb)
            linked_posture = self.linked_posture
            if linked_posture is not None:
                locked_params = linked_posture.get_locked_params(source_posture)
                linked_posture.setup_asm_posture(linked_posture._asm, linked_posture.sim, linked_posture.target, locked_params=locked_params)
                if not self.multi_sim:
                    linked_posture._asm.request(linked_posture._enter_state_name, arb)
            self._entry_anim_complete = True

    def append_idle_to_arb(self, arb):
        self.asm.request(self._state_name, arb)
        if self._linked_posture is not None:
            self._linked_posture.append_idle_to_arb(arb)

    def append_exit_to_arb(self, arb, dest_state, dest_posture, var_map, locked_params=frozendict()):
        if not self._exit_anim_complete:
            self._setup_asm_target_for_transition(dest_posture)
            locked_params += self.locked_params
            if dest_posture is not None:
                locked_params += {TRANSITION_POSTURE_PARAM_NAME: dest_posture.name}
            if locked_params:
                virtual_actor_map = {self._target_name: self.target}
                self.asm.update_locked_params(locked_params, virtual_actor_map)
            self.asm.request(self._exit_state_name, arb)
            self._exit_anim_complete = True

    def _setup_asm_target_for_transition(self, transition_posture):
        if transition_posture is not None and transition_posture._target_name != self._target_name and transition_posture._target_name in self.asm.actors:
            (previous_target, previous_suffix) = self.asm.get_virtual_actor_and_suffix(self._actor_param_name, transition_posture._target_name)
            if previous_target is not None:
                self.asm.remove_virtual_actor(transition_posture.target_name, previous_target, previous_suffix)
            if not transition_posture._setup_asm_container_parameter(self.asm, transition_posture.target, self._actor_param_name, transition_posture.get_part_suffix()):
                logger.error('Failed to setup target container {} on {} from transition posture {}', transition_posture._target_name, self, transition_posture)
                return False
        return True

    def post_route_clothing_change(self, interaction, do_spin=True, **kwargs):
        si_outfit_change = interaction.outfit_change
        if si_outfit_change is not None and si_outfit_change.posture_outfit_change_overrides is not None:
            overrides = si_outfit_change.posture_outfit_change_overrides.get(self.posture_type)
            if overrides is not None:
                entry_outfit = overrides.get_on_entry_outfit(interaction)
                if entry_outfit is not None:
                    return overrides.get_on_entry_change(interaction, do_spin=do_spin, **kwargs)
        if self.outfit_change is not None:
            return self.outfit_change.get_on_entry_change(interaction, do_spin=do_spin, **kwargs)

    @property
    def saved_exit_clothing_change(self):
        return self._saved_exit_clothing_change

    def transfer_exit_clothing_change(self, clothing_change):
        self._saved_exit_clothing_change = clothing_change

    def prepare_exit_clothing_change(self, interaction):
        si_outfit_change = interaction.outfit_change
        if si_outfit_change is not None and si_outfit_change.posture_outfit_change_overrides is not None:
            overrides = si_outfit_change.posture_outfit_change_overrides.get(self.posture_type)
            if overrides is not None:
                exit_outfit = overrides.get_on_exit_outfit(interaction)
                if exit_outfit is not None:
                    self._saved_exit_clothing_change = overrides.get_on_exit_outfit(interaction)
                    return
        if self.outfit_change and self._saved_exit_clothing_change is None:
            self._saved_exit_clothing_change = self.outfit_change.get_on_exit_outfit(interaction)

    def exit_clothing_change(self, interaction, *, sim=DEFAULT, do_spin=True, **kwargs):
        if self._saved_exit_clothing_change is None or interaction is None:
            return
        if sim is DEFAULT:
            sim = interaction.sim
        sim_info = sim.sim_info
        return build_critical_section(sim_info.sim_outfits.get_change_outfit_element(self._saved_exit_clothing_change, do_spin=do_spin), flush_all_animations)

    def ensure_exit_clothing_change_application(self):
        if self.sim.posture_state.body is not self and self._saved_exit_clothing_change is not None:
            self.sim.sim_info.set_current_outfit(self._saved_exit_clothing_change)
            self._saved_exit_clothing_change = None

    @classmethod
    def supports_posture_type(cls, posture_type):
        return (cls, posture_type) in cls._posture_transitions or (posture_type, cls) in cls._posture_transitions

    @classmethod
    def is_valid_transition(cls, source_posture_type, destination_posture_type, targets_match):
        transition_data = cls._posture_transitions.get((source_posture_type, destination_posture_type))
        if transition_data is None:
            return False
        if targets_match:
            return True
        preconditions = transition_data.preconditions
        if preconditions is not None and preconditions & PosturePreconditions.SAME_TARGET:
            return False
        return True

    @classmethod
    def get_transition_cost(cls, posture_type):
        transition_data = cls._posture_transitions.get((cls, posture_type))
        if transition_data is None:
            transition_data = cls._posture_transitions.get((posture_type, cls))
        if transition_data is not None:
            return transition_data.transition_cost

    @classmethod
    def is_valid_target(cls, sim, target, **kwargs):
        return True
Example #44
0
class InteractionContext:
    __qualname__ = 'InteractionContext'
    SOURCE_PIE_MENU = InteractionSource.PIE_MENU
    SOURCE_AUTONOMY = InteractionSource.AUTONOMY
    SOURCE_BODY_CANCEL_AOP = InteractionSource.BODY_CANCEL_AOP
    SOURCE_CARRY_CANCEL_AOP = InteractionSource.CARRY_CANCEL_AOP
    SOURCE_SCRIPT = InteractionSource.SCRIPT
    SOURCE_UNIT_TEST = InteractionSource.UNIT_TEST
    SOURCE_SOCIAL_ADJUSTMENT = InteractionSource.SOCIAL_ADJUSTMENT
    SOURCE_QUICKTIME = InteractionSource.QUICKTIME
    SOURCE_GET_COMFORTABLE = InteractionSource.GET_COMFORTABLE
    SOURCE_SCRIPT_WITH_USER_INTENT = InteractionSource.SCRIPT_WITH_USER_INTENT
    SOURCE_POSTURE_GRAPH = InteractionSource.POSTURE_GRAPH

    def __init__(self, sim, source, priority, run_priority=None, client=None, pick=None, insert_strategy=QueueInsertStrategy.LAST, must_run_next=False, continuation_id=None, group_id=None, shift_held=False, carry_target=None, target_sim_id=None, bucket=InteractionBucketType.BASED_ON_SOURCE, visual_continuation_id=None, restored_from_load=False, cancel_if_incompatible_in_queue=False, always_check_in_use=False, preferred_objects=()):
        self._sim = sim.ref() if sim else None
        self.source = source
        self.priority = priority
        self.client = client
        self.pick = pick
        self.insert_strategy = insert_strategy
        self.must_run_next = must_run_next
        self.shift_held = shift_held
        self.continuation_id = continuation_id
        self.visual_continuation_id = visual_continuation_id
        self.group_id = group_id
        self.carry_target = carry_target
        self.target_sim_id = target_sim_id
        self.run_priority = run_priority
        self.bucket = bucket
        self.restored_from_load = restored_from_load
        self.cancel_if_incompatible_in_queue = cancel_if_incompatible_in_queue
        self.always_check_in_use = always_check_in_use
        self.preferred_objects = WeakSet(preferred_objects)

    def _clone(self, **overrides):
        result = copy.copy(self)
        for (name, value) in overrides.items():
            if value is DEFAULT:
                pass
            getattr(result, name)
            setattr(result, name, value)
        return result

    @property
    def bucket_type(self):
        return self.bucket

    @property
    def is_cancel_aop(self):
        return self.source == InteractionSource.BODY_CANCEL_AOP or self.source == InteractionSource.CARRY_CANCEL_AOP

    def clone_for_user_directed_choice(self):
        return self._clone(source=InteractionContext.SOURCE_PIE_MENU, priority=self.client.interaction_priority, insert_strategy=QueueInsertStrategy.LAST, continuation_id=None, group_id=None)

    def clone_for_autonomous_choice(self):
        return self._clone(source=InteractionContext.SOURCE_AUTONOMY, priority=interactions.priority.Priority.Low, insert_strategy=QueueInsertStrategy.LAST, continuation_id=None, group_id=None)

    def clone_for_insert_next(self, preferred_objects=DEFAULT, **kwargs):
        if preferred_objects is DEFAULT:
            preferred_objects = self.preferred_objects
        return self._clone(insert_strategy=QueueInsertStrategy.NEXT, preferred_objects=preferred_objects, restored_from_load=False, **kwargs)

    def clone_for_continuation(self, continuation_of_si, insert_strategy=QueueInsertStrategy.NEXT, continuation_id=DEFAULT, group_id=DEFAULT, preferred_objects=DEFAULT, **kwargs):
        if not continuation_of_si.immediate:
            if continuation_id is DEFAULT:
                continuation_id = continuation_of_si.id
            group_id = continuation_of_si.group_id
        else:
            logger.error('clone_for_continuation: attempting to create a continuation of an immediate interaction, support for this is deprecated and will be removed soon: {}', continuation_of_si, owner='jpollak/tastle')
        if preferred_objects is DEFAULT:
            preferred_objects = self.preferred_objects
        return self._clone(insert_strategy=insert_strategy, continuation_id=continuation_id, group_id=group_id, preferred_objects=preferred_objects, restored_from_load=False, **kwargs)

    def clone_for_parameterized_autonomy(self, source_si, group_id=DEFAULT, continuation_id=DEFAULT, visual_continuation_id=DEFAULT, **kwargs):
        if group_id is DEFAULT:
            group_id = source_si.group_id
        if continuation_id is DEFAULT:
            continuation_id = source_si.id
        if visual_continuation_id is DEFAULT:
            visual_continuation_id = source_si.id
        return self._clone(insert_strategy=QueueInsertStrategy.FIRST, group_id=group_id, continuation_id=continuation_id, run_priority=None, visual_continuation_id=source_si.id, **kwargs)

    def clone_from_immediate_context(self, continuation_of_si, **kwargs):
        if not continuation_of_si.immediate:
            logger.error('clone_from_immediate_context: attempting to create a continuation of a non-immediate interaction.', owner='tastle/jpollak')
        return self._clone(group_id=continuation_of_si.group_id, **kwargs)

    def clone_for_sim(self, sim, **overrides):
        return self._clone(_sim=sim.ref(), **overrides)

    def clone_for_concurrent_context(self):
        return self._clone(insert_strategy=QueueInsertStrategy.FIRST)

    @property
    def sim(self):
        if self._sim:
            return self._sim()

    def add_preferred_object(self, cur_obj):
        self.preferred_objects.add(cur_obj)

    def add_preferred_objects(self, obj_list):
        pass

    @property
    def carry_target(self):
        if self._carry_target:
            return self._carry_target()

    @carry_target.setter
    def carry_target(self, value):
        self._carry_target = value.ref() if value else None

    def __repr__(self):
        return '{0}.{1}({2}, {3}, {4})'.format(self.__module__, self.__class__.__name__, repr(self.sim), self.source, repr(self.priority))
Example #45
0
class Privacy(LineOfSight):
    __qualname__ = 'Privacy'
    _PRIVACY_FOOTPRINT_TYPE = 5
    _PRIVACY_DISCOURAGEMENT_COST = routing.get_default_discouragement_cost()
    _SHOO_CONSTRAINT_RADIUS = Tunable(description='\n        The radius of the constraint a Shooed Sim will attempt to route to.\n        ', tunable_type=float, default=2.5)
    _UNAVAILABLE_TOOLTIP = TunableLocalizedStringFactory(description='\n        Tooltip displayed when an object is not accessible due to being inside\n        a privacy region.\n        ')
    _EMBARRASSED_AFFORDANCE = TunableReference(description='\n        The affordance a Sim will play when getting embarrassed by walking in\n        on a privacy situation.\n        ', manager=services.affordance_manager())

    def __init__(self, interaction, tests, max_line_of_sight_radius, map_divisions, simplification_ratio, boundary_epsilon, facing_offset):
        super().__init__(max_line_of_sight_radius, map_divisions, simplification_ratio, boundary_epsilon)
        self._max_line_of_sight_radius = max_line_of_sight_radius
        self._interaction = interaction
        self._tests = tests
        self._privacy_constraints = []
        self._allowed_sims = WeakSet()
        self._disallowed_sims = WeakSet()
        self._violators = WeakSet()
        self._late_violators = WeakSet()
        self.is_active = False
        self.has_shooed = False
        self.central_object = None
        self._pushed_interactions = []
        services.privacy_service().add_instance(self)

    @property
    def unavailable_tooltip(self):
        return self._UNAVAILABLE_TOOLTIP

    @property
    def interaction(self):
        return self._interaction

    @property
    def is_active(self) -> bool:
        return self._is_active

    @is_active.setter
    def is_active(self, value):
        self._is_active = value

    def _is_sim_allowed(self, sim):
        if self._tests:
            resolver = self._interaction.get_resolver(target=sim)
            if self._tests and self._tests.run_tests(resolver):
                return True
        if self._interaction.can_sim_violate_privacy(sim):
            return True
        return False

    def evaluate_sim(self, sim):
        if self._is_sim_allowed(sim):
            self._allowed_sims.add(sim)
            return True
        self._disallowed_sims.add(sim)
        return False

    def build_privacy(self, target=None):
        self.is_active = True
        target_object = self._interaction.get_participant(ParticipantType.Object)
        target_object = None if target_object.is_sim else target_object
        self.central_object = target_object or (target or self._interaction.sim)
        self.generate(self.central_object.position, self.central_object.routing_surface)
        for poly in self.constraint.geometry.polygon:
            self._privacy_constraints.append(PolygonFootprint(poly, routing_surface=self._interaction.sim.routing_surface, cost=self._PRIVACY_DISCOURAGEMENT_COST, footprint_type=self._PRIVACY_FOOTPRINT_TYPE, enabled=True))
        self._allowed_sims.update(self._interaction.get_participants(ParticipantType.AllSims))
        for sim in services.sim_info_manager().instanced_sims_gen():
            while sim not in self._allowed_sims:
                self.evaluate_sim(sim)
        violating_sims = self.find_violating_sims()
        self._cancel_unavailable_interactions(violating_sims)
        self._add_overrides_and_constraints_if_needed(violating_sims)

    def cleanup_privacy_instance(self):
        if self.is_active:
            self.is_active = False
            for sim in self._allowed_sims:
                self.remove_override_for_sim(sim)
            for sim in self._late_violators:
                self.remove_override_for_sim(sim)
            del self._privacy_constraints[:]
            self._allowed_sims.clear()
            self._disallowed_sims.clear()
            self._violators.clear()
            self._late_violators.clear()
            self._cancel_pushed_interactions()

    def remove_privacy(self):
        self.cleanup_privacy_instance()
        services.privacy_service().remove_instance(self)

    def intersects_with_object(self, obj):
        if obj.routing_surface != self.central_object.routing_surface:
            return False
        delta = obj.position - self.central_object.position
        distance = delta.magnitude_2d_squared()
        if distance > self.max_line_of_sight_radius*self.max_line_of_sight_radius:
            return False
        object_footprint = obj.footprint_polygon
        if object_footprint is None:
            object_footprint = sims4.geometry.Polygon([obj.position])
        for poly in self.constraint.geometry.polygon:
            intersection = poly.intersect(object_footprint)
            while intersection is not None and intersection.has_enough_vertices:
                return True
        return False

    def find_violating_sims(self):
        if not self.is_active:
            return []
        nearby_sims = placement.get_nearby_sims(self.central_object.position, self.central_object.routing_surface.secondary_id, radius=self.max_line_of_sight_radius, exclude=self._allowed_sims, only_sim_position=True)
        violators = []
        for sim in nearby_sims:
            if any(sim_primitive.is_traversing_portal() for sim_primitive in sim.primitives if isinstance(sim_primitive, FollowPath)):
                pass
            if sim not in self._disallowed_sims and self.evaluate_sim(sim):
                pass
            while sims4.geometry.test_point_in_compound_polygon(sim.position, self.constraint.geometry.polygon):
                violators.append(sim)
        return violators

    def _add_overrides_and_constraints_if_needed(self, violating_sims):
        for sim in self._allowed_sims:
            self.add_override_for_sim(sim)
        for sim in violating_sims:
            self._violators.add(sim)
            liabilities = ((SHOO_LIABILITY, ShooLiability(self, sim)),)
            result = self._route_sim_away(sim, liabilities=liabilities)
            while result:
                self._pushed_interactions.append(result.interaction)

    def _cancel_unavailable_interactions(self, violating_sims):
        for sim in violating_sims:
            interactions_to_cancel = set()
            if sim.queue.running is not None:
                interactions_to_cancel.add(sim.queue.running)
            for interaction in sim.si_state:
                while interaction.is_super and interaction.target is not None and sim.locked_from_obj_by_privacy(interaction.target):
                    interactions_to_cancel.add(interaction)
            for interaction in sim.queue:
                if interaction.target is not None and sim.locked_from_obj_by_privacy(interaction.target):
                    interactions_to_cancel.add(interaction)
                else:
                    while interaction.target is not None:
                        break
            for interaction in interactions_to_cancel:
                interaction.cancel(FinishingType.INTERACTION_INCOMPATIBILITY, cancel_reason_msg='Canceled due to incompatibility with privacy instance.')

    def _route_sim_away(self, sim, liabilities=()):
        context = InteractionContext(sim, InteractionContext.SOURCE_SCRIPT, Priority.High, insert_strategy=QueueInsertStrategy.NEXT)
        from interactions.utils.satisfy_constraint_interaction import BuildAndForceSatisfyShooConstraintInteraction
        result = sim.push_super_affordance(BuildAndForceSatisfyShooConstraintInteraction, None, context, liabilities=liabilities, privacy_inst=self, name_override='BuildShooFromPrivacy')
        if not result:
            logger.debug('Failed to push BuildAndForceSatisfyShooConstraintInteraction on Sim {} to route them out of a privacy area.  Result: {}', sim, result, owner='tastle')
            self.interaction.cancel(FinishingType.TRANSITION_FAILURE, cancel_reason_msg='Failed to shoo Sims away.')
        return result

    def _cancel_pushed_interactions(self):
        for interaction in self._pushed_interactions:
            interaction.cancel(FinishingType.AUTO_EXIT, cancel_reason_msg='Privacy finished and is cleaning up.')
        self._pushed_interactions.clear()

    def handle_late_violator(self, sim):
        self._cancel_unavailable_interactions((sim,))
        self.add_override_for_sim(sim)
        liabilities = ((LATE_SHOO_LIABILITY, LateShooLiability(self, sim)),)
        result = self._route_sim_away(sim, liabilities=liabilities)
        if not result:
            return
        if not self._violators:
            context = InteractionContext(sim, InteractionContext.SOURCE_SCRIPT, Priority.High, insert_strategy=QueueInsertStrategy.NEXT)
            result = sim.push_super_affordance(self._EMBARRASSED_AFFORDANCE, self.interaction.get_participant(ParticipantType.Actor), context)
            if not result:
                logger.error('Failed to push the embarrassed affordance on Sim {}. Interaction {}. Result {}. Context {} ', sim, self.interaction, result, context, owner='tastle')
                return
        self._late_violators.add(sim)

    def add_override_for_sim(self, sim):
        for footprint in self._privacy_constraints:
            sim.routing_context.ignore_footprint_contour(footprint.footprint_id)

    def remove_override_for_sim(self, sim):
        for footprint in self._privacy_constraints:
            sim.routing_context.remove_footprint_contour_override(footprint.footprint_id)

    @property
    def allowed_sims(self):
        return self._allowed_sims

    @property
    def disallowed_sims(self):
        return self._disallowed_sims

    @property
    def violators(self):
        return self._violators

    def remove_violator(self, sim):
        self.remove_override_for_sim(sim)
        self._violators.discard(sim)

    @property
    def late_violators(self):
        return self._late_violators

    def remove_late_violator(self, sim):
        self.remove_override_for_sim(sim)
        self._late_violators.discard(sim)
Example #46
0
 def __init__(self, docid):
     self.docid = docid.encode('latin-1')
     self.avatars = WeakSet()