Changeset - 7b2e8ac4935e
[Not reviewed]
default
0 5 0
Jason Maltzen (jmaltzen) - 8 years ago 2015-12-25 03:17:40
jason.maltzen@unsanctioned.net
Save recipe generator state to allow resume across app runs. Periodically save current generated recipe list, instead of just saving on stop/pause.
5 files changed with 460 insertions and 82 deletions:
0 comments (0 inline, 0 general)
.hgignore
Show inline comments
...
 
@@ -5,4 +5,4 @@ obj/
 
*.swp
 
*.zip
 
.DS_Store
 
mac/build/DesertPaintLab.app
 
mac/bin
RecipeGenerator.cs
Show inline comments
...
 
@@ -21,8 +21,10 @@
 
*/
 

	
 
using System;
 
using System.IO;
 
using System.Collections.Generic;
 
using System.Collections.Concurrent;
 
using System.Text.RegularExpressions;
 
using System.Threading;
 

	
 
namespace DesertPaintLab
...
 
@@ -55,10 +57,18 @@ namespace DesertPaintLab
 

	
 
    public class RecipeGenerator
 
    {
 
        private class SearchNode
 
        protected class SearchNode
 
        {
 
            //int initialReagentCount;
 
            List<uint> reagents;
 
            public List<uint> Reagents
 
            {
 
                get
 
                {
 
                    return reagents;
 
                }
 
            }
 

	
 
            HashSet<uint> reagentInUse = new HashSet<uint>();
 
            List<Reagent> costSortedReagents;
 
            PaintRecipe testRecipe = null;
...
 
@@ -73,8 +83,13 @@ namespace DesertPaintLab
 
                    testRecipe = value;
 
                }
 
            }
 

	
 
            public int InitialCount { get; private set; }
 
            public uint CurrentTargetQuantity { get; set; }
 
            public uint MaxQuantity { get; set; }
 
            public uint UsedQuantity { get; private set; }
 
            public uint CatalystCount { get; set; }
 

	
 
            uint maxReagents;
 
            public uint MaxReagents
 
            {
...
 
@@ -88,9 +103,6 @@ namespace DesertPaintLab
 
                    currentWeights = new uint[maxReagents];
 
                }
 
            }
 
            public uint UsedQuantity { get; private set; }
 

	
 
            public uint CatalystCount { get; set; }
 

	
 
            uint[] currentWeights;
 
            public uint[] CurrentWeights
...
 
@@ -125,13 +137,14 @@ namespace DesertPaintLab
 
                UsedQuantity = 0;
 
            }
 

	
 
            public int InitialCount { get; private set; }
 
            public List<uint> Reagents
 
            public SearchNode(List<Reagent> costSortedReagents)
 
            {
 
                get
 
                {
 
                    return reagents;
 
                }
 
                this.costSortedReagents = costSortedReagents;
 
                this.reagents = new List<uint>();
 
                this.reagents.Add(NextFreeReagent(0));
 
                InitialCount = 0;
 
                MaxReagents = 1;
 
                UsedQuantity = 0;
 
            }
 

	
 
            public Reagent Reagent(int idx)
...
 
