/// <summary> /// Generates schedules for everyone. /// </summary> internal static void GenerateAllSchedules() { Game1.netWorldState.Value.IslandVisitors.Clear(); if (Game1.getLocationFromName("IslandSouth") is not IslandSouth island || !island.resortRestored.Value || !island.resortOpenToday.Value || Game1.IsRainingHere(island) || Utility.isFestivalDay(Game1.Date.DayOfMonth, Game1.Date.Season) || (Game1.Date.DayOfMonth >= 15 && Game1.Date.DayOfMonth <= 17 && Game1.IsWinter)) { return; } Random random = new((int)(Game1.uniqueIDForThisGame * 1.21f) + (int)(Game1.stats.DaysPlayed * 2.5f)); HashSet <NPC> explorers = GenerateExplorerGroup(random); if (explorers.Count > 0) { Globals.ModMonitor.DebugOnlyLog($"Found explorer group: {string.Join(", ", explorers.Select((NPC npc) => npc.Name))}."); IslandNorthScheduler.Schedule(random, explorers); } // Resort capacity set to zero, can skip everything else. if (Globals.Config.Capacity == 0 && (Globals.SaveDataModel is null || Globals.SaveDataModel.NPCsForTomorrow.Count == 0)) { IslandSouthPatches.ClearCache(); GIScheduler.ClearCache(); return; } List <NPC> visitors = GenerateVistorList(random, Globals.Config.Capacity, explorers); Dictionary <string, string> animationDescriptions = Globals.ContentHelper.Load <Dictionary <string, string> >("Data/animationDescriptions", ContentSource.GameContent); GIScheduler.Bartender = SetBartender(visitors); GIScheduler.Musician = SetMusician(random, visitors, animationDescriptions); List <GingerIslandTimeSlot> activities = AssignIslandSchedules(random, visitors, animationDescriptions); Dictionary <NPC, string> schedules = RenderIslandSchedules(random, visitors, activities); foreach (NPC visitor in schedules.Keys) { Globals.ModMonitor.Log($"Calculated island schedule for {visitor.Name}"); visitor.islandScheduleName.Value = "island"; ScheduleUtilities.ParseMasterScheduleAdjustedForChild2NPC(visitor, schedules[visitor]); Game1.netWorldState.Value.IslandVisitors[visitor.Name] = true; ConsoleCommands.IslandSchedules[visitor.Name] = schedules[visitor]; } IslandSouthPatches.ClearCache(); GIScheduler.ClearCache(); #if DEBUG Globals.ModMonitor.Log($"Current memory usage {GC.GetTotalMemory(false):N0}", LogLevel.Alert); GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; GC.Collect(); Globals.ModMonitor.Log($"Post-collection memory usage {GC.GetTotalMemory(true):N0}", LogLevel.Alert); #endif }
private void OnTimeChanged(object?sender, TimeChangedEventArgs e) { MidDayScheduleEditor.AttemptAdjustGISchedule(e); if (e.NewTime > 615 && !this.haveFixedSchedulesToday) { // No longer need the exclusions cache. IslandSouthPatches.ClearCache(); ScheduleUtilities.FixUpSchedules(); if (Globals.Config.DebugMode) { ScheduleDebugPatches.FixNPCs(); } this.haveFixedSchedulesToday = true; } }
/// <summary> /// Clear all caches at the end of the day and if the player exits to menu. /// </summary> private void ClearCaches() { DialoguePatches.ClearTalkRecord(); DialogueUtilities.ClearDialogueLog(); if (Context.IsSplitScreen && Context.ScreenId != 0) { return; } this.haveFixedSchedulesToday = false; MidDayScheduleEditor.Reset(); IslandSouthPatches.ClearCache(); GIScheduler.ClearCache(); GIScheduler.DayEndReset(); ConsoleCommands.ClearCache(); ScheduleUtilities.ClearCache(); }
/// <summary> /// Takes a list of activities and renders them as proper schedules. /// </summary> /// <param name="random">Sedded random.</param> /// <param name="visitors">List of visitors.</param> /// <param name="activities">List of activities.</param> /// <returns>Dictionary of NPC->raw schedule strings.</returns> private static Dictionary <NPC, string> RenderIslandSchedules(Random random, List <NPC> visitors, List <GingerIslandTimeSlot> activities) { Dictionary <NPC, string> completedSchedules = new(); foreach (NPC visitor in visitors) { bool should_dress = IslandSouth.HasIslandAttire(visitor); List <SchedulePoint> scheduleList = new(); if (should_dress) { scheduleList.Add(new SchedulePoint( random: random, npc: visitor, map: "IslandSouth", time: 1150, point: IslandSouth.GetDressingRoomPoint(visitor), animation: "change_beach", isarrivaltime: true)); } foreach (GingerIslandTimeSlot activity in activities) { if (activity.Assignments.TryGetValue(visitor, out SchedulePoint? schedulePoint)) { scheduleList.Add(schedulePoint); } } if (should_dress) { scheduleList.Add(new SchedulePoint( random: random, npc: visitor, map: "IslandSouth", time: 1730, point: IslandSouth.GetDressingRoomPoint(visitor), animation: "change_normal", isarrivaltime: true)); } scheduleList[0].IsArrivalTime = true; // set the first slot, whatever it is, to be the arrival time. // render the schedule points to strings before appending the remainder schedules // which are already strings. List <string> schedPointString = scheduleList.Select((SchedulePoint pt) => pt.ToString()).ToList(); if (visitor.Name.Equals("Gus", StringComparison.OrdinalIgnoreCase)) { // Gus needs to tend bar. Hardcoded same as vanilla. schedPointString.Add("1800 Saloon 10 18 2/2430 bed"); } else { // Try to find a GI remainder schedule, if any. schedPointString.Add(ScheduleUtilities.FindProperGISchedule(visitor, SDate.Now()) // Child2NPC NPCs don't understand "bed", must send them to the bus stop spouse dropoff. ?? (Globals.IsChildToNPC?.Invoke(visitor) == true ? "1800 BusStop -1 23 3" : "1800 bed")); } completedSchedules[visitor] = string.Join("/", schedPointString); Globals.ModMonitor.DebugOnlyLog($"For {visitor.Name}, created island schedule {completedSchedules[visitor]}"); } return(completedSchedules); }
public BreakAvailabilityUpdateHandler(ILogger logger, IBreakRepository breakRepository, Schedule schedule) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _breakRepository = breakRepository ?? throw new ArgumentNullException(nameof(breakRepository)); _scheduleUtilities = CreateScheduleUtilities(schedule); }