Changeset - f1323ba34306
[Not reviewed]
default
0 8 0
Jason Maltzen - 5 years ago 2019-11-07 16:31:54
jason@hiddenachievement.com
Improved logging, sanity checking of settings (especially pixel multiplier), updated readme with some additional details on advanced settings.
8 files changed with 154 insertions and 92 deletions:
0 comments (0 inline, 0 general)
AppSettings.cs
Show inline comments
...
 
@@ -7,19 +7,25 @@ namespace DesertPaintLab
 
        private AppSettings()
 
        {
 
        }
 

	
 
        private static Settings _settings = new Settings();
 

	
 
        public static void Get(string key, out int value)
 
        public static void Get(string key, out int value, int defaultValue)
 
        {
 
            _settings.Get(key, out value);
 
            if (!_settings.TryGet(key, out value))
 
            {
 
                value = defaultValue;
 
            }
 
        }
 
        public static void Get(string key, out bool value)
 
        public static void Get(string key, out bool value, bool defaultValue)
 
        {
 
            _settings.Get(key, out value);
 
            if (!_settings.TryGet(key, out value))
 
            {
 
                value = defaultValue;
 
            }
 
        }
 
        public static void Set(string key, int value)
 
        {
 
            _settings.Set(key, value);
 
        }
 
        public static void Set(string key, bool value)
MainWindow.cs
Show inline comments
...
 
@@ -110,13 +110,13 @@ public partial class MainWindow : Gtk.Wi
 
        // get its width and height
 
        AppSettings.Load();
 

	
 
        ShowPreferencesDialog();
 

	
 
        bool enableDebugMenu;
 
        AppSettings.Get("EnableDebugMenu", out enableDebugMenu);
 
        AppSettings.Get("EnableDebugMenu", out enableDebugMenu, false);
 
        this.DebugAction.Visible = enableDebugMenu;
 

	
 
        ReactionRecorder.Instance.OnReactionRecorded += OnReactionRecorded;
 

	
 
        if (!OpenProfile())
 
        {
...
 
@@ -347,15 +347,16 @@ public partial class MainWindow : Gtk.Wi
 
        }
 
    }
 

	
 
    protected virtual void OnDebugScreenshot(object sender, System.EventArgs e)
 
    {
 
        int screenWidth, screenHeight;
 
        rootWindow.GetSize(out screenWidth, out screenHeight);
 
        DesertPaintLab.AppSettings.Get("ScreenWidth", out screenWidth);
 
        DesertPaintLab.AppSettings.Get("ScreenHeight", out screenHeight);
 
        int windowScreenWidth, windowScreenHeight;
 
        rootWindow.GetSize(out windowScreenWidth, out windowScreenHeight);
 
        AppSettings.Get("ScreenWidth", out screenWidth, windowScreenWidth);
 
        AppSettings.Get("ScreenHeight", out screenHeight, windowScreenHeight);
 
        Gdk.Image rootImage = rootWindow.GetImage(0, 0, screenWidth, screenHeight);
 
        screenBuffer.GetFromImage(rootImage, rootImage.Colormap, 0, 0, 0, 0, screenWidth, screenHeight);
 
        string screenshotDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
 
        string filename;
 
        int i = 0;
 
        do
...
 
@@ -722,18 +723,21 @@ public partial class MainWindow : Gtk.Wi
 
        rootWindow.GetSize(out detectedScreenWidth, out detectedScreenHeight);
 
        int screenWidth = detectedScreenWidth;
 
        int screenHeight = detectedScreenHeight;
 
        int pixelMultiplier = 1;
 
        int interfaceSizeIndex = (int)(InterfaceSize.Small);
 

	
 
        AppSettings.Get("ScreenWidth", out screenWidth);
 
        AppSettings.Get("ScreenHeight", out screenHeight);
 
        AppSettings.Get("PixelMultiplier", out pixelMultiplier);
 
        AppSettings.Get("InterfaceSize", out interfaceSizeIndex);
 
        AppSettings.Get("ScreenWidth", out screenWidth, detectedScreenWidth);
 
        AppSettings.Get("ScreenHeight", out screenHeight, detectedScreenHeight);
 
        AppSettings.Get("PixelMultiplier", out pixelMultiplier, 1);
 
        AppSettings.Get("InterfaceSize", out interfaceSizeIndex, (int)InterfaceSize.Small);
 
        InterfaceSize interfaceSize = (InterfaceSize)interfaceSizeIndex;
 

	
 
        // Sanitize
 
        pixelMultiplier = Math.Max(1, Math.Min(pixelMultiplier, 4));
 

	
 
        ScreenCheckDialog screenCheckDialog = new ScreenCheckDialog {
 
            DetectedScreenWidth = detectedScreenWidth,
 
            DetectedScreenHeight = detectedScreenHeight,
 
            ScreenWidth = screenWidth,
 
            ScreenHeight = screenHeight,
 
            GamePixelWidth = pixelMultiplier,
...
 
@@ -761,19 +765,19 @@ public partial class MainWindow : Gtk.Wi
 
    }
 

	
 
    protected void OnPreferences(object sender, EventArgs e)
 
    {
 
        ShowPreferencesDialog();
 

	
 
        int screenWidth = 1920;
 
        int screenHeight = 1080;
 
        int pixelMultiplier = 1;
 
        int interfaceSizeIndex = (int)(InterfaceSize.Small);
 
        int screenWidth;
 
        int screenHeight;
 
        int pixelMultiplier;
 
        int interfaceSizeIndex;
 

	
 
        AppSettings.Get("ScreenWidth", out screenWidth);
 
        AppSettings.Get("ScreenHeight", out screenHeight);
 
        AppSettings.Get("PixelMultiplier", out pixelMultiplier);
 
        AppSettings.Get("InterfaceSize", out interfaceSizeIndex);
 
        AppSettings.Get("ScreenWidth", out screenWidth, 1920);
 
        AppSettings.Get("ScreenHeight", out screenHeight, 1080);
 
        AppSettings.Get("PixelMultiplier", out pixelMultiplier, 1);
 
        AppSettings.Get("InterfaceSize", out interfaceSizeIndex, (int)InterfaceSize.Small);
 

	
 
        captureView.ScreenBuffer = screenBuffer;
 
    }
 
}
README.md
Show inline comments
...
 