@@ -248,6 +261,131 @@ namespace DesertPaintLab
 
                currentWeights[idx] = quantity;
 
                UsedQuantity += quantity;
 
            }
 

	
 
            public void SaveState(StreamWriter writer)
 
            {
 
                writer.WriteLine("---SearchNode---");
 
                writer.WriteLine("MaxReagents: {0}", MaxReagents);
 
                writer.WriteLine("Reagents: {0}", reagents.Count);
 
                for (int i = 0; i < reagents.Count; ++i)
 
                {
 
                    uint idx = reagents[i];
 
                    uint weight = currentWeights[i];
 
                    writer.WriteLine("Reagent: {0},{1},{2}", idx, reagentInUse.Contains(idx) ? 1 : 0, weight);
 
                }
 
                // pulled from parent: List<Reagent> costSortedReagents;
 
                // new on construct: PaintRecipe testRecipe = null;
 
                writer.WriteLine("CurrentTargetQuantity: {0}", CurrentTargetQuantity);
 
                writer.WriteLine("MaxQuantity: {0}", MaxQuantity);
 
                writer.WriteLine("UsedQuantity: {0}", UsedQuantity);
 
                writer.WriteLine("CatalystCount: {0}", CatalystCount);
 
                writer.WriteLine("InitialCount: {0}", InitialCount);
 
                writer.WriteLine("---EndNode---");
 
                
 
            }
 

	
 
            static Regex keyValueRegex = new Regex(@"(\w+)\:\s*(.*)\s*$");
 
            static Regex reagentPartsRegex = new Regex(@"(?<id>\d+),(?<inUse>\d+),(?<weight>\d+)");
 
            public bool LoadState(StreamReader reader)
 
            {
 
                string line = reader.ReadLine();
 
                if (!line.Equals("---SearchNode---"))
 
                {
 
                    return false;
 
                }
 

	
 
                bool success = true;
 
                Match match;
 
                int reagentIdx = 0;
 
                while ((line = reader.ReadLine()) != null)
 
                {
 
                    if (line.Equals("---EndNode---"))
 
                    {
 
                        break;
 
                    }
 
                    match = keyValueRegex.Match(line);
 
                    if (match.Success)
 
                    {
 
                        switch (match.Groups[1].Value)
 
                        {
 
                            case "Reagents":
 
                                {
 
                                    int reagentCount = int.Parse(match.Groups[2].Value);
 
                                    reagents = new List<uint>(reagentCount);
 
                                    reagentInUse.Clear();
 
                                    reagentIdx = 0;
 
                                }
 
                                break;
 
                            case "Reagent":
 
                                {
 
                                    Match reagentInfo = reagentPartsRegex.Match(match.Groups[2].Value);
 
                                    if (reagentInfo.Success)
 
                                    {
 
                                        uint reagentId = uint.Parse(reagentInfo.Groups["id"].Value);
 
                                        int isInUse = int.Parse(reagentInfo.Groups["inUse"].Value);
 
                                        uint weight = uint.Parse(reagentInfo.Groups["weight"].Value);
 
                                        reagents.Add(reagentId);
 
                                        currentWeights[reagentIdx] = weight;
 
                                        if (isInUse != 0)
 
                                        {
 
                                            reagentInUse.Add(reagentId);
 
                                        }
 
                                    }
 
                                    else
 
                                    {
 
                                        success = false;
 
                                    }
 
                                }
 
                                break;
 
                            case "CurrentTargetQuantity":
 
                                {
 
                                    uint value = uint.Parse(match.Groups[2].Value);
 
                                    CurrentTargetQuantity = value;
 
                                }
 
                                break;
 
                            case "MaxQuantity":
 
                                {
 
                                    uint value = uint.Parse(match.Groups[2].Value);
 
                                    MaxQuantity = value;
 
                                }
 
                                break;
 
                            case "MaxReagents":
 
                                {
 
                                    uint value = uint.Parse(match.Groups[2].Value);
 
                                    MaxReagents = value;
 
                                }
 
                                break;
 
                            case "UsedQuantity":
 
                                {
 
                                    uint value = uint.Parse(match.Groups[2].Value);
 
                                    UsedQuantity = value;
 
                                }
 
                                break;
 
                            case "CatalystCount":
 
                                {
 
                                    uint value = uint.Parse(match.Groups[2].Value);
 
                                    CatalystCount = value;
 
                                }
 
                                break;
 
                            case "InitialCount":
 
                                {
 
                                    int value = int.Parse(match.Groups[2].Value);
 
                                    InitialCount = value;
 
                                }
 
                                break;
 
                            default:
 
                                success = false;
 
                                break;
 
                        }
 
                    }
 
                    else
 
                    {
 
                        success = false;
 
                        break;
 
                    }
 
                }
 
                return success;
 
            }
 
        }
 

	
 
        const uint DEFAULT_MAX_QUANTITY = 14; // minimum recipe: 10 base + 4 catalysts
...
 
