<commit_before>﻿using StardewValley;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using System.Linq;
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using static Microsoft.Xna.Framework.Input.ButtonState;
using StardewValley.Locations;
using StardewValley.Buildings;
using Microsoft.Xna.Framework.Content;
using System.IO;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;

namespace CustomizeExterior
{
    public class Mod : StardewModdingAPI.Mod
    {
        public const string SEASONAL_INDICATOR = "%";
        
        public static Mod instance;
        public static Config config;
        public static ContentManager content;

        public static Dictionary<string, List<string>> choices = new Dictionary<string, List<string>>();

        public override void Entry(IModHelper helper)
        {
            instance = this;

            GameEvents.LoadContent += onContentLoad;
            GameEvents.UpdateTick += onUpdate;
            SaveEvents.AfterLoad += afterLoad;
            SaveEvents.AfterSave += afterSave;
            TimeEvents.SeasonOfYearChanged += onSeasonChange;
        }

        private void onContentLoad(object sender, EventArgs args)
        {
            content = new ContentManager(Game1.content.ServiceProvider, Path.Combine(Helper.DirectoryPath, "Buildings"));
            compileChoices();
        }

        private void afterLoad(object sender, EventArgs args)
        {
            string path = Path.Combine(Constants.CurrentSavePath, "building-exteriors.json");
            Log.info("Loading per-save config file (\"" + path + "\")...");
            config = Helper.ReadJsonFile<Config>(path) ?? new Config();
            syncTexturesWithChoices();
        }

        private void afterSave(object sender, EventArgs args)
        {
            Log.info("Saving per-save config file...");
            Helper.WriteJsonFile(Path.Combine(Constants.CurrentSavePath, "building-exteriors.json"), config);
        }

        private void onSeasonChange( object sender, EventArgs args )
        {
            Log.debug("Season change, syncing textures...");
            syncTexturesWithChoices();
        }

        public MouseState prevMouse;
        private void onUpdate( object sender, EventArgs args)
        {
            MouseState mouse = Mouse.GetState();
            
            if ( prevMouse != null && mouse.RightButton == Pressed && prevMouse.RightButton != Pressed)
            {
                Point pos = new Point(Game1.getMouseX() + Game1.viewport.X, Game1.getMouseY() + Game1.viewport.Y);
                
                if (Game1.currentLocation is BuildableGameLocation)
                {
                    var loc = Game1.currentLocation as BuildableGameLocation;
                    
                    foreach ( var building in loc.buildings )
                    {
                        Rectangle tileBounds = new Rectangle(building.tileX * Game1.tileSize, building.tileY * Game1.tileSize, building.tilesWide * Game1.tileSize, building.tilesHigh * Game1.tileSize);
                        if ( tileBounds.Contains( pos.X, pos.Y ) )
                        {
                            Log.trace("Right clicked a building: " + building.nameOfIndoors);
                            checkBuildingClick(building.nameOfIndoors, building.buildingType);
                        }
                    }
                }
                if ( Game1.currentLocation is Farm )
                {
                    Rectangle house = new Rectangle(59 * Game1.tileSize, 11 * Game1.tileSize, 9 * Game1.tileSize, 6 * Game1.tileSize);
                    Rectangle greenhouse = new Rectangle(25 * Game1.tileSize, 10 * Game1.tileSize, 7 * Game1.tileSize, 6 * Game1.tileSize);

                    if ( house.Contains( pos.X, pos.Y ) )
                    {
                        Log.trace("Right clicked the house.");
                        checkBuildingClick("FarmHouse", "houses");
                    }
                    else if ( greenhouse.Contains( pos.X, pos.Y ) )
                    {
                        Log.trace("Right clicked the greenhouse.");
                        checkBuildingClick("Greenhouse", "houses");
                    }
                }
            }

            prevMouse = mouse;
        }