@@ -101,13 +101,13 @@ When you're done testing your reactions,
 
* _Full Quantity_ is the maximum quantity of any ingredient to use up to the Full Quantity Depth. For example, with a Full Quantity of 15 and a Full Quantity Depth of 3, a recipe could use up to 15 of each of the first 3 ingredients. After that it will be limited by the setting for that specific ingredient.
 

	
 
## Known Issues
 

	
 
### Slowness
 

	
 
If you are running on a multi-screen system, or a very high-resolution screen, you may find that Desert Paint Lab is rather slow in determining paint reactions.  That's because you have a lot of screen real-estate to scan, to look for the Pigment Lab dialog.  You can speed up the scanning process by ensuring that your Pigment Lab Dialog is as far to the upper-left of the screen as possible.
 
If you are running on a multi-screen system, or a very high-resolution screen, you may find that Desert Paint Lab is rather slow in determining paint reactions.  That's because you have a lot of screen real-estate to scan, to look for the Pigment Lab dialog.  You can speed up the scanning process by ensuring that your Pigment Lab Dialog is as far to the upper-left of the screen as possible. Also see the advanced settings (below) for some additional options that may help.
 

	
 
### Multiple Displays
 

	
 
When Desert Paint Lab asks for the resolution for a multiple-display setup, enter the combined resolution of all displays. Generally the detected default for this will be correct. For example, two 1920x1080 displays in a side-by-side configuration would be a combined resolution of 3840x1080. In a stacked configuration, they would be 1920x2160.
 

	
 
### Retina / High-Density Screens
...
 
@@ -117,9 +117,21 @@ High DPI screens may be displaying the g
 
## Mac user FAQ
 

	
 
Q: How do I find my native screen resolution?
 

	
 
A: You can find it by opening up "About this Mac" from the Apple menu and clicking on the "Displays" tab. That should show the screen size and resolution to enter.
 

	
 
## Advanced Settings
 

	
 
The settings file has several advanced options that are not available in the interface. Some of these are for debugging, while others are useful for improving the speed of finding the pigment lab interface. The settings file is found in AppData\Local\DesertPaintLab\settings on Windows, and in ~/.local/share/DesertPaintLab/settings on macOS.
 

	
 
* _scanarea.min.x_ sets the starting horizontal offset when searching for the pigment lab. This is useful in multi-screen setups to skip any leftmost displays. For example, a dual-screen setup with two side-by-side 3840x2160 displays where the game runs on the right screen would set this to 3840 to bypass scanning the left display.
 
* _scanarea.min.y_ Like scanarea.min.x, but skips the upper section of display
 
* _scanarea.max.x_ defines the rightmost edge of the area to scan
 
* _scanarea.max.y_ defines the bottom edge of the area to scan
 
* _enabledebugmenu_ enables debug tool menu to help track down problems. This also causes DPL to write debug log files during scanning and recipe generation. This can slow down scanning and recipe searching.
 
* _debugscreenshot_ automatically saves out a screenshot when searching for the pigment lab to help in debugging
 
* _logging.verbosity_ sets the verbosity of the logging between 0 and 3. The higher the value, the more detail is included in the log file.
 

	
 
## For Developers
 

	
 
This application was developed using [MonoDevelop](http://www.monodevelop.com/), and originally used the [Stetic GTK UI designer](http://www.monodevelop.com/documentation/stetic-gui-designer/).
ReactionRecorder.cs
Show inline comments
...
 
@@ -28,12 +28,20 @@ namespace DesertPaintLab
 
    // ReactionRecorder - business logic for recording paint reactions
 
    public class ReactionRecorder
 
    {
 
        public delegate void CaptureProgressHandler(int x, int y);
 
        public CaptureProgressHandler OnCaptureProgress;
 

	
 
        public enum LogVerbosity
 
        {
 
            Low,
 
            Normal,
 
            High,
 
            Excessive
 
        }
 

	
 
        const int COLOR_TOLERANCE = 3;
 

	
 
        const InterfaceSize DEFAULT_INTERFACE_SIZE = InterfaceSize.Small;
 

	
 
        // Swatch is 301x20 solid color, 1px darker left/top, 1px black outer left/top, 1px light right/bottom, 1px bright right/bottom
 
        // top-right and bottom-left are bright instead of black
...
 
@@ -154,12 +162,14 @@ namespace DesertPaintLab
 
        bool firstRun = true;
 
        int lastSwatchX = -1;
 
        int lastSwatchY = -1;
 
        public int SwatchX { get { return lastSwatchX; } }
 
        public int SwatchY { get { return lastSwatchY; } }
 

	
 
        private LogVerbosity logVerbosity = LogVerbosity.Normal;
 

	
 
        private class PixelColor
 
        {
 
            public byte r;
 
            public byte g;
 
            public byte b;
 

	
...
 
@@ -303,15 +313,15 @@ namespace DesertPaintLab
 
                }
 
                return _instance;
 
            }
 
        }
 

	
 
        public StreamWriter Log { get; set; }
 
        private void WriteLog(string format, params object[] args)
 
        private void WriteLog(LogVerbosity verbosity, string format, params object[] args)
 
        {
 
            if (Log != null)
 
            if ((Log != null) && (verbosity <= logVerbosity))
 
            {
 
                Log.WriteLine(format, args);
 
            }
 
        }
 

	
 
        public delegate void ReactionRecordedHandler(Reagent reagent1, Reagent reagent2, Reaction reaction);