@@ -260,6 +398,8 @@ namespace DesertPaintLab
 

	
 
        ReactionSet reactions;
 
        bool running = false;
 

	
 
        int runningThreads = 0;
 
        
 
        SortedDictionary<string, uint> recipeCosts = new SortedDictionary<string, uint>();
 
        SortedDictionary<string, PaintRecipe> recipes = new SortedDictionary<string, PaintRecipe>();
...
 
@@ -282,8 +422,9 @@ namespace DesertPaintLab
 
        public event EventHandler Progress;
 
        public event EventHandler<NewRecipeEventArgs> NewRecipe;
 

	
 
        public RecipeGenerator()
 
        public RecipeGenerator(ReactionSet reactions)
 
        {
 
            this.reactions = reactions;
 
        }
 

	
 
        public SortedDictionary<string, PaintRecipe> Recipes
...
 
@@ -302,6 +443,14 @@ namespace DesertPaintLab
 
            }
 
        }
 

	
 
        public bool CanResume
 
        {
 
            get
 
            {
 
                return (!running && (searchQueue.Count > 0));
 
            }
 
        }
 

	
 
        private class ReagentCostSort : IComparer<Reagent>
 
        {
 
            public int Compare(Reagent reagent1, Reagent reagent2)
...
 
@@ -310,36 +459,21 @@ namespace DesertPaintLab
 
            }
 
        }
 

	
 
        public void InitRecipes(SortedDictionary<string, PaintRecipe> recipes, ReactionSet reactions)
 
        public void InitRecipes(SortedDictionary<string, PaintRecipe> recipes)
 
        {
 
            if (running)
 
            {
 
                return;
 
            }
 
            this.reactions = reactions;
 
            foreach (PaintRecipe recipe in recipes.Values)
 
            {
 
                // TODO: copy?
 
                AddCheapestRecipe(recipe);
 
                PaintRecipe recipeCopy = new PaintRecipe(recipe);
 
                AddCheapestRecipe(recipeCopy);
 
            }
 
        }
 

	
 
        public void BeginRecipeGeneration(ReactionSet reactions, uint maxQuantity, uint maxReagents, uint fullQuantityDepth, uint fullQuantity)
 
        private void InitSortedReagents()
 
        {
 
            if (running)
 
            {
 
                // Already running - don't start again
 
                return;
 
            }
 
            this.running = true;
 

	
 
            this.reactions = reactions;
 
            //this.maxQuantity = maxQuantity;
 
            this.maxReagents = maxReagents;
 
            this.fullQuantity = fullQuantity;
 
            this.fullQuantityDepth = fullQuantityDepth;
 

	
 
            // first, sort reagents by cost.
 
            costSortedReagents.Clear();
 
            foreach (string name in ReagentManager.Names)
 
            {
...
 
@@ -350,6 +484,23 @@ namespace DesertPaintLab
 
                }
 
            }
 
            costSortedReagents.Sort(new ReagentCostSort());
 
        }
 

	
 
        public void BeginRecipeGeneration(uint maxQuantity, uint maxReagents, uint fullQuantityDepth, uint fullQuantity)
 
        {
 
            if (running)
 
            {
 
                // Already running - don't start again
 
                return;
 
            }
 

	
 
            //this.maxQuantity = maxQuantity;
 
            this.maxReagents = maxReagents;
 
            this.fullQuantity = fullQuantity;
 
            this.fullQuantityDepth = fullQuantityDepth;
 

	
 
            // first, sort reagents by cost.
 
            InitSortedReagents();
 
            this.maxReagents = (uint)Math.Min(costSortedReagents.Count, this.maxReagents);
 

	
 
            totalReagents = (uint)costSortedReagents.Count;
...
 
@@ -368,6 +519,11 @@ namespace DesertPaintLab
 
                }
 
            }
 

	
 
            while (!searchQueue.IsEmpty)
 
            {
 
                SearchNode node;
 
                searchQueue.TryDequeue(out node);
 
            }
 
            for (uint reagentIdx = 0; reagentIdx < costSortedReagents.Count; ++reagentIdx)
 
            {
 
                SearchNode initialNode = new SearchNode(costSortedReagents, reagentIdx);
...
 
@@ -378,19 +534,7 @@ namespace DesertPaintLab
 
            
 
            // start worker threads to do the actual work
 

	
 
            requestCancel = false;
 
            running = true;
 
            // Start the workers thread
 
            for (int i = 0; i < costSortedReagents.Count; ++i)
 
            {
 
                Thread thr = new Thread(new ThreadStart(this.Generate));
 
                generatorThreads.Add(thr);
 
            }
 
            foreach (Thread thr in generatorThreads)
 
            {
 
                thr.Start();
 
            }
 
        
 
            ResumeRecipeGeneration();
 
        }
 

	
 
        public void ResumeRecipeGeneration()
