private void LateSetup()
        {
            this.Monitor.Log("Performing late setup...", LogLevel.Debug);
            var promenade = Game1.getLocationFromName("SundropPromenade");
            var start     = DateTime.Now;

            if (promenade == null)
            {
                return;
            }
            List <Task> tasks = new List <Task>
            {
                Task.Run(() =>
                {
                    this.Monitor.Log("Repairing locations...", LogLevel.Trace);
                    Parallel.ForEach(Game1.locations, loc =>
                    {
                        if (loc.map.Properties.ContainsKey("IsSundropLocation"))
                        {
                            this.SetupLocation(loc);
                        }
                    });
                }),
                Task.Run(() =>
                {
                    this.Monitor.Log("Spawning characters...", LogLevel.Trace);
                    Parallel.ForEach(this.Helper.Data.ReadJsonFile <CharacterInfo[]>("assets/Data/CharacterSpawns.json"), info =>
                    {
                        if (Game1.getLocationFromName(info.Map) == null)
                        {
                            this.Monitor.Log("Unable to add villager by name of `" + info.Name + "` because their default map failed to load, this character will not appear in your game as a result.", LogLevel.Error);
                        }
                        else
                        {
                            try
                            {
                                this.Monitor.Log("Adding sundrop villager: " + info.Name, LogLevel.Trace);
                                var pos         = new Vector2(info.Position[0], info.Position[1]);
                                var villagerNpc = new NPC(new AnimatedSprite(this.Helper.Content.GetActualAssetKey("assets/Characters/Sprites/" + info.Texture + ".png"), 18, 16, 32), pos * 64f, 2, info.Name)
                                {
                                    Portrait        = this.Helper.Content.Load <Texture2D>("assets/Characters/Portraits/" + info.Texture + ".png"),
                                    DefaultMap      = info.Map,
                                    DefaultPosition = pos * 64f
                                };
                                villagerNpc.setNewDialogue(info.Message);
                                lock (Game1.getLocationFromName(info.Map))
                                    Game1.getLocationFromName(info.Map).addCharacter(villagerNpc);
                            }
                            catch (Exception err)
                            {
                                this.Monitor.Log("Unable to add villager by name of `" + info.Name + "` due to a unexpected issue, this character will not appear in your game as a result.\n" + err, LogLevel.Error);
                            }
                        }
                    });
                }),
                Task.Run(() =>
                {
                    this.Monitor.Log("Spawning cameos...", LogLevel.Trace);
                    Parallel.ForEach(this.Helper.Data.ReadJsonFile <CharacterInfo[]>("assets/Data/CameoSpawns.json"), info =>
                    {
                        if (Game1.getLocationFromName(info.Map) == null)
                        {
                            this.Monitor.Log("Unable to add cameo character for `" + info.Name + "` because their default map failed to load, this character will not appear in your game as a result.", LogLevel.Warn);
                        }
                        else
                        {
                            try
                            {
                                this.Monitor.Log("Adding sundrop cameo: " + info.Name, LogLevel.Trace);
                                var pos      = new Vector2(info.Position[0], info.Position[1]);
                                var cameoNpc = new NPC(new AnimatedSprite(this.Helper.Content.GetActualAssetKey("assets/Characters/Cameos/" + info.Name + "Sprite.png"), 18, 16, 32), pos * 64f, 2, info.Name)
                                {
                                    Portrait        = this.Helper.Content.Load <Texture2D>("assets/Characters/Cameos/" + info.Name + "Portrait.png"),
                                    DefaultMap      = info.Map,
                                    DefaultPosition = pos * 64f
                                };
                                cameoNpc.setNewDialogue(info.Message);
                                lock (Game1.getLocationFromName(info.Map))
                                    Game1.getLocationFromName(info.Map).addCharacter(cameoNpc);
                            }
                            catch (Exception err)
                            {
                                this.Monitor.Log("Unable to add cameo character for `" + info.Name + "` due to a unexpected issue, this character will not appear in your game as a result.\n" + err, LogLevel.Warn);
                            }
                        }
                    });
                })
            };

            Task.WaitAll(tasks.ToArray());
            var npc = Game1.getCharacterFromName("Joe");

            if (npc != null)
            {
                npc.Schedule = this.Helper.Reflection.GetMethod(npc, "parseMasterSchedule").Invoke <Dictionary <int, SchedulePathDescription> >("610 80 20 2/630 23 20 2/710 80 20 2/730 23 20 2/810 80 20 2/830 23 20 2/910 80 20 2/930 23 20 2");
                NPC cake = new MrCake(new Vector2(22, 20), npc);
                cake.setNewDialogue("Mr. Cake looks at you with approval.");
                promenade?.addCharacter(cake);
            }
            SundropCityMod.FixBushes();
            var end  = DateTime.Now;
            var time = end.Subtract(start);

            this.Monitor.Log("Late setup took " + time.TotalMilliseconds + " milliseconds, sundrop is now ready for you - enjoy!", LogLevel.Debug);
        }