...
 
@@ -400,25 +410,25 @@ namespace DesertPaintLab
 
            {
 
                result &= pixels.DoesPixelMatch(x, y + i, color.IsMatch);
 
            }
 

	
 
            if (!result)
 
            {
 
                WriteLog("Swatch slice at {0}, {1} failed to match", x, y);
 
                WriteLog(LogVerbosity.Normal, "Swatch slice at {0}, {1} failed to match", x, y);
 
            }
 

	
 
            return result;
 
        }
 

	
 
        unsafe private bool IsPossibleSwatchUpperLeft(Pixels pixels, int x, int y)
 
        {
 
            int testPixelStart = pixels.ComputeOffset(x, y);
 

	
 
            if (testPixelStart < pixels.stride)
 
            {
 
                WriteLog("Can't test {0},{1} - is not at least 1 row in", x, y);
 
                WriteLog(LogVerbosity.Normal, "Can't test {0},{1} - is not at least 1 row in", x, y);
 
                return false;
 
            }
 

	
 
            bool result = true;
 

	
 
            int swatchSolidWidth = swatchWidth - 4;
...
 
@@ -431,37 +441,37 @@ namespace DesertPaintLab
 
            PixelColor swatchColor = new PixelColor();
 
            pixels.ColorAt(swatchSolidLeftX, swatchSolidTopY, ref swatchColor);
 

	
 
            // Check the other 3 corners of the swatch size for color match
 
            PixelColor testColor = new PixelColor();
 
            bool upperRightResult = pixels.DoesPixelMatch(swatchSolidRightX, swatchSolidTopY, swatchColor.IsMatch);
 
            //if (!upperRightResult)
 
            //{
 
            //    pixels.ColorAt(swatchSolidRightX, swatchSolidTopY, ref testColor);
 
            //    WriteLog("Upper-right mismatch for {8}, {9} - found {0},{1},{2} at {3}, {4} expected {5},{6},{7}", testColor.r, testColor.g, testColor.b, swatchSolidRightX, swatchSolidTopY, swatchColor.r, swatchColor.g, swatchColor.b, x, y);
 
            //}
 
            if (!upperRightResult)
 
            {
 
                pixels.ColorAt(swatchSolidRightX, swatchSolidTopY, ref testColor);
 
                WriteLog(LogVerbosity.Excessive, "Upper-right mismatch for {8}, {9} - found {0},{1},{2} at {3}, {4} expected {5},{6},{7}", testColor.r, testColor.g, testColor.b, swatchSolidRightX, swatchSolidTopY, swatchColor.r, swatchColor.g, swatchColor.b, x, y);
 
            }
 
            bool lowerLeftResult = pixels.DoesPixelMatch(swatchSolidLeftX, swatchSolidBottomY, swatchColor.IsMatch);
 
            //if (!lowerLeftResult)
 
            //{
 
            //    pixels.ColorAt(swatchSolidLeftX, swatchSolidBottomY, ref testColor);
 
            //    WriteLog("Lower-left mismatch for {8}, {9} - found {0},{1},{2} at {3}, {4} expected {5},{6},{7}", testColor.r, testColor.g, testColor.b, swatchSolidLeftX, swatchSolidBottomY, swatchColor.r, swatchColor.g, swatchColor.b, x, y);
 
            //}
 
            if (!lowerLeftResult)
 
            {
 
                pixels.ColorAt(swatchSolidLeftX, swatchSolidBottomY, ref testColor);
 
                WriteLog(LogVerbosity.Excessive, "Lower-left mismatch for {8}, {9} - found {0},{1},{2} at {3}, {4} expected {5},{6},{7}", testColor.r, testColor.g, testColor.b, swatchSolidLeftX, swatchSolidBottomY, swatchColor.r, swatchColor.g, swatchColor.b, x, y);
 
            }
 
            bool lowerRightResult = pixels.DoesPixelMatch(swatchSolidRightX, swatchSolidBottomY, swatchColor.IsMatch);
 
            //if (!lowerRightResult)
 
            //{
 
            //    pixels.ColorAt(swatchSolidRightX, swatchSolidBottomY, ref testColor);
 
            //    WriteLog("Lower-right mismatch for {8}, {9} - found {0},{1},{2} at {3}, {4} expected {5},{6},{7}", testColor.r, testColor.g, testColor.b, swatchSolidRightX, swatchSolidBottomY, swatchColor.r, swatchColor.g, swatchColor.b, x, y);
 
            //}
 
            if (!lowerRightResult)
 
            {
 
                pixels.ColorAt(swatchSolidRightX, swatchSolidBottomY, ref testColor);
 
                WriteLog(LogVerbosity.Excessive, "Lower-right mismatch for {8}, {9} - found {0},{1},{2} at {3}, {4} expected {5},{6},{7}", testColor.r, testColor.g, testColor.b, swatchSolidRightX, swatchSolidBottomY, swatchColor.r, swatchColor.g, swatchColor.b, x, y);
 
            }
 

	
 
            result &= upperRightResult;
 
            result &= lowerLeftResult;
 
            result &= lowerRightResult;
 
            if (!result)
 
            {
 
                // Box corners test failed
 
                // WriteLog("Failed to find left edge for potential swatch of color {2}, {3}, {4} at {0}, {1}", x, y, swatch_r, swatch_g, swatch_b);
 
                WriteLog(LogVerbosity.High, "Failed to find left edge for potential swatch of color {2}, {3}, {4} at {0}, {1}", x, y, swatchColor.r, swatchColor.g, swatchColor.b);
 
                return false;
 
            }
 

	
 
            // scan down the right and left sides
 
            for (int yOff = 1; yOff < (swatchSolidHeight - 1); ++yOff)
 
            {
...
 
@@ -476,13 +486,13 @@ namespace DesertPaintLab
 
                {
 
                    pixels.ColorAt(swatchSolidRightX, swatchSolidTopY + yOff, ref testColor);
 
                }
 
            }
 
            if (!result)
 
            {
 
                WriteLog("Failed to find left/right edges for potential swatch of color {2}, {3}, {4} at {0}, {1} [failed color = {5},{6},{7}]", x, y, swatchColor.r, swatchColor.g, swatchColor.b, testColor.r, testColor.g, testColor.b);
 
                WriteLog(LogVerbosity.Normal, "Failed to find left/right edges for potential swatch of color {2}, {3}, {4} at {0}, {1} [failed color = {5},{6},{7}]", x, y, swatchColor.r, swatchColor.g, swatchColor.b, testColor.r, testColor.g, testColor.b);
 
                return false;
 
            }
 
            for (int xOff = 1; xOff < (swatchSolidWidth - 1); ++xOff)
 
            {
 
                result &= pixels.DoesPixelMatch(swatchSolidLeftX + xOff, swatchSolidTopY, swatchColor.IsMatch);
 
                if (!result)
...
 
@@ -496,13 +506,13 @@ namespace DesertPaintLab
 
                    pixels.ColorAt(swatchSolidLeftX + xOff, swatchSolidBottomY, ref testColor);
 
                    break;
 
                }
 
            }
 
            if (!result)
 
            {
 
                WriteLog("Failed to match upper/lower edges for potential swatch of color {2}, {3}, {4} at {0}, {1} [failed color = {5},{6},{7}]", x, y, swatchColor.r, swatchColor.g, swatchColor.b, testColor.r, testColor.g, testColor.b);
 
                WriteLog(LogVerbosity.Normal, "Failed to match upper/lower edges for potential swatch of color {2}, {3}, {4} at {0}, {1} [failed color = {5},{6},{7}]", x, y, swatchColor.r, swatchColor.g, swatchColor.b, testColor.r, testColor.g, testColor.b);
 
                return false;
 
            }
 

	
 

	
 
            // test the left edge for dark pixels -- the bottom-most pixel is bright now
 
            int i = 0;