...
 
@@ -400,10 +544,22 @@ namespace DesertPaintLab
 
                // Already running - don't start again
 
                return;
 
            }
 
            this.running = true;
 
            running = true;
 
            requestCancel = false;
 

	
 
            for (int i = 0; i < costSortedReagents.Count; ++i)
 
            //System.Console.WriteLine("Resuming recipe generation: pre-threads={0} reagent count={1} search queue={2}", runningThreads, costSortedReagents.Count, searchQueue.Count);
 
            runningThreads = 0; // presumably!
 

	
 
            int threadCount = Math.Min(costSortedReagents.Count, searchQueue.Count);
 
            if (threadCount == 0)
 
            {
 
                if (Finished != null)
 
                {
 
                    Finished(this, null);
 
                }
 
            }
 
            generatorThreads.Clear();
 
            for (int i = 0; i < threadCount; ++i)
 
            {
 
                Thread thr = new Thread(new ThreadStart(this.Generate));
 
                generatorThreads.Add(thr);
...
 
@@ -414,10 +570,147 @@ namespace DesertPaintLab
 
            }
 
        }
 

	
 
        public bool SaveState(string file)
 
        {
 
            if (running)
 
            {
 
                // can't save state while running
 
                return false;
 
            }
 

	
 
            using (StreamWriter writer = new StreamWriter(file, false))
 
            {
 
                writer.WriteLine("MaxReagents: {0}", maxReagents);
 
                writer.WriteLine("FullQuantityDepth: {0}", fullQuantityDepth);
 
                writer.WriteLine("FullQuantity: {0}", fullQuantity);
 
                writer.WriteLine("TotalReagents: {0}", totalReagents);
 
                writer.WriteLine("RecipeCount: {0}", recipeCount);
 
                foreach (KeyValuePair<string, PaintRecipe> pair in recipes)
 
                {
 
                    PaintRecipe recipe = pair.Value;
 
                    string colorName = Palette.FindNearest(recipe.ReactedColor);
 
                    writer.WriteLine("BeginRecipe: {0}", colorName);
 
                    foreach (PaintRecipe.RecipeIngredient ingredient in recipe.Ingredients)
 
                    {
 
                        writer.WriteLine("Ingredient: {0}={1}", ingredient.name, ingredient.quantity);
 
                    }
 
                    writer.WriteLine("EndRecipe: {0}", colorName);
 
                }
 
                writer.WriteLine("SearchNodes: {0}", searchQueue.Count);
 
                foreach (SearchNode node in searchQueue)
 
                {
 
                    node.SaveState(writer);
 
               }
 
            }
 
            return true;
 
        }
 

	
 
        static Regex keyValueRegex = new Regex(@"(?<key>\w+)\:\s*(?<value>.+)\s*");
 
        static Regex ingredientRegex = new Regex(@"(?<ingredient>(\w+\s)*\w+)\s*=\s*(?<quantity>\d)\s*");
 
        public bool LoadState(string file)
 
        {
 
            // cannot be running, and reactions must be set
 
            if (running)
 
            {
 
                return false;
 
            }
 

	
 
            InitSortedReagents();
 
            bool success = true;
 

	
 
            PaintRecipe currentRecipe = null;
 
            Match match;
 
            string line;
 
            using (StreamReader reader = new StreamReader(file, false))
 
            {
 
                while (success && ((line = reader.ReadLine()) != null))
 
                {
 
                    match = keyValueRegex.Match(line);
 
                    if (match.Success)
 
                    {
 
                        string value = match.Groups["value"].Value;
 
                        switch(match.Groups["key"].Value)
 
                        {
 
                            case "MaxReagents":
 
                                maxReagents = uint.Parse(value);
 
                                break;
 
                            case "FullQuantityDepth":
 
                                fullQuantityDepth = uint.Parse(value);
 
                                break;
 
                            case "FullQuantity":
 
                                fullQuantity = uint.Parse(value);
 
                                break;
 
                            case "TotalReagents":
 
                                totalReagents = uint.Parse(value);
 
                                break;
 
                            case "RecipeCount":
 
                                recipeCount = int.Parse(value);
 
                                break;
 
                            case "BeginRecipe":
 
                                currentRecipe = new PaintRecipe();
 
                                currentRecipe.Reactions = reactions;
 
                                break;
 
                            case "EndRecipe":
 
                                if (currentRecipe != null)
 
                                {
 
                                    PaintColor color = currentRecipe.ReactedColor;
 
                                    uint cost = currentRecipe.Cost;
 
                                    recipes[color.Name] = currentRecipe; // replace
 
                                    recipeCosts[color.Name] = cost;
 
                                    currentRecipe = null;
 
                                }
 
                                break;
 
                            case "Ingredient":
 
                                if (currentRecipe != null)
 
                                {
 
                                    Match ingredientMatch = ingredientRegex.Match(match.Groups["value"].Value);
 
                                    if (ingredientMatch.Success)
 
                                    {
 
                                        uint quantity = uint.Parse(ingredientMatch.Groups["quantity"].Value);
 
                                        currentRecipe.AddReagent(ingredientMatch.Groups["ingredient"].Value, quantity);
 
                                    }
 
                                    else
 
                                    {
 
                                        success = false;
 
                                    }
 
                                }
 
                                break;
 
                            case "SearchNodes":
 
                                int nodeCount = int.Parse(match.Groups["value"].Value);
 
                                for (int i = 0; i < nodeCount; ++i)
 
                                {
 
                                    SearchNode node = new SearchNode(costSortedReagents);
 
                                    success = success && node.LoadState(reader);
 
                                    if (success)
 
                                    {
 
                                        searchQueue.Enqueue(node);
 
                                    }
 
                                }
 
                                break;
 
                            default:
 
                                success = false;
 
                                break;
 
                        }
 
                    }
 
                    else
 
                    {
 
                        success = false;
 
                        break;
 
                    }
 
                }
 
                return success;
 
            }
 
        }
 

	
 
        private void Generate()
 
        {
 
            SearchNode node;
 

	
 
            lock(workerLock)
 
            {
 
                ++runningThreads;
 
            }
 

	
 
            bool ok = true;
 
            do
 
            {
...
 
@@ -433,7 +726,7 @@ namespace DesertPaintLab
 
                        node.InitForQuantity(targetQuantity);
 
                    } while (targetQuantity > 10 && (node.CurrentTargetQuantity != node.UsedQuantity));
 

	
 
                    while (ok = Iterate(node) && !requestCancel)
 
                    while ((ok = Iterate(node)) && !requestCancel)
 
                    {
 
                        if (Progress != null)
 
                        {
...
 
@@ -451,17 +744,19 @@ namespace DesertPaintLab
 
            bool done = false;
 
            lock(workerLock)
 
            {
 
                generatorThreads.Remove(Thread.CurrentThread);
 
                --runningThreads;
 
                //generatorThreads.Remove(Thread.CurrentThread);
 

	
 
                done = (generatorThreads.Count == 0);
 
                done = (runningThreads == 0);
 
            }
 
            if (done)
 
            {
 
                running = false;
 
                requestCancel = false;
 
                if (Finished != null)
 
                {
 
                    Finished(this, null);
 
                }
 
                running = false;
 
            }
 
        }
 

	
...
 
@@ -698,12 +993,13 @@ namespace DesertPaintLab
 

	
 
        public void Wait()
 
        {
 
            if (running)
 
            if (generatorThreads.Count > 0)
 
            {
 
                foreach (Thread thr in generatorThreads)
 
                {
 
                    thr.Join();
 
                }
 
                generatorThreads.Clear();
 
            }
 
        }
 

	
RecipeGeneratorWindow.cs
Show inline comments
...
 
@@ -31,6 +31,11 @@ namespace DesertPaintLab
 
        PlayerProfile profile;
 
        bool canceling = false;
 
        bool running = false;
 
        bool pauseForCheckpoint = false;
 

	
 
        const long RECIPE_SAVE_INTERVAL = 30000; // msec between saving recipes
 
        const long CHECKPOINT_INTERVAL = 17000; // msec between saving out generator state
 
        const string STATE_FILE = "dp_generator_state";
 

	
 
        static Gtk.ListStore colorStore = new Gtk.ListStore(typeof(string));
 

	
...
 
@@ -38,6 +43,8 @@ namespace DesertPaintLab
 

	
 
        long lastProgressUpdate;
 
        long lastStatusUpdate;
 
        long lastProfileSave;
 
        long lastCheckpoint;
 

	
 
        static public Gtk.ListStore RecipeModel
 
        {
...
 
@@ -67,6 +74,8 @@ namespace DesertPaintLab
 
            recipeList.AppendColumn(recipeColorColumn);
 
            recipeColorColumn.AddAttribute(recipeColumnCell, "text", 0);
 

	
 
            colorStore.Clear();
 

	
 
            colorStore.SetSortColumnId(0, Gtk.SortType.Ascending);
 
            recipeList.Model = RecipeModel;
 

	
...
 
@@ -80,9 +89,31 @@ namespace DesertPaintLab
 
                colorStore.AppendValues(key);
 
            }
 

	
 
            countLabel.Text = String.Format("{0} / {1}", profile.Recipes.Count, Palette.Count);
 
            canceling = false;
 
            running = false;
 
            pauseForCheckpoint = false;
 

	
 
            generator = new RecipeGenerator(profile.Reactions);
 
            generator.InitRecipes(profile.Recipes);
 

	
 
            generator.Progress += OnProgress;
 
            generator.Finished += OnFinished;
 
            generator.NewRecipe += OnNewRecipe;
 

	
 
            string stateFile = System.IO.Path.Combine(profile.Directory, STATE_FILE);
 
            if (System.IO.File.Exists(stateFile))
 
            {
 
                generator.LoadState(stateFile);
 
                if (generator.CanResume)
 
                {
 
                    beginButton.Label = "Restart";
 
                    stopResumeButton.Label = "Resume";
 
                    stopResumeButton.Sensitive = true;
 
                }
 
            }
 
            countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
 

	
 
            Destroyed += OnDestroyed;
 
        }
 

	
 
        protected void OnMaxIngredientsChanged(object sender, EventArgs e)
...
 
@@ -112,22 +143,16 @@ namespace DesertPaintLab
 
        protected void OnBegin(object sender, EventArgs e)
 
        {
 
            maxIngredientsSpinButton.Sensitive = false;
 
            ExportAction.Sensitive = false;
 
            SettingsAction.Sensitive = false;
 
            ExportToWikiAction.Sensitive = false;
 
            IngredientsAction.Sensitive = false;
 
            maxRecipeSpinButton.Sensitive = false;
 
            beginButton.Sensitive = false; // TODO: change to "pause"?
 
            stopResumeButton.Sensitive = true;
 
            fullQuantitySpinButton.Sensitive = false;
 
            fullQuantityDepthSpinButton.Sensitive = false;
 

	
 
            generator = new RecipeGenerator();
 

	
 
            generator.InitRecipes(profile.Recipes, profile.Reactions);
 
            countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
 

	
 
            generator.Progress += OnProgress;
 
            generator.Finished += OnFinished;
 
            generator.NewRecipe += OnNewRecipe;
 
            // TODO: hook up event notifications
 
            // - progress
 
            // - complete
...
 
@@ -146,10 +171,15 @@ namespace DesertPaintLab
 
            lastProgressUpdate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
 
            lastStatusUpdate = lastProgressUpdate;
 

	
 
            lastProfileSave = lastProgressUpdate;
 
            lastCheckpoint = lastProgressUpdate;
 

	
 
            running = true;
 
            stopResumeButton.Label = "Stop";
 
            canceling = false;
 
            pauseForCheckpoint = false;
 
            stopResumeButton.Label = "Pause";
 

	
 
            generator.BeginRecipeGeneration(profile.Reactions, (uint)maxRecipeSpinButton.ValueAsInt, (uint)maxIngredientsSpinButton.ValueAsInt, (uint)fullQuantityDepthSpinButton.ValueAsInt, (uint)fullQuantitySpinButton.ValueAsInt);
 
            generator.BeginRecipeGeneration((uint)maxRecipeSpinButton.ValueAsInt, (uint)maxIngredientsSpinButton.ValueAsInt, (uint)fullQuantityDepthSpinButton.ValueAsInt, (uint)fullQuantitySpinButton.ValueAsInt);
 
        }
 

	
 
        protected void OnStopResume(object sender, EventArgs e)
...
 
@@ -159,19 +189,25 @@ namespace DesertPaintLab
 
                if (running)
 
                {
 
                    canceling = true;
 
                    pauseForCheckpoint = false;
 
                    generator.Stop();
 
                }
 
                else
 
                {
 
                    // this must be a resume
 
                    // Resume previous run
 
                    ExportToWikiAction.Sensitive = false;
 
                    IngredientsAction.Sensitive = false;
 
                    lastProgressUpdate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
 
                    lastStatusUpdate = lastProgressUpdate;
 
                    lastProfileSave = lastProgressUpdate;
 
                    lastCheckpoint = lastProgressUpdate;
 

	
 
                    canceling = false;
 
                        pauseForCheckpoint = false;
 
                    running = true;
 
        
 
                    stopResumeButton.Label = "Stop";
 
                    generator.BeginRecipeGeneration(profile.Reactions, (uint)maxRecipeSpinButton.ValueAsInt, (uint)maxIngredientsSpinButton.ValueAsInt, (uint)fullQuantityDepthSpinButton.ValueAsInt, (uint)fullQuantitySpinButton.ValueAsInt);
 
                    stopResumeButton.Label = "Pause";
 
                    generator.ResumeRecipeGeneration();
 
                }
 
            }
 
        }
