Skip to content

Commit

Permalink
Attempt to reduce resource usage and GC calls
Browse files Browse the repository at this point in the history
Only run fixposition every 5 "ticks", and only actually update the
position if it is different

Use a class-defined Bgr to clear the image instead of creating one every
loop

Only reset the stopwatch if it is being used

Clear the list of rectangles instead of creating a new instance
  • Loading branch information
Sean committed Jun 10, 2016
1 parent 7eebc9c commit 60b08ce
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 22 deletions.
25 changes: 14 additions & 11 deletions LoveBoot/BotLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ public void PressThread()
{
if (bar_image_source == null) continue;

Dictionary<object, Rectangle[]> matches = barImageFinder.FindAllMatches(bar_image_source, "", false);
IDictionary<object, Rectangle[]> matches = barImageFinder.FindAllMatches(bar_image_source, "", false);

foreach (KeyValuePair<object, Rectangle[]> pairs in matches)
{
Expand Down Expand Up @@ -518,7 +518,7 @@ public void StateThread()
{
if (key_image_source == null) continue;

Dictionary<object, Rectangle[]> matches = stateImageFinder.FindAllMatches(key_image_source, "", false, EightKeyMode ? "" : "Key_8_"); // ignore key_8 if eight key mode is not enabled
IDictionary<object, Rectangle[]> matches = stateImageFinder.FindAllMatches(key_image_source, "", false, EightKeyMode ? "" : "Key_8_"); // ignore key_8 if eight key mode is not enabled

bool addedAtLeastOne = false;

Expand All @@ -545,14 +545,17 @@ public void StateThread()
}
}

if (addedAtLeastOne)
if (AutoReady)
{
stopwatch.Restart();
}
else if(AutoReady && stopwatch.ElapsedMilliseconds > TIME_BEFORE_AUTO_READY_MS)
{
windowFinder.SendKeystroke((ushort)VirtualKeyCode.F5);
stopwatch.Reset(); // reset ensures bot does not auto ready more than once (un-readying). can be bad if it misses ready moment, if cooldown is too short
if (addedAtLeastOne)
{
stopwatch.Restart();
}
else if (stopwatch.ElapsedMilliseconds > TIME_BEFORE_AUTO_READY_MS)
{
windowFinder.SendKeystroke((ushort)VirtualKeyCode.F5);
stopwatch.Reset(); // reset ensures bot does not auto ready more than once (un-readying). can be bad if it misses ready moment, if cooldown is too short
}
}
}

Expand All @@ -561,7 +564,7 @@ public void StateThread()

