├── .gitattributes
├── .gitignore
├── HDT.Plugins.MetaDetector.sln
├── HDT.Plugins.MetaDetector
├── Controls
│ ├── AnimatedCard.xaml
│ ├── AnimatedCard.xaml.cs
│ ├── AnimatedCardList.xaml
│ ├── AnimatedCardList.xaml.cs
│ ├── CardTemplate.xaml
│ ├── CardTemplate.xaml.cs
│ ├── OpDeckWindow.xaml
│ ├── OpDeckWindow.xaml.cs
│ ├── PluginMenu.xaml
│ ├── PluginMenu.xaml.cs
│ ├── VersionWindow.xaml
│ └── VersionWindow.xaml.cs
├── GitHub.cs
├── HDT.Plugins.MetaDetector.csproj
├── MetaDetector.cs
├── MetaDetectorPlugin.cs
├── MetaLog.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── Resources
│ └── metaDecks.xml
├── favicon.ico
└── packages.config
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | [Xx]64/
19 | [Xx]86/
20 | [Bb]uild/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 |
85 | # Visual Studio profiler
86 | *.psess
87 | *.vsp
88 | *.vspx
89 | *.sap
90 |
91 | # TFS 2012 Local Workspace
92 | $tf/
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 | *.DotSettings.user
101 |
102 | # JustCode is a .NET coding add-in
103 | .JustCode
104 |
105 | # TeamCity is a build add-in
106 | _TeamCity*
107 |
108 | # DotCover is a Code Coverage Tool
109 | *.dotCover
110 |
111 | # NCrunch
112 | _NCrunch_*
113 | .*crunch*.local.xml
114 | nCrunchTemp_*
115 |
116 | # MightyMoose
117 | *.mm.*
118 | AutoTest.Net/
119 |
120 | # Web workbench (sass)
121 | .sass-cache/
122 |
123 | # Installshield output folder
124 | [Ee]xpress/
125 |
126 | # DocProject is a documentation generator add-in
127 | DocProject/buildhelp/
128 | DocProject/Help/*.HxT
129 | DocProject/Help/*.HxC
130 | DocProject/Help/*.hhc
131 | DocProject/Help/*.hhk
132 | DocProject/Help/*.hhp
133 | DocProject/Help/Html2
134 | DocProject/Help/html
135 |
136 | # Click-Once directory
137 | publish/
138 |
139 | # Publish Web Output
140 | *.[Pp]ublish.xml
141 | *.azurePubxml
142 |
143 | # TODO: Un-comment the next line if you do not want to checkin
144 | # your web deploy settings because they may include unencrypted
145 | # passwords
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # NuGet Packages
150 | *.nupkg
151 | # The packages folder can be ignored because of Package Restore
152 | **/packages/*
153 | # except build/, which is used as an MSBuild target.
154 | !**/packages/build/
155 | # Uncomment if necessary however generally it will be regenerated when needed
156 | #!**/packages/repositories.config
157 | # NuGet v3's project.json files produces more ignoreable files
158 | *.nuget.props
159 | *.nuget.targets
160 |
161 | # Microsoft Azure Build Output
162 | csx/
163 | *.build.csdef
164 |
165 | # Microsoft Azure Emulator
166 | ecf/
167 | rcf/
168 |
169 | # Microsoft Azure ApplicationInsights config file
170 | ApplicationInsights.config
171 |
172 | # Windows Store app package directory
173 | AppPackages/
174 | BundleArtifacts/
175 |
176 | # Visual Studio cache files
177 | # files ending in .cache can be ignored
178 | *.[Cc]ache
179 | # but keep track of directories ending in .cache
180 | !*.[Cc]ache/
181 |
182 | # Others
183 | ClientBin/
184 | [Ss]tyle[Cc]op.*
185 | ~$*
186 | *~
187 | *.dbmdl
188 | *.dbproj.schemaview
189 | *.pfx
190 | *.publishsettings
191 | node_modules/
192 | orleans.codegen.cs
193 |
194 | # RIA/Silverlight projects
195 | Generated_Code/
196 |
197 | # Backup & report files from converting an old project file
198 | # to a newer Visual Studio version. Backup files are not needed,
199 | # because we have git ;-)
200 | _UpgradeReport_Files/
201 | Backup*/
202 | UpgradeLog*.XML
203 | UpgradeLog*.htm
204 |
205 | # SQL Server files
206 | *.mdf
207 | *.ldf
208 |
209 | # Business Intelligence projects
210 | *.rdl.data
211 | *.bim.layout
212 | *.bim_*.settings
213 |
214 | # Microsoft Fakes
215 | FakesAssemblies/
216 |
217 | # GhostDoc plugin setting file
218 | *.GhostDoc.xml
219 |
220 | # Node.js Tools for Visual Studio
221 | .ntvs_analysis.dat
222 |
223 | # Visual Studio 6 build log
224 | *.plg
225 |
226 | # Visual Studio 6 workspace options file
227 | *.opt
228 |
229 | # Visual Studio LightSwitch build output
230 | **/*.HTMLClient/GeneratedArtifacts
231 | **/*.DesktopClient/GeneratedArtifacts
232 | **/*.DesktopClient/ModelManifest.xml
233 | **/*.Server/GeneratedArtifacts
234 | **/*.Server/ModelManifest.xml
235 | _Pvt_Extensions
236 |
237 | # LightSwitch generated files
238 | GeneratedArtifacts/
239 | ModelManifest.xml
240 |
241 | # Paket dependency manager
242 | .paket/paket.exe
243 |
244 | # FAKE - F# Make
245 | .fake/
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25123.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HDT.Plugins.MetaDetector", "HDT.Plugins.MetaDetector\HDT.Plugins.MetaDetector.csproj", "{D5E137DB-2464-47D1-9395-9153D549C1CF}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hearthstone Deck Tracker", "..\..\..\..\..\..\Hearthstone-Deck-Tracker\Hearthstone Deck Tracker\Hearthstone Deck Tracker.csproj", "{E63A3F1C-E662-4E62-BE43-AF27CB9E953D}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x86 = Debug|x86
14 | Release|Any CPU = Release|Any CPU
15 | Release|x86 = Release|x86
16 | Squirrel|Any CPU = Squirrel|Any CPU
17 | Squirrel|x86 = Squirrel|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Debug|x86.ActiveCfg = Debug|x86
23 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Debug|x86.Build.0 = Debug|x86
24 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Release|x86.ActiveCfg = Release|x86
27 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Release|x86.Build.0 = Release|x86
28 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Squirrel|Any CPU.ActiveCfg = Release|Any CPU
29 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Squirrel|Any CPU.Build.0 = Release|Any CPU
30 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Squirrel|x86.ActiveCfg = Release|x86
31 | {D5E137DB-2464-47D1-9395-9153D549C1CF}.Squirrel|x86.Build.0 = Release|x86
32 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Debug|x86.ActiveCfg = Debug|x86
35 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Release|x86.ActiveCfg = Release|x86
38 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Release|x86.Build.0 = Release|x86
39 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Squirrel|Any CPU.ActiveCfg = Squirrel|Any CPU
40 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Squirrel|Any CPU.Build.0 = Squirrel|Any CPU
41 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Squirrel|x86.ActiveCfg = Squirrel|x86
42 | {E63A3F1C-E662-4E62-BE43-AF27CB9E953D}.Squirrel|x86.Build.0 = Squirrel|x86
43 | EndGlobalSection
44 | GlobalSection(SolutionProperties) = preSolution
45 | HideSolutionNode = FALSE
46 | EndGlobalSection
47 | EndGlobal
48 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/AnimatedCard.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/AnimatedCard.xaml.cs:
--------------------------------------------------------------------------------
1 | using Hearthstone_Deck_Tracker.Hearthstone;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using System.Windows.Media.Animation;
5 |
6 | namespace HDT.Plugins.MetaDetector.Controls
7 | {
8 | ///
9 | /// Interaction logic for AnimatedCard.xaml
10 | ///
11 | public partial class AnimatedCard
12 | {
13 | public AnimatedCard(Card card)
14 | {
15 | InitializeComponent();
16 | DataContext = card;
17 | }
18 |
19 | public Card Card => (Card) DataContext;
20 |
21 | public async Task FadeIn(bool fadeIn)
22 | {
23 | //Card.Update();
24 |
25 | await RunStoryBoard("StoryboardFadeIn");
26 | }
27 |
28 | public async Task FadeOut(bool highlight)
29 | {
30 | await RunStoryBoard("StoryboardUpdate");
31 |
32 | //Card.Update();
33 |
34 | await RunStoryBoard("StoryboardFadeOut");
35 | }
36 |
37 | public async Task Update(bool highlight)
38 | {
39 | await RunStoryBoard("StoryboardUpdate");
40 | //Card.Update();
41 | }
42 |
43 | private readonly List _runningStoryBoards = new List();
44 | public async Task RunStoryBoard(string key)
45 | {
46 | if (_runningStoryBoards.Contains(key))
47 | return;
48 | _runningStoryBoards.Add(key);
49 | var sb = (Storyboard)FindResource(key);
50 | sb.Begin();
51 | await Task.Delay(sb.Duration.TimeSpan);
52 | _runningStoryBoards.Remove(key);
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/AnimatedCardList.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/AnimatedCardList.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Linq;
5 | using Hearthstone_Deck_Tracker.Utility.Extensions;
6 | using HDT.Plugins.MetaDetector.Logging;
7 | using Hearthstone_Deck_Tracker.Hearthstone;
8 |
9 | namespace HDT.Plugins.MetaDetector.Controls
10 | {
11 | ///
12 | /// Interaction logic for AnimatedCardList.xaml
13 | ///
14 | public partial class AnimatedCardList
15 | {
16 | private readonly ObservableCollection _animatedCards = new ObservableCollection();
17 |
18 | public AnimatedCardList()
19 | {
20 | InitializeComponent();
21 | }
22 |
23 | public void Update(List cards, bool reset)
24 | {
25 | try
26 | {
27 | if (reset)
28 | {
29 | _animatedCards.Clear();
30 | ItemsControl.Items.Clear();
31 | }
32 | var newCards = new List();
33 | foreach (var card in cards)
34 | {
35 | var existing = _animatedCards.FirstOrDefault(x => AreEqualForList(x.Card, card));
36 | if (existing == null)
37 | newCards.Add(card);
38 | else if (existing.Card.Count != card.Count || existing.Card.HighlightInHand != card.HighlightInHand)
39 | {
40 | var highlight = existing.Card.Count != card.Count;
41 | existing.Card.Count = card.Count;
42 | existing.Card.HighlightInHand = card.HighlightInHand;
43 | existing.Update(highlight).Forget();
44 | }
45 | else if (existing.Card.IsCreated != card.IsCreated)
46 | existing.Update(false).Forget();
47 | }
48 | var toUpdate = new List();
49 | foreach (var aCard in _animatedCards)
50 | {
51 | if (!cards.Any(x => AreEqualForList(x, aCard.Card)))
52 | toUpdate.Add(aCard);
53 | }
54 | var toRemove = new List>();
55 | foreach (var card in toUpdate)
56 | {
57 | var newCard = newCards.FirstOrDefault(x => x.Id == card.Card.Id);
58 | toRemove.Add(new Tuple(card, newCard == null));
59 | if (newCard != null)
60 | {
61 | var newAnimated = new AnimatedCard(newCard);
62 | _animatedCards.Insert(_animatedCards.IndexOf(card), newAnimated);
63 | ItemsControl.Items.Insert(_animatedCards.IndexOf(card), newAnimated);
64 | newAnimated.Update(true).Forget();
65 | newCards.Remove(newCard);
66 | }
67 | }
68 | foreach (var card in toRemove)
69 | RemoveCard(card.Item1, card.Item2);
70 | foreach (var card in newCards)
71 | {
72 | var newCard = new AnimatedCard(card);
73 | _animatedCards.Insert(cards.IndexOf(card), newCard);
74 | ItemsControl.Items.Insert(cards.IndexOf(card), newCard);
75 | newCard.FadeIn(!reset).Forget();
76 | }
77 | }
78 | catch (Exception e)
79 | {
80 | MetaLog.Error(e);
81 | }
82 | }
83 |
84 | private async void RemoveCard(AnimatedCard card, bool fadeOut)
85 | {
86 | if (fadeOut)
87 | await card.FadeOut(card.Card.Count > 0);
88 | _animatedCards.Remove(card);
89 | ItemsControl.Items.Remove(card);
90 | }
91 |
92 | private bool AreEqualForList(Card c1, Card c2)
93 | {
94 |
95 | return c1.Id == c2.Id && c1.Jousted == c2.Jousted && c1.IsCreated == c2.IsCreated
96 | && ( c1.WasDiscarded == c2.WasDiscarded);
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/CardTemplate.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/CardTemplate.xaml.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 | namespace HDT.Plugins.MetaDetector.Controls
4 | {
5 | ///
6 | /// Interaction logic for Card.xaml
7 | ///
8 | public partial class TemplateCard
9 | {
10 | public TemplateCard()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/OpDeckWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
31 | Click Here for Suggestions or Bugs
32 |
33 |
34 |
35 |
38 | ** New Version Available **
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/OpDeckWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Media;
4 | using System.Linq;
5 | using HDT.Plugins.MetaDetector.Logging;
6 | using Hearthstone_Deck_Tracker;
7 | using Hearthstone_Deck_Tracker.Hearthstone;
8 | using System.Windows.Navigation;
9 |
10 | namespace HDT.Plugins.MetaDetector.Controls
11 | {
12 | ///
13 | /// Interaction logic for OpDeckWindow.xaml
14 | ///
15 | public partial class OpDeckWindow
16 | {
17 | public bool showOverlay = false;
18 | public bool topMost = false;
19 |
20 | public OpDeckWindow()
21 | {
22 | InitializeComponent();
23 |
24 | lbDecks.DisplayMemberPath = "GetClass";
25 | }
26 |
27 | public void clearLists()
28 | {
29 | lvDeckList.ItemsSource = null;
30 | lbDecks.Items.Clear();
31 | }
32 |
33 | public void resetWindow(List metaDecks)
34 | {
35 | lvDeckList.ItemsSource = null;
36 | lbDecks.Items.Clear();
37 | /*foreach (Deck deck in metaDecks.OrderBy(d => d.Class))
38 | {
39 | deck.Name = "Meta Deck";
40 | lbDecks.Items.Add(deck);
41 | }*/
42 | tbInformation.Text = "Waiting For Cards...";
43 | tbInformation.Foreground = Brushes.White;
44 | tbMetaRank.Text = "";
45 | }
46 |
47 | public void updateCardList(Deck deck)
48 | {
49 | lvDeckList.ItemsSource = deck.Cards;
50 | Helper.SortCardCollection(lvDeckList.Items, false);
51 | }
52 |
53 | public void updateCardsCount(int count)
54 | {
55 | tbCardsPlayed.Text = "Cards Revealed: " + count.ToString();
56 | }
57 |
58 | public void updateVersion(Version pluginVersion)
59 | {
60 | tbVersion.Text = "v" + pluginVersion.ToString();
61 | }
62 |
63 | public void newVersionAvailable()
64 | {
65 | tbWebsite.Visibility = System.Windows.Visibility.Hidden;
66 | tbNewVersion.Visibility = System.Windows.Visibility.Visible;
67 | }
68 |
69 | public void updateDeckList(List metaDecks)
70 | {
71 | try
72 | {
73 | if (metaDecks.Count > 0)
74 | {
75 | lbDecks.Items.Clear();
76 |
77 | foreach (Deck deck in metaDecks.OrderByDescending(x => Convert.ToInt32(x.Note)).ThenBy(x => x.Class))
78 | {
79 | lbDecks.Items.Add(deck);
80 | }
81 |
82 | if (lbDecks.Items.Count > 0)
83 | {
84 | lbDecks.SelectedIndex = 0;
85 | }
86 | }
87 | }
88 | catch (Exception ex)
89 | {
90 | MetaLog.Error(ex);
91 | }
92 | }
93 |
94 | public Deck getSelectedDeck()
95 | {
96 | return (Deck)lbDecks.SelectedItem;
97 | }
98 |
99 | public void setSelectedDeck(Deck selectedDeck)
100 | {
101 | //lbDecks.SelectedItem = selectedDeck;
102 | }
103 |
104 | public void updateText(string message, Brush color)
105 | {
106 | tbInformation.Text = message;
107 | tbInformation.Foreground = color;
108 | }
109 |
110 | private void DeckWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
111 | {
112 | e.Cancel = true;
113 | this.Visibility = System.Windows.Visibility.Hidden;
114 | }
115 |
116 | private void lbDecks_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
117 | {
118 | if (lbDecks.SelectedItem != null)
119 | {
120 | lvDeckList.ItemsSource = ((Deck)lbDecks.SelectedItem).Cards;
121 | Hearthstone_Deck_Tracker.Helper.SortCardCollection(lvDeckList.Items, false);
122 |
123 | double rank = Convert.ToDouble(((Deck)lbDecks.SelectedItem).Note) / 100;
124 | tbMetaRank.Text = "Meta Rank: " + rank.ToString();
125 | }
126 | }
127 |
128 | private void lbDecks_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
129 | {
130 |
131 | }
132 |
133 | private void btnSaveDeck_Click(object sender, System.Windows.RoutedEventArgs e)
134 | {
135 | if (lbDecks.SelectedIndex >= 0)
136 | {
137 | Deck temp = (Deck)lbDecks.SelectedItem;
138 |
139 | temp.Name = "Meta Deck - " + temp.Class;
140 |
141 | Hearthstone_Deck_Tracker.API.Core.MainWindow.SetNewDeck(temp);
142 | Hearthstone_Deck_Tracker.API.Core.MainWindow.ActivateWindow();
143 | }
144 | }
145 |
146 | private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
147 | {
148 | try
149 | {
150 | System.Diagnostics.Process.Start(e.Uri.ToString());
151 | }
152 | catch (Exception ex)
153 | {
154 | MetaLog.Error(ex);
155 | }
156 | }
157 |
158 | private void cbAlwaysOnTop_Checked(object sender, System.Windows.RoutedEventArgs e)
159 | {
160 | if (cbAlwaysOnTop.IsChecked.Value == true)
161 | {
162 | this.Topmost = true;
163 | }
164 | }
165 |
166 | private void cbAlwaysOnTop_Unchecked(object sender, System.Windows.RoutedEventArgs e)
167 | {
168 | if (cbAlwaysOnTop.IsChecked.Value == false)
169 | {
170 | this.Topmost = false;
171 | }
172 | }
173 |
174 | private void cbOverlay_Checked(object sender, System.Windows.RoutedEventArgs e)
175 | {
176 | showOverlay = true;
177 | }
178 |
179 | private void cbOverlay_Unchecked(object sender, System.Windows.RoutedEventArgs e)
180 | {
181 | showOverlay = false;
182 | }
183 |
184 | public void setOverlay(bool overlay)
185 | {
186 | this.showOverlay = overlay;
187 | cbOverlay.IsChecked = overlay;
188 | }
189 |
190 | public void setTopMost(bool topmost)
191 | {
192 | this.Topmost = topmost;
193 | cbAlwaysOnTop.IsChecked = topmost;
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/PluginMenu.xaml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/PluginMenu.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace HDT.Plugins.MetaDetector.Controls
4 | {
5 | ///
6 | /// Interaction logic for PluginMenu.xaml
7 | ///
8 | public partial class PluginMenu
9 | {
10 | private OpDeckWindow _mainWindow;
11 | public PluginMenu(OpDeckWindow mainWindow)
12 | {
13 | InitializeComponent();
14 |
15 | _mainWindow = mainWindow;
16 | }
17 |
18 | private void MenuItem_Click(object sender, RoutedEventArgs e)
19 | {
20 | if (_mainWindow.Visibility == System.Windows.Visibility.Hidden || _mainWindow.Visibility == System.Windows.Visibility.Collapsed)
21 | _mainWindow.Show();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/VersionWindow.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | MetaStats Plugin is currently active. Please disable MetaStats plugin and restart HDT to avoid data conflict.
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Controls/VersionWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 | using HDT.Plugins.MetaDetector.Logging;
16 |
17 | namespace HDT.Plugins.MetaDetector.Controls
18 | {
19 | ///
20 | /// Interaction logic for VersionWindow.xaml
21 | ///
22 | public partial class VersionWindow : Window
23 | {
24 | public VersionWindow()
25 | {
26 | InitializeComponent();
27 | }
28 |
29 | private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
30 | {
31 | try
32 | {
33 | System.Diagnostics.Process.Start(e.Uri.ToString());
34 | }
35 | catch (Exception ex)
36 | {
37 | MetaLog.Error(ex);
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/GitHub.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using HDT.Plugins.MetaDetector.Logging;
6 | using System.Net;
7 | using System.IO;
8 | using System.Runtime.Serialization.Json;
9 | using System.Text;
10 |
11 | namespace HDT.Plugins.MetaDetector
12 | {
13 | public class GitHub
14 | {
15 | // Check if there is a newer release on Github than current
16 | public static async Task CheckForUpdate(string user, string repo, Version version)
17 | {
18 | try
19 | {
20 | var latest = await GetLatestRelease(user, repo);
21 |
22 | // tag needs to be in strict version format: e.g. 0.0.0
23 | latest.tag_name = latest.tag_name.Replace("v", "");
24 |
25 | Version v = new Version(latest.tag_name);
26 |
27 | // check if latest is newer than current
28 | if (v.CompareTo(version) > 0)
29 | {
30 | return latest;
31 | }
32 | }
33 | catch (Exception ex)
34 | {
35 | MetaLog.Error(ex);
36 | }
37 | return null;
38 | }
39 |
40 | // Use the Github API to get the latest release for a repo
41 | public static async Task GetLatestRelease(string user, string repo)
42 | {
43 | var url = String.Format("https://api.github.com/repos/{0}/{1}/releases", user, repo);
44 | try
45 | {
46 | var json = "";
47 | using (WebClient wc = new WebClient())
48 | {
49 | // API requires user-agent string, user name or app name preferred
50 | wc.Headers.Add(HttpRequestHeader.UserAgent, user);
51 | json = await wc.DownloadStringTaskAsync(url);
52 | }
53 |
54 | byte[] byteArray = Encoding.UTF8.GetBytes(json);
55 | MemoryStream stream = new MemoryStream(byteArray);
56 |
57 | DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List));
58 | var releases = (List)serializer.ReadObject(stream);
59 | return releases.FirstOrDefault();
60 | }
61 | catch (Exception ex)
62 | {
63 | throw ex;
64 | }
65 | }
66 |
67 | // Basic release info for JSON deserialization
68 | public class GithubRelease
69 | {
70 | public string html_url { get; set; }
71 | public string tag_name { get; set; }
72 | public string prerelease { get; set; }
73 | public string published_at { get; set; }
74 | }
75 |
76 | }
77 | }
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/HDT.Plugins.MetaDetector.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D5E137DB-2464-47D1-9395-9153D549C1CF}
8 | Library
9 | Properties
10 | HDT.Plugins.MetaDetector
11 | MetaDetector
12 | v4.5.2
13 | 512
14 | publish\
15 | true
16 | Disk
17 | false
18 | Foreground
19 | 7
20 | Days
21 | false
22 | false
23 | true
24 | 0
25 | 1.0.0.%2a
26 | false
27 | false
28 | true
29 |
30 |
31 | true
32 | full
33 | false
34 | ..\..\..\..\..\Dropbox\HearthStoneDeckTracker\Plugins\MetaDetector\
35 | DEBUG;TRACE
36 | prompt
37 | 4
38 |
39 |
40 | pdbonly
41 | true
42 | bin\Release\
43 | TRACE
44 | prompt
45 | 4
46 |
47 |
48 | favicon.ico
49 |
50 |
51 | true
52 | ..\..\..\..\..\Dropbox\HearthStoneDeckTracker\Plugins\MetaDetector\
53 | DEBUG;TRACE
54 | full
55 | x86
56 | prompt
57 | MinimumRecommendedRules.ruleset
58 |
59 |
60 | bin\x86\Release\
61 | TRACE
62 | true
63 | pdbonly
64 | x86
65 | prompt
66 | MinimumRecommendedRules.ruleset
67 |
68 |
69 |
70 | ..\..\..\..\..\..\..\Hearthstone-Deck-Tracker\Hearthstone Deck Tracker\bin\x86\Debug\HearthDb.dll
71 | False
72 |
73 |
74 | ..\..\..\..\..\..\..\Hearthstone-Deck-Tracker\Hearthstone Deck Tracker\bin\x86\Debug\HearthMirror.dll
75 | False
76 |
77 |
78 | ..\..\..\..\..\..\..\Hearthstone-Deck-Tracker\Hearthstone Deck Tracker\bin\x86\Debug\HearthstoneDeckTracker.exe
79 | False
80 |
81 |
82 | ..\packages\MahApps.Metro.1.2.4.0\lib\net45\MahApps.Metro.dll
83 | False
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | ..\packages\MahApps.Metro.1.2.4.0\lib\net45\System.Windows.Interactivity.dll
100 | False
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | AnimatedCard.xaml
115 |
116 |
117 | AnimatedCardList.xaml
118 |
119 |
120 | CardTemplate.xaml
121 |
122 |
123 | OpDeckWindow.xaml
124 |
125 |
126 | PluginMenu.xaml
127 |
128 |
129 | VersionWindow.xaml
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | True
138 | True
139 | Resources.resx
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 | Designer
148 | MSBuild:Compile
149 |
150 |
151 | Designer
152 | MSBuild:Compile
153 |
154 |
155 | Designer
156 | MSBuild:Compile
157 |
158 |
159 | Designer
160 | MSBuild:Compile
161 |
162 |
163 | Designer
164 | MSBuild:Compile
165 |
166 |
167 | Designer
168 | MSBuild:Compile
169 |
170 |
171 |
172 |
173 | ResXFileCodeGenerator
174 | Resources.Designer.cs
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | False
183 | Microsoft .NET Framework 4.5.2 %28x86 and x64%29
184 | true
185 |
186 |
187 | False
188 | .NET Framework 3.5 SP1
189 | false
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
206 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/MetaDetector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.IO.Compression;
4 | using System.Collections.Generic;
5 | using System.Windows.Media;
6 | using System.Linq;
7 | using System.Net;
8 | using System.Xml.Serialization;
9 | using System.Threading.Tasks;
10 | using System.ComponentModel;
11 | using Hearthstone_Deck_Tracker;
12 | using HearthDb.Enums;
13 | using Hearthstone_Deck_Tracker.Enums;
14 | using HDT.Plugins.MetaDetector.Logging;
15 | using Hearthstone_Deck_Tracker.Hearthstone;
16 | using HDT.Plugins.MetaDetector.Controls;
17 | using System.Text;
18 | using Hearthstone_Deck_Tracker.Hearthstone.Entities;
19 |
20 | namespace HDT.Plugins.MetaDetector
21 | {
22 |
23 | public class MetaDetector
24 | {
25 | private OpDeckWindow _mainWindow;
26 | private Deck _lastGuessDeck;
27 |
28 | private bool _validGameMode = true;
29 |
30 | private List _metaDecks;
31 | private List _matchedDecks;
32 | private List _opponentCardsPlayed;
33 | private MyConfig _appConfig;
34 | private trackCards _cardsPlayedOpponent;
35 | private trackCards _cardsPlayedPlayer;
36 | private static string _deckDirectory = Path.Combine(Config.AppDataPath, @"MetaDetector");
37 | private static string _deckFilename = Path.Combine(_deckDirectory, @"metaDecks.xml");
38 | private bool _downloadingMetaFile = false;
39 | //private int _opponentCardCheck = 2;
40 | private int _opponentCardCount = 0;
41 | private int _opponentTurnCount = 0;
42 | private int _playerTurnCount = 0;
43 | private int _bestMetaRank = 0;
44 | private int _metaRank = 0;
45 | private Card _lastCardPlayed = null;
46 | //private Card _lastOpponentCard = null;
47 | internal bool _statsUpdated = false;
48 | private bool _closestMatchedDecks = false;
49 | Dictionary _trackOpponentCards = new Dictionary();
50 | Dictionary _trackPlayerCards = new Dictionary();
51 |
52 | private List gameOpCardList = new List();
53 |
54 | public MetaDetector(OpDeckWindow mainWindow)
55 | {
56 | //_mainWindow = new OpDeckWindow();
57 | MetaLog.Initialize();
58 |
59 | _mainWindow = mainWindow;
60 | _lastGuessDeck = new Deck();
61 |
62 | _metaDecks = new List();
63 | _matchedDecks = new List();
64 | _statsUpdated = false;
65 |
66 | _opponentCardsPlayed = new List();
67 |
68 | _cardsPlayedOpponent = new trackCards();
69 | _cardsPlayedPlayer = new trackCards();
70 |
71 | _appConfig = MyConfig.Load();
72 | _appConfig.Save();
73 |
74 | _mainWindow.setOverlay(_appConfig.showOverlay);
75 | _mainWindow.setTopMost(_appConfig.topMost);
76 |
77 |
78 |
79 | MetaLog.Info("Meta Detector Initialized", "MetaDetector");
80 | }
81 |
82 | private void checkGameMode()
83 | {
84 | //if (Core.Game.CurrentGameMode == GameMode.All)
85 | _validGameMode = true;
86 | //else
87 | //_validGameMode = false;
88 | }
89 |
90 | internal void GameStart()
91 | {
92 | try
93 | {
94 | //MetaLog.Info("Opponent Class: " + Core.Game.MatchInfo.OpposingPlayer.Name, "GameStart");
95 | MetaLog.Info("Game Mode: " + Core.Game.CurrentGameMode, "GameStart");
96 | MetaLog.Info("Game Format: " + Core.Game.CurrentFormat, "GameStart");
97 | MetaLog.Info("Region: " + Core.Game.CurrentRegion, "GameStart");
98 | MetaLog.Info("Mode: " + Core.Game.CurrentMode, "GameStart");
99 |
100 | checkClassDecks();
101 | //if (_metaDecks.Count == 0)
102 | // LoadMetaDecks();
103 |
104 | //_matchedDecks = new List(_metaDecks);
105 |
106 |
107 | _cardsPlayedOpponent.Clear();
108 | _cardsPlayedPlayer.Clear();
109 | _trackOpponentCards.Clear();
110 | _trackPlayerCards.Clear();
111 | checkGameMode();
112 |
113 | if (_validGameMode)
114 | {
115 | //_opponentCardCheck = 2;
116 | _opponentCardCount = 0;
117 | _opponentTurnCount = 0;
118 | _playerTurnCount = 0;
119 | _bestMetaRank = 0;
120 | _metaRank = 0;
121 | _closestMatchedDecks = false;
122 | _statsUpdated = false;
123 |
124 | //if (_mainWindow.Visibility == System.Windows.Visibility.Hidden || _mainWindow.Visibility == System.Windows.Visibility.Collapsed)
125 | // _mainWindow.Show();
126 |
127 | _mainWindow.updateCardsCount(_opponentCardCount);
128 | _mainWindow.resetWindow(_metaDecks);
129 |
130 | MetaLog.Info("New Game Started. Waiting for opponent to play cards.", "GameStart");
131 | }
132 |
133 |
134 | if (Core.Game.Player.HasCoin && _opponentTurnCount == 0)
135 | _opponentTurnCount++;
136 |
137 | if (Core.Game.Opponent.HasCoin && _playerTurnCount == 0)
138 | _playerTurnCount++;
139 | }
140 | catch (Exception ex)
141 | {
142 | MetaLog.Error(ex);
143 | }
144 | }
145 |
146 | internal void PlayerMulligan(Card c)
147 | {
148 | _trackPlayerCards.FirstOrDefault(x => x.Value.cardId == c.Id).Value.mulligan = true;
149 | //_trackPlayerCards.FirstOrDefault(x => x.Value.cardId == c.Id).Value.cardId = "";
150 |
151 | MetaLog.Info("Player Mulliganed " + c.Name, "PlayerMulligan");
152 | }
153 |
154 | internal void OpponentMulligan()
155 | {
156 | //_metaDecks = new List(_metaDecks.Where(x => x.Class == Core.Game.Opponent.Class).ToList());
157 | //_metaDecks.TrimExcess();
158 | //_matchedDecks.Clear();
159 | //_matchedDecks = _metaDecks;
160 | }
161 |
162 | internal void TurnStart(ActivePlayer activePlayer)
163 | {
164 | if (ActivePlayer.Player == activePlayer)
165 | {
166 | _playerTurnCount++;
167 | updateOpponentCardsPlayed();
168 | }
169 | else
170 | {
171 | _opponentTurnCount++;
172 | }
173 |
174 | /*if (Core.Game.Player.HasCoin)
175 | _opponentTurnCount++;
176 | else
177 | _playerTurnCount++;*/
178 |
179 | try
180 | {
181 | checkGameMode();
182 |
183 | if (_validGameMode)
184 | {
185 | if (ActivePlayer.Player == activePlayer)
186 | {
187 | updateDecks();
188 | }
189 | }
190 | }
191 | catch (Exception ex)
192 | {
193 | MetaLog.Error(ex);
194 | }
195 | }
196 |
197 | public void PlayerDraw(Card c)
198 | {
199 | try
200 | {
201 | updatePlayerHandCards();
202 | }
203 | catch (Exception ex)
204 | {
205 | MetaLog.Error(ex);
206 | }
207 | }
208 |
209 | private void updatePlayerHandCards()
210 | {
211 | foreach (var e in Core.Game.Entities.Where(x => x.Value.CardId != null && x.Value.CardId != "" &&
212 | !x.Value.IsHero && !x.Value.IsHeroPower && x.Value.IsInHand &&
213 | x.Value.GetTag(GameTag.CONTROLLER) == Core.Game.Player.Id).ToList())
214 | {
215 | if (_trackPlayerCards.Where(x => x.Key == e.Value.Id).Count() > 0)
216 | {
217 | if (_trackPlayerCards[e.Value.Id].turnInHand == 0 && e.Value.Info.Turn > 0)
218 | _trackPlayerCards[e.Value.Id].turnInHand = e.Value.Info.Turn;
219 | }
220 | else
221 | {
222 | MetaLog.Info("Turn " + _playerTurnCount + ": Player Draws " + e.Value.LocalizedName);
223 |
224 | if (e.Value.GetTag(GameTag.CREATOR) > 0)
225 | {
226 | _trackPlayerCards.Add(e.Value.Id, new CardInfo(e.Value.Info.Turn, e.Value.Info.Mulliganed, e.Value.CardId, -1, -1, -1, -1,
227 | e.Value.Info.Created, Core.Game.Entities[e.Value.GetTag(GameTag.CREATOR)].CardId));
228 | }
229 | else
230 | {
231 | _trackPlayerCards.Add(e.Value.Id, new CardInfo(e.Value.Info.Turn, e.Value.Info.Mulliganed, e.Value.CardId, -1, -1, -1, -1,
232 | e.Value.Info.Created, ""));
233 | }
234 | }
235 | }
236 | }
237 |
238 | public void OpponentSecretTriggered(Card c)
239 | {
240 | try
241 | {
242 | foreach (Entity e in Core.Game.Entities.Where(x => x.Value.CardId != null && !x.Value.IsHeroPower
243 | && !x.Value.IsHero && x.Value.GetTag(GameTag.CONTROLLER) == Core.Game.Opponent.Id
244 | && x.Value.IsSecret).Select(x => x.Value))
245 | {
246 | CardInfo temp;
247 | if (_trackOpponentCards.TryGetValue(e.Id, out temp))
248 | {
249 | if (_trackOpponentCards[e.Id].cardId == "")
250 | {
251 | _trackOpponentCards[e.Id].cardId = e.CardId;
252 | _trackOpponentCards[e.Id].turnCardPlayed = e.Info.Turn;
253 | _trackOpponentCards[e.Id].mana = Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES);
254 | _trackOpponentCards[e.Id].manaoverload = Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED);
255 |
256 | if (e.GetTag(GameTag.CREATOR) > 0)
257 | {
258 | _trackOpponentCards[e.Id].created = e.Info.Created;
259 | _trackOpponentCards[e.Id].createdBy = Core.Game.Entities[e.GetTag(GameTag.CREATOR)].CardId;
260 | }
261 | }
262 | }
263 | else
264 | {
265 | if (e.GetTag(GameTag.CREATOR) > 0)
266 | {
267 | _trackOpponentCards.Add(e.Id, new CardInfo(-1, false, e.CardId, e.Info.Turn,
268 | Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES), Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED), -1,
269 | e.Info.Created, Core.Game.Entities[e.GetTag(GameTag.CREATOR)].CardId));
270 | }
271 | else
272 | {
273 | _trackOpponentCards.Add(e.Id, new CardInfo(-1, false, e.CardId, e.Info.Turn,
274 | Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES), Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED), -1,
275 | e.Info.Created, ""));
276 | }
277 | }
278 | }
279 | }
280 | catch (Exception ex)
281 | {
282 | MetaLog.Error(ex);
283 | }
284 | }
285 |
286 | public void OpponentDraw()
287 | {
288 | try
289 | {
290 | foreach (Entity e in Core.Game.Entities.Select(x => x.Value).Where(x => !x.IsHero
291 | && !x.IsHeroPower && x.GetTag(GameTag.CONTROLLER) == Core.Game.Opponent.Id))
292 | {
293 | if (e.CardId == null || e.CardId == "")
294 | {
295 | if (_trackOpponentCards.Where(x => x.Key == e.Id).Count() > 0)
296 | {
297 | _trackOpponentCards[e.Id].turnInHand = e.Info.Turn;
298 | _trackOpponentCards[e.Id].mulligan = e.Info.Mulliganed;
299 | _trackOpponentCards[e.Id].created = e.Info.Created;
300 |
301 | if (e.GetTag(GameTag.CREATOR) > 0)
302 | _trackOpponentCards[e.Id].createdBy = Core.Game.Entities[e.GetTag(GameTag.CREATOR)].CardId;
303 | }
304 | else
305 | {
306 | if (e.GetTag(GameTag.CREATOR) > 0)
307 | {
308 | _trackOpponentCards.Add(e.Id, new CardInfo(e.Info.Turn, e.Info.Mulliganed, "", -1, -1, -1, -1,
309 | e.Info.Created, Core.Game.Entities[e.GetTag(GameTag.CREATOR)].CardId));
310 | }
311 | else
312 | {
313 | _trackOpponentCards.Add(e.Id, new CardInfo(e.Info.Turn, e.Info.Mulliganed, "", -1, -1, -1, -1,
314 | e.Info.Created, ""));
315 | }
316 | }
317 | }
318 | }
319 | }
320 | catch (Exception ex)
321 | {
322 | MetaLog.Error(ex);
323 | }
324 | }
325 |
326 | public void PlayerPlay(Card cardPlayed)
327 | {
328 | try
329 | {
330 | _lastCardPlayed = cardPlayed;
331 |
332 | updatePlayerHandCards();
333 | updatePlayerBoardEntities();
334 |
335 | MetaLog.Info("Turn " + _playerTurnCount + ": Player Played - " + cardPlayed.Name, "PlayerPlay");
336 | }
337 | catch (Exception ex)
338 | {
339 | MetaLog.Error(ex);
340 | }
341 | }
342 |
343 | private void updatePlayerBoardEntities()
344 | {
345 | foreach (Entity e in Core.Game.Player.Board.Where(x => !x.IsHero && !x.IsHeroPower))
346 | {
347 | CardInfo temp;
348 | if (_trackPlayerCards.TryGetValue(e.Id, out temp))
349 | {
350 | _trackPlayerCards[e.Id].turnCardPlayed = e.Info.Turn;
351 |
352 | if (e.GetTag(GameTag.CREATOR) > 0)
353 | {
354 | _trackPlayerCards[e.Id].created = e.Info.Created;
355 | _trackPlayerCards[e.Id].createdBy = Core.Game.Entities[e.GetTag(GameTag.CREATOR)].CardId;
356 | }
357 | }
358 | else
359 | {
360 | if (e.GetTag(GameTag.CREATOR) > 0)
361 | {
362 | _trackPlayerCards.Add(e.Id, new CardInfo(-1, false, e.CardId, e.Info.Turn, -1, -1, -1,
363 | e.Info.Created, Core.Game.Entities[e.GetTag(GameTag.CREATOR)].CardId));
364 | }
365 | else
366 | {
367 | _trackPlayerCards.Add(e.Id, new CardInfo(-1, false, e.CardId, e.Info.Turn, -1, -1, -1,
368 | e.Info.Created, ""));
369 | }
370 | }
371 | }
372 | }
373 |
374 | public void OpponentCreateInPlay(Card cardCreated)
375 | {
376 | updateOpponentCardsPlayed();
377 | /*if (cardCreated.Type == "Minion")
378 | {
379 | int turn = Core.Game.OpponentEntity.GetTag(GameTag.TURN);
380 | _cardsPlayedOpponent.Add(cardCreated.Id, turn, true, -1, false, -1, cardCreated.Name, Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES), Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED), "Opponent", _lastCardPlayed.Id);
381 | MetaLog.Info(cardCreated.Name + " was created by " + _lastCardPlayed.Name, "OpponentCreateInPlay");
382 | }*/
383 | }
384 |
385 | public void OpponentCreateInDeck(Card cardCreated)
386 | {
387 | /*
388 | int turn = Core.Game.OpponentEntity.GetTag(GameTag.TURN);
389 | _cardsPlayedOpponent.Add(cardCreated.Id, turn, true, -1, false, -1, cardCreated.Name, Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES), Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED), "Opponent", _lastCardPlayed.Id);
390 | MetaLog.Info(cardCreated.Name + " was created by " + _lastCardPlayed.Name, "OpponentCreateInDeck");
391 | */
392 | }
393 |
394 | public void PlayerCreateInPlay(Card cardCreated)
395 | {
396 | updatePlayerBoardEntities();
397 | /*if (cardCreated.Type == "Minion")
398 | {
399 | int turn = Core.Game.PlayerEntity.GetTag(GameTag.TURN);
400 | _cardsPlayedOpponent.Add(cardCreated.Id, turn, true, -1, false, -1, cardCreated.Name, Core.Game.PlayerEntity.GetTag(GameTag.RESOURCES), Core.Game.PlayerEntity.GetTag(GameTag.OVERLOAD_OWED), "Player", _lastCardPlayed.Id);
401 |
402 | MetaLog.Info(cardCreated.Name + " was created by " + _lastCardPlayed.Name, "PlayerCreateInPlay");
403 | }*/
404 |
405 |
406 | }
407 |
408 | public void PlayerCreateInDeck(Card cardCreated)
409 | {
410 | /*
411 | int turn = Core.Game.PlayerEntity.GetTag(GameTag.TURN);
412 | _cardsPlayedOpponent.Add(cardCreated.Id, turn, true, -1, false, -1, cardCreated.Name, Core.Game.PlayerEntity.GetTag(GameTag.RESOURCES), Core.Game.PlayerEntity.GetTag(GameTag.OVERLOAD_OWED), "Player", _lastCardPlayed.Id);
413 |
414 | MetaLog.Info(cardCreated.Name + " was created by " + _lastCardPlayed.Name, "PlayerCreateInDeck");
415 | */
416 |
417 | }
418 |
419 | public void OpponentPlay(Card cardPlayed)
420 | {
421 | try
422 | {
423 | if (_metaDecks.Count == 0)
424 | {
425 | loadClassDecks(Core.Game.Opponent.Class);
426 | }
427 |
428 | _lastCardPlayed = cardPlayed;
429 |
430 | if (_validGameMode)
431 | {
432 | //_opponentCardsPlayed.Add(cardPlayed);
433 |
434 | if (cardPlayed.Id != "GAME_005") //ignore the coin
435 | {
436 | _opponentCardCount++;
437 | updateDecks();
438 | }
439 | }
440 |
441 | updateOpponentCardsPlayed();
442 | MetaLog.Info("Turn " + _opponentTurnCount + ": Opponent Played - " + cardPlayed.Name, "OpponentPlay");
443 | }
444 | catch (Exception ex)
445 | {
446 | MetaLog.Error(ex);
447 | }
448 | }
449 |
450 | private void updateOpponentCardsPlayed()
451 | {
452 | try
453 | {
454 | foreach (Entity e in Core.Game.Entities.Select(v => v.Value).Where(x => x.CardId != null && !x.IsHeroPower
455 | && !x.IsHero && x.GetTag(GameTag.CONTROLLER) == Core.Game.Opponent.Id && x.IsInPlay)
456 | )
457 | /* foreach (Entity e in Core.Game.Entities.Where(x => x.Value.CardId != null && !x.Value.IsHeroPower
458 | && !x.Value.IsHero && x.Value.GetTag(GameTag.CONTROLLER) == Core.Game.Opponent.Id
459 | && x.Value.IsInPlay).Select(x => x.Value))*/
460 | {
461 | CardInfo temp;
462 | if (_trackOpponentCards.TryGetValue(e.Id, out temp))
463 | {
464 | if (_trackOpponentCards[e.Id].cardId == "")
465 | {
466 | _trackOpponentCards[e.Id].cardId = e.CardId;
467 | _trackOpponentCards[e.Id].turnCardPlayed = e.Info.Turn;
468 | _trackOpponentCards[e.Id].mana = Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES);
469 | _trackOpponentCards[e.Id].manaoverload = Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED);
470 |
471 | if (e.GetTag(GameTag.CREATOR) > 0)
472 | {
473 | _trackOpponentCards[e.Id].created = e.Info.Created;
474 | _trackOpponentCards[e.Id].createdBy = Core.Game.Entities[e.GetTag(GameTag.CREATOR)].CardId;
475 | }
476 | }
477 | }
478 | else
479 | {
480 | if (e.GetTag(GameTag.CREATOR) > 0)
481 | {
482 | _trackOpponentCards.Add(e.Id, new CardInfo(-1, false, e.CardId, e.Info.Turn,
483 | Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES), Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED), -1,
484 | e.Info.Created, Core.Game.Entities[e.GetTag(GameTag.CREATOR)].CardId));
485 | }
486 | else
487 | {
488 | _trackOpponentCards.Add(e.Id, new CardInfo(-1, false, e.CardId, e.Info.Turn,
489 | Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES), Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED), -1,
490 | e.Info.Created, ""));
491 | }
492 | }
493 | }
494 | }
495 | catch (Exception ex)
496 | {
497 | //MetaLog.Error(ex);
498 | }
499 |
500 | }
501 |
502 | public void OpponentHeroPower()
503 | {
504 | _cardsPlayedOpponent.Add("HERO_POWER", Convert.ToInt16(Math.Ceiling(Core.Game.GameEntity.GetTag(GameTag.TURN) / 2.0)), false, -1, false, -1,
505 | Core.Game.MatchInfo.OpposingPlayer.StandardRank, Core.Game.MatchInfo.OpposingPlayer.StandardLegendRank, Core.Game.MatchInfo.LocalPlayer.StandardRank,
506 | Core.Game.MatchInfo.LocalPlayer.StandardLegendRank, Core.Game.MatchInfo.RankedSeasonId,
507 | "Hero Power", Core.Game.OpponentEntity.GetTag(GameTag.RESOURCES), Core.Game.OpponentEntity.GetTag(GameTag.OVERLOAD_OWED), "Opponent");
508 | MetaLog.Info("Turn " + _opponentTurnCount + ": Opponent Hero Power", "OpponentHeroPower");
509 | }
510 |
511 | public void PlayerHeroPower()
512 | {
513 | if (Core.Game.Opponent.HasCoin && _playerTurnCount == 0)
514 | _playerTurnCount++;
515 |
516 | _cardsPlayedOpponent.Add("HERO_POWER", Convert.ToInt16(Math.Ceiling(Core.Game.GameEntity.GetTag(GameTag.TURN) / 2.0)), false, -1, false, -1,
517 | Core.Game.MatchInfo.OpposingPlayer.StandardRank, Core.Game.MatchInfo.OpposingPlayer.StandardLegendRank, Core.Game.MatchInfo.LocalPlayer.StandardRank,
518 | Core.Game.MatchInfo.LocalPlayer.StandardLegendRank, Core.Game.MatchInfo.RankedSeasonId,
519 | "Hero Power", Core.Game.PlayerEntity.GetTag(GameTag.RESOURCES), Core.Game.PlayerEntity.GetTag(GameTag.OVERLOAD_OWED), "Player");
520 | MetaLog.Info("Turn " + _playerTurnCount + ": Player Hero Power", "PlayerHeroPower");
521 | }
522 |
523 | public void OpponentPlayToGraveyard(Card c)
524 | {
525 | MetaLog.Info("Turn " + _opponentTurnCount + ": Minion Dead - " + c.Name, "OpponentPlayToGraveyard");
526 | }
527 |
528 | public async void GameEnd()
529 | {
530 | //string matchedDeck = "";
531 |
532 | try
533 | {
534 | /*if (_metaDecks != null)
535 | {
536 | if (_metaDecks.Count < 10)
537 | matchedDeck = _metaDecks.FirstOrDefault().DeckId.ToString();
538 | }*/
539 | }
540 | catch (Exception ex)
541 | {
542 | MetaLog.Error(ex);
543 | }
544 |
545 | if (_validGameMode)
546 | try
547 | {
548 | MetaLog.Info("Matched Decks: " + _matchedDecks.Count);
549 |
550 | if (_matchedDecks.Count <= 30)
551 | {
552 | _metaRank = _opponentCardCount;
553 | }
554 |
555 | if (_matchedDecks.Count <= 10 & !_closestMatchedDecks)
556 | {
557 | _bestMetaRank = _opponentTurnCount;
558 | }
559 |
560 | if (_matchedDecks.Count <= 5)
561 | {
562 | _bestMetaRank = _opponentTurnCount;
563 | }
564 |
565 | if (Core.Game.CurrentFormat == Format.Standard)
566 | if (_metaRank > 0 || _bestMetaRank > 0)
567 | {
568 | MetaLog.Info("Updating ranks (" + _metaRank + "+" + _bestMetaRank + ") for " + _matchedDecks.Count + " deck(s).", "GameEnd");
569 |
570 | foreach (Deck d in _matchedDecks)
571 | {
572 | _metaDecks.Find(x => x.DeckId == d.DeckId).Note = (Convert.ToInt32(_metaDecks.Find(x => x.DeckId == d.DeckId).Note) + _metaRank + _bestMetaRank).ToString();
573 | }
574 |
575 | if (Core.Game.Opponent.Class != "")
576 | SaveMetaDecks(Core.Game.Opponent.Class, _metaDecks);
577 |
578 | //await sendMetaRanks();
579 | }
580 |
581 | //_matchedDecks = new List(_metaDecks);
582 |
583 | _mainWindow.updateText("Waiting for new Game...", Brushes.White);
584 | MetaLog.Info("Game Ended. Waiting for new Game", "GameEnd");
585 | }
586 | catch (Exception ex)
587 | {
588 | MetaLog.Error(ex);
589 | }
590 |
591 | _metaDecks.Clear();
592 | _metaDecks.TrimExcess();
593 | _matchedDecks.Clear();
594 | _matchedDecks.TrimExcess();
595 |
596 | //get all cards played / died in the game
597 | try
598 | {
599 | foreach (var x in Core.Game.Opponent.Graveyard.Where(x => !x.IsHero && !x.IsHeroPower && x.CardId != ""))
600 | {
601 | CardInfo temp;
602 | if (_trackOpponentCards.TryGetValue(x.Id, out temp))
603 | {
604 | _trackOpponentCards[x.Id].turnCardDied = x.Info.Turn;
605 | }
606 | }
607 |
608 | foreach (var x in Core.Game.Player.Graveyard.Where(x => !x.IsHero && !x.IsHeroPower && x.CardId != ""))
609 | {
610 | CardInfo temp;
611 | if (_trackPlayerCards.TryGetValue(x.Id, out temp))
612 | {
613 | _trackPlayerCards[x.Id].turnCardDied = x.Info.Turn;
614 | }
615 | }
616 |
617 | //_cardsPlayed.Clear();
618 | foreach (CardInfo x in _trackOpponentCards.Values.Where(x => x.cardId != "" && x.cardId != null).OrderBy(x => x.turnCardPlayed).ToList())
619 | {
620 | _cardsPlayedOpponent.Add(x.cardId, x.turnCardPlayed, x.created, x.turnInHand, x.mulligan,
621 | x.turnCardDied,
622 | Core.Game.MatchInfo.OpposingPlayer.StandardRank, Core.Game.MatchInfo.OpposingPlayer.StandardLegendRank, Core.Game.MatchInfo.LocalPlayer.StandardRank,
623 | Core.Game.MatchInfo.LocalPlayer.StandardLegendRank, Core.Game.MatchInfo.RankedSeasonId,
624 | Database.GetCardFromId(x.cardId).Name, x.mana, x.manaoverload, "Opponent", x.createdBy);
625 | }
626 |
627 | foreach (CardInfo x in _trackPlayerCards.Values.Where(x => x.cardId != "" && x.cardId != null).OrderBy(x => x.turnCardPlayed).ToList())
628 | {
629 | _cardsPlayedOpponent.Add(x.cardId, x.turnCardPlayed, x.created, x.turnInHand, x.mulligan,
630 | x.turnCardDied,
631 | Core.Game.MatchInfo.OpposingPlayer.StandardRank, Core.Game.MatchInfo.OpposingPlayer.StandardLegendRank, Core.Game.MatchInfo.LocalPlayer.StandardRank,
632 | Core.Game.MatchInfo.LocalPlayer.StandardLegendRank, Core.Game.MatchInfo.RankedSeasonId,
633 | Database.GetCardFromId(x.cardId).Name, x.mana, x.manaoverload, "Player", x.createdBy);
634 | }
635 |
636 | if (Core.Game.CurrentGameStats.Result == GameResult.Win)
637 | _cardsPlayedOpponent.setPlayerWin();
638 | else if (Core.Game.CurrentGameStats.Result == GameResult.Loss)
639 | _cardsPlayedOpponent.setOpponentWin();
640 |
641 | _cardsPlayedOpponent.Save();
642 | await sendCardStats();
643 | }
644 | catch (Exception ex)
645 | {
646 | MetaLog.Error(ex);
647 | }
648 | }
649 |
650 | internal void updateDecks()
651 | {
652 | if (_validGameMode)
653 | try
654 | {
655 | if (_opponentCardCount > 0)
656 | {
657 | List displayDecks = matchMetaDeck();
658 |
659 | _mainWindow.updateCardsCount(Core.Game.Opponent.OpponentCardList.Where(x => !x.IsCreated).Count());
660 |
661 | if (_matchedDecks.Count == 0)
662 | {
663 | _mainWindow.updateText("No Decks Found.", Brushes.IndianRed);
664 | _statsUpdated = false;
665 | return;
666 | }
667 |
668 | if (displayDecks != null && displayDecks.Count > 0)
669 | {
670 | _mainWindow.updateDeckList(displayDecks);
671 | }
672 |
673 | if (_matchedDecks.Count > 0 && _mainWindow.showOverlay)
674 | {
675 | Core.Game.Opponent.InDeckPrecitions.Clear();
676 |
677 | foreach (Card c in _matchedDecks[0].Cards.OrderBy(x => x.Cost))
678 | {
679 | if (!Core.Game.Opponent.OpponentCardList.Contains(c))
680 | Core.Game.Opponent.InDeckPrecitions.Add(new PredictedCard(c.Id, 0));
681 | }
682 | }
683 | }
684 | }
685 | catch (Exception ex)
686 | {
687 | MetaLog.Error(ex);
688 | }
689 | }
690 |
691 | internal bool checkNewVersion()
692 | {
693 | try
694 | {
695 | string currentVersion = _appConfig.currentVersion;
696 | DateTime lastCheck = _appConfig.lastCheck;
697 |
698 | if ((DateTime.Now - lastCheck).TotalDays > 2)
699 | {
700 | MetaLog.Info("Checking for new version of Meta File", "checkNewVersion");
701 | WebClient client = new WebClient();
702 | String versionNumber = client.DownloadString("http://metastats.net/metadetector/metaversion.php");
703 |
704 | if (versionNumber.Trim() != "")
705 | {
706 | if (versionNumber != currentVersion)
707 | {
708 | DownloadMetaFile();
709 | }
710 | }
711 |
712 | _appConfig.currentVersion = versionNumber;
713 | _appConfig.lastCheck = DateTime.Now;
714 | _appConfig.Save();
715 | return true;
716 | }
717 | return false;
718 | }
719 | catch (Exception ex)
720 | {
721 | MetaLog.Error(ex);
722 | return false;
723 | }
724 | }
725 |
726 | internal void LoadMetaDecks()
727 | {
728 | try
729 | {
730 | if (File.Exists(_deckFilename))
731 | {
732 | _metaDecks = XmlManager>.Load(_deckFilename);
733 | _matchedDecks = new List(_metaDecks);
734 |
735 | if (_matchedDecks.Count == 0)
736 | DownloadMetaFile();
737 |
738 | //_mainWindow.updateDeckList(_metaDecks);
739 | //Log.Info(code.ToString());
740 | }
741 | else
742 | {
743 | if (!Directory.Exists(_deckDirectory))
744 | Directory.CreateDirectory(_deckDirectory);
745 |
746 | DownloadMetaFile();
747 | //_metaDecks.Clear();
748 | //XmlManager>.Save(_deckFilename, _metaDecks);
749 | }
750 | }
751 | catch (Exception ex)
752 | {
753 | MetaLog.Error(ex);
754 | }
755 | }
756 |
757 | private void checkClassDecks()
758 | {
759 | MetaLog.Info("Check Class Deck Files", "checkClassDecks");
760 |
761 | if (checkNewVersion())
762 | return;
763 |
764 | string[] classDecks = { "Druid", "Hunter", "Mage", "Paladin", "Priest", "Rogue", "Shaman", "Warlock", "Warrior" };
765 |
766 | if (_metaDecks.Count == 0)
767 | LoadMetaDecks();
768 |
769 | if (_metaDecks.Count > 0)
770 | {
771 |
772 | foreach (var c in classDecks)
773 | {
774 | string deckFile = Path.Combine(_deckDirectory, c + ".xml");
775 |
776 | if (!File.Exists(deckFile))
777 | {
778 | List temp = new List(_metaDecks.Where(x => x.Class == c).ToList());
779 | SaveMetaDecks(c, temp);
780 | }
781 | }
782 | }
783 | _metaDecks.Clear();
784 | _metaDecks.TrimExcess();
785 | }
786 |
787 | private void loadClassDecks(string opponentClass)
788 | {
789 | try
790 | {
791 | string deckFile = Path.Combine(_deckDirectory, opponentClass + ".xml");
792 |
793 | if (File.Exists(deckFile))
794 | {
795 | _metaDecks = XmlManager>.Load(deckFile);
796 | //_matchedDecks = new List(_metaDecks);
797 |
798 | if (_metaDecks.Count == 0)
799 | checkClassDecks();
800 |
801 | //_mainWindow.updateDeckList(_metaDecks);
802 | //Log.Info(code.ToString());
803 | }
804 | else
805 | {
806 | if (!Directory.Exists(_deckDirectory))
807 | Directory.CreateDirectory(_deckDirectory);
808 |
809 | checkClassDecks();
810 | //_metaDecks.Clear();
811 | //XmlManager>.Save(_deckFilename, _metaDecks);
812 | }
813 | }
814 | catch (Exception ex)
815 | {
816 | MetaLog.Error(ex);
817 | }
818 | }
819 |
820 | private void createClassDecks()
821 | {
822 | try
823 | {
824 | string[] classDecks = { "Druid", "Hunter", "Mage", "Paladin", "Priest", "Rogue", "Shaman", "Warlock", "Warrior" };
825 |
826 | if (_metaDecks.Count == 0)
827 | LoadMetaDecks();
828 |
829 | if (_metaDecks.Count > 0)
830 | {
831 | foreach (var c in classDecks)
832 | {
833 | List temp = new List(_metaDecks.Where(x => x.Class == c).ToList());
834 |
835 | SaveMetaDecks(c, temp);
836 | }
837 | }
838 | }
839 | catch (Exception ex)
840 | {
841 | MetaLog.Error(ex);
842 | }
843 | }
844 |
845 | internal void DecompressFile(FileInfo fileToDecompress)
846 | {
847 | try
848 | {
849 | if (!_downloadingMetaFile)
850 | {
851 | using (FileStream originalFileStream = fileToDecompress.OpenRead())
852 | {
853 | string currentFileName = fileToDecompress.FullName;
854 | string newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);
855 |
856 | using (FileStream decompressedFileStream = File.Create(newFileName))
857 | {
858 | using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
859 | {
860 | decompressionStream.CopyTo(decompressedFileStream);
861 | }
862 | }
863 | }
864 | }
865 | }
866 | catch (Exception ex)
867 | {
868 | MetaLog.Info("Unable to decompress Meta file", "DecompressFile");
869 | MetaLog.Error(ex);
870 | }
871 | }
872 |
873 | internal void DownloadMetaFile()
874 | {
875 | try
876 | {
877 | MetaLog.Info("Downloading Meta File");
878 | using (WebClient wc = new WebClient())
879 | {
880 | _downloadingMetaFile = true;
881 | wc.DownloadProgressChanged += wc_DownloadProgressChanged;
882 | wc.DownloadFileCompleted += (wc_DownloadFileCompleted);
883 | wc.DownloadFileAsync(new Uri("https://s3.amazonaws.com/metadetector/metaDecks.xml.gz"), _deckFilename + ".gz");
884 | }
885 | }
886 | catch (Exception ex)
887 | {
888 | _mainWindow.updateText("Unable to download Meta File.", Brushes.PaleVioletRed);
889 | MetaLog.Info("Error while downloing Meta File");
890 | MetaLog.Error(ex);
891 | _downloadingMetaFile = false;
892 | }
893 | }
894 |
895 |
896 | void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
897 | {
898 | _mainWindow.updateText("Downloading Meta File: " + e.ProgressPercentage + "%", Brushes.Orange);
899 | }
900 |
901 | void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
902 | {
903 | try
904 | {
905 | _downloadingMetaFile = false;
906 | MetaLog.Info("Meta File Download Complete");
907 | _mainWindow.updateText("Meta File Downloaded", Brushes.LightGreen);
908 | FileInfo fi = new FileInfo(_deckFilename + ".gz");
909 | DecompressFile(fi);
910 |
911 | if (File.Exists(_deckFilename))
912 | {
913 | //_metaDecks = XmlManager>.Load(_deckFilename);
914 | createClassDecks();
915 | }
916 | }
917 | catch (Exception ex)
918 | {
919 | _downloadingMetaFile = false;
920 | MetaLog.Error(ex);
921 | }
922 | }
923 |
924 | internal void LoadMetaDeckfromZip()
925 | {
926 | try
927 | {
928 | using (var file = File.OpenRead(_deckFilename))
929 | using (var zip = new ZipArchive(file, ZipArchiveMode.Read))
930 | {
931 | foreach (var entry in zip.Entries)
932 | {
933 | using (var stream = entry.Open())
934 | {
935 | StreamReader reader = new StreamReader(stream);
936 | string text = reader.ReadToEnd();
937 | _metaDecks = XmlManager>.LoadFromString(text);
938 | }
939 | }
940 | }
941 | }
942 | catch (Exception ex)
943 | {
944 | MetaLog.Error(ex);
945 | }
946 | }
947 |
948 | internal List matchMetaDeckbyCards()
949 | {
950 | if (_validGameMode)
951 | {
952 | try
953 | {
954 | var validDecks = _metaDecks.Where(x => x.Class == Core.Game.Opponent.Class).ToList();
955 |
956 | //var cardEntites = Core.Game.Opponent.RevealedEntities.Where(x => (x.IsMinion || x.IsSpell || x.IsWeapon) && !x.Info.Created && !x.Info.Stolen).GroupBy(x => x.CardId).ToList();
957 | var cardEntites = Core.Game.Opponent.OpponentCardList.Where(x => !x.IsCreated).ToList();
958 |
959 | var opponentCardEntities = Core.Game.Entities.Select(x => x.Value).Where(x => !x.IsHero &&
960 | !x.IsHeroPower && x.CardId != "" && !x.Info.Created &&
961 | x.GetTag(GameTag.CONTROLLER) == Core.Game.Opponent.Id).OrderBy(x => x.CardId).Select(x => x.CardId).ToList();
962 |
963 | //MetaLog.Info(opponentCardEntities.ToString());
964 |
965 | if (validDecks.Count > 0)
966 | {
967 | //validDecks = validDecks.Where(x => cardEntites.All(ce => x.GetSelectedDeckVersion().Cards.Any(c => c.Id == ce.Id && c.Count >= ce.Count))).ToList();
968 |
969 | _matchedDecks = new List(validDecks);
970 |
971 | validDecks.Clear();
972 | int lastCount = 0;
973 | foreach (Deck d in _matchedDecks.OrderBy(x => Convert.ToInt16(x.Note)))
974 | {
975 | int count = d.Cards.Intersect(Core.Game.Opponent.PlayerCardList.Where(x => !x.IsCreated)).ToList().Count();
976 | if (count > 0)
977 | {
978 | if (count >= lastCount)
979 | {
980 | validDecks.Insert(0, d);
981 | lastCount = count;
982 | }
983 | else
984 | {
985 | validDecks.Add(d);
986 | }
987 | }
988 | }
989 | _matchedDecks = new List(validDecks);
990 | }
991 | else if (validDecks.Count == 0)
992 | {
993 | _mainWindow.updateText("No Match Found. Showing Closest Decks", Brushes.YellowGreen);
994 | //MetaLog.Info("No Match Found. Showing Closest Decks");
995 | _closestMatchedDecks = true;
996 |
997 | if (_matchedDecks.Count <= 10 && _opponentTurnCount > 10)
998 | return _matchedDecks;
999 |
1000 | validDecks = _metaDecks.Where(x => x.Class == Core.Game.Opponent.Class).ToList();
1001 |
1002 | _matchedDecks = new List(validDecks);
1003 |
1004 | validDecks.Clear();
1005 | int lastCount = 0;
1006 | foreach (Deck d in _matchedDecks.OrderByDescending(x => Convert.ToInt16(x.Note)))
1007 | {
1008 | int count = d.Cards.Intersect(Core.Game.Opponent.OpponentCardList.Where(x => !x.IsCreated)).ToList().Count();
1009 | if (count > 0)
1010 | {
1011 | if (count >= lastCount)
1012 | {
1013 | validDecks.Insert(0, d);
1014 | lastCount = count;
1015 | }
1016 | else
1017 | {
1018 | validDecks.Add(d);
1019 | }
1020 | }
1021 | }
1022 | _matchedDecks = new List(validDecks);
1023 |
1024 | if (validDecks.Count > 10)
1025 | {
1026 | validDecks = validDecks.Take(10).ToList();
1027 | }
1028 |
1029 | return validDecks;
1030 | }
1031 |
1032 | //_matchedDecks = new List(validDecks);
1033 |
1034 | if (validDecks.Count > 20)
1035 | {
1036 | validDecks = validDecks.Take(20).ToList();
1037 | }
1038 |
1039 | //if (validDecks.Count > 20)
1040 | // validDecks = validDecks.Where(x => cardEntites.Any(ce => x.GetSelectedDeckVersion().Cards.Any(c => c.Id == ce.Id))).Take(20).ToList();
1041 |
1042 | _mainWindow.updateText(_matchedDecks.Count + " Matching Deck(s) Found", Brushes.LightGreen);
1043 |
1044 | return validDecks;
1045 | }
1046 | catch (Exception ex)
1047 | {
1048 | MetaLog.Error(ex);
1049 | return null;
1050 | }
1051 | }
1052 | else
1053 | return null;
1054 | }
1055 |
1056 | internal List matchMetaDeck()
1057 | {
1058 | if (_validGameMode)
1059 | {
1060 | try
1061 | {
1062 | if (_metaDecks.Count > 0)
1063 | {
1064 | var validDecks = _metaDecks.Where(x => x.Class == Core.Game.Opponent.Class).ToList();
1065 |
1066 | //var cardEntites = Core.Game.Opponent.RevealedEntities.Where(x => (x.IsMinion || x.IsSpell || x.IsWeapon) && !x.Info.Created && !x.Info.Stolen).GroupBy(x => x.CardId).ToList();
1067 | var cardEntites = Core.Game.Opponent.OpponentCardList.Where(x => !x.IsCreated).ToList();
1068 |
1069 | if (validDecks.Count > 0 && cardEntites != null)
1070 | {
1071 | validDecks = validDecks.Where(x => cardEntites.All(ce => x.GetSelectedDeckVersion().Cards.Any(c => c.Id == ce.Id && c.Count >= ce.Count))).ToList();
1072 | }
1073 |
1074 | if (validDecks.Count == 0)
1075 | {
1076 | _mainWindow.updateText("No Match Found. Showing Closest Decks", Brushes.YellowGreen);
1077 | //MetaLog.Info("No Match Found. Showing Closest Decks");
1078 | _closestMatchedDecks = true;
1079 |
1080 | //if (_matchedDecks.Count <= 10 && _opponentTurnCount > 10)
1081 | // return _matchedDecks;
1082 |
1083 | validDecks = _metaDecks.Where(x => x.Class == Core.Game.Opponent.Class).ToList();
1084 |
1085 | _matchedDecks = new List(validDecks);
1086 |
1087 | validDecks.Clear();
1088 | int lastCount = 0;
1089 |
1090 | //var opponentCards = Core.Game.Opponent.OpponentCardList.Where(x => !x.IsCreated).Select(x => x.Id).ToArray();
1091 | var opponentCards = Core.Game.Opponent.PlayerEntities.Where(x => (x.IsMinion || x.IsSpell || x.IsWeapon) && !x.Info.Created && !x.Info.Stolen).Select(x => x.CardId).ToArray();
1092 | //MetaLog.Info(String.Join(",", (IEnumerable)opponentCards));
1093 | foreach (Deck d in _matchedDecks.OrderBy(x => Convert.ToInt16(x.Note)))
1094 | {
1095 | var matchDeckCards = d.Cards.OrderByDescending(x => x.Id).Select(x => x.Id).ToArray();
1096 |
1097 | //int count = d.Cards.Intersect(Core.Game.Opponent.PlayerCardList.Where(x => !x.IsCreated)).ToList().Count();
1098 | int count = opponentCards.Intersect(matchDeckCards).Count();
1099 |
1100 | if (count > 0)
1101 | {
1102 | if (count > lastCount)
1103 | {
1104 | validDecks.Insert(0, d);
1105 | lastCount = count;
1106 | }
1107 | else
1108 | {
1109 | validDecks.Add(d);
1110 | }
1111 | }
1112 | }
1113 | _matchedDecks = new List(validDecks);
1114 |
1115 | if (validDecks.Count > 10)
1116 | {
1117 | validDecks = validDecks.Take(10).ToList();
1118 | }
1119 |
1120 | return validDecks;
1121 | }
1122 |
1123 | _matchedDecks = new List(validDecks);
1124 |
1125 |
1126 | if (validDecks.Count > 15)
1127 | validDecks = validDecks.Take(15).ToList();
1128 |
1129 | //validDecks = validDecks.Where(x => cardEntites.Any(ce => x.GetSelectedDeckVersion().Cards.Any(c => c.Id == ce.Id))).Take(20).ToList();
1130 |
1131 | _mainWindow.updateText(_matchedDecks.Count + " Matching Deck(s) Found", Brushes.LightGreen);
1132 |
1133 | return validDecks;
1134 | }
1135 | else
1136 | return null;
1137 | }
1138 | catch (Exception ex)
1139 | {
1140 | MetaLog.Error(ex);
1141 | return null;
1142 | }
1143 | }
1144 | else
1145 | return null;
1146 | }
1147 |
1148 | public void SaveMetaDeckStats()
1149 | {
1150 | if (_metaDecks.Count > 0)
1151 | {
1152 | MetaLog.Info("Saving Meta Ranks to file", "SaveMetaDeckStats");
1153 | XmlManager>.Save(_deckFilename, _metaDecks);
1154 | }
1155 | else
1156 | {
1157 | MetaLog.Info("No Meta Decks Found. File not saved.", "SaveMetaDecks");
1158 | }
1159 | }
1160 |
1161 | public void SaveMetaDecks(string opponentClass, List metaDecks)
1162 | {
1163 | if (metaDecks.Count > 0)
1164 | {
1165 | string deckFilename = Path.Combine(_deckDirectory, opponentClass + ".xml");
1166 | MetaLog.Info("Saving Meta Decks to file " + deckFilename, "SaveMetaDecks");
1167 | XmlManager>.Save(deckFilename, metaDecks);
1168 | }
1169 | else
1170 | {
1171 | MetaLog.Info("No Meta Decks Found. File not saved.", "SaveMetaDecks");
1172 | }
1173 | }
1174 |
1175 | internal async Task sendCardStats()
1176 | {
1177 | try
1178 | {
1179 | if (_validGameMode)
1180 | {
1181 | {
1182 | MetaLog.Info("Uploading Card Stats...", "sendRequest");
1183 |
1184 | string url = "http://metastats.net/metadetector/cards.php?v=0.0.9d";
1185 |
1186 | string postData = _cardsPlayedOpponent.GetCardStats();
1187 |
1188 | if (postData != "")
1189 | {
1190 |
1191 | WebClient client = new WebClient();
1192 | byte[] data = Encoding.UTF8.GetBytes(postData);
1193 | Uri uri = new Uri(url);
1194 | var response = Encoding.UTF8.GetString(await client.UploadDataTaskAsync(uri, "POST", data));
1195 |
1196 | _appConfig.lastUpload = DateTime.Now;
1197 | _appConfig.Save();
1198 |
1199 | MetaLog.Info("Uploading Card Stats Done", "sendRequest");
1200 |
1201 | /*
1202 | client.Headers.Add("Content-Type", "binary/octet-stream");
1203 |
1204 | byte[] result = client.UploadFile("http://metastats.net/metadetector/upload.php", "POST",
1205 | trackCards.statsPath);
1206 |
1207 | string s = Encoding.UTF8.GetString(result, 0, result.Length);
1208 | */
1209 | return response;
1210 | }
1211 | }
1212 | }
1213 |
1214 | return null;
1215 | }
1216 | catch (Exception ex)
1217 | {
1218 | MetaLog.Error(ex);
1219 | return null;
1220 | }
1221 | }
1222 |
1223 | public void saveConfig()
1224 | {
1225 | _appConfig.showOverlay = _mainWindow.showOverlay;
1226 | _appConfig.topMost = _mainWindow.Topmost;
1227 | _appConfig.Save();
1228 | }
1229 |
1230 | internal async Task sendMetaRanks()
1231 | {
1232 | try
1233 | {
1234 | if (_validGameMode)
1235 | {
1236 | if ((DateTime.Now - _appConfig.lastUpload).TotalDays > 1)
1237 | {
1238 | MetaLog.Info("Uploading Meta Ranks...", "sendRequest");
1239 |
1240 | string url = "http://metastats.net/metadetector/meta.php";
1241 |
1242 | StringBuilder builder = new StringBuilder();
1243 | foreach (Deck d in _metaDecks.Where(x => x.Note != "0"))
1244 | {
1245 | builder.Append(d.DeckId.ToString()).Append(":").Append(d.Note).Append(',');
1246 | }
1247 |
1248 | string postData = builder.ToString().TrimEnd(',');
1249 |
1250 | WebClient client = new WebClient();
1251 | byte[] data = Encoding.UTF8.GetBytes(postData);
1252 | Uri uri = new Uri(url);
1253 | var response = Encoding.UTF8.GetString(await client.UploadDataTaskAsync(uri, "POST", data));
1254 |
1255 | _appConfig.lastUpload = DateTime.Now;
1256 | _appConfig.Save();
1257 |
1258 | MetaLog.Info("Uploading Meta Ranks Done", "sendRequest");
1259 | return response;
1260 | }
1261 | }
1262 | return null;
1263 | }
1264 | catch (Exception ex)
1265 | {
1266 | MetaLog.Error(ex);
1267 | return null;
1268 | }
1269 | }
1270 |
1271 | internal string SendDeckStats()
1272 | {
1273 | if (_validGameMode)
1274 | {
1275 | if ((DateTime.Now - _appConfig.lastUpload).TotalDays > 1)
1276 | {
1277 | string url = "http://metastats.net/metadetector/meta.php";
1278 |
1279 | List> deckStats = new List>();
1280 | StringBuilder builder = new StringBuilder();
1281 |
1282 |
1283 | foreach (Deck d in _metaDecks.Where(x => x.Note != "0"))
1284 | {
1285 | builder.Append(d.DeckId.ToString()).Append(":").Append(d.Note).Append(',');
1286 | }
1287 |
1288 | string result = builder.ToString().TrimEnd(',');
1289 |
1290 | string postData = result;
1291 |
1292 | string webpageContent = string.Empty;
1293 |
1294 | try
1295 | {
1296 | byte[] byteArray = Encoding.UTF8.GetBytes(postData);
1297 |
1298 | HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
1299 |
1300 | webRequest.ContentType = "application/x-www-form-urlencoded";
1301 | webRequest.ContentLength = byteArray.Length;
1302 | webRequest.Method = "POST";
1303 |
1304 | using (Stream webpageStream = webRequest.GetRequestStream())
1305 | {
1306 | webpageStream.Write(byteArray, 0, byteArray.Length);
1307 | }
1308 |
1309 | using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
1310 | {
1311 | using (StreamReader reader = new StreamReader(webResponse.GetResponseStream()))
1312 | {
1313 | webpageContent = reader.ReadToEnd();
1314 | }
1315 | }
1316 | }
1317 | catch (Exception ex)
1318 | {
1319 | //throw or return an appropriate response/exception
1320 | MetaLog.Error(ex);
1321 | }
1322 |
1323 | _appConfig.lastUpload = DateTime.Now;
1324 | _appConfig.Save();
1325 | return webpageContent;
1326 | }
1327 |
1328 | return "";
1329 | }
1330 | else
1331 | {
1332 | return "";
1333 | }
1334 | }
1335 | }
1336 |
1337 | public class CardInfo
1338 | {
1339 | public string cardId;
1340 | public int turnCardPlayed;
1341 | public int turnInHand;
1342 | public int turnCardDied;
1343 | public bool mulligan;
1344 | public bool created;
1345 | public string createdBy;
1346 | public int mana;
1347 | public int manaoverload;
1348 |
1349 | public CardInfo(int InHand, bool mul = false, string scardId = "",
1350 | int nturnplayed = -1, int nmana = -1, int nmanaoverload = -1, int nturndied = -1, bool bCreated = false, string sCreatedBy = "")
1351 | {
1352 | this.mulligan = mul;
1353 | this.turnInHand = InHand;
1354 | this.cardId = scardId;
1355 | this.turnCardPlayed = nturnplayed;
1356 | this.mana = nmana;
1357 | this.manaoverload = nmanaoverload;
1358 | this.turnCardDied = nturndied;
1359 | this.created = bCreated;
1360 | this.createdBy = sCreatedBy;
1361 | }
1362 | }
1363 |
1364 | public class trackCards
1365 | {
1366 | private static string statsDirectory = Path.Combine(Config.AppDataPath, "MetaDetector");
1367 | public static string statsPath = Path.Combine(statsDirectory, "cardStats.xml");
1368 |
1369 | public string gameId { get; set; }
1370 | public string playerClass { get; set; }
1371 | public string opponentClass { get; set; }
1372 | public string gameFormat { get; set; }
1373 | public string gameMode { get; set; }
1374 | public string rankString { get; set; }
1375 | public string region { get; set; }
1376 | public int rankedSeasonId { get; set; }
1377 | public int opponentRank { get; set; }
1378 | public int opponentLegendRank { get; set; }
1379 | public bool opponentCoin { get; set; }
1380 | public int playerRank { get; set; }
1381 | public int playerLegendRank { get; set; }
1382 | public bool opponentWin { get; set; }
1383 | public bool playerWin { get; set; }
1384 | public string cardId { get; set; }
1385 | public string cardName { get; set; }
1386 | public int turn { get; set; }
1387 | public int turnDrawn { get; set; }
1388 | public int turnToGraveyard { get; set; }
1389 | public bool mulligan { get; set; }
1390 | public int mana { get; set; }
1391 | public int manaOverload { get; set; }
1392 | public bool isCreated { get; set; }
1393 | public string createdBy { get; set; }
1394 | public string activePlayer { get; set; }
1395 |
1396 | private List _cardsPlayed = new List();
1397 |
1398 | public trackCards()
1399 | {
1400 | this.turnDrawn = -1;
1401 | this.turnToGraveyard = -1;
1402 | this.turn = -1;
1403 | this.mana = -1;
1404 | this.manaOverload = -1;
1405 | this.mulligan = false;
1406 | }
1407 |
1408 | public void Add(string cardId, int nturn, bool isCreated,
1409 | int nturnInHand, bool bmulligan,
1410 | int nturnCardDied,
1411 | int nopponentRank, int nopponentLengendRank, int nplayrank, int nplayerLegendRank,
1412 | int nrankedSeasonId,
1413 | string sName = "", int nMana = -1,
1414 | int nManaOverload = -1, string sActivePlayer = "Opponent", string createdBy = ""
1415 | )
1416 | {
1417 | trackCards temp = new trackCards();
1418 |
1419 | var standard = Core.Game.CurrentFormat == Format.Standard;
1420 |
1421 | temp.gameId = null;
1422 | temp.playerClass = Core.Game.CurrentGameStats.PlayerHero;
1423 | temp.opponentClass = Core.Game.CurrentGameStats.OpponentHero;
1424 | temp.gameFormat = Core.Game.CurrentFormat.ToString();
1425 | temp.gameMode = Core.Game.CurrentGameMode.ToString();
1426 |
1427 | //temp.opponentRank = Core.Game.MatchInfo.OpposingPlayer.StandardRank;
1428 |
1429 | /*temp.opponentRank = standard ? Core.Game.MatchInfo.OpposingPlayer.StandardRank : Core.Game.MatchInfo.OpposingPlayer.WildRank;
1430 | temp.opponentLegendRank = standard ? Core.Game.MatchInfo.OpposingPlayer.StandardLegendRank : Core.Game.MatchInfo.OpposingPlayer.WildLegendRank;
1431 | temp.playerLegendRank = standard ? Core.Game.MatchInfo.LocalPlayer.StandardLegendRank : Core.Game.MatchInfo.LocalPlayer.WildLegendRank;
1432 | temp.playerRank = standard ? Core.Game.MatchInfo.LocalPlayer.StandardRank : Core.Game.MatchInfo.LocalPlayer.WildRank;
1433 | temp.rankedSeasonId = Core.Game.MatchInfo.RankedSeasonId;*/
1434 |
1435 | temp.opponentRank = nopponentRank;
1436 | temp.opponentLegendRank = nopponentLengendRank;
1437 | temp.playerRank = nplayrank;
1438 | temp.playerLegendRank = nplayerLegendRank;
1439 | temp.rankedSeasonId = nrankedSeasonId;
1440 |
1441 | temp.region = Core.Game.CurrentRegion.ToString();
1442 | temp.opponentCoin = Core.Game.Opponent.HasCoin;
1443 | temp.opponentWin = false;
1444 | temp.playerWin = false;
1445 | temp.isCreated = isCreated;
1446 | temp.createdBy = createdBy;
1447 | temp.turnDrawn = nturnInHand;
1448 | temp.mulligan = bmulligan;
1449 | temp.turnToGraveyard = nturnCardDied;
1450 | temp.turn = nturn;
1451 | temp.cardId = cardId;
1452 | temp.cardName = sName;
1453 | temp.mana = nMana;
1454 | temp.manaOverload = nManaOverload;
1455 | temp.activePlayer = sActivePlayer;
1456 |
1457 | _cardsPlayed.Add(temp);
1458 | }
1459 |
1460 | public void Clear()
1461 | {
1462 | _cardsPlayed.Clear();
1463 | }
1464 |
1465 | public string GetCardStats()
1466 | {
1467 | var serializer = new XmlSerializer(typeof(List));
1468 |
1469 | using (StringWriter textWriter = new StringWriter())
1470 | {
1471 | serializer.Serialize(textWriter, _cardsPlayed);
1472 | return textWriter.ToString();
1473 | }
1474 | }
1475 |
1476 | public void Save()
1477 | {
1478 | try
1479 | {
1480 | if (!Directory.Exists(statsDirectory))
1481 | Directory.CreateDirectory(statsDirectory);
1482 |
1483 | var serializer = new XmlSerializer(typeof(List));
1484 | using (var writer = new StreamWriter(statsPath))
1485 | serializer.Serialize(writer, _cardsPlayed);
1486 | }
1487 | catch (Exception ex)
1488 | {
1489 | MetaLog.Error(ex);
1490 | }
1491 | }
1492 |
1493 | public void setPlayerWin()
1494 | {
1495 | foreach (trackCards c in _cardsPlayed)
1496 | {
1497 | c.playerWin = true;
1498 | }
1499 | }
1500 |
1501 | public void setOpponentWin()
1502 | {
1503 | foreach (trackCards c in _cardsPlayed)
1504 | {
1505 | c.opponentWin = true;
1506 | }
1507 | }
1508 |
1509 | public void setTurnInHand(Dictionary cardsTracked)
1510 | {
1511 | foreach (var c in cardsTracked.Where(x => x.Value.cardId != null))
1512 | {
1513 | var t = (trackCards)_cardsPlayed.Where(x => x.turn == c.Value.turnCardPlayed && x.cardId == c.Value.cardId);
1514 | t.mulligan = c.Value.mulligan;
1515 | t.turnDrawn = c.Value.turnInHand;
1516 | }
1517 | }
1518 | }
1519 |
1520 | public class MyConfig
1521 | {
1522 | private static string configDirectory = Path.Combine(Config.AppDataPath, "MetaDetector");
1523 | private static string configPath = Path.Combine(configDirectory, "metaConfig.xml");
1524 |
1525 | public string currentVersion { get; set; }
1526 | public DateTime lastCheck { get; set; }
1527 | public DateTime lastUpload { get; set; }
1528 | public bool showOverlay { get; set; }
1529 | public bool topMost { get; set; }
1530 |
1531 | public MyConfig()
1532 | {
1533 |
1534 | }
1535 |
1536 | public MyConfig(string v, DateTime c, DateTime u)
1537 | {
1538 | this.currentVersion = v;
1539 | this.lastCheck = c;
1540 | this.lastUpload = u;
1541 | this.showOverlay = true;
1542 | this.topMost = false;
1543 | }
1544 |
1545 | public static MyConfig Load()
1546 | {
1547 | try
1548 | {
1549 | if (File.Exists(configPath))
1550 | {
1551 | var serializer = new XmlSerializer(typeof(MyConfig));
1552 |
1553 | using (var reader = new StreamReader(configPath))
1554 | return (MyConfig)serializer.Deserialize(reader);
1555 | }
1556 | else
1557 | {
1558 | return new MyConfig("1", DateTime.Now, DateTime.Now);
1559 | }
1560 | }
1561 | catch (Exception ex)
1562 | {
1563 | MetaLog.Error(ex);
1564 | return new MyConfig("1", DateTime.Now, DateTime.Now);
1565 | //return null;
1566 | }
1567 | }
1568 |
1569 | public void Save()
1570 | {
1571 | try
1572 | {
1573 | if (!Directory.Exists(configDirectory))
1574 | Directory.CreateDirectory(configDirectory);
1575 |
1576 | var serializer = new XmlSerializer(typeof(MyConfig));
1577 | using (var writer = new StreamWriter(configPath))
1578 | serializer.Serialize(writer, this);
1579 | }
1580 | catch (Exception ex)
1581 | {
1582 | MetaLog.Error(ex);
1583 | }
1584 | }
1585 | }
1586 | }
1587 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/MetaDetectorPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Controls;
3 | using Hearthstone_Deck_Tracker.API;
4 | using Hearthstone_Deck_Tracker.Plugins;
5 | using HDT.Plugins.MetaDetector.Controls;
6 | using HDT.Plugins.MetaDetector.Logging;
7 | using System.Threading.Tasks;
8 | using System.Net;
9 | using System.IO;
10 | using Hearthstone_Deck_Tracker;
11 | using System.ComponentModel;
12 | using System.Linq;
13 | using System.Xml.Linq;
14 |
15 | namespace HDT.Plugins.MetaDetector
16 | {
17 | public class MetaDetectorPlugin : IPlugin
18 | {
19 | private MenuItem _MetaDetectorMenuItem;
20 | private OpDeckWindow _MainWindow = null;
21 | private MetaDetector _MetaDetector = null;
22 |
23 | public string Author
24 | {
25 | get { return "AdnanC"; }
26 | }
27 |
28 | public string ButtonText
29 | {
30 | get { return "Settings"; }
31 | }
32 |
33 | public string Description
34 | {
35 | get { return "Shows which deck opponent might be playing"; }
36 | }
37 |
38 | public MenuItem MenuItem
39 | {
40 | //get { return null; }
41 | get { return _MetaDetectorMenuItem; }
42 | }
43 |
44 | public string Name
45 | {
46 | get { return "Meta Detector"; }
47 | }
48 |
49 | public void OnButtonPress()
50 | {
51 |
52 | }
53 |
54 | public void OnLoad()
55 | {
56 |
57 | var xml = XDocument.Load(Config.Instance.DataDir + @"\plugins.xml");
58 |
59 | // Query the data and write out a subset of contacts
60 | /*var query = from c in xml.Root.Descendants("ArrayOfPluginSettings")
61 | where c.Element("FileName").Value.ToString() == "Plugins/MetaStats/MetaStats.dll"
62 | select c.Element("IsEnabled");*/
63 |
64 | var allPlugins = xml.Root.Descendants("PluginSettings").Where(x => x.Element("IsEnabled").Value == "true");
65 |
66 | //MetaLog.Info("Testing XML: " + allPlugins);
67 |
68 | foreach (var enabledPluging in allPlugins)
69 | {
70 | if (enabledPluging.Element("Name").Value.Trim() == "Meta Stats")
71 | {
72 | VersionWindow _ver = new VersionWindow();
73 | _ver.Show();
74 | //throw new Exception("MetaStats Plugin already Enabled. Please Disable that first.");
75 | }
76 | }
77 |
78 | try
79 | {
80 |
81 | _MainWindow = new OpDeckWindow();
82 |
83 | _MetaDetectorMenuItem = new PluginMenu(_MainWindow);
84 |
85 | _MetaDetector = new MetaDetector(_MainWindow);
86 |
87 | _MainWindow.updateVersion(Version);
88 |
89 | GameEvents.OnGameStart.Add(_MetaDetector.GameStart);
90 | GameEvents.OnGameEnd.Add(_MetaDetector.GameEnd);
91 |
92 | GameEvents.OnTurnStart.Add(_MetaDetector.TurnStart);
93 |
94 | GameEvents.OnOpponentPlay.Add(_MetaDetector.OpponentPlay);
95 | GameEvents.OnOpponentDraw.Add(_MetaDetector.OpponentDraw);
96 |
97 | GameEvents.OnOpponentCreateInPlay.Add(_MetaDetector.OpponentCreateInPlay);
98 | GameEvents.OnOpponentCreateInDeck.Add(_MetaDetector.OpponentCreateInDeck);
99 | GameEvents.OnOpponentHeroPower.Add(_MetaDetector.OpponentHeroPower);
100 | GameEvents.OnOpponentSecretTriggered.Add(_MetaDetector.OpponentSecretTriggered);
101 | GameEvents.OnOpponentPlayToGraveyard.Add(_MetaDetector.OpponentPlayToGraveyard);
102 | GameEvents.OnOpponentMulligan.Add(_MetaDetector.OpponentMulligan);
103 |
104 | GameEvents.OnPlayerDraw.Add(_MetaDetector.PlayerDraw);
105 | GameEvents.OnPlayerPlay.Add(_MetaDetector.PlayerPlay);
106 | GameEvents.OnPlayerCreateInPlay.Add(_MetaDetector.PlayerCreateInPlay);
107 | GameEvents.OnPlayerCreateInDeck.Add(_MetaDetector.PlayerCreateInDeck);
108 | GameEvents.OnPlayerHeroPower.Add(_MetaDetector.PlayerHeroPower);
109 | GameEvents.OnPlayerMulligan.Add(_MetaDetector.PlayerMulligan);
110 |
111 | CheckForUpdate();
112 |
113 | //_MainWindow.Show();
114 | //_MainWindow.Visibility = System.Windows.Visibility.Hidden;
115 | MetaLog.Info("Plugin Load Successful");
116 |
117 | }
118 | catch (Exception ex)
119 | {
120 | MetaLog.Error(ex);
121 | MetaLog.Info("Plugin Load Unsuccessful");
122 | }
123 | }
124 |
125 | public void OnUnload()
126 | {
127 | _MetaDetector.saveConfig();
128 | _MainWindow.Close();
129 | _MetaDetector = null;
130 | _MainWindow = null;
131 | MetaLog.Info("Plugin Unload Successful");
132 | }
133 |
134 | public void OnUpdate()
135 | {
136 |
137 | }
138 |
139 | public Version Version
140 | {
141 | get { return new Version(0, 0, 10); }
142 | }
143 |
144 | private async void CheckForUpdate()
145 | {
146 | try
147 | {
148 | var latest = await GitHub.CheckForUpdate("adnanc", "HDT.Plugins.MetaDetector", Version);
149 | if (latest != null)
150 | {
151 | //_MainWindow.newVersionAvailable();
152 | //VersionWindow newVersion = new VersionWindow();
153 | //newVersion.Show();
154 | string pluginDLL = Path.Combine(Config.Instance.DataDir, @"Plugins\MetaDetector\MetaDetector.tmp");
155 |
156 | using (WebClient wc = new WebClient())
157 | {
158 | wc.DownloadFileCompleted += (wc_DownloadFileCompleted);
159 | wc.DownloadFileAsync(new Uri("https://s3.amazonaws.com/metadetector/MetaDetector.dll"), pluginDLL);
160 | }
161 | }
162 | }
163 | catch (Exception ex)
164 | {
165 | MetaLog.Error(ex);
166 | }
167 | }
168 |
169 | void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
170 | {
171 | try
172 | {
173 | string tempFile = Path.Combine(Config.Instance.DataDir, @"Plugins\MetaDetector\MetaDetector.tmp");
174 | string pluginDLL = Path.Combine(Config.Instance.DataDir, @"Plugins\MetaDetector\MetaDetector.dll");
175 | if (File.Exists(tempFile))
176 | {
177 | File.Copy(tempFile, pluginDLL, true);
178 | File.Delete(tempFile);
179 | }
180 | }
181 | catch (Exception ex)
182 | {
183 | MetaLog.Error(ex);
184 | }
185 | }
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/MetaLog.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.CompilerServices;
6 | using System.Windows;
7 | using Hearthstone_Deck_Tracker;
8 | using Hearthstone_Deck_Tracker.Utility.Extensions;
9 | using Hearthstone_Deck_Tracker.Utility.Logging;
10 |
11 | namespace HDT.Plugins.MetaDetector.Logging
12 | {
13 | public class MetaLog
14 | {
15 | private const int MaxLogFileAge = 2;
16 | private const int KeepOldLogs = 1;
17 |
18 | private static string logDir = Path.Combine(Config.Instance.DataDir, @"MetaDetector\Logs");
19 | private static string logFile = Path.Combine(logDir, "meta_log.txt");
20 |
21 | internal static void Initialize()
22 | {
23 | Trace.AutoFlush = true;
24 |
25 | if (!Directory.Exists(logDir))
26 | Directory.CreateDirectory(logDir);
27 | else
28 | {
29 | try
30 | {
31 | var fileInfo = new FileInfo(logFile);
32 | if (fileInfo.Exists)
33 | {
34 | using (var fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.None))
35 | {
36 | //can access log file => no other instance of same installation running
37 | }
38 | File.Move(logFile, logFile.Replace(".txt", "_" + DateTime.Now.ToUnixTime() + ".txt"));
39 | //keep logs from the last 2 days plus 1 before that
40 | foreach (var file in
41 | new DirectoryInfo(logDir).GetFiles("meta_log*")
42 | .Where(x => x.CreationTime < DateTime.Now.AddDays(-MaxLogFileAge))
43 | .OrderByDescending(x => x.LastWriteTime)
44 | .Skip(KeepOldLogs))
45 | {
46 | try
47 | {
48 | File.Delete(file.FullName);
49 | }
50 | catch
51 | {
52 |
53 | }
54 | }
55 | }
56 | else
57 | File.Create(logFile).Dispose();
58 | }
59 | catch (Exception)
60 | {
61 | try
62 | {
63 | var errLogFile = Path.Combine(logDir, "meta_log_err.txt");
64 | using (var writer = new StreamWriter(errLogFile, true))
65 | writer.WriteLine("[{0}]: {1}", DateTime.Now.ToLongTimeString(), "Unable to write to Meta Log");
66 | //MessageBox.Show("Another instance of Hearthstone Deck Tracker is already running.", "Error starting Hearthstone Deck Tracker",
67 | // MessageBoxButton.OK, MessageBoxImage.Error);
68 | }
69 | catch (Exception)
70 | {
71 | }
72 | //Application.Current.Shutdown();
73 | return;
74 | }
75 | }
76 | }
77 |
78 | public static void WriteLine(string msg, LogType type, [CallerMemberName] string memberName = "",
79 | [CallerFilePath] string sourceFilePath = "")
80 | {
81 | var file = sourceFilePath?.Split('/', '\\').LastOrDefault()?.Split('.').FirstOrDefault();
82 |
83 | StreamWriter sw = new StreamWriter(logFile, true);
84 | sw.WriteLine($"{DateTime.Now.ToLongTimeString()}|{type}|{file}.{memberName} >> {msg}");
85 | sw.Close();
86 | }
87 |
88 | public static void Debug(string msg, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "")
89 | => WriteLine(msg, LogType.Debug, memberName, sourceFilePath);
90 |
91 | public static void Info(string msg, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "")
92 | => WriteLine(msg, LogType.Info, memberName, sourceFilePath);
93 |
94 | public static void Warn(string msg, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "")
95 | => WriteLine(msg, LogType.Warning, memberName, sourceFilePath);
96 |
97 | public static void Error(string msg, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "")
98 | => WriteLine(msg, LogType.Error, memberName, sourceFilePath);
99 |
100 | public static void Error(Exception ex, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "")
101 | => WriteLine(ex.ToString(), LogType.Error, memberName, sourceFilePath);
102 | }
103 | }
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("HDT.Plugins.MetaDetector")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("HDT.Plugins.MetaDetector")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("d5e137db-2464-47d1-9395-9153d549c1cf")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace HDT.Plugins.MetaDetector.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HDT.Plugins.MetaDetector.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AdnanC/HDT.Plugins.MetaDetector/f33830cd1f252e2286771e1ed1d48f0f3768234a/HDT.Plugins.MetaDetector/favicon.ico
--------------------------------------------------------------------------------
/HDT.Plugins.MetaDetector/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hearthstone MetaDetector
2 |
3 | [](https://gitter.im/adnanc/HDT.Plugins.MetaDetector?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
4 |
5 | This Hearthstone Deck Tracker plugin tries to detect what deck your opponent is playing based on the cards played. Cards are compared with the most popular decks available on metastats.net and the closest matching decks are displayed. Decks are regulary updated and plugin automatically downloads the latest deck lists and stats from metastats.net. Deck ranks are based on how often a certain deck is played in the current meta.
6 |
7 |
8 | # Installation
9 |
10 | 1. Download the latest version from https://github.com/adnanc/HDT.Plugins.MetaDetector/releases
11 | 2. Then unzip the release into the HDT Plugins directory; this directory can be opened through Hearthstone Deck Tracker > Options > Tracker > Plugins > Plugins Folder or go to %AppData%\HearthstoneDeckTracker\Plugins
12 | 3. The directory should look like Plugins/MetaDetector/[some files]
13 | 4. Enable the plugin from Options > Tracker > Plugins. You can use both MetaStats and MetaDetector together now.
14 | 5. If the plugin does not show up in that list, right click 'MetaDetector.dll', go into Properties and click "Unblock" at the bottom.
15 |
--------------------------------------------------------------------------------