...
 
@@ -179,21 +215,37 @@ namespace DesertPaintLab
 
        protected void OnFinished(object sender, EventArgs args)
 
        {
 
            Gtk.Application.Invoke(delegate {
 
                running = false;
 
                beginButton.Sensitive = true;
 
                ExportAction.Sensitive = true;
 
                SettingsAction.Sensitive = true;
 
                stopResumeButton.Sensitive = false;
 
                maxIngredientsSpinButton.Sensitive = true;
 
                maxRecipeSpinButton.Sensitive = true;
 
                fullQuantitySpinButton.Sensitive = true;
 
                fullQuantityDepthSpinButton.Sensitive = true;
 
                //generator = null; // don't. Hang on to generator for resume.
 
                profile.SaveRecipes();
 
                if (canceling)
 
                generator.Wait();
 
                if (pauseForCheckpoint)
 
                {
 
                    pauseForCheckpoint = false;
 
                    generator.SaveState(System.IO.Path.Combine(profile.Directory, STATE_FILE));
 
                    generator.ResumeRecipeGeneration();
 
                }
 
                else
 
                {
 
                    stopResumeButton.Label = "Resume";
 
                    stopResumeButton.Sensitive = true;
 
                    running = false;
 
                    beginButton.Sensitive = true;
 
                    ExportToWikiAction.Sensitive = true;
 
                    IngredientsAction.Sensitive = true;
 
                    stopResumeButton.Sensitive = false;
 
                    maxIngredientsSpinButton.Sensitive = true;
 
                    maxRecipeSpinButton.Sensitive = true;
 
                    fullQuantitySpinButton.Sensitive = true;
 
                    fullQuantityDepthSpinButton.Sensitive = true;
 
                    //generator = null; // don't. Hang on to generator for resume.
 
                    profile.SaveRecipes();
 
                    if (canceling)
 
                    {
 
                        generator.SaveState(System.IO.Path.Combine(profile.Directory, STATE_FILE));
 
                        stopResumeButton.Label = "Resume";
 
                        stopResumeButton.Sensitive = true;
 
                        beginButton.Label = "Restart";
 
                    }
 
                    else
 
                    {
 
                        System.IO.File.Delete(System.IO.Path.Combine(profile.Directory, STATE_FILE));
 
                    }
 
                }
 
            });
 
        }
