public void Edit <T>(IAssetData asset)
        {
            var data = asset.AsDictionary <string, string>().Data;

            foreach (Letter letter in MailDao.GetSavedLetters())
            {
                if (letter.Title != null && !letter.AutoOpen)
                {
                    data[letter.Id] = letter.Text + "[#]" + letter.Title;
                }
            }
            foreach (string letterId in MailDao.GetRemovedLetterIds())
            {
                if (data.ContainsKey(letterId))
                {
                    data.Remove(letterId);
                }
            }
            MailDao.CleanDataToUpdate();
        }
        public static void LoadContentPacks(object sender, EventArgs e)
        {
            foreach (IContentPack contentPack in MailFrameworkModEntry.ModHelper.ContentPacks.GetOwned())
            {
                if (File.Exists(Path.Combine(contentPack.DirectoryPath, "mail.json")))
                {
                    bool hasTranslation = contentPack.Translation.GetTranslations().Any();

                    MailFrameworkModEntry.ModMonitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
                    List <MailItem> mailItems = contentPack.ReadJsonFile <List <MailItem> >("mail.json");
                    foreach (MailItem mailItem in mailItems)
                    {
                        Dictionary <int, string> objects    = null;
                        Dictionary <int, string> bigObjects = null;
                        Dictionary <int, string> furnitures = null;
                        Dictionary <int, string> weapons    = null;
                        Dictionary <int, string> boots      = null;

                        //Populate all Indexes based on the given name. Ignore the letter otherwise.
                        if (mailItem.CollectionConditions != null && mailItem.CollectionConditions.Any(c =>
                        {
                            if (c.Name != null && c.Collection != Collection.Crafting)
                            {
                                objects ??= MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >(PathUtilities.NormalizeAssetName("Data/ObjectInformation"), ContentSource.GameContent);
                                KeyValuePair <int, string> pair = objects.FirstOrDefault(o => o.Value.StartsWith(c.Name + "/"));
                                if (pair.Value != null)
                                {
                                    c.Index = pair.Key;
                                }
                                else
                                {
                                    MailFrameworkModEntry.ModMonitor.Log($"No object found with the name '{c.Name}' for a condition for letter '{mailItem.Id}'.\n This letter will be ignored.", LogLevel.Warn);
                                    MailDao.RemoveLetter(new Letter(mailItem.Id, null, null));
                                    return(true);
                                }
                            }
                            return(false);
                        }))
                        {
                            continue;
                        }

                        bool Condition(Letter l) =>
                        (!Game1.player.mailReceived.Contains(l.Id) || mailItem.Repeatable) &&
                        (mailItem.Recipe == null || !Game1.player.cookingRecipes.ContainsKey(mailItem.Recipe)) &&
                        (mailItem.Date == null || SDate.Now() >= new SDate(Convert.ToInt32(mailItem.Date.Split(' ')[0]), mailItem.Date.Split(' ')[1], Convert.ToInt32(mailItem.Date.Split(' ')[2].Replace("Y", "")))) &&
                        (mailItem.Days == null || mailItem.Days.Contains(SDate.Now().Day)) &&
                        (mailItem.Seasons == null || mailItem.Seasons.Contains(SDate.Now().Season)) &&
                        (mailItem.Weather == null || (Game1.isRaining && "rainy".Equals(mailItem.Weather)) || (!Game1.isRaining && "sunny".Equals(mailItem.Weather))) &&
                        (mailItem.FriendshipConditions == null || (mailItem.FriendshipConditions.TrueForAll(f => Game1.player.getFriendshipHeartLevelForNPC(f.NpcName) >= f.FriendshipLevel)) &&
                         mailItem.FriendshipConditions.TrueForAll(f => f.FriendshipStatus == null || (Game1.player.friendshipData.ContainsKey(f.NpcName) && f.FriendshipStatus.Any(s => s == Game1.player.friendshipData[f.NpcName].Status)))) &&
                        (mailItem.SkillConditions == null || mailItem.SkillConditions.TrueForAll(s => Game1.player.getEffectiveSkillLevel((int)s.SkillName) >= s.SkillLevel)) &&
                        (mailItem.StatsConditions == null || (mailItem.StatsConditions.TrueForAll(s => s.StatsLabel == null || Game1.player.stats.getStat(s.StatsLabel) >= s.Amount) && mailItem.StatsConditions.TrueForAll(s => s.StatsName == null || MailFrameworkModEntry.ModHelper.Reflection.GetProperty <uint>(Game1.player.stats, s.StatsName.ToString()).GetValue() >= s.Amount))) &&
                        (mailItem.CollectionConditions == null || (mailItem.CollectionConditions.TrueForAll(c =>
                                                                                                            (c.Collection == Collection.Shipped && Game1.player.basicShipped.ContainsKey(c.Index) && Game1.player.basicShipped[c.Index] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Fish && Game1.player.fishCaught.ContainsKey(c.Index) && Game1.player.fishCaught[c.Index][0] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Artifacts && Game1.player.archaeologyFound.ContainsKey(c.Index) && Game1.player.archaeologyFound[c.Index][0] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Minerals && Game1.player.mineralsFound.ContainsKey(c.Index) && Game1.player.mineralsFound[c.Index] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Cooking && Game1.player.recipesCooked.ContainsKey(c.Index) && Game1.player.recipesCooked[c.Index] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Crafting && Game1.player.craftingRecipes.ContainsKey(c.Name) && Game1.player.craftingRecipes[c.Name] >= c.Amount)
                                                                                                            ))) &&
                        (mailItem.RandomChance == null || new Random((int)(((ulong)Game1.stats.DaysPlayed * 1000000000000000) + (((ulong)l.Id.GetHashCode()) % 1000000000 * 1000000) + Game1.uniqueIDForThisGame % 1000000)).NextDouble() < mailItem.RandomChance) &&
                        (mailItem.Buildings == null || (mailItem.RequireAllBuildings ? mailItem.Buildings.TrueForAll(b => Game1.getFarm().isBuildingConstructed(b)) : mailItem.Buildings.Any(b => Game1.getFarm().isBuildingConstructed(b)))) &&
                        (mailItem.MailReceived == null || (mailItem.RequireAllMailReceived ? !mailItem.MailReceived.Except(Game1.player.mailReceived).Any() : mailItem.MailReceived.Intersect(Game1.player.mailReceived).Any())) &&
                        (mailItem.MailNotReceived == null || !mailItem.MailNotReceived.Intersect(Game1.player.mailReceived).Any()) &&
                        (mailItem.EventsSeen == null || (mailItem.RequireAllEventsSeen ? !mailItem.EventsSeen.Except(Game1.player.eventsSeen).Any() : mailItem.EventsSeen.Intersect(Game1.player.eventsSeen).Any())) &&
                        (mailItem.EventsNotSeen == null || !mailItem.EventsNotSeen.Intersect(Game1.player.eventsSeen).Any()) &&
                        (mailItem.RecipeKnown == null || (mailItem.RequireAllRecipeKnown ? mailItem.RecipeKnown.All(r => Game1.player.knowsRecipe(r)) : mailItem.RecipeKnown.Any(r => Game1.player.knowsRecipe(r)))) &&
                        (mailItem.RecipeNotKnown == null || mailItem.RecipeNotKnown.All(r => !Game1.player.knowsRecipe(r))) &&
                        (mailItem.ExpandedPrecondition == null || (ConditionsCheckerApi != null && ConditionsCheckerApi.CheckConditions(mailItem.ExpandedPrecondition))) &&
                        (mailItem.ExpandedPreconditions == null || (ConditionsCheckerApi != null && ConditionsCheckerApi.CheckConditions(mailItem.ExpandedPreconditions))) &&
                        (mailItem.HouseUpgradeLevel == null || mailItem.HouseUpgradeLevel <= Game1.player.HouseUpgradeLevel)
                        ;

                        if (mailItem.Attachments != null && mailItem.Attachments.Count > 0)
                        {
                            List <Item> attachments = new List <Item>();
                            mailItem.Attachments.ForEach(i =>
                            {
                                if (i == null)
                                {
                                    return;
                                }
                                switch (i.Type)
                                {
                                case ItemType.Object:
                                    if (i.Name != null)
                                    {
                                        objects ??= MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >(PathUtilities.NormalizeAssetName("Data/ObjectInformation"), ContentSource.GameContent);
                                        KeyValuePair <int, string> pair = objects.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No object found with the name {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue)
                                    {
                                        attachments.Add(new StardewValley.Object(Vector2.Zero, i.Index.Value, i.Stack ?? 1));
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach an object for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.BigObject:
                                case ItemType.BigCraftable:
                                    if (i.Name != null)
                                    {
                                        bigObjects ??= MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >(PathUtilities.NormalizeAssetName("Data/BigCraftablesInformation"), ContentSource.GameContent);
                                        KeyValuePair <int, string> pair = bigObjects.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No big craftable found with the name {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue)
                                    {
                                        Item item = new StardewValley.Object(Vector2.Zero, i.Index.Value);
                                        if (i.Stack.HasValue)
                                        {
                                            item.Stack = i.Stack.Value;
                                        }
                                        attachments.Add(item);
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach a big craftable for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.Tool:
                                    Tool tool = null;
                                    switch (i.Name)
                                    {
                                    case "Axe":
                                        tool = new Axe();
                                        break;

                                    case "Hoe":
                                        tool = new Hoe();
                                        break;

                                    case "Watering Can":
                                        tool = new WateringCan();
                                        break;

                                    case "Scythe":
                                        tool = new MeleeWeapon(47);
                                        break;

                                    case "Golden Scythe":
                                        tool = new MeleeWeapon(53);
                                        break;

                                    case "Pickaxe":
                                        tool = new Pickaxe();
                                        break;

                                    case "Milk Pail":
                                        tool = new MilkPail();
                                        break;

                                    case "Shears":
                                        tool = new Shears();
                                        break;

                                    case "Fishing Rod":
                                        tool = new FishingRod(i.UpgradeLevel);
                                        break;

                                    case "Pan":
                                        tool = new Pan();
                                        break;

                                    case "Return Scepter":
                                        tool = new Wand();
                                        break;

                                    default:
                                        MailFrameworkModEntry.ModMonitor.Log($"Tool with name {i.Name} not found for letter {mailItem.Id}.", LogLevel.Warn);
                                        break;
                                    }
                                    if (tool != null)
                                    {
                                        if (!NoUpgradeLevelTools.Contains(i.Name))
                                        {
                                            tool.UpgradeLevel = i.UpgradeLevel;
                                        }
                                        attachments.Add(tool);
                                    }
                                    break;

                                case ItemType.Ring:
                                    objects ??= MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >("Data\\ObjectInformation", ContentSource.GameContent);
                                    if (i.Name != null)
                                    {
                                        KeyValuePair <int, string> pair = objects.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No ring found with the name {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }
                                    if (i.Index.HasValue)
                                    {
                                        if (objects[i.Index.Value].Split('/')[3] == "Ring")
                                        {
                                            attachments.Add(new Ring(i.Index.Value));
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"A valid ring is required to attach an ring for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach an ring for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.Furniture:
                                    if (i.Name != null)
                                    {
                                        furnitures ??= MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >(PathUtilities.NormalizeAssetName("Data/Furniture"), ContentSource.GameContent);
                                        KeyValuePair <int, string> pair = furnitures.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No furniture found with the name {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue)
                                    {
                                        attachments.Add(Furniture.GetFurnitureInstance(i.Index.Value));
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach a furniture for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.Weapon:
                                    if (i.Name != null)
                                    {
                                        weapons ??= MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >(PathUtilities.NormalizeAssetName("Data/Weapons"), ContentSource.GameContent);
                                        KeyValuePair <int, string> pair = weapons.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No weapon found with the name {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue)
                                    {
                                        int index = i.Index.Value;
                                        attachments.Add(SlingshotIndexes.Contains(index) ? (Item) new Slingshot(index) : (Item) new MeleeWeapon(index));
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach a weapon for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.Boots:
                                    if (i.Name != null)
                                    {
                                        boots ??= MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >(PathUtilities.NormalizeAssetName("Data/Boots"), ContentSource.GameContent);
                                        KeyValuePair <int, string> pair = boots.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No boots found with the name {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue)
                                    {
                                        attachments.Add(new Boots(i.Index.Value));
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach a boots for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.DGA:
                                    if (DgaApi != null)
                                    {
                                        try
                                        {
                                            object dgaObject = DgaApi.SpawnDGAItem(i.Name);
                                            if (dgaObject is StardewValley.Item dgaItem)
                                            {
                                                if (dgaItem is StardewValley.Object)
                                                {
                                                    dgaItem.Stack = i.Stack ?? 1;
                                                }
                                                else
                                                {
                                                    dgaItem.Stack = 1;
                                                }

                                                attachments.Add(dgaItem);
                                            }
                                            else
                                            {
                                                MailFrameworkModEntry.ModMonitor.Log($"No DGA item found with the ID {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"Error trying to create item with the DGA ID {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                            MailFrameworkModEntry.ModMonitor.Log(ex.Message, LogLevel.Trace);
                                        }
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"No DGA API found, so item with the ID {i.Name} for letter {mailItem.Id} will be ignored.", LogLevel.Warn);
                                    }
                                    break;

                                default:
                                    MailFrameworkModEntry.ModMonitor.Log($"Invalid attachment type '{i.Type}' found in letter {mailItem.Id}.", LogLevel.Warn);
                                    break;
                                }
                            });
                            MailDao.SaveLetter(
                                new Letter(
                                    mailItem.Id
                                    , hasTranslation && mailItem.Text != null ? contentPack.Translation.Get(mailItem.Text) : mailItem.Text
                                    , attachments
                                    , Condition
                                    , (l) =>
                            {
                                Game1.player.mailReceived.Add(l.Id);
                                if (mailItem.AdditionalMailReceived != null)
                                {
                                    Game1.player.mailReceived.AddRange(mailItem.AdditionalMailReceived);
                                }
                            }
                                    , mailItem.WhichBG
                                    )
                            {
                                TextColor     = mailItem.TextColor,
                                Title         = hasTranslation && mailItem.Title != null ? contentPack.Translation.Get(mailItem.Title) : mailItem.Title,
                                GroupId       = mailItem.GroupId,
                                LetterTexture = mailItem.LetterBG != null ? GetTextureAsset(contentPack, mailItem.LetterBG) : null,
                                UpperRightCloseButtonTexture = mailItem.UpperRightCloseButton != null ? GetTextureAsset(contentPack, mailItem.UpperRightCloseButton) : null,
                                AutoOpen = mailItem.AutoOpen,
                            });
                        }
                        else
                        {
                            MailDao.SaveLetter(
                                new Letter(
                                    mailItem.Id
                                    , hasTranslation && mailItem.Text != null ? contentPack.Translation.Get(mailItem.Text) : mailItem.Text
                                    , mailItem.Recipe
                                    , Condition
                                    , (l) =>
                            {
                                Game1.player.mailReceived.Add(l.Id);
                                if (mailItem.AdditionalMailReceived != null)
                                {
                                    Game1.player.mailReceived.AddRange(mailItem.AdditionalMailReceived);
                                }
                            }
                                    , mailItem.WhichBG
                                    )
                            {
                                TextColor     = mailItem.TextColor,
                                Title         = hasTranslation && mailItem.Title != null ? contentPack.Translation.Get(mailItem.Title) : mailItem.Title,
                                GroupId       = mailItem.GroupId,
                                LetterTexture = mailItem.LetterBG != null ? GetTextureAsset(contentPack, mailItem.LetterBG) : null,
                                UpperRightCloseButtonTexture = mailItem.UpperRightCloseButton != null ? GetTextureAsset(contentPack, mailItem.UpperRightCloseButton) : null,
                                AutoOpen = mailItem.AutoOpen,
                            });
                        }
                    }
                }
                else
                {
                    MailFrameworkModEntry.ModMonitor.Log($"Ignoring content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}\nIt does not have an mail.json file.", LogLevel.Warn);
                }
            }
        }
        public static void LoadContentPacks(object sender, EventArgs e)
        {
            foreach (IContentPack contentPack in MailFrameworkModEntry.ModHelper.ContentPacks.GetOwned())
            {
                if (File.Exists(Path.Combine(contentPack.DirectoryPath, "mail.json")))
                {
                    MailFrameworkModEntry.ModMonitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
                    List <MailItem> mailItems = contentPack.ReadJsonFile <List <MailItem> >("mail.json");
                    foreach (MailItem mailItem in mailItems)
                    {
                        bool Condition(Letter l) =>
                        (!Game1.player.mailReceived.Contains(l.Id) || mailItem.Repeatable) &&
                        (mailItem.Recipe == null || !Game1.player.cookingRecipes.ContainsKey(mailItem.Recipe)) &&
                        (mailItem.Date == null || SDate.Now() >= new SDate(Convert.ToInt32(mailItem.Date.Split(' ')[0]), mailItem.Date.Split(' ')[1], Convert.ToInt32(mailItem.Date.Split(' ')[2].Replace("Y", "")))) &&
                        (mailItem.Days == null || mailItem.Days.Contains(SDate.Now().Day)) &&
                        (mailItem.Seasons == null || mailItem.Seasons.Contains(SDate.Now().Season)) &&
                        (mailItem.Weather == null || (Game1.isRaining && "rainy".Equals(mailItem.Weather)) || (!Game1.isRaining && "sunny".Equals(mailItem.Weather))) &&
                        (mailItem.FriendshipConditions == null || mailItem.FriendshipConditions.TrueForAll(f => Game1.player.getFriendshipHeartLevelForNPC(f.NpcName) >= f.FriendshipLevel)) &&
                        (mailItem.SkillConditions == null || mailItem.SkillConditions.TrueForAll(s => Game1.player.getEffectiveSkillLevel((int)s.SkillName) >= s.SkillLevel));

                        if (mailItem.Attachments != null && mailItem.Attachments.Count > 0)
                        {
                            List <Item> attachments             = new List <Item>();
                            Dictionary <int, string> objects    = null;
                            Dictionary <int, string> bigObjects = null;
                            mailItem.Attachments.ForEach(i =>
                            {
                                switch (i.Type)
                                {
                                case ItemType.Object:
                                    if (i.Name != null)
                                    {
                                        if (objects == null)
                                        {
                                            objects = MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >("Data\\ObjectInformation", ContentSource.GameContent);
                                        }
                                        KeyValuePair <int, string> pair = objects.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No object found with the name {i.Name}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue && i.Stack.HasValue)
                                    {
                                        attachments.Add(new StardewValley.Object(Vector2.Zero, i.Index.Value, i.Stack.Value));
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index and a stack value is required to attach an object for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.BigObject:
                                    if (i.Name != null)
                                    {
                                        if (bigObjects == null)
                                        {
                                            bigObjects = MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >("Data\\BigCraftablesInformation", ContentSource.GameContent);
                                        }
                                        KeyValuePair <int, string> pair = bigObjects.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No big object found with the name {i.Name}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue)
                                    {
                                        attachments.Add(new StardewValley.Object(Vector2.Zero, i.Index.Value));
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach a big object for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.Tool:
                                    switch (i.Name)
                                    {
                                    case "Axe":
                                        attachments.Add(new Axe());
                                        break;

                                    case "Hoe":
                                        attachments.Add(new Hoe());
                                        break;

                                    case "Watering Can":
                                        attachments.Add(new WateringCan());
                                        break;

                                    case "Scythe":
                                        attachments.Add(new MeleeWeapon(47));
                                        break;

                                    case "Pickaxe":
                                        attachments.Add(new Pickaxe());
                                        break;

                                    default:
                                        MailFrameworkModEntry.ModMonitor.Log($"Tool with name {i.Name} not found for letter {mailItem.Id}.", LogLevel.Warn);
                                        break;
                                    }
                                    break;
                                }
                            });
                            MailDao.SaveLetter(
                                new Letter(
                                    mailItem.Id
                                    , mailItem.Text
                                    , attachments
                                    , Condition
                                    , (l) => Game1.player.mailReceived.Add(l.Id)
                                    , mailItem.WhichBG
                                    )
                            {
                                TextColor = mailItem.TextColor
                            });
                        }
                        else
                        {
                            MailDao.SaveLetter(
                                new Letter(
                                    mailItem.Id
                                    , mailItem.Text
                                    , mailItem.Recipe
                                    , Condition
                                    , (l) => Game1.player.mailReceived.Add(l.Id)
                                    , mailItem.WhichBG
                                    )
                            {
                                TextColor = mailItem.TextColor
                            });
                        }
                    }
                }
                else
                {
                    MailFrameworkModEntry.ModMonitor.Log($"Ignoring content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}\nIt does not have an mail.json file.", LogLevel.Warn);
                }
            }
        }
Beispiel #4
0
        public static void LoadContentPacks(object sender, EventArgs e)
        {
            foreach (IContentPack contentPack in MailFrameworkModEntry.ModHelper.ContentPacks.GetOwned())
            {
                if (File.Exists(Path.Combine(contentPack.DirectoryPath, "mail.json")))
                {
                    bool hasTranslation = contentPack.Translation.GetTranslations().Any();

                    MailFrameworkModEntry.ModMonitor.Log($"Reading content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}");
                    List <MailItem> mailItems = contentPack.ReadJsonFile <List <MailItem> >("mail.json");
                    foreach (MailItem mailItem in mailItems)
                    {
                        Dictionary <int, string> objects    = null;
                        Dictionary <int, string> bigObjects = null;

                        //Populate all Indexs based on the given name. Ignore the letter otherwise.
                        if (mailItem.CollectionConditions != null && mailItem.CollectionConditions.Any(c =>
                        {
                            if (c.Name != null)
                            {
                                objects = objects ?? MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >("Data\\ObjectInformation", ContentSource.GameContent);
                                KeyValuePair <int, string> pair = objects.FirstOrDefault(o => o.Value.StartsWith(c.Name + "/"));
                                if (pair.Value != null)
                                {
                                    c.Index = pair.Key;
                                }
                                else
                                {
                                    MailFrameworkModEntry.ModMonitor.Log($"No object found with the name '{c.Name}' for a condition for letter '{mailItem.Id}'.\n This letter will be ignored.", LogLevel.Warn);
                                    MailDao.RemoveLetter(new Letter(mailItem.Id, null, null));
                                    return(true);
                                }
                            }
                            return(false);
                        }))
                        {
                            break;
                        }

                        bool Condition(Letter l) =>
                        (!Game1.player.mailReceived.Contains(l.Id) || mailItem.Repeatable) &&
                        (mailItem.Recipe == null || !Game1.player.cookingRecipes.ContainsKey(mailItem.Recipe)) &&
                        (mailItem.Date == null || SDate.Now() >= new SDate(Convert.ToInt32(mailItem.Date.Split(' ')[0]), mailItem.Date.Split(' ')[1], Convert.ToInt32(mailItem.Date.Split(' ')[2].Replace("Y", "")))) &&
                        (mailItem.Days == null || mailItem.Days.Contains(SDate.Now().Day)) &&
                        (mailItem.Seasons == null || mailItem.Seasons.Contains(SDate.Now().Season)) &&
                        (mailItem.Weather == null || (Game1.isRaining && "rainy".Equals(mailItem.Weather)) || (!Game1.isRaining && "sunny".Equals(mailItem.Weather))) &&
                        (mailItem.FriendshipConditions == null || (mailItem.FriendshipConditions.TrueForAll(f => Game1.player.getFriendshipHeartLevelForNPC(f.NpcName) >= f.FriendshipLevel)) &&
                         mailItem.FriendshipConditions.TrueForAll(f => f.FriendshipStatus == null || (Game1.player.friendshipData.ContainsKey(f.NpcName) && f.FriendshipStatus.Any(s => s == Game1.player.friendshipData[f.NpcName].Status)))) &&
                        (mailItem.SkillConditions == null || mailItem.SkillConditions.TrueForAll(s => Game1.player.getEffectiveSkillLevel((int)s.SkillName) >= s.SkillLevel)) &&
                        (mailItem.StatsConditions == null || (mailItem.StatsConditions.TrueForAll(s => s.StatsLabel == null || Game1.player.stats.getStat(s.StatsLabel) >= s.Amount) && mailItem.StatsConditions.TrueForAll(s => s.StatsName == null || MailFrameworkModEntry.ModHelper.Reflection.GetProperty <uint>(Game1.player.stats, s.StatsName.ToString()).GetValue() >= s.Amount))) &&
                        (mailItem.CollectionConditions == null || (mailItem.CollectionConditions.TrueForAll(c =>
                                                                                                            (c.Collection == Collection.Shipped && Game1.player.basicShipped.ContainsKey(c.Index) && Game1.player.basicShipped[c.Index] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Fish && Game1.player.fishCaught.ContainsKey(c.Index) && Game1.player.fishCaught[c.Index][0] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Artifacts && Game1.player.archaeologyFound.ContainsKey(c.Index) && Game1.player.archaeologyFound[c.Index][0] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Minerals && Game1.player.mineralsFound.ContainsKey(c.Index) && Game1.player.mineralsFound[c.Index] >= c.Amount) ||
                                                                                                            (c.Collection == Collection.Cooking && Game1.player.recipesCooked.ContainsKey(c.Index) && Game1.player.recipesCooked[c.Index] >= c.Amount)
                                                                                                            ))) &&
                        (mailItem.RandomChance == null || new Random((int)(((ulong)Game1.stats.DaysPlayed * 1000000000000000) + (((ulong)l.Id.GetHashCode()) % 1000000000 * 1000000) + Game1.uniqueIDForThisGame % 1000000)).NextDouble() < mailItem.RandomChance) &&
                        (mailItem.Buildings == null || (mailItem.RequireAllBuildings ? mailItem.Buildings.TrueForAll(b => Game1.getFarm().isBuildingConstructed(b)) : mailItem.Buildings.Any(b => Game1.getFarm().isBuildingConstructed(b)))) &&
                        (mailItem.MailReceived == null || (mailItem.RequireAllMailReceived ? !mailItem.MailReceived.Except(Game1.player.mailReceived).Any() : mailItem.MailReceived.Intersect(Game1.player.mailReceived).Any())) &&
                        (mailItem.MailNotReceived == null || !mailItem.MailNotReceived.Intersect(Game1.player.mailReceived).Any()) &&
                        (mailItem.EventsSeen == null || (mailItem.RequireAllEventsSeen ? !mailItem.EventsSeen.Except(Game1.player.eventsSeen).Any() : mailItem.EventsSeen.Intersect(Game1.player.eventsSeen).Any())) &&
                        (mailItem.EventsNotSeen == null || !mailItem.EventsNotSeen.Intersect(Game1.player.eventsSeen).Any())
                        ;


                        if (mailItem.Attachments != null && mailItem.Attachments.Count > 0)
                        {
                            List <Item> attachments = new List <Item>();
                            mailItem.Attachments.ForEach(i =>
                            {
                                switch (i.Type)
                                {
                                case ItemType.Object:
                                    if (i.Name != null)
                                    {
                                        objects = objects ?? MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >("Data\\ObjectInformation", ContentSource.GameContent);
                                        KeyValuePair <int, string> pair = objects.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No object found with the name {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue)
                                    {
                                        attachments.Add(new StardewValley.Object(Vector2.Zero, i.Index.Value, i.Stack ?? 1));
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach an object for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.BigObject:
                                case ItemType.BigCraftable:
                                    if (i.Name != null)
                                    {
                                        bigObjects = bigObjects ?? MailFrameworkModEntry.ModHelper.Content.Load <Dictionary <int, string> >("Data\\BigCraftablesInformation", ContentSource.GameContent);
                                        KeyValuePair <int, string> pair = bigObjects.FirstOrDefault(o => o.Value.StartsWith(i.Name + "/"));
                                        if (pair.Value != null)
                                        {
                                            i.Index = pair.Key;
                                        }
                                        else
                                        {
                                            MailFrameworkModEntry.ModMonitor.Log($"No big craftable found with the name {i.Name} for letter {mailItem.Id}.", LogLevel.Warn);
                                        }
                                    }

                                    if (i.Index.HasValue)
                                    {
                                        Item item = new StardewValley.Object(Vector2.Zero, i.Index.Value);
                                        if (i.Stack.HasValue)
                                        {
                                            item.Stack = i.Stack.Value;
                                        }
                                        attachments.Add(item);
                                    }
                                    else
                                    {
                                        MailFrameworkModEntry.ModMonitor.Log($"An index value is required to attach a big craftable for letter {mailItem.Id}.", LogLevel.Warn);
                                    }
                                    break;

                                case ItemType.Tool:
                                    switch (i.Name)
                                    {
                                    case "Axe":
                                        attachments.Add(new Axe());
                                        break;

                                    case "Hoe":
                                        attachments.Add(new Hoe());
                                        break;

                                    case "Watering Can":
                                        attachments.Add(new WateringCan());
                                        break;

                                    case "Scythe":
                                        attachments.Add(new MeleeWeapon(47));
                                        break;

                                    case "Pickaxe":
                                        attachments.Add(new Pickaxe());
                                        break;

                                    default:
                                        MailFrameworkModEntry.ModMonitor.Log($"Tool with name {i.Name} not found for letter {mailItem.Id}.", LogLevel.Warn);
                                        break;
                                    }
                                    break;
                                }
                            });
                            MailDao.SaveLetter(
                                new Letter(
                                    mailItem.Id
                                    , hasTranslation? contentPack.Translation.Get(mailItem.Text) : mailItem.Text
                                    , attachments
                                    , Condition
                                    , (l) => Game1.player.mailReceived.Add(l.Id)
                                    , mailItem.WhichBG
                                    )
                            {
                                TextColor = mailItem.TextColor,
                                Title     = hasTranslation && mailItem.Title != null ? contentPack.Translation.Get(mailItem.Title) : mailItem.Title,
                                GroupId   = mailItem.GroupId
                            });
                        }
                        else
                        {
                            MailDao.SaveLetter(
                                new Letter(
                                    mailItem.Id
                                    , hasTranslation ? contentPack.Translation.Get(mailItem.Text) : mailItem.Text
                                    , mailItem.Recipe
                                    , Condition
                                    , (l) => Game1.player.mailReceived.Add(l.Id)
                                    , mailItem.WhichBG
                                    )
                            {
                                TextColor = mailItem.TextColor,
                                Title     = hasTranslation && mailItem.Title != null ? contentPack.Translation.Get(mailItem.Title) : mailItem.Title,
                                GroupId   = mailItem.GroupId
                            });
                        }
                    }
                }
                else
                {
                    MailFrameworkModEntry.ModMonitor.Log($"Ignoring content pack: {contentPack.Manifest.Name} {contentPack.Manifest.Version} from {contentPack.DirectoryPath}\nIt does not have an mail.json file.", LogLevel.Warn);
                }
            }
        }