...
 
@@ -510,26 +520,26 @@ namespace DesertPaintLab
 
            {
 
                result &= pixels.DoesPixelMatch(x, y + i, PixelColor.IsDark);
 
            }
 
            if (!result)
 
            {
 
                // No dark border on the left side
 
                WriteLog("Failed to find left border for potential swatch of color {2}, {3}, {4} at {0}, {1}", x, y, swatchColor.r, swatchColor.g, swatchColor.b);
 
                WriteLog(LogVerbosity.Normal, "Failed to find left border for potential swatch of color {2}, {3}, {4} at {0}, {1}", x, y, swatchColor.r, swatchColor.g, swatchColor.b);
 
                return false;
 
            }
 

	
 
            // test the dark top border and for papyrus above and below the swatch
 
            bool borderError = false;
 
            int papyErrorCount = 0;
 
            for (i = 0; result && (i < swatchWidth - 1); ++i)
 
            {
 
                bool isBorder = pixels.DoesPixelMatch(x + i, y, PixelColor.IsDark);
 
                result &= isBorder;
 
                if (!isBorder)
 
                {
 
                    WriteLog("Probably swatch at {0},{1} failed upper border test at {2},{3}", x, y, x + i, y);
 
                    WriteLog(LogVerbosity.Normal, "Probable swatch at {0},{1} failed upper border test at {2},{3}", x, y, x + i, y);
 
                    borderError = true;
 
                }
 

	
 
                // Checking along the top of the swatch for papyrus
 
                // The row just above is shaded, so check 2 above
 
                if (y > 1)
...
 
@@ -557,13 +567,13 @@ namespace DesertPaintLab
 

	
 
            result &= (papyErrorCount < (swatchWidth / 20)); // allow up to 5% error rate checking for papy texture, because this seems to be inconsistent
 
            if (!result && ((i > (swatchWidth*0.8)) || (papyErrorCount >= (swatchWidth/20))))
 
            {
 
                if (!borderError && (papyErrorCount < swatchWidth))
 
                {
 
                    WriteLog("Found a potential swatch candidate of width {0} at {1},{2} that had {3} failures matching papyrus texture", i, x, y, papyErrorCount);
 
                    WriteLog(LogVerbosity.Normal, "Found a potential swatch candidate of width {0} at {1},{2} that had {3} failures matching papyrus texture", i, x, y, papyErrorCount);
 
                }
 
            }
 

	
 
            return result;
 
        }
 

	