for (int i = 0; i < newGameState.Length; i++)
{
if (newGameState[i].Count > 0 && oldPhysicalGameState[i].Count > 1 && oldPhysicalGameState[i].Count > newGameState[i].Count)
if (oldPhysicalGameState != null && newGameState[i].Count > 0 && oldPhysicalGameState[i].Count > 1 && oldPhysicalGameState[i].Count > newGameState[i].Count)
{
// TEST: replaces gamestates per column if old game state had >=2 keys and this state has less, but not 0 (attempt to "fix" keys occasionally not being recognized in high bpm songs due to particles)
// similar to caching
Expand All @@ -574,7 +577,7 @@ public void StateThread()
Array.Sort(physicalSignalArray);

rawGameState[i] = new Signal[KEY_COLUMNS_MAX];
for (int i2 = 0; i2 < physicalSignalArray.Length; i2++)
for (int i2 = 0; i2 < physicalSignalArray.Length && i2 < KEY_COLUMNS_MAX; i2++)
{
rawGameState[i][i2] = physicalSignalArray[i2].Type;
}
Expand Down
33 changes: 25 additions & 8 deletions LoveBoot/ImageFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using System.Threading.Tasks;
using System.Collections.Concurrent;

namespace LoveBoot
{
Expand All @@ -29,6 +31,7 @@ public class ImageFinder
{
private List<Rectangle> rectangles;
private Stopwatch stopwatch;
private Bgr fillColor;

public double Threshold { get; set; }

Expand All @@ -44,13 +47,15 @@ public ImageFinder(double threshold)
rectangles = new List<Rectangle>();
stopwatch = new Stopwatch();
Threshold = threshold;
fillColor = new Bgr(Color.Magenta);
}

public ImageFinder()
{
rectangles = new List<Rectangle>();
stopwatch = new Stopwatch();
Threshold = 0.85;
fillColor = new Bgr(Color.Magenta);
}

/// <summary>
Expand All @@ -67,9 +72,9 @@ public ImageFinder()
}
}*/

public Dictionary<object, Rectangle[]> FindAllMatches(Image<Bgr, Byte> source, string match = "", bool copy = true, string ignore = "") // todo: proper order
public IDictionary<object, Rectangle[]> FindAllMatches(Image<Bgr, Byte> source, string match = "", bool copy = true, string ignore = "") // todo: proper order
{
Dictionary <object, Rectangle[]> matches = new Dictionary<object, Rectangle[]>();
var matches = new ConcurrentDictionary<object, Rectangle[]>();

Image<Bgr, Byte> sourceImage = copy ? source.Copy() : source;

Expand All @@ -79,39 +84,51 @@ public Dictionary<object, Rectangle[]> FindAllMatches(Image<Bgr, Byte> source, s
if (ignore.Length > 0 && subImageKeyValuePair.Key.ToString().Contains(ignore)) continue;

Rectangle[] subImageMatches = FindMatches(sourceImage, subImageKeyValuePair.Value, copy);
matches.Add(subImageKeyValuePair.Key, subImageMatches);
matches[subImageKeyValuePair.Key] = subImageMatches;
}

/*Parallel.ForEach(SubImages, (subImageKeyValuePair) =>
{
if (match.Length > 0 && !subImageKeyValuePair.Key.ToString().Contains(match)) return;
if (ignore.Length > 0 && subImageKeyValuePair.Key.ToString().Contains(ignore)) return;
Rectangle[] subImageMatches = FindMatches(sourceImage, subImageKeyValuePair.Value, copy);
matches[subImageKeyValuePair.Key] = subImageMatches;
//matches.Add(subImageKeyValuePair.Key, subImageMatches);
});*/

return matches;
}

public Rectangle[] FindMatches(Image<Bgr, Byte> source, Image<Bgr, Byte> target, bool copy = true)
{
rectangles = new List<Rectangle>();
//rectangles = new List<Rectangle>();
rectangles.Clear();
//stopwatch = new Stopwatch();
//stopwatch.Start();

Image<Bgr, Byte> imgSrc = copy ? source.Copy() : source;

// FindImage all occurences of imgFind

double[] minValues, maxValues;
Point[] minLocations, maxLocations;

while (true)
{
using (
Image<Gray, float> result = imgSrc.MatchTemplate(target,
Emgu.CV.CvEnum.TemplateMatchingType.CcoeffNormed))
{
double[] minValues, maxValues;
Point[] minLocations, maxLocations;
result.MinMax(out minValues, out maxValues, out minLocations, out maxLocations);

// You can try different values of the threshold. I guess somewhere between 0.75 and 0.95 would be good.
if (maxValues[0] < Threshold || minValues[0] == maxValues[0]) break;
// This is a match. Do something with it, for example draw a rectangle around it.
Rectangle match = new Rectangle(maxLocations[0], target.Size);

// Fill the drawing with red in order to ellimate this as a source.
imgSrc.Draw(match, new Bgr(Color.Magenta), -1);
imgSrc.Draw(match, fillColor, -1);

// Add the found rectangle to the results.
rectangles.Add(match);
Expand Down
16 changes: 13 additions & 3 deletions LoveBoot/Overlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,15 +334,23 @@ private void fixPosition()
}

WindowFinder.Rect windowRect = windowFinder.GetWindowLocation();
this.Size = new Size(windowRect.Right - windowRect.Left, windowRect.Bottom - windowRect.Top);
this.Location = new Point(windowRect.Left, windowRect.Top);
if (this.Location.X != windowRect.Left || this.Location.Y != windowRect.Top)
{
this.Size = new Size(windowRect.Right - windowRect.Left, windowRect.Bottom - windowRect.Top);
this.Location = new Point(windowRect.Left, windowRect.Top);
}
}

private int tmrOverlayTicks = 0;
private void tmrOverlay_Tick(object sender, EventArgs e)
{
if (!windowFinder.ProcessFound) this.Close(); // attempts to close when the process isn't found, does not really work

fixPosition();
if (tmrOverlayTicks % 5 == 0)
{
fixPosition();
tmrOverlayTicks = 0;
}

bool refresh = false;

Expand All @@ -362,6 +370,8 @@ private void tmrOverlay_Tick(object sender, EventArgs e)
refresh = true;
}
if(refresh) this.Refresh();

tmrOverlayTicks++;
}
}
}

0 comments on commit 60b08ce

Please sign in to comment.