        private void compileChoices()
        {
            Log.info("Creating list of building choices...");
            var choices = Directory.GetDirectories(Path.Combine(Helper.DirectoryPath, "Buildings"));
            foreach ( var choice in choices )
            {
                Log.info("Choice type: " + Path.GetFileName(choice));
                var types = Directory.GetFiles(choice);
                foreach ( var type in types )
                {
                    if (Path.GetExtension(type) != ".xnb" && Path.GetExtension(type) != ".png")
                        continue;

                    string choiceStr = Path.GetFileName(choice);
                    string typeStr = Path.GetFileNameWithoutExtension(type);
                    List<string> forType = Mod.choices.ContainsKey(typeStr) ? Mod.choices[typeStr] : new List<string>();
                    forType.Add(choiceStr);
                    if (!Mod.choices.ContainsKey(typeStr))
                        Mod.choices.Add(typeStr, forType);

                    Log.info("\tChoice: " + typeStr);
                }

                var seasons = Directory.GetDirectories(choice);
                bool foundSpring = false, foundSummer = false, foundFall = false, foundWinter = false;
                foreach ( var season in seasons )
                {
                    var filename = Path.GetFileName(season);
                    if (filename == "spring") foundSpring = true;
                    else if (filename == "summer") foundSummer = true;
                    else if (filename == "fall") foundFall = true;
                    else if (filename == "winter") foundWinter = true;
                }
                
                if ( foundSpring && foundSummer && foundFall && foundWinter )
                {
                    Log.info("Found a seasonal set: " + Path.GetFileName(choice));

                    var spring = new List<string>(Directory.GetFiles(Path.Combine(choice, "spring")));
                    var summer = new List<string>(Directory.GetFiles(Path.Combine(choice, "summer")));
                    var fall = new List<string>(Directory.GetFiles(Path.Combine(choice, "fall")));
                    var winter = new List<string>(Directory.GetFiles(Path.Combine(choice, "winter")));
                    spring = spring.Select(b => { return Path.GetFileName(b); }).ToList();
                    summer = summer.Select(b => { return Path.GetFileName(b); }).ToList();
                    fall = fall.Select(b => { return Path.GetFileName(b); }).ToList();
                    winter = winter.Select(b => { return Path.GetFileName(b); }).ToList();
                    
                    var common = new List<string>();
                    foreach ( var building in spring )
                    {
                        string choiceStr = Path.GetFileName(choice);
                        string typeStr = Path.GetFileNameWithoutExtension(building);
                        if ( summer.Contains( building ) && fall.Contains( building ) && winter.Contains( building ) )
                        {
                            List<string> forType = Mod.choices.ContainsKey(typeStr) ? Mod.choices[typeStr] : new List<string>();
                            forType.Add(SEASONAL_INDICATOR + choiceStr);
                            if (!Mod.choices.ContainsKey(typeStr))
                                Mod.choices.Add(typeStr, forType);

                            Log.info("\tChoice: " + typeStr);
                        }
                    }
                }
            }
        }
        
