Skip to content

Commit

Permalink
card count detection for arena importing [wip]
Browse files Browse the repository at this point in the history
  • Loading branch information
Epix37 committed Aug 17, 2015
1 parent 668b118 commit 6a32869
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 5 deletions.
3 changes: 3 additions & 0 deletions Hearthstone Deck Tracker/Config.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ public class Config
[DefaultValue(DeckLayout.Layout1)]
public DeckLayout DeckPickerItemLayout = DeckLayout.Layout1;

[DefaultValue(false)]
public bool DeckImportAutoDetectCardCount = false;

[DefaultValue(false)]
public bool DiscardGameIfIncorrectDeck = false;

Expand Down
2 changes: 1 addition & 1 deletion Hearthstone Deck Tracker/DeckExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ private static async Task SetDeckName(string name, double ratio, int width, int
SendKeys.SendWait("{ENTER}");
}

private static double GetXPos(double left, int width, double ratio)
public static double GetXPos(double left, int width, double ratio)
{
return (width * ratio * left) + (width * (1 - ratio) / 2);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
d:DesignHeight="600" d:DesignWidth="300">
<Grid>
<GroupBox Header="Importing">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<CheckBox x:Name="CheckBoxAutoDetectCardCount" Content="[BETA] Auto detect card count for arena"
HorizontalAlignment="Left" Margin="10,5,0,0"
VerticalAlignment="Top" Checked="CheckBoxAutoDetectCardCount_Checked"
Unchecked="CheckBoxAutoDetectCardCount_Unchecked" />
<TextBlock Margin="10,5,0,0" Text="[This feature is still a work in progress!]" FontWeight="Bold"></TextBlock>
<TextBlock Margin="10,5,0,15" Text="Currently only for arena. Can currently only detect &quot;more than 1&quot;, which sets it to 2, not the actual number. Yes, both of those things will come." TextWrapping="Wrap"></TextBlock>
<CheckBox x:Name="CheckboxTagOnImport" Content="Tag decks on import"
HorizontalAlignment="Left" Margin="10,5,0,0"
VerticalAlignment="Top" Checked="CheckboxTagOnImport_Checked"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e

public void Load()
{
CheckBoxAutoDetectCardCount.IsChecked = Config.Instance.DeckImportAutoDetectCardCount;
CheckboxTagOnImport.IsChecked = Config.Instance.TagDecksOnImport;
CheckboxImportNetDeck.IsChecked = Config.Instance.NetDeckClipboardCheck ?? false;
CheckboxAutoSaveOnImport.IsChecked = Config.Instance.AutoSaveOnImport;
Expand Down Expand Up @@ -128,5 +129,21 @@ private void ButtonActivateHdtProtocol_OnClick(object sender, RoutedEventArgs e)
{
Helper.MainWindow.SetupProtocol();
}

private void CheckBoxAutoDetectCardCount_Checked(object sender, RoutedEventArgs e)
{
if(!_initialized)
return;
Config.Instance.DeckImportAutoDetectCardCount = true;
Config.Save();
}

private void CheckBoxAutoDetectCardCount_Unchecked(object sender, RoutedEventArgs e)
{
if(!_initialized)
return;
Config.Instance.DeckImportAutoDetectCardCount = false;
Config.Save();
}
}
}
123 changes: 122 additions & 1 deletion Hearthstone Deck Tracker/MainWindow/MainWindow_Import.cs
Original file line number Diff line number Diff line change
Expand Up @@ -319,15 +319,136 @@ private async void BtnArena_Click(object sender, RoutedEventArgs e)
}

var deck = new Deck {Name = Helper.ParseDeckNameTemplate(Config.Instance.ArenaDeckNameTemplate), IsArenaDeck = true};
foreach(var card in Game.PossibleArenaCards)
foreach(var card in Game.PossibleArenaCards.OrderBy(x => x.Cost).ThenBy(x => x.Type).ThenBy(x => x.LocalizedName))
{
deck.Cards.Add(card);
if(deck.Class == null && card.GetPlayerClass != "Neutral")
deck.Class = card.GetPlayerClass;
}
if(Config.Instance.DeckImportAutoDetectCardCount)
{
await this.ShowMessageAsync("Arena cards found!", "[WORK IN PROGRESS] Please enter the arena screen, then click ok. Wait until HDT has loaded the deck.\n\nPlease don't move your mouse.\n\nNote: For right now, this can currently only detect if a card has 1 or more than 1 copy (sets count to 2). Cards with more than 2 copies still have to be manually adjusted.");
var controller = await this.ShowProgressAsync("Please wait...", "Detecting card counts...");
await GetCardCounts(deck);
await controller.CloseAsync();
}
SetNewDeck(deck);
}