...
 
@@ -572,26 +582,26 @@ namespace DesertPaintLab
 
            PixelColor pixelColor = new PixelColor();
 

	
 
            // Check 4 corners of solid area and left/right solid bar areas
 
            bool foundSwatch = IsPossibleSwatchUpperLeft(pixels, x, y); // ((pixel_r < 0x46) && (pixel_g < 0x46) && (pixel_b < 0x46));
 
            if (foundSwatch)
 
            {
 
                WriteLog("Found probable swatch at {0},{1} - checking border slices", x, y);
 
                WriteLog(LogVerbosity.Normal, "Found probable swatch at {0},{1} - checking border slices", x, y);
 
                int borderXOffset = 0;
 
                for (borderXOffset = 2; foundSwatch && (borderXOffset < swatchTestWidth); ++borderXOffset)
 
                {
 
                    foundSwatch &= IsPossibleSwatchSlice(pixels, x + borderXOffset, y);
 
                    if (!foundSwatch)
 
                    {
 
                        WriteLog("Failed slice test at {0},{1}", x + borderXOffset, y);
 
                        WriteLog(LogVerbosity.Normal, "Failed slice test at {0},{1}", x + borderXOffset, y);
 
                        break;
 
                    }
 
                    foundSwatch &= IsPossibleSwatchSlice(pixels, x + swatchWidth - borderXOffset, y);
 
                    if (!foundSwatch)
 
                    {
 
                        WriteLog("Failed slice test at {0},{1}", x + swatchWidth - borderXOffset, y);
 
                        WriteLog(LogVerbosity.Normal, "Failed slice test at {0},{1}", x + swatchWidth - borderXOffset, y);
 
                        break;
 
                    }
 
                }
 
            }
 

	
 
            if (foundSwatch)
...
 
@@ -603,13 +613,13 @@ namespace DesertPaintLab
 

	
 
                int greenPixelCount = pixels.LengthOfColorAt(x, y + greenBarSpacing, PixelColor.IsGreen);
 
                reactedColor.Green = (byte)Math.Round((float)greenPixelCount * 255f / (float)colorBarWidth);
 

	
 
                int bluePixelCount = pixels.LengthOfColorAt(x, y + blueBarSpacing, PixelColor.IsBlue);
 
                reactedColor.Blue = (byte)Math.Round((float)bluePixelCount * 255f / (float)colorBarWidth);
 
                WriteLog("Found the color swatch at {0}, {1}. Color={2} Red={3}px Green={4}px Blue={5}px", x, y, reactedColor, redPixelCount, greenPixelCount, bluePixelCount);
 
                WriteLog(LogVerbosity.Low, "Found the color swatch at {0}, {1}. Color={2} Red={3}px Green={4}px Blue={5}px", x, y, reactedColor, redPixelCount, greenPixelCount, bluePixelCount);
 
                return true;
 
            }
 
            return false;
 
        }
 

	
 
        unsafe public bool CaptureReaction(byte* pixBytes, int screenshotWidth, int screenshotHeight, int stride, int numChannels, int bitsPerSample)
...
 