...
 
@@ -228,6 +280,14 @@ namespace DesertPaintLab
 
                    countLabel.Text = String.Format("{0} / {1}", generator.Recipes.Count, Palette.Count);
 
                }
 
                profile.SetRecipe(recipe);
 

	
 
                long progressTime = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
 
                long delta = progressTime - lastProfileSave;
 
                if (delta >= RECIPE_SAVE_INTERVAL)
 
                {
 
                    profile.SaveRecipes();
 
                    lastProfileSave = progressTime;
 
                }
 
            });
 
        }
 

	
...
 
@@ -251,6 +311,14 @@ namespace DesertPaintLab
 
                    lastStatusUpdate = progressTime;
 
                }
 
                //progressBar.Fraction = (double)((generator.RecipeCount / 10000) % 100) / 100.0;
 

	
 
                delta = progressTime - lastCheckpoint;
 
                if (delta > CHECKPOINT_INTERVAL)
 
                {
 
                    pauseForCheckpoint = true;
 
                    lastCheckpoint = progressTime;
 
                    generator.Stop();
 
                }
 
            });
 
        }
 

	
...
 
@@ -306,6 +374,20 @@ namespace DesertPaintLab
 
            ReagentWindow win = new ReagentWindow(profile);
 
            win.Show();
 
        }
 

	
 
        protected void OnDestroyed(object o, EventArgs args)
 
        {
 
            if (running)
 
            {
 
                // window closed while generator running: stop and save
 
                generator.Finished -= OnFinished;
 
                generator.Progress -= OnProgress;
 
                generator.NewRecipe -= OnNewRecipe;
 
                generator.Stop();
 
                generator.Wait();
 
                generator.SaveState(System.IO.Path.Combine(profile.Directory, STATE_FILE));
 
            }
 
        }
 
    }
 
}
 

	
gtk-gui/gui.stetic
Show inline comments
...
 