public async Task GetCardCounts(Deck deck)
{
var hsHandle = User32.GetHearthstoneWindow();
if(!User32.IsHearthstoneInForeground())
{
//restore window and bring to foreground
User32.ShowWindow(hsHandle, User32.SwRestore);
User32.SetForegroundWindow(hsHandle);
//wait it to actually be in foreground, else the rect might be wrong
await Task.Delay(500);
}
if(!User32.IsHearthstoneInForeground())
{
MessageBox.Show("Can't find Hearthstone window.");
Logger.WriteLine("Can't find Hearthstone window.", "ArenaImport");
return;
}
await Task.Delay(1000);
Overlay.ForceHidden = true;
Overlay.UpdatePosition();
const double xScale = 0.013;
const double yScale = 0.017;
const int targetHue = 53;
const int hueMargin = 3;
const int numVisibleCards = 21;
var hsRect = User32.GetHearthstoneRect(false);
var ratio = (4.0 / 3.0) / ((double)hsRect.Width / hsRect.Height);
var posX = (int)DeckExporter.GetXPos(0.92, hsRect.Width, ratio);
var startY = 71.0/768.0 * hsRect.Height;
var strideY = 29.0/768.0 * hsRect.Height;
int width = (int)Math.Round(hsRect.Width * xScale);
int height = (int)Math.Round(hsRect.Height * yScale);

for(var i = 0; i < Math.Min(numVisibleCards, deck.Cards.Count); i++)
{
var posY = (int)(startY + strideY * i);
var capture = Helper.CaptureHearthstone(new System.Drawing.Point(posX, posY), width, height, hsHandle);
if(capture != null)
{
var yellowPixels = 0;
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
var pixel = capture.GetPixel(x, y);
if(Math.Abs(pixel.GetHue() - targetHue) < hueMargin)
yellowPixels++;
}
}
//Console.WriteLine(yellowPixels + " of " + width * height + " - " + yellowPixels / (double)(width * height));
//capture.Save("arenadeckimages/" + i + ".png");
var yellowPixelRatio = yellowPixels / (double)(width * height);
if(yellowPixelRatio > 0.25 && yellowPixelRatio < 50)
deck.Cards[i].Count = 2;
}
}

if(deck.Cards.Count > numVisibleCards)
{
const int scrollClicksPerCard = 4;
const int scrollDistance = 120;
var clientPoint = new System.Drawing.Point(posX, (int)startY);
var previousPos = System.Windows.Forms.Cursor.Position;
User32.ClientToScreen(hsHandle, ref clientPoint);
System.Windows.Forms.Cursor.Position = new System.Drawing.Point(clientPoint.X, clientPoint.Y);
for(int j = 0; j < scrollClicksPerCard * (deck.Cards.Count - numVisibleCards); j++)
{
User32.mouse_event((uint)User32.MouseEventFlags.Wheel, 0, 0, -scrollDistance, UIntPtr.Zero);
await Task.Delay(30);
}
System.Windows.Forms.Cursor.Position = previousPos;
await Task.Delay(100);

var remainingCards = deck.Cards.Count - numVisibleCards;
startY = 76.0 / 768.0 * hsRect.Height + (numVisibleCards - remainingCards) * strideY;
for(int i = 0; i < remainingCards ; i++)
{
var posY = (int)(startY + strideY * i);
var capture = Helper.CaptureHearthstone(new System.Drawing.Point(posX, posY), width, height, hsHandle);
if(capture != null)
{
var yellowPixels = 0;
for(int x = 0; x < width; x++)
{
for(int y = 0; y < height; y++)
{
var pixel = capture.GetPixel(x, y);
if(Math.Abs(pixel.GetHue() - targetHue) < hueMargin)
yellowPixels++;
}
}
//Console.WriteLine(yellowPixels + " of " + width * height + " - " + yellowPixels / (double)(width * height));
//capture.Save("arenadeckimages/" + i + 21 + ".png");
var yellowPixelRatio = yellowPixels / (double)(width * height);
if(yellowPixelRatio > 0.25 && yellowPixelRatio < 50)
deck.Cards[numVisibleCards + i].Count = 2;
}
}

System.Windows.Forms.Cursor.Position = new System.Drawing.Point(clientPoint.X, clientPoint.Y);
for(int j = 0; j < scrollClicksPerCard * (deck.Cards.Count - 21); j++)
{
User32.mouse_event((uint)User32.MouseEventFlags.Wheel, 0, 0, scrollDistance, UIntPtr.Zero);
await Task.Delay(30);
}
System.Windows.Forms.Cursor.Position = previousPos;
}

Overlay.ForceHidden = false;
Overlay.UpdatePosition();

ActivateWindow();
}

private async void BtnConstructed_Click(object sender, RoutedEventArgs e)
{
if(Config.Instance.ShowConstructedImportMessage || Game.PossibleConstructedCards.Count < 10)
Expand Down
5 changes: 3 additions & 2 deletions Hearthstone Deck Tracker/Utility/User32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public enum MouseEventFlags : uint
LeftDown = 0x00000002,
LeftUp = 0x00000004,
RightDown = 0x00000008,
RightUp = 0x00000010
RightUp = 0x00000010,
Wheel = 0x00000800
}

private const int WsExTransparent = 0x00000020;
Expand Down Expand Up @@ -48,7 +49,7 @@ public enum MouseEventFlags : uint
public static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, UIntPtr dwExtraInfo);
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, int dwData, UIntPtr dwExtraInfo);

[DllImport("user32.dll")]
public static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
Expand Down

0 comments on commit 6a32869

Please sign in to comment.