@@ -645,44 +655,44 @@ namespace DesertPaintLab
 
                else
 
                {
 
                    firstRun = true;
 
                }
 
            }
 

	
 
            int verbosityIdx;
 
            AppSettings.Get("Log.Verbosity", out verbosityIdx, 1);
 
            logVerbosity = (LogVerbosity)verbosityIdx;
 

	
 
            int startX;
 
            int endX;
 
            int startY;
 
            int endY;
 
            DesertPaintLab.AppSettings.Get("ScanOffsetX", out startX);
 
            DesertPaintLab.AppSettings.Get("ScanOffsetY", out startY);
 
            DesertPaintLab.AppSettings.Get("ScanLimitX", out endX);
 
            DesertPaintLab.AppSettings.Get("ScanLimitY", out endY);
 
            if (endX == 0) endX = screenshotWidth;
 
            if (endY == 0) endY = screenshotHeight;
 
            if (endX > screenshotWidth) endX = screenshotWidth;
 
            if (endY > screenshotHeight) endY = screenshotHeight;
 
            if (startX < 2) startX = 2;
 
            if (startY < 2) startY = 2;
 
            if (startX > screenshotWidth) startX = 2;
 
            if (startY > screenshotHeight) startY = 2;
 
            AppSettings.Get("ScanArea.Min.X", out startX, 0);
 
            AppSettings.Get("ScanArea.Min.Y", out startY, 0);
 
            AppSettings.Get("ScanArea.Max.X", out endX, screenshotWidth);
 
            AppSettings.Get("ScanArea.Max.Y", out endY, screenshotHeight);
 
            startX = Math.Max(2, Math.Min(startX, screenshotWidth-2));
 
            startY = Math.Max(2, Math.Min(startY, screenshotHeight-2));
 
            endX = Math.Min(screenshotWidth-2, Math.Max(2, endX));
 
            endY = Math.Min(screenshotHeight-2, Math.Max(2, endY));
 

	
 
            int patchTestSize = ((swatchHeight - 5) / 2) - 1;
 
            PixelColor patchColor = new PixelColor();
 
            for (int roughX = startX; roughX < endX - colorBarWidth + patchTestSize; roughX += patchTestSize)
 
            {
 
                for (int roughY = startY; roughY < (endY - (blueBarSpacing + 10) + patchTestSize  /*53*/); roughY += patchTestSize)
 
                {
 
                    OnCaptureProgress?.Invoke(roughX, roughY);
 
                    if (!pixels.IsSolidPatchAt(roughX, roughY, patchTestSize, patchTestSize)) continue;
 
                    pixels.ColorAt(roughX, roughY, ref patchColor);
 
                    //Console.WriteLine("Found a solid patch of {2},{3},{4} at {0}, {1}", roughX, roughY, patchColor.r, patchColor.g, patchColor.b);
 
                    WriteLog(LogVerbosity.Excessive, "Found a solid patch of {2},{3},{4} at {0}, {1}", roughX, roughY, patchColor.r, patchColor.g, patchColor.b);
 
                    for (X = Math.Max(0, roughX - patchTestSize); X < roughX; ++X)
 
                    {
 
                        for (Y = Math.Max(0, roughY - patchTestSize); Y < roughY; ++Y)
 
                        {
 
                            //WriteLog("Checking for potential swatch at {0},{1} after found square at {2},{3}", X, Y, roughX, roughY);
 
                            WriteLog(LogVerbosity.Excessive, "Searching for potential swatch at {0},{1} after found square at {2},{3}", X, Y, roughX, roughY);
 
                            if (TestPosition(X, Y, pixels, ref reactedColor, ref redPixelStart))
 
                            {
 
                                RedBarX = (redPixelStart % stride) / numChannels;
 
                                RedBarY = redPixelStart / stride;
 
                                RecordedColor = reactedColor;
 
                                lastSwatchX = X;
...
 
@@ -690,13 +700,13 @@ namespace DesertPaintLab
 
                                firstRun = false;
 
                                IsCaptured = true;
 
                                return true;
 
                            }
 
                        }
 
                    }
 
                    //System.Console.WriteLine("False-positive patch of color {0},{1},{2} at {3},{4}", patchColor.r, patchColor.g, patchColor.b, roughX, roughY);
 
                    WriteLog(LogVerbosity.Excessive, "False-positive patch of color {0},{1},{2} at {3},{4}", patchColor.r, patchColor.g, patchColor.b, roughX, roughY);
 
                }
 
            }
 
            return false;
 
        }
 

	
 
        public bool RecordReaction(PlayerProfile profile, PaintColor expectedColor, PaintColor reactedColor, Reagent[] reagents)
Settings.cs
Show inline comments
...
 
@@ -10,29 +10,33 @@ namespace DesertPaintLab
 
        public Settings()
 
        {
 
        }
 

	
 
        private Dictionary<string, string> _settings = new Dictionary<string, string>();
 

	
 
        public void Get(string key, out int value)
 
        public bool TryGet(string key, out int value)
 
        {
 
            value = 0;
 
            string valStr;
 
            if ( _settings.TryGetValue(key.ToLower(), out valStr) )
 
            bool found = _settings.TryGetValue(key.ToLower(), out valStr);
 
            if (found)
 
            {
 
                Int32.TryParse(valStr, out value);
 
            }
 
            return found;
 
        }
 
        public void Get(string key, out bool value)
 
        public bool TryGet(string key, out bool value)
 
        {
 
            value = false;
 
            string valStr;
 
            if ( _settings.TryGetValue(key.ToLower(), out valStr) )
 
            bool found = _settings.TryGetValue(key.ToLower(), out valStr);
 
            if (found)
 
            {
 
                Boolean.TryParse(valStr, out value);
 
            }
 
            return found;
 
        }
 
        public void Set(string key, int value)
 
        {
 
            _settings[key.ToLower()] = value.ToString();
 
        }
 
        public void Set(string key, bool value)
UI/CaptureView.cs
Show inline comments
...
 
@@ -273,14 +273,14 @@ namespace DesertPaintLab
 
            ingredient3ComboBox.Sensitive = false;
 
            clearReactionButton.Sensitive = false;
 

	
 
            progressBar.Show();
 
            recordButton.Hide();
 

	
 
            bool enableDebugMenu = false;
 
            DesertPaintLab.AppSettings.Get("EnableDebugMenu", out enableDebugMenu);
 
            bool enableDebugMenu;
 
            AppSettings.Get("EnableDebugMenu", out enableDebugMenu, false);
 

	
 
            StreamWriter log = null;
 
            if (enableDebugMenu)
 
            {
 
                string logfile = FileUtils.FindNumberedFile("DesertPaintLab_Capture", "log", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments));
 
                log = new StreamWriter(logfile);
...
 
