def time_until_hour_of_day(now, hour_of_day): cur_hour = now.hour() + now.minute() / date_and_time.SECONDS_PER_MINUTE cur_day = int(now.absolute_days()) if cur_hour < hour_of_day: future = date_and_time.create_date_and_time(days=cur_day, hours=hour_of_day) else: future = date_and_time.create_date_and_time(days=cur_day + 1, hours=hour_of_day) return future - now
def precise_time_until_hour_of_day(self, hour_of_day): cur_hour = self.now().hour() cur_day = int(self.now().absolute_days()) if cur_hour < hour_of_day: future = date_and_time.create_date_and_time(days=cur_day, hours=hour_of_day) else: future = date_and_time.create_date_and_time(days=cur_day + 1, hours=hour_of_day) return future - self.now()
def get_timespan_to_next_shift_time(self, time_of_day): if not self.entries: return days_to_schedule_ahead = 1 current_day = time_of_day.day() next_day = (current_day + days_to_schedule_ahead) % 7 next_day_sorted_times = self._get_sorted_situation_schedule(next_day) if next_day_sorted_times: next_shift_hour = next_day_sorted_times[0][0] else: next_shift_hour = 0 now = services.time_service().sim_now sorted_times = self._get_sorted_situation_schedule(current_day) scheduled_day = int(now.absolute_days()) now_hour = now.hour() for (shift_hour, _) in sorted_times: if shift_hour > now_hour: next_shift_hour = shift_hour break else: scheduled_day += 1 future = date_and_time.create_date_and_time(days=scheduled_day, hours=next_shift_hour) time_span_until = future - now return time_span_until
def setup(self, gameplay_zone_data=None, save_slot_data=None): if gameplay_zone_data is None: return world_game_time = self._initial_ticks if save_slot_data is not None and save_slot_data.HasField( 'gameplay_data'): world_game_time = save_slot_data.gameplay_data.world_game_time self._zone_init_world_game_time = DateAndTime(world_game_time) initial_time = world_game_time if gameplay_zone_data.HasField('game_time'): saved_ticks = gameplay_zone_data.game_time tick_diff = world_game_time - saved_ticks time_diff = TimeSpan(tick_diff) self._time_of_last_save = DateAndTime(saved_ticks) if time_diff.in_minutes( ) < PersistenceTuning.MAX_LOT_SIMULATE_ELAPSED_TIME: initial_time = saved_ticks else: max_minutes = date_and_time.create_date_and_time( minutes=PersistenceTuning.MAX_LOT_SIMULATE_ELAPSED_TIME) initial_time = world_game_time - max_minutes.absolute_ticks() self._initial_ticks = initial_time if gameplay_zone_data.HasField('clock_speed_mode'): self._client_connect_speed = ClockSpeedMode( gameplay_zone_data.clock_speed_mode) else: self._client_connect_speed = ClockSpeedMode.NORMAL
def _times_from_voting_time_of_week(self, relative_to_time, voting_time_of_week): day = voting_time_of_week.day hour = voting_time_of_week.hour minute = voting_time_of_week.minute time = create_date_and_time(days=day, hours=hour, minutes=minute) time_span = relative_to_time.time_to_week_time(time) return (time, time_span)
def _get_time_span_to_next_moonlight_schedule(self, time_of_day): if not self.bowling_venue.moonlight_on_off_schedule: return days_to_schedule_ahead = 1 current_day = time_of_day.day() next_day = (current_day + days_to_schedule_ahead) % 7 next_day_sorted_times = self._get_sorted_moonlight_schedule(next_day) if next_day_sorted_times: next_moonlight_hour = next_day_sorted_times[0][0] else: next_moonlight_hour = 0 now = services.time_service().sim_now sorted_times = self._get_sorted_moonlight_schedule(current_day) scheduled_day = int(now.absolute_days()) now_hour = now.hour() for (moonlight_hour, _) in sorted_times: if moonlight_hour > now_hour: next_moonlight_hour = moonlight_hour break else: scheduled_day += 1 future = date_and_time.create_date_and_time(days=scheduled_day, hours=next_moonlight_hour) time_span_until = future - now return time_span_until
def schedule_node(drama_node: TunableInstanceParam( sims4.resources.Types.DRAMA_NODE), actor_sim_id: OptionalSimInfoParam = None, target_sim_id: OptionalSimInfoParam = None, days_from_now: int = None, _connection=None): actor_sim_info = get_optional_target(actor_sim_id, _connection, OptionalSimInfoParam) if target_sim_id is not None: target_sim_info = get_optional_target(target_sim_id, _connection, OptionalSimInfoParam) else: target_sim_info = None specific_time = None if days_from_now is not None: scheduled_day = int( services.time_service().sim_now.absolute_days()) + days_from_now specific_time = create_date_and_time(days=scheduled_day) resolver = DoubleSimResolver(actor_sim_info, target_sim_info) uid = services.drama_scheduler_service().schedule_node( drama_node, resolver, specific_time=specific_time) if uid is not None: sims4.commands.output( 'Successfully scheduled drama node: {}'.format( drama_node.__name__), _connection) else: sims4.commands.output( 'Failed to scheduled drama node: {}'.format(drama_node.__name__), _connection)
def _get_default_sleep_schedule_work_time(self, offset_time): now = services.time_service().sim_now if offset_time is not None: now += offset_time work_time = date_and_time.create_date_and_time(days=int(now.absolute_days()), hours=self.SLEEP_SCHEDULE.default_work_time.hour(), minutes=self.SLEEP_SCHEDULE.default_work_time.minute()) if work_time < now: work_time += date_and_time.create_time_span(days=1) return work_time
def _create_curfew_callback(self, now, time): if time is not self.UNSET: alarm_time = date_and_time.create_date_and_time(hours=time) curfew_span = now.time_till_next_day_time(alarm_time) if curfew_span.in_ticks() == 0: curfew_span += TimeSpan(date_and_time.sim_ticks_per_day()) self._curfew_started_alarm_handle = alarms.add_alarm( self, curfew_span, self._handle_curfew_callback, False)
def _create_warning_callback(self, now, time): if time is not CurfewService.UNSET: alarm_time = date_and_time.create_date_and_time(hours=time - 1) warning_span = now.time_till_next_day_time(alarm_time) if warning_span.in_ticks() == 0: warning_span += TimeSpan(date_and_time.sim_ticks_per_day()) self._curfew_warning_alarm_handle = alarms.add_alarm( self, warning_span, self._handle_warning_callback, False)
def _setup_scoring_alarm(self): day_time = date_and_time.create_date_and_time(hours=self.SCORING_TIME) now = services.time_service().sim_now time_delay = now.time_till_next_day_time(day_time) if time_delay.in_ticks() == 0: time_delay = date_and_time.create_time_span(days=1) schedule_time = now + time_delay sim_timeline = services.time_service().sim_timeline self._processor = sim_timeline.schedule(elements.GeneratorElement(self._process_scoring_gen), when=schedule_time)
def _create_curfew_ended_callback(self, now, time): if time is not CurfewService.UNSET: alarm_time = date_and_time.create_date_and_time( hours=CurfewService.CURFEW_END_TIME) curfew_span = now.time_till_next_day_time(alarm_time) if curfew_span.in_ticks() == 0: curfew_span += TimeSpan(date_and_time.sim_ticks_per_day()) self._curfew_ended_alarm_handle = alarms.add_alarm( self, curfew_span, self._handle_curfew_ended_callback, False)
def _get_default_sleep_schedule_work_time(self, offset_time): now = services.time_service().sim_now if offset_time is not None: now += offset_time work_time = date_and_time.create_date_and_time( days=int(now.absolute_days()), hours=self.SLEEP_SCHEDULE.default_work_time.hour(), minutes=self.SLEEP_SCHEDULE.default_work_time.minute()) if work_time < now: work_time += date_and_time.create_time_span(days=1) return work_time
def _set_next_daily_random_voting_alarm(self): if self._voting_daily_random_alarm is not None: alarms.cancel_alarm(self._voting_daily_random_alarm) if not self.voting_open: self._voting_daily_random_alarm = None return time_of_day = create_date_and_time(hours=0) now = services.time_service().sim_now daily_random_voting_span = now.time_till_next_day_time(time_of_day) if daily_random_voting_span == TimeSpan.ZERO: daily_random_voting_span += TimeSpan(sim_ticks_per_day()) self._voting_daily_random_alarm = alarms.add_alarm(self, daily_random_voting_span, lambda _: self._do_daily_random_voting(), cross_zone=True)
def _setup_lottery(self): time = create_date_and_time(days=self.end_time.day, hours=self.end_time.hour, minutes=self.end_time.minute) time_until_end = services.time_service().sim_now.time_to_week_time( time) self._end_alarm_handle = alarms.add_alarm(self, time_until_end, self._end_lottery, cross_zone=True) services.get_event_manager().register_single_event( self, self.lottery_event)
def _set_up_bill_timer(self): day = self.TIME_TO_PLACE_BILL_IN_HIDDEN_INVENTORY.day hour = self.TIME_TO_PLACE_BILL_IN_HIDDEN_INVENTORY.hour minute = self.TIME_TO_PLACE_BILL_IN_HIDDEN_INVENTORY.minute time = create_date_and_time(days=day, hours=hour, minutes=minute) time_until_bill_delivery = services.time_service().sim_now.time_to_week_time(time) bill_delivery_time = services.time_service().sim_now + time_until_bill_delivery end_of_first_week = DateAndTime(0) + interval_in_sim_weeks(1) if bill_delivery_time < end_of_first_week: time_until_bill_delivery += interval_in_sim_weeks(1) if time_until_bill_delivery.in_ticks() <= 0: time_until_bill_delivery = TimeSpan(1) self._bill_timer_handle = alarms.add_alarm(self, time_until_bill_delivery, lambda _: self.allow_bill_delivery())
def _set_up_bill_timer(self): day = self.TIME_TO_PLACE_BILL_IN_HIDDEN_INVENTORY.day hour = self.TIME_TO_PLACE_BILL_IN_HIDDEN_INVENTORY.hour minute = self.TIME_TO_PLACE_BILL_IN_HIDDEN_INVENTORY.minute time = create_date_and_time(days=day, hours=hour, minutes=minute) time_until_bill_delivery = services.time_service( ).sim_now.time_to_week_time(time) bill_delivery_time = services.time_service( ).sim_now + time_until_bill_delivery end_of_first_week = DateAndTime(0) + interval_in_sim_weeks(1) if bill_delivery_time < end_of_first_week: time_until_bill_delivery += interval_in_sim_weeks(1) if time_until_bill_delivery.in_ticks() <= 0: time_until_bill_delivery = TimeSpan(1) self._bill_timer_handle = alarms.add_alarm( self, time_until_bill_delivery, lambda _: self.allow_bill_delivery())
def _setup_curfew_text_message(self): if self._curfew_message_alarm_handle is not None: self._curfew_message_alarm_handle.cancel() self._curfew_message_alarm_handle = None current_household = services.active_household() if current_household is None: return home_zone_id = current_household.home_zone_id curfew_setting = self._zone_curfew_data.get(home_zone_id, CurfewService.UNSET) if curfew_setting is CurfewService.UNSET: return now = services.time_service().sim_now alarm_time = date_and_time.create_date_and_time(hours=curfew_setting) time_till_alarm = now.time_till_next_day_time(alarm_time) span = date_and_time.create_time_span( minutes=CurfewService.MINUTES_BEFORE_CURFEW_WARNING) time_till_alarm -= span self._curfew_message_alarm_handle = alarms.add_alarm( self, time_till_alarm, self._handle_curfew_message_callback, False)
def verify_valid_time(self, drama_node): time_option = drama_node.time_option if time_option.option != TimeSelectionOption.SINGLE_TIME: logger.error( 'Drama Node ({}) does not have a valid time tuned and will not schedule.', drama_node) return else: now = services.time_service().sim_now org_day_and_hour = create_date_and_time( days=time_option.valid_time.day, hours=time_option.valid_time.hour) org_start_time = date_and_time_from_week_time( now.week(), org_day_and_hour) if org_start_time < now: org_start_time = date_and_time_from_week_time( now.week() + 1, org_day_and_hour) if org_start_time < now: return return org_start_time
def date_and_time_from_days_hours_minutes(day, hour, minute): return date_and_time.create_date_and_time(days=day, hours=hour, minutes=minute)
def date_and_time_from_hours_minutes(hour, minute): return date_and_time.create_date_and_time(hours=hour, minutes=minute)
def _score_and_schedule_drama_nodes_gen(self, timeline, from_zone_spin_up=False): active_household = services.active_household() if active_household is None: return current_time = services.time_service().sim_now current_day = current_time.day() venue_manager = services.get_instance_manager(sims4.resources.Types.VENUE) for neighborhood_proto in services.get_persistence_service().get_neighborhoods_proto_buf_gen(): for lot_owner_info in neighborhood_proto.lots: zone_id = lot_owner_info.zone_instance_id if not zone_id: continue venue_tuning = venue_manager.get(build_buy.get_current_venue(zone_id)) if venue_tuning is None: continue if not venue_tuning.drama_node_events: continue if is_scoring_archive_enabled(): gsi_data = GSIDramaScoringData() gsi_data.bucket = 'Venue' else: gsi_data = None yield from self.score_and_schedule_nodes_gen(venue_tuning.drama_node_events, venue_tuning.drama_node_events_to_schedule, timeline=timeline, gsi_data=gsi_data, zone_id=zone_id) if gsi_data is not None: archive_drama_scheduler_scoring(gsi_data) if timeline is not None: yield timeline.run_child(elements.SleepElement(date_and_time.TimeSpan(0))) bucketted_nodes = defaultdict(list) drama_node_manager = services.get_instance_manager(sims4.resources.Types.DRAMA_NODE) for drama_node in drama_node_manager.types.values(): if drama_node.scoring is None: continue bucketted_nodes[drama_node.scoring.bucket].append(drama_node) buckets_to_score = [] if from_zone_spin_up or not self._check_day(current_day, self.VENUE_BUCKET_DAYS) or from_zone_spin_up: buckets = self.STARTUP_BUCKETS - self._startup_buckets_used if current_time < create_date_and_time(days=int(current_time.absolute_days()), hours=self.SCORING_TIME): day_modifier = -1 else: day_modifier = 0 for bucket in buckets: if not bucketted_nodes[bucket]: continue self._startup_buckets_used.add(bucket) rules = self.BUCKET_SCORING_RULES[bucket] smallest_day_modification = None for (day, day_enabled) in rules.days.items(): if not day_enabled: continue potential_modification = current_day + day_modifier - day potential_modification += DAYS_PER_WEEK if not potential_modification < 0 or smallest_day_modification is None or potential_modification < smallest_day_modification: smallest_day_modification = potential_modification if smallest_day_modification is None: time_modification = TimeSpan.ZERO else: time_modification = TimeSpan(current_time.absolute_ticks()) - create_time_span(days=int(current_time.absolute_days()) - smallest_day_modification + day_modifier, hours=self.SCORING_TIME) buckets_to_score.append((bucket, rules, time_modification)) else: for (bucket_type, rules) in self.BUCKET_SCORING_RULES.items(): valid_day = self._check_day(current_day, rules.days) for drama_node in self._scheduled_nodes.values(): if drama_node.scoring is None: continue if drama_node.scoring.bucket == bucket_type: break else: valid_day = True if valid_day or not rules.score_if_no_nodes_are_scheduled or valid_day: buckets_to_score.append((bucket_type, rules, TimeSpan.ZERO)) for (bucket_type, rules, time_modifier) in buckets_to_score: if is_scoring_archive_enabled(): gsi_data = GSIDramaScoringData() gsi_data.bucket = bucket_type else: gsi_data = None if rules.number_to_schedule.option == NodeSelectionOption.BASED_ON_HOUSEHOLD: nodes_to_schedule = 1 + math.floor(len(active_household)/2) elif rules.number_to_schedule.option == NodeSelectionOption.STATIC_AMOUNT: nodes_to_schedule = rules.number_to_schedule.number_of_nodes else: logger.error('Trying to determine how many nodes to run with invalid option {}', rules.number_to_schedule.option) if gsi_data is not None: archive_drama_scheduler_scoring(gsi_data) if nodes_to_schedule == 0: if gsi_data is not None: archive_drama_scheduler_scoring(gsi_data) for node in list(self._scheduled_nodes.values()): if not not node.scoring is not None and node.scoring.bucket == bucket_type: self.cancel_scheduled_node(node.uid) yield from self.score_and_schedule_nodes_gen(bucketted_nodes[bucket_type], nodes_to_schedule, time_modifier=time_modifier, timeline=timeline, gsi_data=gsi_data) if not rules.refresh_nodes_on_scheduling or gsi_data is not None: archive_drama_scheduler_scoring(gsi_data) if timeline is not None: yield timeline.run_child(elements.SleepElement(date_and_time.TimeSpan(0))) else: gsi_data.nodes_to_schedule = nodes_to_schedule for node in list(self._scheduled_nodes.values()): if not not node.scoring is not None and node.scoring.bucket == bucket_type: self.cancel_scheduled_node(node.uid) yield from self.score_and_schedule_nodes_gen(bucketted_nodes[bucket_type], nodes_to_schedule, time_modifier=time_modifier, timeline=timeline, gsi_data=gsi_data) if not rules.refresh_nodes_on_scheduling or gsi_data is not None: archive_drama_scheduler_scoring(gsi_data) if timeline is not None: yield timeline.run_child(elements.SleepElement(date_and_time.TimeSpan(0))) if nodes_to_schedule == 0: if gsi_data is not None: archive_drama_scheduler_scoring(gsi_data) for node in list(self._scheduled_nodes.values()): if not not node.scoring is not None and node.scoring.bucket == bucket_type: self.cancel_scheduled_node(node.uid) yield from self.score_and_schedule_nodes_gen(bucketted_nodes[bucket_type], nodes_to_schedule, time_modifier=time_modifier, timeline=timeline, gsi_data=gsi_data) if not rules.refresh_nodes_on_scheduling or gsi_data is not None: archive_drama_scheduler_scoring(gsi_data) if timeline is not None: yield timeline.run_child(elements.SleepElement(date_and_time.TimeSpan(0))) else: gsi_data.nodes_to_schedule = nodes_to_schedule for node in list(self._scheduled_nodes.values()): if not not node.scoring is not None and node.scoring.bucket == bucket_type: self.cancel_scheduled_node(node.uid) yield from self.score_and_schedule_nodes_gen(bucketted_nodes[bucket_type], nodes_to_schedule, time_modifier=time_modifier, timeline=timeline, gsi_data=gsi_data) if not rules.refresh_nodes_on_scheduling or gsi_data is not None: archive_drama_scheduler_scoring(gsi_data) if timeline is not None: yield timeline.run_child(elements.SleepElement(date_and_time.TimeSpan(0)))
def date_and_time_from_days_hours_minutes(day, hour, minute): return date_and_time.create_date_and_time( days=day, hours=hour, minutes=minute)