        private DateTime recentClickTime;
        private string recentClickTarget = null;
        private string recentClickTargetType = null;
        private void checkBuildingClick( string target, string type )
        {
            if (Game1.activeClickableMenu != null) return;

            if (recentClickTarget != target)
            {
                recentClickTarget = target;
                recentClickTargetType = type;
                recentClickTime = DateTime.Now;<commit_msg>Probably fix crashes from having XNB and PNG versions of the same building image.<commit_after>﻿using StardewValley;
using StardewModdingAPI;
using StardewModdingAPI.Events;
using System.Linq;
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using static Microsoft.Xna.Framework.Input.ButtonState;
using StardewValley.Locations;
using StardewValley.Buildings;
using Microsoft.Xna.Framework.Content;
using System.IO;
using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;

namespace CustomizeExterior
{
    public class Mod : StardewModdingAPI.Mod
    {
        public const string SEASONAL_INDICATOR = "%";
        
        public static Mod instance;
        public static Config config;
        public static ContentManager content;

        public static Dictionary<string, List<string>> choices = new Dictionary<string, List<string>>();

        public override void Entry(IModHelper helper)
        {
            instance = this;

            GameEvents.LoadContent += onContentLoad;
            GameEvents.UpdateTick += onUpdate;
            SaveEvents.AfterLoad += afterLoad;
            SaveEvents.AfterSave += afterSave;
            TimeEvents.SeasonOfYearChanged += onSeasonChange;
        }

        private void onContentLoad(object sender, EventArgs args)
        {
            content = new ContentManager(Game1.content.ServiceProvider, Path.Combine(Helper.DirectoryPath, "Buildings"));
            compileChoices();
        }

        private void afterLoad(object sender, EventArgs args)
        {
            string path = Path.Combine(Constants.CurrentSavePath, "building-exteriors.json");
            Log.info("Loading per-save config file (\"" + path + "\")...");
            config = Helper.ReadJsonFile<Config>(path) ?? new Config();
            syncTexturesWithChoices();
        }

        private void afterSave(object sender, EventArgs args)
        {
            Log.info("Saving per-save config file...");
            Helper.WriteJsonFile(Path.Combine(Constants.CurrentSavePath, "building-exteriors.json"), config);
        }

        private void onSeasonChange( object sender, EventArgs args )
        {
            Log.debug("Season change, syncing textures...");
            syncTexturesWithChoices();
        }

        public MouseState prevMouse;
        private void onUpdate( object sender, EventArgs args)
        {
            MouseState mouse = Mouse.GetState();
            
            if ( prevMouse != null && mouse.RightButton == Pressed && prevMouse.RightButton != Pressed)
            {
                Point pos = new Point(Game1.getMouseX() + Game1.viewport.X, Game1.getMouseY() + Game1.viewport.Y);
                
                if (Game1.currentLocation is BuildableGameLocation)
                {
                    var loc = Game1.currentLocation as BuildableGameLocation;
                    
                    foreach ( var building in loc.buildings )
                    {
                        Rectangle tileBounds = new Rectangle(building.tileX * Game1.tileSize, building.tileY * Game1.tileSize, building.tilesWide * Game1.tileSize, building.tilesHigh * Game1.tileSize);
                        if ( tileBounds.Contains( pos.X, pos.Y ) )
                        {
                            Log.trace("Right clicked a building: " + building.nameOfIndoors);
                            checkBuildingClick(building.nameOfIndoors, building.buildingType);
                        }
                    }
                }
                if ( Game1.currentLocation is Farm )
                {
                    Rectangle house = new Rectangle(59 * Game1.tileSize, 11 * Game1.tileSize, 9 * Game1.tileSize, 6 * Game1.tileSize);
                    Rectangle greenhouse = new Rectangle(25 * Game1.tileSize, 10 * Game1.tileSize, 7 * Game1.tileSize, 6 * Game1.tileSize);

                    if ( house.Contains( pos.X, pos.Y ) )
                    {
                        Log.trace("Right clicked the house.");
                        checkBuildingClick("FarmHouse", "houses");
                    }
                    else if ( greenhouse.Contains( pos.X, pos.Y ) )
                    {
                        Log.trace("Right clicked the greenhouse.");
                        checkBuildingClick("Greenhouse", "houses");
                    }
                }
            }

            prevMouse = mouse;
        }

        private void compileChoices()
        {
            Log.info("Creating list of building choices...");
            var choices = Directory.GetDirectories(Path.Combine(Helper.DirectoryPath, "Buildings"));
            foreach ( var choice in choices )
            {
                if (choice == "spring" || choice == "summer" || choice == "fall" || choice == "winter")
                {
                    Log.warn("A seasonal texture set was installed incorrectly. '" + choice + "' should not be directly in the Buildings folder.");
                    continue;
                }

                Log.info("Choice type: " + Path.GetFileName(choice));
                var types = Directory.GetFiles(choice);
                foreach ( var type in types )
                {
                    if (Path.GetExtension(type) != ".xnb" && Path.GetExtension(type) != ".png")
                        continue;

                    string choiceStr = Path.GetFileName(choice);
                    string typeStr = Path.GetFileNameWithoutExtension(type);
                    List<string> forType = Mod.choices.ContainsKey(typeStr) ? Mod.choices[typeStr] : new List<string>();
                    if ( !forType.Contains( choiceStr ) )
                        forType.Add(choiceStr);
                    if (!Mod.choices.ContainsKey(typeStr))
                        Mod.choices.Add(typeStr, forType);

                    Log.info("\tChoice: " + typeStr);
                }

                var seasons = Directory.GetDirectories(choice);
                bool foundSpring = false, foundSummer = false, foundFall = false, foundWinter = false;
                foreach ( var season in seasons )
                {
                    var filename = Path.GetFileName(season);
                    if (filename == "spring") foundSpring = true;
                    else if (filename == "summer") foundSummer = true;
                    else if (filename == "fall") foundFall = true;
                    else if (filename == "winter") foundWinter = true;
                }
                
                if ( foundSpring && foundSummer && foundFall && foundWinter )
                {
                    Log.info("Found a seasonal set: " + Path.GetFileName(choice));

                    var spring = new List<string>(Directory.GetFiles(Path.Combine(choice, "spring")));
                    var summer = new List<string>(Directory.GetFiles(Path.Combine(choice, "summer")));
                    var fall = new List<string>(Directory.GetFiles(Path.Combine(choice, "fall")));
                    var winter = new List<string>(Directory.GetFiles(Path.Combine(choice, "winter")));
                    spring = spring.Select(b => { return Path.GetFileName(b); }).ToList();
                    summer = summer.Select(b => { return Path.GetFileName(b); }).ToList();
                    fall = fall.Select(b => { return Path.GetFileName(b); }).ToList();
                    winter = winter.Select(b => { return Path.GetFileName(b); }).ToList();
                    
                    var common = new List<string>();
                    foreach ( var building in spring )
                    {
                        string choiceStr = Path.GetFileName(choice);
                        string typeStr = Path.GetFileNameWithoutExtension(building);
                        if ( summer.Contains( building ) && fall.Contains( building ) && winter.Contains( building ) )
                        {
                            List<string> forType = Mod.choices.ContainsKey(typeStr) ? Mod.choices[typeStr] : new List<string>();
                            if (!forType.Contains(SEASONAL_INDICATOR + choiceStr))
                                forType.Add(SEASONAL_INDICATOR + choiceStr);
                            if (!Mod.choices.ContainsKey(typeStr))
                                Mod.choices.Add(typeStr, forType);

                            Log.info("\tChoice: " + typeStr);
                        }
                    }
                }
            }
        }
        
        private DateTime recentClickTime;
        private string recentClickTarget = null;
        private string recentClickTargetType = null;
        private void checkBuildingClick( string target, string type )
        {
            if (Game1.activeClickableMenu != null) return;

            if (recentClickTarget != target)
            {
                recentClickTarget = target;
                recentClickTargetType = type;
                recentClickTime = DateTime.Now;
{'fraction_non_alphanumeric': 0.09831267217630854, 'fraction_numerical': 0.003787878787878788, 'mean_word_length': 1.6179387019230769, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6426505', 'n_tokens_mistral': 4381, 'n_tokens_neox': 4094, 'n_words': 960}