@@ -344,16 +344,16 @@ namespace DesertPaintLab
 
                log.Flush();
 
                log.Close();
 
                log = null;
 
                ReactionRecorder.Instance.Log = null;
 
            }
 

	
 
            bool enableDebugMenu = false;
 
            DesertPaintLab.AppSettings.Get("EnableDebugMenu", out enableDebugMenu);
 
            bool debugScreenshot = false;
 
            DesertPaintLab.AppSettings.Get("DebugScreenshot", out debugScreenshot);
 
            bool enableDebugMenu;
 
            DesertPaintLab.AppSettings.Get("EnableDebugMenu", out enableDebugMenu, false);
 
            bool debugScreenshot;
 
            DesertPaintLab.AppSettings.Get("DebugScreenshot", out debugScreenshot, false);
 
            if (enableDebugMenu && debugScreenshot)
 
            {
 
                if (!isCaptured)
 
                {
 
                    // write out the whole screenshot on a failure to capture
 
                    string screenshotDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
...
 
@@ -470,25 +470,25 @@ namespace DesertPaintLab
 

	
 
        unsafe void CaptureReactionColor()
 
        {
 
            // Take a screenshot.
 
            int screenWidth, screenHeight;
 
            Gdk.Window rootWindow = Gdk.Global.DefaultRootWindow;
 
            DesertPaintLab.AppSettings.Get("ScreenWidth", out screenWidth);
 
            DesertPaintLab.AppSettings.Get("ScreenHeight", out screenHeight);
 
            AppSettings.Get("ScreenWidth", out screenWidth, 1920);
 
            AppSettings.Get("ScreenHeight", out screenHeight, 1080);
 
            Gdk.Image rootImage = rootWindow.GetImage(0, 0, screenWidth, screenHeight);
 
            RecordBuffer = screenBuffer;
 
            RecordBuffer.GetFromImage(rootImage, rootImage.Colormap, 0, 0, 0, 0, screenWidth, screenHeight);
 
            rootImage.Unref();
 
            System.GC.Collect(); // really, clean up now
 

	
 
            int pixelMultiplier;
 
            AppSettings.Get("PixelMultiplier", out pixelMultiplier);
 
            AppSettings.Get("PixelMultiplier", out pixelMultiplier, 1);
 
            if (pixelMultiplier == 0) pixelMultiplier = 1;
 
            int interfaceSizeIndex = 1;
 
            AppSettings.Get("InterfaceSize", out interfaceSizeIndex);
 
            int interfaceSizeIndex;
 
            AppSettings.Get("InterfaceSize", out interfaceSizeIndex, (int)InterfaceSize.Small);
 
            InterfaceSize interfaceSize = (InterfaceSize)interfaceSizeIndex;
 
            ReactionRecorder.Instance.PixelMultiplier = pixelMultiplier;
 
            ReactionRecorder.Instance.InterfaceSize = interfaceSize;
 

	
 
            BeginCapture();
 
        }
UI/RecipeGeneratorView.cs
Show inline comments
...
 
@@ -110,13 +110,13 @@ namespace DesertPaintLab
 
            canceling = false;
 
            running = false;
 
            pauseForCheckpoint = false;
 

	
 
            generator = new RecipeGenerator(profile.Reactions);
 
            int threads;
 
            DesertPaintLab.AppSettings.Get("GeneratorThreads", out threads);
 
            DesertPaintLab.AppSettings.Get("GeneratorThreads", out threads, 15);
 
            if (threads <= 0) { threads = 15; }
 
            generator.MaxThreads = (uint)threads;
 
            generator.InitRecipes(profile.Recipes);
 

	
 
            generator.Progress += OnProgress;
 
            generator.Finished += OnFinished;
...
 
@@ -208,13 +208,13 @@ namespace DesertPaintLab
 
            reagentListView.AppendColumn(reagentEnabledColumn);
 
            reagentListView.AppendColumn(reagentNameColumn);
 
            reagentListView.AppendColumn(reagentCostColumn);
 
            reagentListView.AppendColumn(reagentMaxColumn);
 

	
 
            bool ribbons = false;
 
            profile.ProfileSettings.Get("Generator.Ribbons", out ribbons);
 
            bool foundSetting = profile.ProfileSettings.TryGet("Generator.Ribbons", out ribbons);
 
            if (ribbons)
 
            {
 
                checkButtonRibbon.Active = true;
 
                InitStateForRibbons();
 
            }
 
            else
...
 
@@ -231,24 +231,24 @@ namespace DesertPaintLab
 
            maxRecipeSpinButton.Adjustment.Lower = PaintRecipe.PAINT_RECIPE_MIN_CONCENTRATION;
 
            fullQuantitySpinButton.Adjustment.Upper = 30;
 
            if (generator == null)
 
            {
 
                generator = new RecipeGenerator(profile.Reactions);
 
                int threads;
 
                DesertPaintLab.AppSettings.Get("GeneratorThreads", out threads);
 
                AppSettings.Get("GeneratorThreads", out threads, 15);
 
                if (threads <= 0) { threads = 15; }
 
                generator.MaxThreads = (uint)threads;
 

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

	
 
                bool enableDebugMenu = false;
 
                DesertPaintLab.AppSettings.Get("EnableDebugMenu", out enableDebugMenu);
 
                bool logGenerator = false;
 
                DesertPaintLab.AppSettings.Get("GeneratorLog", out logGenerator);
 
                bool enableDebugMenu;
 
                AppSettings.Get("EnableDebugMenu", out enableDebugMenu, false);
 
                bool logGenerator;
 
                AppSettings.Get("GeneratorLog", out logGenerator, false);
 
                if (enableDebugMenu && logGenerator)
 
                {
 
                    string logDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
 
                    generator.Log = System.IO.Path.Combine(logDir, "dpl_generator.txt");
 
                }
 
            }
...
 
@@ -301,13 +301,13 @@ namespace DesertPaintLab
 
            maxRecipeSpinButton.Adjustment.Lower = PaintRecipe.RIBBON_RECIPE_MIN_CONCENTRATION;
 
            fullQuantitySpinButton.Adjustment.Upper = 100;
 
            if (generator == null)
 
            {
 
                generator = new RecipeGenerator(profile.Reactions);
 
                int threads;
 
                DesertPaintLab.AppSettings.Get("GeneratorThreads", out threads);
 
                AppSettings.Get("GeneratorThreads", out threads, 15);
 
                if (threads <= 0) { threads = 15; }
 
                generator.MaxThreads = (uint)threads;
 

	
 
                generator.Progress += OnProgress;
 
                generator.Finished += OnFinished;
 
                generator.NewRecipe += OnNewRecipe;
...
 
@@ -363,13 +363,13 @@ namespace DesertPaintLab
 
                    // TODO: ensure not running
 
                    profile = value;
 
                    profile.LoadRecipes();
 

	
 
                    generator = new RecipeGenerator(profile.Reactions);
 
                    int threads;
 
                    DesertPaintLab.AppSettings.Get("GeneratorThreads", out threads);
 
                    AppSettings.Get("GeneratorThreads", out threads, 15);
 
                    if (threads <= 0) { threads = 15; }
 
                    generator.MaxThreads = (uint)threads;
 
        
 
                    generator.Progress += OnProgress;
 
                    generator.Finished += OnFinished;
 
                    generator.NewRecipe += OnNewRecipe;
gtk-gui/DesertPaintLab.ScreenCheckDialog.cs
Show inline comments
...
 
@@ -15,16 +15,20 @@ namespace DesertPaintLab
 
        private global::Gtk.Entry screenWidthEntry;
 
		
 
		private global::Gtk.Entry screenHeightEntry;
 
		
 
		private global::Gtk.HBox hbox2;
 
		
 
        private global::Gtk.VBox vbox3;
 
		
 
		private global::Gtk.Label label2;
 
		
 
		private global::Gtk.Entry gamePixelWidthEntry;
 

	
 
        private global::Gtk.Label label3;
 

	
 
        private global::Gtk.HBox hbox3;
 

	
 
        private global::Gtk.Label interfaceSizeLlabel;
 

	
 
        private global::Gtk.ComboBox interfaceSizeComboBox;
 

	
...
 
@@ -95,12 +99,18 @@ namespace DesertPaintLab
 
            this.vbox2.Add(this.detectedResolutionLabel);
 
            global::Gtk.Box.BoxChild wDR = ((global::Gtk.Box.BoxChild)(this.vbox2[this.detectedResolutionLabel]));
 
            wDR.Position =  1;
 
            wDR.Expand = false;
 
            wDR.Fill = false;
 

	
 
            // Container child dialog1_VBox.Gtk.Box+BoxChild
 
            this.vbox3 = new global::Gtk.VBox();
 
            this.vbox3.Name = "vbox3";
 
            this.vbox3.Spacing = 2;
 
            this.vbox3.BorderWidth = ((uint)(20));
 

	
 
            // Container child vbox2.Gtk.Box+BoxChild
 
            this.hbox2 = new global::Gtk.HBox ();
 
			this.hbox2.Name = "hbox2";
 
			this.hbox2.Spacing = 20;
 
			this.hbox2.BorderWidth = ((uint)(10));
 
			// Container child hbox2.Gtk.Box+BoxChild
...
 
@@ -121,18 +131,34 @@ namespace DesertPaintLab
 
			this.gamePixelWidthEntry.InvisibleChar = '●';
 
			this.hbox2.Add (this.gamePixelWidthEntry);
 
			global::Gtk.Box.BoxChild w7 = ((global::Gtk.Box.BoxChild)(this.hbox2 [this.gamePixelWidthEntry]));
 
			w7.Position = 1;
 
			w7.Expand = false;
 
			w7.Fill = false;
 
			this.vbox2.Add (this.hbox2);
 
			global::Gtk.Box.BoxChild w8 = ((global::Gtk.Box.BoxChild)(this.vbox2 [this.hbox2]));
 
			w8.Position = 2;
 
			this.vbox3.Add (this.hbox2);
 
			global::Gtk.Box.BoxChild w8 = ((global::Gtk.Box.BoxChild)(this.vbox3 [this.hbox2]));
 
			w8.Position = 0;
 
			w8.Expand = false;
 
			w8.Fill = false;
 

	
 
            // Container child hbox2.Gtk.Box+BoxChild
 
            this.label3 = new global::Gtk.Label();
 
            this.label3.Name = "label2";
 
            this.label3.LabelProp = "(Advanced, should be 1 for most displays and 2 for Macs with retina displays)";
 
            this.vbox3.Add(this.label3);
 
            global::Gtk.Box.BoxChild w8a = ((global::Gtk.Box.BoxChild)(this.vbox3[this.label3]));
 
            w8a.Position = 1;
 
            w8a.Expand = false;
 
            w8a.Fill = false;
 

	
 
            this.vbox2.Add(this.vbox3);
 
            global::Gtk.Box.BoxChild w8b = ((global::Gtk.Box.BoxChild)(this.vbox2[this.vbox3]));
 
            w8b.Position = 2;
 
            w8b.Expand = false;
 
            w8b.Fill = false;
 

	
 
            // Container child vbox2.Gtk.Box+BoxChild
 
            this.hbox3 = new global::Gtk.HBox();
 
            this.hbox3.Name = "hbox3";
 
            this.hbox3.Spacing = 20;
 
            this.hbox3.BorderWidth = ((uint)(10));
 
            // Container child hbox3.Gtk.Box+BoxChild
0 comments (0 inline, 0 general)