@@ -6,7 +6,7 @@
 
  </configuration>
 
  <import>
 
    <widget-library name="glade-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
 
    <widget-library name="../bin/Debug/DesertPaintLab.exe" internal="true" />
 
    <widget-library name="../bin/Release/DesertPaintLab.exe" internal="true" />
 
  </import>
 
  <widget class="Gtk.Window" id="MainWindow" design-size="629 265">
 
    <action-group name="Default">
mac/build-mac-bundle.sh
Show inline comments
...
 
@@ -19,8 +19,8 @@ fi
 
/bin/cp ../bin/Release/ingredients.txt bin/DesertPaintLab.app/Contents/Resources/
 
/bin/cp -r ../bin/Release/template bin/DesertPaintLab.app/Contents/Resources/template
 

	
 
/usr/bin/defaults write bin/DesertPaintLab.app/Info.plist CFBundleShortVersionString ${VERSION}
 
/usr/bin/defaults write bin/DesertPaintLab.app/Info.plist CFBundleVersion ${VERSION}
 
/usr/bin/defaults write `pwd`/bin/DesertPaintLab.app/Contents/Info.plist CFBundleShortVersionString ${VERSION}
 
/usr/bin/defaults write `pwd`/bin/DesertPaintLab.app/Contents/Info.plist CFBundleVersion ${VERSION}
 

	
 
# package up into a DMG
 
/usr/bin/hdiutil create -volname DesertPaintLab -srcfolder bin/ -ov -format UDIF -fs HFS+ DesertPaintLab.dmg
0 comments (0 inline, 0 general)