├── .gitignore
├── GeniusInvokationAutoToy.sln
├── GeniusInvokationAutoToy
├── App.config
├── Core
│ ├── GameControl.cs
│ ├── ImageCapture.cs
│ ├── ImageRecognition.cs
│ ├── ImageResCollections.cs
│ ├── Model
│ │ ├── ElementalType.cs
│ │ └── RollPhaseDice.cs
│ ├── MyException
│ │ ├── DuelEndException.cs
│ │ └── RetryException.cs
│ └── YuanShenWindow.cs
├── FormMain.Designer.cs
├── FormMain.cs
├── FormMain.resx
├── FormMask.Designer.cs
├── FormMask.cs
├── FormMask.resx
├── FormMask1.Designer.cs
├── FormMask1.cs
├── FormMask1.resx
├── Forms
│ └── HotKey
│ │ ├── Hotkey.cs
│ │ ├── HotkeyHook.cs
│ │ └── HotkeyTextBox.cs
├── GeniusInvokationAutoToy.csproj
├── Nlog.config
├── Program.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Raiden.ico
├── Resources
│ └── Raiden.ico
├── Strategy
│ ├── BaseStrategy.cs
│ ├── KeqingRaidenGanyuStrategy.cs
│ ├── Model
│ │ ├── ActionCommand.cs
│ │ ├── ActionEnum.cs
│ │ ├── Character.cs
│ │ ├── CharacterStatusEnum.cs
│ │ ├── Duel.cs
│ │ ├── Old
│ │ │ └── CurrentCharacterStatus.cs
│ │ ├── RoundStrategy.cs
│ │ └── Skill.cs
│ ├── MonaSucroseJeanStrategy.cs
│ └── Script
│ │ └── ScriptParser.cs
├── Utils
│ ├── Device.cs
│ ├── Extension
│ │ ├── RectangleExtension.cs
│ │ └── RetryExtension.cs
│ ├── GAHelper.cs
│ ├── MouseUtils.cs
│ ├── MyLogger.cs
│ ├── Native.cs
│ ├── PrimaryScreen.cs
│ └── Retry.cs
├── app.manifest
└── packages.config
├── Image
├── p1.png
└── p2.png
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific files
2 | *.suo
3 | *.user
4 | *.userosscache
5 | *.sln.docstates
6 | .vs/
7 |
8 | # User-specific files (MonoDevelop/Xamarin Studio)
9 | *.userprefs
10 |
11 | # Build results
12 | [Dd]ebug/
13 | [Dd]ebugPublic/
14 | [Rr]elease/
15 | [Rr]eleases/
16 | x64/
17 | x86/
18 | bld/
19 | [Bb]in/
20 | [Oo]bj/
21 | [Ll]og/
22 |
23 | # Mine
24 | Tmp/
25 | /packages/
26 | node_modules/
27 |
28 | .idea
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32228.430
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GeniusInvokationAutoToy", "GeniusInvokationAutoToy\GeniusInvokationAutoToy.csproj", "{F17BE4C5-926C-456D-9CC0-606DAE304ED8}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {DFA8F1CD-513D-45D7-856D-378146C4D367}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | False
27 |
28 |
29 | 0
30 |
31 |
32 | 0
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Core/ImageCapture.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Utils;
2 | using System;
3 | using System.Drawing;
4 |
5 | namespace GeniusInvokationAutoToy.Core
6 | {
7 | public class ImageCapture
8 | {
9 | IntPtr hwnd;
10 | IntPtr hdc;
11 |
12 | public int X { get; set; }
13 | public int Y { get; set; }
14 | public int W { get; set; }
15 | public int H { get; set; }
16 |
17 | public void Start(int x, int y, int w, int h)
18 | {
19 | hwnd = Native.GetDesktopWindow();
20 | hdc = Native.GetDC(hwnd);
21 |
22 | this.X = x;
23 | this.Y = y;
24 | this.W = w;
25 | this.H = h;
26 | }
27 |
28 | public Bitmap Capture()
29 | {
30 | Bitmap bmp = new Bitmap(W, H);
31 | Graphics bmpGraphic = Graphics.FromImage(bmp);
32 | //get handle to source graphic
33 | IntPtr bmpHdc = bmpGraphic.GetHdc();
34 |
35 | //copy it
36 | bool res = Native.StretchBlt(bmpHdc, 0, 0, W, H,
37 | hdc, X, Y, W, H, Native.CopyPixelOperation.SourceCopy);
38 | bmpGraphic.ReleaseHdc();
39 | return bmp;
40 | }
41 |
42 | public void Stop()
43 | {
44 | Native.ReleaseDC(hwnd, hdc);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Core/ImageRecognition.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Utils;
2 | using OpenCvSharp;
3 | using OpenCvSharp.Aruco;
4 | using OpenCvSharp.Extensions;
5 | using System;
6 | using System.Collections;
7 | using System.Collections.Generic;
8 | using System.Drawing;
9 | using System.Drawing.Imaging;
10 | using System.Linq;
11 | using System.Reflection;
12 | using System.Runtime.InteropServices;
13 | using System.Text;
14 | using System.Threading.Tasks;
15 | using System.Xml.Linq;
16 | using static GeniusInvokationAutoToy.Utils.Native;
17 | using static System.Windows.Forms.AxHost;
18 | using Point = System.Drawing.Point;
19 |
20 | namespace GeniusInvokationAutoToy.Core
21 | {
22 | class ImageRecognition
23 | {
24 | public static bool IsDebug = false;
25 | public static double WidthScale = 1;
26 | public static double HeightScale = 1;
27 |
28 | ///
29 | /// 所有图片是等比放大的
30 | ///
31 | ///
32 | ///
33 | ///
34 | public static Mat Resize(Mat src, double scale)
35 | {
36 | if (scale != 1)
37 | {
38 | return Resize(src, scale, scale);
39 | }
40 | return src;
41 | }
42 |
43 | public static Mat Resize(Mat src, double widthScale, double heightScale)
44 | {
45 | if (widthScale != 1 || heightScale != 1)
46 | {
47 | Mat dst = new Mat();
48 | Cv2.Resize(src, dst, new OpenCvSharp.Size(src.Width * widthScale, src.Height * heightScale));
49 | return dst;
50 | }
51 | return src;
52 | }
53 |
54 | public static Point FindSingleTarget(Bitmap imgSrc, Bitmap imgSub, double threshold = 0.8)
55 | {
56 | Mat srcMat = null;
57 | Mat dstMat = null;
58 | try
59 | {
60 | srcMat = imgSrc.ToMat();
61 | dstMat = imgSub.ToMat();
62 | return FindSingleTarget(srcMat, dstMat, threshold);
63 | }
64 | catch (Exception ex)
65 | {
66 | MyLogger.Error(ex.ToString());
67 | return new Point();
68 | }
69 | finally
70 | {
71 | srcMat?.Dispose();
72 | dstMat?.Dispose();
73 | }
74 | }
75 |
76 | public static Point FindSingleTarget(Mat srcMat, Mat dstMat, double threshold = 0.8)
77 | {
78 | Point p = new Point();
79 |
80 | OutputArray outArray = null;
81 | try
82 | {
83 | dstMat = Resize(dstMat, WidthScale);
84 |
85 | outArray = OutputArray.Create(srcMat);
86 | Cv2.MatchTemplate(srcMat, dstMat, outArray, TemplateMatchModes.CCoeffNormed);
87 | double minValue, maxValue;
88 | OpenCvSharp.Point location, point;
89 | Cv2.MinMaxLoc(InputArray.Create(outArray.GetMat()), out minValue, out maxValue,
90 | out location, out point);
91 |
92 | if (maxValue >= threshold)
93 | {
94 | p = new Point(point.X + dstMat.Width / 2, point.Y + dstMat.Height / 2);
95 | if (IsDebug)
96 | {
97 | var imgTar = srcMat.Clone();
98 | Cv2.Rectangle(imgTar, point,
99 | new OpenCvSharp.Point(point.X + dstMat.Width, point.Y + dstMat.Height),
100 | Scalar.Red, 2);
101 | Cv2.PutText(imgTar, maxValue.ToString("0.00"), new OpenCvSharp.Point(point.X, point.Y - 10),
102 | HersheyFonts.HersheySimplex, 0.5, Scalar.Red);
103 |
104 | Cv2.ImShow("识别窗口", imgTar);
105 | }
106 | }
107 |
108 | return p;
109 | }
110 | catch (Exception ex)
111 | {
112 | MyLogger.Error(ex.ToString());
113 | return p;
114 | }
115 | finally
116 | {
117 | outArray?.Dispose();
118 | }
119 | }
120 |
121 | //public static List FindMultiTarget(Bitmap imgSrc, Bitmap imgSub, out Mat resMat, double threshold = 0.9,
122 | // int findTargetCount = 8)
123 | //{
124 | // Mat srcMat = null;
125 | // Mat dstMat = null;
126 | // try
127 | // {
128 | // srcMat = imgSrc.ToMat();
129 | // dstMat = imgSub.ToMat();
130 | // return FindMultiTarget(srcMat, dstMat, resMat, threshold, findTargetCount);
131 | // }
132 | // catch (Exception ex)
133 | // {
134 | // return new List();
135 | // }
136 | // finally
137 | // {
138 | // srcMat?.Dispose();
139 | // dstMat?.Dispose();
140 | // }
141 | //}
142 |
143 | public static List FindMultiTarget(Mat srcMat, Mat dstMat, string title, out Mat resMat,
144 | double threshold = 0.8, int findTargetCount = 8)
145 | {
146 | List pointList = new List();
147 | resMat = srcMat.Clone();
148 | try
149 | {
150 | dstMat = Resize(dstMat, WidthScale);
151 |
152 | Mat matchResult = new Mat();
153 | Cv2.MatchTemplate(srcMat, dstMat, matchResult, TemplateMatchModes.CCoeffNormed);
154 |
155 | double minValue = 0;
156 | double maxValue = 0;
157 | OpenCvSharp.Point minLoc = new OpenCvSharp.Point();
158 |
159 | //寻找最几个最值的位置
160 | Mat mask = new Mat(matchResult.Height, matchResult.Width, MatType.CV_8UC1, Scalar.White);
161 | Mat maskSub = new Mat(matchResult.Height, matchResult.Width, MatType.CV_8UC1, Scalar.Black);
162 | var point = new OpenCvSharp.Point(0, 0);
163 | for (int i = 0; i < findTargetCount; i++)
164 | {
165 | Cv2.MinMaxLoc(matchResult, out minValue, out maxValue, out minLoc, out point, mask);
166 | Rect maskRect = new Rect(point.X - dstMat.Width / 2, point.Y - dstMat.Height / 2, dstMat.Width,
167 | dstMat.Height);
168 | maskSub.Rectangle(maskRect, Scalar.White, -1);
169 | mask -= maskSub;
170 | if (maxValue >= threshold)
171 | {
172 | pointList.Add(new Point(point.X + dstMat.Width / 2, point.Y + dstMat.Height / 2));
173 |
174 | if (IsDebug)
175 | {
176 | MyLogger.Info(title + " " + maxValue.ToString("0.000") + " " + point);
177 | Cv2.Rectangle(resMat, point,
178 | new OpenCvSharp.Point(point.X + dstMat.Width, point.Y + dstMat.Height),
179 | Scalar.Red, 2);
180 | Cv2.PutText(resMat, title + " " + maxValue.ToString("0.00"),
181 | new OpenCvSharp.Point(point.X, point.Y - 10),
182 | HersheyFonts.HersheySimplex, 0.5, Scalar.Red);
183 | }
184 | }
185 | else
186 | {
187 | break;
188 | }
189 | }
190 |
191 | if (IsDebug)
192 | {
193 | Cv2.ImShow("识别窗口", resMat);
194 | }
195 |
196 | return pointList;
197 | }
198 | catch (Exception ex)
199 | {
200 | MyLogger.Error(ex.ToString());
201 | return pointList;
202 | }
203 | finally
204 | {
205 | srcMat?.Dispose();
206 | dstMat?.Dispose();
207 | }
208 | }
209 |
210 |
211 | public static Dictionary> FindPicFromImage(Bitmap imgSrc,
212 | Dictionary imgSubDictionary, double threshold = 0.8)
213 | {
214 | Dictionary> dictionary = new Dictionary>();
215 | Mat srcMat = imgSrc.ToMat();
216 | Mat resMat;
217 |
218 | foreach (KeyValuePair kvp in imgSubDictionary)
219 | {
220 | dictionary.Add(kvp.Key, FindMultiTarget(srcMat, kvp.Value.ToMat(), kvp.Key, out resMat, threshold));
221 | srcMat = resMat.Clone();
222 | if (IsDebug)
223 | {
224 | MyLogger.Info($"{kvp.Key} 识别完成");
225 | }
226 | }
227 |
228 | return dictionary;
229 | }
230 |
231 | public static Dictionary> FindPicFromImage(Mat srcMat,
232 | Dictionary imgSubDictionary, double threshold = 0.8)
233 | {
234 | Dictionary> dictionary = new Dictionary>();
235 | Mat resMat;
236 | foreach (KeyValuePair kvp in imgSubDictionary)
237 | {
238 | dictionary.Add(kvp.Key, FindMultiTarget(srcMat, kvp.Value.ToMat(), kvp.Key, out resMat, threshold));
239 | srcMat = resMat.Clone();
240 | if (IsDebug)
241 | {
242 | MyLogger.Info($"{kvp.Key} 识别完成");
243 | }
244 | }
245 |
246 | return dictionary;
247 | }
248 |
249 | ///
250 | /// 二值化
251 | ///
252 | ///
253 | ///
254 | public static Mat Threshold(Mat src, Scalar lowPurple, Scalar highPurple)
255 | {
256 | Mat mask = new Mat();
257 | using (Mat rgbMat = new Mat())
258 | {
259 | Cv2.CvtColor(src, rgbMat, ColorConversionCodes.BGR2RGB);
260 | Cv2.InRange(rgbMat, lowPurple, highPurple, mask);
261 | Cv2.Threshold(mask, mask, 0, 255, ThresholdTypes.Binary); //二值化
262 | //Cv2.ImShow("识别窗口", mask);
263 | return mask;
264 | }
265 | }
266 |
267 | public static int[] HorizontalProjection(Mat gray)
268 | {
269 | var projection = new int[gray.Height];
270 | //对每一行计算投影值
271 | for (int y = 0; y < gray.Height; ++y)
272 | {
273 | //遍历这一行的每一个像素,如果是有效的,累加投影值
274 | for (int x = 0; x < gray.Width; ++x)
275 | {
276 | var s = gray.Get(y, x);
277 | if (s.Item0 == 255)
278 | {
279 | projection[y]++;
280 | }
281 | }
282 | }
283 |
284 | return projection;
285 | }
286 |
287 | public static int[] VerticalProjection(Mat gray)
288 | {
289 | var projection = new int[gray.Width];
290 | //遍历每一列计算投影值
291 | for (int x = 0; x < gray.Width; ++x)
292 | {
293 | for (int y = 0; y < gray.Height; ++y)
294 | {
295 | var s = gray.Get(y, x);
296 | if (s.Item0 == 255)
297 | {
298 | projection[x]++;
299 | }
300 | }
301 | }
302 |
303 | return projection;
304 | }
305 | }
306 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Core/ImageResCollections.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows.Forms;
9 |
10 | namespace GeniusInvokationAutoToy.Core
11 | {
12 | ///
13 | /// 识别图片资源
14 | ///
15 | public class ImageResCollections
16 | {
17 |
18 | public static string RollPhaseDiceBitmapPath = Path.Combine(Application.StartupPath, "config\\1920x1080\\dice");
19 | public static string CardBitmapPath = Path.Combine(Application.StartupPath, "config\\1920x1080\\card");
20 |
21 | // 投掷期间的骰子
22 | public static Dictionary RollPhaseDiceBitmaps = new Dictionary()
23 | {
24 | { "anemo",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"roll_anemo.png")) },
25 | { "geo",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"roll_geo.png")) },
26 | { "electro",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"roll_electro.png")) },
27 | { "dendro",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"roll_dendro.png")) },
28 | { "hydro",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"roll_hydro.png")) },
29 | { "pyro",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"roll_pyro.png")) },
30 | { "cryo",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"roll_cryo.png")) },
31 | { "omni",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"roll_omni.png")) },
32 | };
33 |
34 | // 主界面骰子
35 | public static Dictionary ActionPhaseDiceBitmaps = new Dictionary()
36 | {
37 | { "anemo",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"action_anemo.png")) },
38 | { "geo",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"action_geo.png")) },
39 | { "electro",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"action_electro.png")) },
40 | { "dendro",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"action_dendro.png")) },
41 | { "hydro",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"action_hydro.png")) },
42 | { "pyro",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"action_pyro.png")) },
43 | { "cryo",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"action_cryo.png")) },
44 | { "omni",new Bitmap(Path.Combine(RollPhaseDiceBitmapPath,"action_omni.png")) },
45 | };
46 |
47 | public static Bitmap ConfirmButton = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\确定.png"));
48 | public static Bitmap RoundEndButton = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\回合结束.png"));
49 | public static Bitmap ElementalTuningConfirmButton = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\元素调和.png"));
50 | public static Bitmap ExitDuelButton = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\退出挑战.png"));
51 |
52 | public static Bitmap InMyActionBitmap = RoundEndButton;
53 | public static Bitmap InOpponentActionBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\对方行动中.png"));
54 | public static Bitmap EndPhaseBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\回合结算阶段.png"));
55 | public static Bitmap ElementalDiceLackWarning = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\元素骰子不足.png"));
56 | public static Bitmap CharacterTakenOutBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\角色死亡.png"));
57 | public static Bitmap CharacterDefeatedBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\角色被打败.png"));
58 | public static Bitmap InCharacterPickBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\出战角色.png"));
59 |
60 | // 角色区域
61 | public static Bitmap CharacterHpUpperBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\角色血量上方.png"));
62 | public static Bitmap CharacterStatusFreezeBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\角色状态_冻结.png"));
63 | public static Bitmap CharacterStatusDizzinessBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\角色状态_水泡.png"));
64 | public static Bitmap CharacterEnergyOnBitmap = new Bitmap(Path.Combine(Application.StartupPath, "config\\1920x1080\\other_zh-cn\\满能量.png"));
65 |
66 | // 卡牌
67 | public static Bitmap ElementalResonanceWovenWindsCard = new Bitmap(Path.Combine(CardBitmapPath, "Elemental Resonance Woven Winds.png"));
68 | public static Bitmap TheBestestTravelCompanionCard = new Bitmap(Path.Combine(CardBitmapPath, "The Bestest Travel Companion.png"));
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Core/Model/ElementalType.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace GeniusInvokationAutoToy.Core.Model
8 | {
9 | public enum ElementalType
10 | {
11 | Omni,
12 | Cryo,
13 | Hydro,
14 | Pyro,
15 | Electro,
16 | Dendro,
17 | Anemo,
18 | Geo
19 | }
20 |
21 | public static class ElementalTypeExtension
22 | {
23 | public static ElementalType ToElementalType(this string type)
24 | {
25 | type = type.ToLower();
26 | switch (type)
27 | {
28 | case "omni":
29 | return ElementalType.Omni;
30 | case "cryo":
31 | return ElementalType.Cryo;
32 | case "hydro":
33 | return ElementalType.Hydro;
34 | case "pyro":
35 | return ElementalType.Pyro;
36 | case "electro":
37 | return ElementalType.Electro;
38 | case "dendro":
39 | return ElementalType.Dendro;
40 | case "anemo":
41 | return ElementalType.Anemo;
42 | case "geo":
43 | return ElementalType.Geo;
44 | default:
45 | throw new ArgumentOutOfRangeException(nameof(type), type, null);
46 | }
47 | }
48 |
49 | public static ElementalType ChineseToElementalType(this string type)
50 | {
51 | type = type.ToLower();
52 | switch (type)
53 | {
54 | case "全":
55 | return ElementalType.Omni;
56 | case "冰":
57 | return ElementalType.Cryo;
58 | case "水":
59 | return ElementalType.Hydro;
60 | case "火":
61 | return ElementalType.Pyro;
62 | case "雷":
63 | return ElementalType.Electro;
64 | case "草":
65 | return ElementalType.Dendro;
66 | case "风":
67 | return ElementalType.Anemo;
68 | case "岩":
69 | return ElementalType.Geo;
70 | default:
71 | throw new ArgumentOutOfRangeException(nameof(type), type, null);
72 | }
73 | }
74 |
75 | public static string ToChinese(this ElementalType type)
76 | {
77 | switch (type)
78 | {
79 | case ElementalType.Omni:
80 | return "全";
81 | case ElementalType.Cryo:
82 | return "冰";
83 | case ElementalType.Hydro:
84 | return "水";
85 | case ElementalType.Pyro:
86 | return "火";
87 | case ElementalType.Electro:
88 | return "雷";
89 | case ElementalType.Dendro:
90 | return "草";
91 | case ElementalType.Anemo:
92 | return "风";
93 | case ElementalType.Geo:
94 | return "岩";
95 | default:
96 | throw new ArgumentOutOfRangeException(nameof(type), type, null);
97 | }
98 | }
99 |
100 | public static string ToLowerString(this ElementalType type)
101 | {
102 | return type.ToString().ToLower();
103 | }
104 | }
105 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Core/Model/RollPhaseDice.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Utils;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Drawing;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace GeniusInvokationAutoToy.Core.Model
10 | {
11 | ///
12 | /// 投掷期间骰子
13 | ///
14 | public class RollPhaseDice
15 | {
16 | ///
17 | /// 元素类型
18 | ///
19 | public ElementalType Type { get; set; }
20 |
21 | ///
22 | /// 中心点位置
23 | ///
24 | public Point CenterPosition { get; set; }
25 |
26 | public RollPhaseDice(ElementalType type, Point centerPosition)
27 | {
28 | Type = type;
29 | CenterPosition = centerPosition;
30 | }
31 |
32 | public RollPhaseDice()
33 | {
34 | }
35 |
36 | public override string ToString()
37 | {
38 | return $"Type:{Type},CenterPosition:{CenterPosition}";
39 | }
40 |
41 | public void Click()
42 | {
43 | MouseUtils.Click(CenterPosition.X, CenterPosition.Y);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Core/MyException/DuelEndException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace GeniusInvokationAutoToy.Core.MyException
8 | {
9 | public class DuelEndException: System.Exception
10 | {
11 | public DuelEndException(string message) : base(message)
12 | {
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Core/MyException/RetryException.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.Forms;
7 |
8 | namespace GeniusInvokationAutoToy.Core.MyException
9 | {
10 | public class RetryException : System.Exception
11 | {
12 | public RetryException() : base()
13 | {
14 | }
15 |
16 | public RetryException(string message) : base(message)
17 | {
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Core/YuanShenWindow.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Utils;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace GeniusInvokationAutoToy.Core
13 | {
14 | public class YuanShenWindow
15 | {
16 | public static uint WM_LBUTTONDOWN = 0x201; //按下鼠标左键
17 |
18 | public static uint WM_LBUTTONUP = 0x202; //释放鼠标左键
19 |
20 |
21 | private IntPtr hWnd;
22 | public YuanShenWindow()
23 | {
24 |
25 | }
26 |
27 | public bool FindYSHandle()
28 | {
29 | var pros = Process.GetProcessesByName("YuanShen");
30 | if (pros.Any())
31 | {
32 | hWnd = pros[0].MainWindowHandle;
33 | return true;
34 | }
35 | else
36 | {
37 | pros = Process.GetProcessesByName("GenshinImpact");
38 | if (pros.Any())
39 | {
40 | hWnd = pros[0].MainWindowHandle;
41 | return true;
42 | }
43 | else
44 | {
45 | return false;
46 | }
47 | }
48 | }
49 |
50 | public void Focus()
51 | {
52 | Native.SendMessage(hWnd, 0x0112, (IntPtr)0xF120, (IntPtr)0);
53 | Native.SetForegroundWindow(hWnd);
54 | }
55 |
56 | public Rectangle GetSize()
57 | {
58 | Native.RECT rc = new Native.RECT();
59 | Native.GetWindowRect(hWnd, ref rc);
60 | return new Rectangle(rc.Left, rc.Top, rc.Right - rc.Left, rc.Bottom - rc.Top);
61 | }
62 |
63 | public void MouseLeftButtonDown()
64 | {
65 | IntPtr p = (IntPtr)((0 << 16) | 0);
66 | Native.PostMessage(hWnd, WM_LBUTTONDOWN, IntPtr.Zero, p);
67 |
68 | }
69 |
70 | public void MouseLeftButtonUp()
71 | {
72 | IntPtr p = (IntPtr)((0 << 16) | 0);
73 | Native.PostMessage(hWnd, WM_LBUTTONUP, IntPtr.Zero, p);
74 | }
75 |
76 | public void MouseClick(int x, int y)
77 | {
78 | IntPtr p = (IntPtr)((y << 16) | x);
79 | Native.PostMessage(hWnd, WM_LBUTTONDOWN, IntPtr.Zero, p);
80 | Thread.Sleep(100);
81 | Native.PostMessage(hWnd, WM_LBUTTONUP, IntPtr.Zero, p);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/FormMain.Designer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GeniusInvokationAutoToy
3 | {
4 | partial class FormMain
5 | {
6 | ///
7 | /// 必需的设计器变量。
8 | ///
9 | private System.ComponentModel.IContainer components = null;
10 |
11 | ///
12 | /// 清理所有正在使用的资源。
13 | ///
14 | /// 如果应释放托管资源,为 true;否则为 false。
15 | protected override void Dispose(bool disposing)
16 | {
17 | if (disposing && (components != null))
18 | {
19 | components.Dispose();
20 | }
21 | base.Dispose(disposing);
22 | }
23 |
24 | #region Windows 窗体设计器生成的代码
25 |
26 | ///
27 | /// 设计器支持所需的方法 - 不要修改
28 | /// 使用代码编辑器修改此方法的内容。
29 | ///
30 | private void InitializeComponent()
31 | {
32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain));
33 | this.rtbConsole = new System.Windows.Forms.RichTextBox();
34 | this.chkTopMost = new System.Windows.Forms.CheckBox();
35 | this.btnSwitch = new System.Windows.Forms.Button();
36 | this.linkLabel1 = new System.Windows.Forms.LinkLabel();
37 | this.lblYSStatus = new System.Windows.Forms.Label();
38 | this.label1 = new System.Windows.Forms.Label();
39 | this.label2 = new System.Windows.Forms.Label();
40 | this.label3 = new System.Windows.Forms.Label();
41 | this.cboGameResolution = new System.Windows.Forms.ComboBox();
42 | this.cboStrategy = new System.Windows.Forms.ComboBox();
43 | this.SuspendLayout();
44 | //
45 | // rtbConsole
46 | //
47 | this.rtbConsole.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
48 | this.rtbConsole.Location = new System.Drawing.Point(9, 93);
49 | this.rtbConsole.Margin = new System.Windows.Forms.Padding(2);
50 | this.rtbConsole.Name = "rtbConsole";
51 | this.rtbConsole.Size = new System.Drawing.Size(387, 390);
52 | this.rtbConsole.TabIndex = 7;
53 | this.rtbConsole.Text = "";
54 | this.rtbConsole.TextChanged += new System.EventHandler(this.rtbConsole_TextChanged);
55 | //
56 | // chkTopMost
57 | //
58 | this.chkTopMost.AutoSize = true;
59 | this.chkTopMost.Location = new System.Drawing.Point(142, 14);
60 | this.chkTopMost.Margin = new System.Windows.Forms.Padding(2);
61 | this.chkTopMost.Name = "chkTopMost";
62 | this.chkTopMost.Size = new System.Drawing.Size(72, 16);
63 | this.chkTopMost.TabIndex = 9;
64 | this.chkTopMost.Text = "置顶界面";
65 | this.chkTopMost.UseVisualStyleBackColor = true;
66 | this.chkTopMost.CheckedChanged += new System.EventHandler(this.chkTopMost_CheckedChanged);
67 | //
68 | // btnSwitch
69 | //
70 | this.btnSwitch.Location = new System.Drawing.Point(266, 38);
71 | this.btnSwitch.Margin = new System.Windows.Forms.Padding(2);
72 | this.btnSwitch.Name = "btnSwitch";
73 | this.btnSwitch.Size = new System.Drawing.Size(130, 51);
74 | this.btnSwitch.TabIndex = 10;
75 | this.btnSwitch.Text = "开始自动打牌(F11)";
76 | this.btnSwitch.UseVisualStyleBackColor = true;
77 | this.btnSwitch.Click += new System.EventHandler(this.btnSwitch_Click);
78 | //
79 | // linkLabel1
80 | //
81 | this.linkLabel1.AutoSize = true;
82 | this.linkLabel1.Location = new System.Drawing.Point(219, 15);
83 | this.linkLabel1.Name = "linkLabel1";
84 | this.linkLabel1.Size = new System.Drawing.Size(113, 12);
85 | this.linkLabel1.TabIndex = 11;
86 | this.linkLabel1.TabStop = true;
87 | this.linkLabel1.Text = "软件主页(免费开源)";
88 | this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
89 | //
90 | // lblYSStatus
91 | //
92 | this.lblYSStatus.AutoSize = true;
93 | this.lblYSStatus.ForeColor = System.Drawing.Color.Red;
94 | this.lblYSStatus.Location = new System.Drawing.Point(80, 15);
95 | this.lblYSStatus.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
96 | this.lblYSStatus.Name = "lblYSStatus";
97 | this.lblYSStatus.Size = new System.Drawing.Size(41, 12);
98 | this.lblYSStatus.TabIndex = 19;
99 | this.lblYSStatus.Text = "未启动";
100 | //
101 | // label1
102 | //
103 | this.label1.AutoSize = true;
104 | this.label1.Location = new System.Drawing.Point(11, 15);
105 | this.label1.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
106 | this.label1.Name = "label1";
107 | this.label1.Size = new System.Drawing.Size(65, 12);
108 | this.label1.TabIndex = 18;
109 | this.label1.Text = "原神状态:";
110 | //
111 | // label2
112 | //
113 | this.label2.AutoSize = true;
114 | this.label2.Location = new System.Drawing.Point(11, 43);
115 | this.label2.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
116 | this.label2.Name = "label2";
117 | this.label2.Size = new System.Drawing.Size(65, 12);
118 | this.label2.TabIndex = 22;
119 | this.label2.Text = "卡牌策略:";
120 | //
121 | // label3
122 | //
123 | this.label3.AutoSize = true;
124 | this.label3.Location = new System.Drawing.Point(11, 71);
125 | this.label3.Margin = new System.Windows.Forms.Padding(2, 0, 2, 0);
126 | this.label3.Name = "label3";
127 | this.label3.Size = new System.Drawing.Size(77, 12);
128 | this.label3.TabIndex = 23;
129 | this.label3.Text = "游戏分辨率:";
130 | //
131 | // cboGameResolution
132 | //
133 | this.cboGameResolution.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
134 | this.cboGameResolution.Enabled = false;
135 | this.cboGameResolution.FormattingEnabled = true;
136 | this.cboGameResolution.Items.AddRange(new object[] {
137 | "1920x1080"});
138 | this.cboGameResolution.Location = new System.Drawing.Point(99, 69);
139 | this.cboGameResolution.Margin = new System.Windows.Forms.Padding(2);
140 | this.cboGameResolution.Name = "cboGameResolution";
141 | this.cboGameResolution.Size = new System.Drawing.Size(149, 20);
142 | this.cboGameResolution.TabIndex = 21;
143 | //
144 | // cboStrategy
145 | //
146 | this.cboStrategy.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
147 | this.cboStrategy.FormattingEnabled = true;
148 | this.cboStrategy.Location = new System.Drawing.Point(99, 41);
149 | this.cboStrategy.Margin = new System.Windows.Forms.Padding(2);
150 | this.cboStrategy.Name = "cboStrategy";
151 | this.cboStrategy.Size = new System.Drawing.Size(149, 20);
152 | this.cboStrategy.TabIndex = 20;
153 | //
154 | // FormMain
155 | //
156 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
157 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
158 | this.ClientSize = new System.Drawing.Size(407, 494);
159 | this.Controls.Add(this.label3);
160 | this.Controls.Add(this.label2);
161 | this.Controls.Add(this.cboGameResolution);
162 | this.Controls.Add(this.cboStrategy);
163 | this.Controls.Add(this.lblYSStatus);
164 | this.Controls.Add(this.label1);
165 | this.Controls.Add(this.linkLabel1);
166 | this.Controls.Add(this.btnSwitch);
167 | this.Controls.Add(this.chkTopMost);
168 | this.Controls.Add(this.rtbConsole);
169 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
170 | this.Margin = new System.Windows.Forms.Padding(2);
171 | this.Name = "FormMain";
172 | this.Text = "原神自动打牌(自动七胜召唤对局)";
173 | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormMain_FormClosed);
174 | this.Load += new System.EventHandler(this.FormMain_Load);
175 | this.ResumeLayout(false);
176 | this.PerformLayout();
177 |
178 | }
179 |
180 | #endregion
181 | private System.Windows.Forms.RichTextBox rtbConsole;
182 | private System.Windows.Forms.CheckBox chkTopMost;
183 | private System.Windows.Forms.Button btnSwitch;
184 | private System.Windows.Forms.LinkLabel linkLabel1;
185 | private System.Windows.Forms.Label lblYSStatus;
186 | private System.Windows.Forms.Label label1;
187 | private System.Windows.Forms.Label label2;
188 | private System.Windows.Forms.Label label3;
189 | private System.Windows.Forms.ComboBox cboGameResolution;
190 | private System.Windows.Forms.ComboBox cboStrategy;
191 | }
192 | }
193 |
194 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/FormMain.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Core;
2 | using GeniusInvokationAutoToy.Forms.Hotkey;
3 | using GeniusInvokationAutoToy.Strategy;
4 | using GeniusInvokationAutoToy.Strategy.Model;
5 | using GeniusInvokationAutoToy.Strategy.Script;
6 | using GeniusInvokationAutoToy.Utils;
7 | using System;
8 | using System.Diagnostics;
9 | using System.Drawing;
10 | using System.IO;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading;
14 | using System.Threading.Tasks;
15 | using System.Windows.Forms;
16 |
17 |
18 | namespace GeniusInvokationAutoToy
19 | {
20 | public partial class FormMain : Form
21 | {
22 | private static NLog.Logger logger;
23 |
24 | private YuanShenWindow window = new YuanShenWindow();
25 |
26 | private bool isAutoPlaying = false;
27 |
28 | private string thisVersion;
29 |
30 | CancellationTokenSource cts;
31 |
32 | public FormMain()
33 | {
34 | InitializeComponent();
35 | }
36 |
37 | public void RtbConsoleDeleteLine()
38 | {
39 | Invoke(new Action(() =>
40 | {
41 | rtbConsole.Lines = rtbConsole.Lines.Take(rtbConsole.Lines.Length - 2).ToArray();
42 | rtbConsole.Text += Environment.NewLine;
43 | }));
44 | }
45 |
46 | private void FormMain_Load(object sender, EventArgs e)
47 | {
48 | logger = NLog.LogManager.GetCurrentClassLogger();
49 | MyLogger.formMain = this;
50 | // 标题加上版本号
51 | string currentVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
52 | if (currentVersion.Length > 3)
53 | {
54 | thisVersion = currentVersion.Substring(0, 3);
55 | currentVersion = " v" + thisVersion;
56 | }
57 |
58 | this.Text += currentVersion;
59 | GAHelper.Instance.RequestPageView($"七圣召唤自动打牌_{thisVersion}", $"进入七圣召唤自动打牌{thisVersion}版本主界面");
60 |
61 |
62 | rtbConsole.Text = @"软件在Github上开源且免费 by huiyadanli
63 |
64 | 支持角色邀请、每周来客挑战、大世界NPC挑战(部分场景不支持、或者打不过/拿不满奖励)。
65 |
66 | 现在已经支持出现以下异常情况时继续进行对局:1.角色被动切换角色,比如超载、琴/砂糖技能;2.当前角色无法行动,比如冻结、被泡泡困住(水深渊法师技能)
67 |
68 | 使用方法:
69 | 1、牌组必须是和策略一致,比如【莫娜、砂糖、琴】或者【刻晴、雷电将军、甘雨】等,顺序不能变,带什么牌无所谓。策略可以自定义,放在软件所在目录的 strategy 文件夹下,格式参考自带的策略。
70 | 2、只支持1920x1080窗口或全屏游戏,游戏整个界面不能被其他窗口遮挡!
71 | 3、在游戏内进入七圣召唤对局,到初始手牌界面
72 | 4、然后直接点击开始自动打牌,双手离开键盘鼠标(快捷键F11)。
73 | ";
74 |
75 | LoadCustomScript();
76 | YSStatus();
77 |
78 | cboGameResolution.SelectedIndex = 0;
79 | if (cboStrategy.Items.Count - 1 >= Properties.Settings.Default.CboStrategySelectIndex)
80 | {
81 | cboStrategy.SelectedIndex = Properties.Settings.Default.CboStrategySelectIndex;
82 | }
83 | else
84 | {
85 | cboStrategy.SelectedIndex = 0;
86 | }
87 |
88 | chkTopMost.Checked = Properties.Settings.Default.TopMostChecked;
89 |
90 | try
91 | {
92 | RegisterHotKey("F11");
93 | }
94 | catch (Exception ex)
95 | {
96 | MyLogger.Warn(ex.Message);
97 | MessageBox.Show(ex.Message, "热键注册失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
98 | }
99 |
100 | //RichTextBoxTarget target = new RichTextBoxTarget();
101 | //target.Layout = "${longdate} [${threadname:whenEmpty=${threadid}}] ${uppercase:${level}} ${message:withException=true} ${all-event-properties}";
102 | //target.TargetRichTextBox = rtbConsole;
103 | //target.UseDefaultRowColoringRules = true;
104 | //NLog.Config.SimpleConfigurator.ConfigureForTargetLogging(target, NLog.LogLevel.Trace);
105 |
106 | }
107 |
108 | private bool YSStatus()
109 | {
110 | if (window.FindYSHandle())
111 | {
112 | lblYSStatus.ForeColor = Color.Green;
113 | lblYSStatus.Text = "已启动";
114 | return true;
115 | }
116 | else
117 | {
118 | lblYSStatus.ForeColor = Color.Red;
119 | lblYSStatus.Text = "未启动";
120 | return false;
121 | }
122 | }
123 |
124 | private void LoadCustomScript()
125 | {
126 | string[] files = Directory.GetFiles(Path.Combine(Application.StartupPath, "strategy"), "*.*",
127 | SearchOption.AllDirectories);
128 |
129 | foreach (string file in files)
130 | {
131 | if (file.EndsWith(".txt"))
132 | {
133 | string fileName = Path.GetFileNameWithoutExtension(file);
134 | cboStrategy.Items.Add(fileName);
135 | }
136 | }
137 | }
138 |
139 | private async void StartGame()
140 | {
141 | if (!window.FindYSHandle())
142 | {
143 | MyLogger.Warn("未找到原神进程,请先启动原神!");
144 | return;
145 | }
146 |
147 | Duel duel = ScriptParser.Parse(File.ReadAllText(Path.Combine(Application.StartupPath, "strategy",
148 | cboStrategy.Text + ".txt"), Encoding.UTF8));
149 | if (duel != null)
150 | {
151 | window.Focus();
152 |
153 | rtbConsole.Text = ""; // 清空日志
154 |
155 | cts = new CancellationTokenSource();
156 |
157 | await duel.CustomStrategyRunAsync(cts);
158 |
159 | // 打完了切回来
160 | isAutoPlaying = false;
161 | btnSwitch.Text = "开始自动打牌(F11)";
162 | }
163 | else
164 | {
165 | throw new Exception("加载打牌策略失败");
166 | }
167 | }
168 |
169 | private void StopGame()
170 | {
171 | cts?.Cancel();
172 | }
173 |
174 | private void btnSwitch_Click(object sender, EventArgs e)
175 | {
176 | if (!isAutoPlaying)
177 | {
178 | StartGame();
179 | isAutoPlaying = true;
180 | btnSwitch.Text = "关闭自动打牌(F11)";
181 | }
182 | else
183 | {
184 | StopGame();
185 | isAutoPlaying = false;
186 | btnSwitch.Text = "开始自动打牌(F11)";
187 | }
188 | }
189 |
190 | private void chkTopMost_CheckedChanged(object sender, EventArgs e)
191 | {
192 | this.TopMost = chkTopMost.Checked;
193 | }
194 |
195 | private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
196 | {
197 | Properties.Settings.Default.TopMostChecked = chkTopMost.Checked;
198 | Properties.Settings.Default.CboStrategySelectIndex = cboStrategy.SelectedIndex;
199 | //Properties.Settings.Default.CboGameResolutionSelectIndex = cboGameResolution.SelectedIndex;
200 | Properties.Settings.Default.Save();
201 | }
202 |
203 | private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
204 | {
205 | Process.Start("https://github.com/babalae/genius-invokation-auto-toy");
206 | }
207 |
208 | #region Hotkey
209 |
210 | private Hotkey hotkey;
211 | private HotkeyHook hotkeyHook;
212 |
213 | private void rtbConsole_TextChanged(object sender, EventArgs e)
214 | {
215 | rtbConsole.SelectionStart = rtbConsole.Text.Length;
216 | rtbConsole.ScrollToCaret();
217 | }
218 |
219 | public void RegisterHotKey(string hotkeyStr)
220 | {
221 | if (string.IsNullOrEmpty(hotkeyStr))
222 | {
223 | UnregisterHotKey();
224 | return;
225 | }
226 |
227 | hotkey = new Hotkey(hotkeyStr);
228 |
229 | if (hotkeyHook != null)
230 | {
231 | hotkeyHook.Dispose();
232 | }
233 |
234 | hotkeyHook = new HotkeyHook();
235 | // register the event that is fired after the key press.
236 | hotkeyHook.KeyPressed += new EventHandler(btnSwitch_Click);
237 | hotkeyHook.RegisterHotKey(hotkey.ModifierKey, hotkey.Key);
238 | }
239 |
240 | public void UnregisterHotKey()
241 | {
242 | if (hotkeyHook != null)
243 | {
244 | hotkeyHook.UnregisterHotKey();
245 | hotkeyHook.Dispose();
246 | }
247 | }
248 |
249 | #endregion
250 | }
251 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/FormMask.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace GeniusInvokationAutoToy
2 | {
3 | partial class FormMask
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.SuspendLayout();
32 | //
33 | // FormMask
34 | //
35 | this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
36 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
37 | this.ClientSize = new System.Drawing.Size(545, 399);
38 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
39 | this.Name = "FormMask";
40 | this.Text = "FormMask";
41 | this.TopMost = true;
42 | this.Load += new System.EventHandler(this.FormMask_Load);
43 | this.ResumeLayout(false);
44 |
45 | }
46 |
47 | #endregion
48 | }
49 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/FormMask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Runtime.InteropServices;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 | using System.Windows.Forms;
12 |
13 | namespace GeniusInvokationAutoToy
14 | {
15 | ///
16 | /// https://stackoverflow.com/questions/21896080/how-to-make-non-interactive-graphical-overlay-on-top-of-another-program-in-c
17 | /// edit by huiyadanli
18 | ///
19 | public partial class FormMask : Form
20 | {
21 | BackgroundWorker bw = new BackgroundWorker();
22 | Random rand = new Random(DateTime.Now.Millisecond);
23 |
24 | [DllImport("user32.dll")]
25 | [return: MarshalAs(UnmanagedType.Bool)]
26 | static extern bool BringWindowToTop(IntPtr hWnd);
27 |
28 | [DllImport("user32.dll")]
29 | [return: MarshalAs(UnmanagedType.Bool)]
30 | static extern bool SetForegroundWindow(IntPtr hWnd);
31 |
32 | [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
33 | public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy,
34 | int wFlags);
35 |
36 |
37 | [DllImport("user32.dll")]
38 | static extern int
39 | SendMessage(IntPtr hWnd, uint wMsg, UIntPtr wParam, IntPtr lParam); //used for maximizing the screen
40 |
41 | const int WM_SYSCOMMAND = 0x0112; //used for maximizing the screen.
42 | const int myWParam = 0xf120; //used for maximizing the screen.
43 | const int myLparam = 0x5073d; //used for maximizing the screen.
44 |
45 |
46 | int oldWindowLong;
47 |
48 | [Flags]
49 | enum WindowStyles : uint
50 | {
51 | WS_OVERLAPPED = 0x00000000,
52 | WS_POPUP = 0x80000000,
53 | WS_CHILD = 0x40000000,
54 | WS_MINIMIZE = 0x20000000,
55 | WS_VISIBLE = 0x10000000,
56 | WS_DISABLED = 0x08000000,
57 | WS_CLIPSIBLINGS = 0x04000000,
58 | WS_CLIPCHILDREN = 0x02000000,
59 | WS_MAXIMIZE = 0x01000000,
60 | WS_BORDER = 0x00800000,
61 | WS_DLGFRAME = 0x00400000,
62 | WS_VSCROLL = 0x00200000,
63 | WS_HSCROLL = 0x00100000,
64 | WS_SYSMENU = 0x00080000,
65 | WS_THICKFRAME = 0x00040000,
66 | WS_GROUP = 0x00020000,
67 | WS_TABSTOP = 0x00010000,
68 |
69 | WS_MINIMIZEBOX = 0x00020000,
70 | WS_MAXIMIZEBOX = 0x00010000,
71 |
72 | WS_CAPTION = WS_BORDER | WS_DLGFRAME,
73 | WS_TILED = WS_OVERLAPPED,
74 | WS_ICONIC = WS_MINIMIZE,
75 | WS_SIZEBOX = WS_THICKFRAME,
76 | WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW,
77 |
78 | WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX |
79 | WS_MAXIMIZEBOX,
80 | WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
81 | WS_CHILDWINDOW = WS_CHILD,
82 |
83 | //Extended Window Styles
84 |
85 | WS_EX_DLGMODALFRAME = 0x00000001,
86 | WS_EX_NOPARENTNOTIFY = 0x00000004,
87 | WS_EX_TOPMOST = 0x00000008,
88 | WS_EX_ACCEPTFILES = 0x00000010,
89 | WS_EX_TRANSPARENT = 0x00000020,
90 |
91 | //#if(WINVER >= 0x0400)
92 |
93 | WS_EX_MDICHILD = 0x00000040,
94 | WS_EX_TOOLWINDOW = 0x00000080,
95 | WS_EX_WINDOWEDGE = 0x00000100,
96 | WS_EX_CLIENTEDGE = 0x00000200,
97 | WS_EX_CONTEXTHELP = 0x00000400,
98 |
99 | WS_EX_RIGHT = 0x00001000,
100 | WS_EX_LEFT = 0x00000000,
101 | WS_EX_RTLREADING = 0x00002000,
102 | WS_EX_LTRREADING = 0x00000000,
103 | WS_EX_LEFTSCROLLBAR = 0x00004000,
104 | WS_EX_RIGHTSCROLLBAR = 0x00000000,
105 |
106 | WS_EX_CONTROLPARENT = 0x00010000,
107 | WS_EX_STATICEDGE = 0x00020000,
108 | WS_EX_APPWINDOW = 0x00040000,
109 |
110 | WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE),
111 | WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST),
112 | //#endif /* WINVER >= 0x0400 */
113 |
114 | //#if(WIN32WINNT >= 0x0500)
115 |
116 | WS_EX_LAYERED = 0x00080000,
117 | //#endif /* WIN32WINNT >= 0x0500 */
118 |
119 | //#if(WINVER >= 0x0500)
120 |
121 | WS_EX_NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children
122 | WS_EX_LAYOUTRTL = 0x00400000, // Right to left mirroring
123 | //#endif /* WINVER >= 0x0500 */
124 |
125 | //#if(WIN32WINNT >= 0x0500)
126 |
127 | WS_EX_COMPOSITED = 0x02000000,
128 |
129 | WS_EX_NOACTIVATE = 0x08000000
130 | //#endif /* WIN32WINNT >= 0x0500 */
131 | }
132 |
133 | public enum GetWindowLongConst
134 | {
135 | GWL_WNDPROC = (-4),
136 | GWL_HINSTANCE = (-6),
137 | GWL_HWNDPARENT = (-8),
138 | GWL_STYLE = (-16),
139 | GWL_EXSTYLE = (-20),
140 | GWL_USERDATA = (-21),
141 | GWL_ID = (-12)
142 | }
143 |
144 | public enum LWA
145 | {
146 | ColorKey = 0x1,
147 | Alpha = 0x2,
148 | }
149 |
150 | [DllImport("user32.dll", SetLastError = true)]
151 | static extern int GetWindowLong(IntPtr hWnd, int nIndex);
152 |
153 | [DllImport("user32.dll")]
154 | static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
155 |
156 | [DllImport("user32.dll")]
157 | static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);
158 |
159 | ///
160 | /// Make the form (specified by its handle) a window that supports transparency.
161 | ///
162 | /// The window to make transparency supporting
163 | public void SetFormTransparent(IntPtr Handle)
164 | {
165 | oldWindowLong = GetWindowLong(Handle, (int)GetWindowLongConst.GWL_EXSTYLE);
166 | SetWindowLong(Handle, (int)GetWindowLongConst.GWL_EXSTYLE,
167 | Convert.ToInt32(oldWindowLong | (uint)WindowStyles.WS_EX_LAYERED |
168 | (uint)WindowStyles.WS_EX_TRANSPARENT));
169 | }
170 |
171 | ///
172 | /// Make the form (specified by its handle) a normal type of window (doesn't support transparency).
173 | ///
174 | /// The Window to make normal
175 | public void SetFormNormal(IntPtr Handle)
176 | {
177 | SetWindowLong(Handle, (int)GetWindowLongConst.GWL_EXSTYLE,
178 | Convert.ToInt32(oldWindowLong | (uint)WindowStyles.WS_EX_LAYERED));
179 | }
180 |
181 | ///
182 | /// Makes the form change White to Transparent and clickthrough-able
183 | /// Can be modified to make the form translucent (with different opacities) and change the Transparency Color.
184 | ///
185 | public void SetTheLayeredWindowAttribute()
186 | {
187 | uint transparentColor = 0xffffffff;
188 |
189 | SetLayeredWindowAttributes(this.Handle, transparentColor, 125, 0x2);
190 |
191 | this.TransparencyKey = Color.White;
192 | }
193 |
194 | ///
195 | /// Finds the Size of all computer screens combined (assumes screens are left to right, not above and below).
196 | ///
197 | /// The width and height of all screens combined
198 | public static Size getFullScreensSize()
199 | {
200 | int height = int.MinValue;
201 | int width = 0;
202 |
203 | foreach (Screen screen in System.Windows.Forms.Screen.AllScreens)
204 | {
205 | //take largest height
206 | height = Math.Max(screen.WorkingArea.Height, height);
207 |
208 | width += screen.Bounds.Width;
209 | }
210 |
211 | return new Size(width, height);
212 | }
213 |
214 | ///
215 | /// Finds the top left pixel position (with multiple screens this is often not 0,0)
216 | ///
217 | /// Position of top left pixel
218 | public static Point getTopLeft()
219 | {
220 | int minX = int.MaxValue;
221 | int minY = int.MaxValue;
222 |
223 | foreach (Screen screen in System.Windows.Forms.Screen.AllScreens)
224 | {
225 | minX = Math.Min(screen.WorkingArea.Left, minX);
226 | minY = Math.Min(screen.WorkingArea.Top, minY);
227 | }
228 |
229 | return new Point(minX, minY);
230 | }
231 |
232 | public FormMask(int x, int y, int w, int h)
233 | {
234 | InitializeComponent();
235 |
236 | this.Opacity = .5D; //Make trasparent
237 | this.DoubleBuffered = true;
238 |
239 | MaximizeEverything(x, y, w, h);
240 |
241 | SetFormTransparent(this.Handle);
242 |
243 | SetTheLayeredWindowAttribute();
244 |
245 | //BackgroundWorker tmpBw = new BackgroundWorker();
246 | //tmpBw.DoWork += new DoWorkEventHandler(bw_DoWork);
247 |
248 | //this.bw = tmpBw;
249 |
250 | //this.bw.RunWorkerAsync();
251 | }
252 |
253 | private void MaximizeEverything(int x, int y, int w, int h)
254 | {
255 | this.Location = new Point(x, y);
256 | this.Size = new Size(w, h);
257 |
258 | SendMessage(this.Handle, WM_SYSCOMMAND, (UIntPtr)myWParam, (IntPtr)myLparam);
259 | }
260 |
261 | private void bw_DoWork(object sender, DoWorkEventArgs e)
262 | {
263 | BackgroundWorker worker = sender as BackgroundWorker;
264 |
265 | int numRedLines = 500;
266 | int numWhiteLines = 1000;
267 |
268 | Size fullSize = getFullScreensSize();
269 | Point topLeft = getTopLeft();
270 |
271 | using (Pen redPen = new Pen(Color.Red, 10f), whitePen = new Pen(Color.White, 10f))
272 | {
273 | using (Graphics formGraphics = this.CreateGraphics())
274 | {
275 | while (true)
276 | {
277 | bool makeRedLines = true;
278 |
279 | for (int i = 0; i < numRedLines + numWhiteLines; i++)
280 | {
281 | if (i > numRedLines)
282 | {
283 | makeRedLines = false;
284 | }
285 |
286 | //Choose points for random lines...but don't draw over the top 100 px of the screen so you can
287 | //still find the stop run button.
288 | int pX = rand.Next(0, (-1 * topLeft.X) + fullSize.Width);
289 | int pY = rand.Next(100, (-1 * topLeft.Y) + fullSize.Height);
290 |
291 | int qX = rand.Next(0, (-1 * topLeft.X) + fullSize.Width);
292 | int qY = rand.Next(100, (-1 * topLeft.Y) + fullSize.Height);
293 |
294 | if (makeRedLines)
295 | {
296 | formGraphics.DrawLine(redPen, pX, pY, qX, qY);
297 | }
298 | else
299 | {
300 | formGraphics.DrawLine(whitePen, pX, pY, qX, qY);
301 | }
302 |
303 | Thread.Sleep(10);
304 | }
305 | }
306 | }
307 | }
308 | }
309 |
310 | private void FormMask_Load(object sender, EventArgs e)
311 | {
312 | }
313 | }
314 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/FormMask.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 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/FormMask1.Designer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace GeniusInvokationAutoToy
3 | {
4 | partial class FormMask1
5 | {
6 | ///
7 | /// Required designer variable.
8 | ///
9 | private System.ComponentModel.IContainer components = null;
10 |
11 | ///
12 | /// Clean up any resources being used.
13 | ///
14 | /// true if managed resources should be disposed; otherwise, false.
15 | protected override void Dispose(bool disposing)
16 | {
17 | if (disposing && (components != null))
18 | {
19 | components.Dispose();
20 | }
21 | base.Dispose(disposing);
22 | }
23 |
24 | #region Windows Form Designer generated code
25 |
26 | ///
27 | /// Required method for Designer support - do not modify
28 | /// the contents of this method with the code editor.
29 | ///
30 | private void InitializeComponent()
31 | {
32 | this.SuspendLayout();
33 | //
34 | // FormMotionArea
35 | //
36 | this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 18F);
37 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
38 | this.ClientSize = new System.Drawing.Size(599, 55);
39 | this.Cursor = System.Windows.Forms.Cursors.SizeAll;
40 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
41 | this.MinimumSize = new System.Drawing.Size(30, 30);
42 | this.Name = "FormMotionArea";
43 | this.Text = "钓鱼运动框选区";
44 | this.TopMost = true;
45 | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormMaskArea_FormClosed);
46 | this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.FormMotionArea_MouseDown);
47 | this.ResumeLayout(false);
48 |
49 | }
50 |
51 | #endregion
52 | }
53 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/FormMask1.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Utils;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Data;
6 | using System.Drawing;
7 | using System.Linq;
8 | using System.Runtime.InteropServices;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Windows.Forms;
12 |
13 | namespace GeniusInvokationAutoToy
14 | {
15 | ///
16 | /// https://github.com/nishanc/csharp-screenshot-winforms/blob/master/Screenshot/SelectArea.cs
17 | ///
18 | public partial class FormMask1 : Form
19 | {
20 | public FormMain FormMainInstance { get; set; }
21 |
22 | public FormMask1()
23 | {
24 | InitializeComponent();
25 | this.Opacity = .5D; //Make trasparent
26 | this.DoubleBuffered = true;
27 | this.SetStyle(ControlStyles.ResizeRedraw, true); // this is to avoid visual artifacts
28 | }
29 |
30 | protected override void OnPaint(PaintEventArgs e)
31 | {
32 | ControlPaint.DrawBorder(e.Graphics,
33 | this.ClientRectangle,
34 | Color.Red,
35 | ButtonBorderStyle.Solid);
36 | }
37 |
38 | private void FormMaskArea_FormClosed(object sender, FormClosedEventArgs e)
39 | {
40 |
41 | }
42 |
43 | #region Moving window by click-drag on a control https://stackoverflow.com/a/13477624/5260872
44 |
45 | public bool DragEnabled { get; set; } = true;
46 |
47 | public const int WM_NCLBUTTONDOWN = 0xA1;
48 | public const int HTCAPTION = 0x2;
49 |
50 | [DllImport("User32.dll")]
51 | public static extern bool ReleaseCapture();
52 |
53 | [DllImport("User32.dll")]
54 | public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
55 |
56 | private void FormMotionArea_MouseDown(object sender, MouseEventArgs e)
57 | {
58 | if (DragEnabled)
59 | {
60 | ReleaseCapture();
61 | SendMessage(Handle, WM_NCLBUTTONDOWN, HTCAPTION, 0);
62 | }
63 | }
64 | #endregion
65 |
66 | #region How to resize a form without a border? https://stackoverflow.com/a/32261547/5260872
67 | private const int
68 | HTLEFT = 10,
69 | HTRIGHT = 11,
70 | HTTOP = 12,
71 | HTTOPLEFT = 13,
72 | HTTOPRIGHT = 14,
73 | HTBOTTOM = 15,
74 | HTBOTTOMLEFT = 16,
75 | HTBOTTOMRIGHT = 17;
76 |
77 | const int _ = 10; // you can rename this variable if you like
78 |
79 | Rectangle Top { get { return new Rectangle(0, 0, this.ClientSize.Width, _); } }
80 | Rectangle Left { get { return new Rectangle(0, 0, _, this.ClientSize.Height); } }
81 |
82 | Rectangle Bottom { get { return new Rectangle(0, this.ClientSize.Height - _, this.ClientSize.Width, _); } }
83 | Rectangle Right { get { return new Rectangle(this.ClientSize.Width - _, 0, _, this.ClientSize.Height); } }
84 | Rectangle TopLeft { get { return new Rectangle(0, 0, _, _); } }
85 | Rectangle TopRight { get { return new Rectangle(this.ClientSize.Width - _, 0, _, _); } }
86 | Rectangle BottomLeft { get { return new Rectangle(0, this.ClientSize.Height - _, _, _); } }
87 | Rectangle BottomRight { get { return new Rectangle(this.ClientSize.Width - _, this.ClientSize.Height - _, _, _); } }
88 |
89 |
90 | protected override void WndProc(ref Message message)
91 | {
92 | base.WndProc(ref message);
93 |
94 | if (message.Msg == 0x84) // WM_NCHITTEST
95 | {
96 | var cursor = this.PointToClient(Cursor.Position);
97 |
98 | if (TopLeft.Contains(cursor)) message.Result = (IntPtr)HTTOPLEFT;
99 | else if (TopRight.Contains(cursor)) message.Result = (IntPtr)HTTOPRIGHT;
100 | else if (BottomLeft.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMLEFT;
101 | else if (BottomRight.Contains(cursor)) message.Result = (IntPtr)HTBOTTOMRIGHT;
102 |
103 | else if (Top.Contains(cursor)) message.Result = (IntPtr)HTTOP;
104 | else if (Left.Contains(cursor)) message.Result = (IntPtr)HTLEFT;
105 | else if (Right.Contains(cursor)) message.Result = (IntPtr)HTRIGHT;
106 | else if (Bottom.Contains(cursor)) message.Result = (IntPtr)HTBOTTOM;
107 | }
108 | }
109 | #endregion
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/FormMask1.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 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Forms/HotKey/Hotkey.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Windows.Forms;
4 |
5 | namespace GeniusInvokationAutoToy.Forms.Hotkey
6 | {
7 | public class Hotkey
8 | {
9 | public bool Alt { get; set; }
10 |
11 | public bool Control { get; set; }
12 |
13 | public bool Shift { get; set; }
14 |
15 | public bool Windows { get; set; }
16 |
17 | private Keys key;
18 | public Keys Key
19 | {
20 | get { return key; }
21 | set
22 | {
23 | if (value != Keys.ControlKey && value != Keys.Alt
24 | && value != Keys.Menu && value != Keys.ShiftKey)
25 | {
26 | key = value;
27 | }
28 | else
29 | {
30 | key = Keys.None;
31 | }
32 | }
33 | }
34 |
35 | public ModifierKeys ModifierKey
36 | {
37 | get
38 | {
39 | return
40 | (Windows ? ModifierKeys.Win : 0) |
41 | (Control ? ModifierKeys.Control : 0) |
42 | (Shift ? ModifierKeys.Shift : 0) |
43 | (Alt ? ModifierKeys.Alt : 0);
44 | }
45 | }
46 |
47 | public Hotkey()
48 | {
49 | Reset();
50 | }
51 |
52 | public Hotkey(string hotkeyStr)
53 | {
54 | try
55 | {
56 | string[] keyStrs = hotkeyStr.Replace(" ", "").Split('+');
57 | foreach (string keyStr in keyStrs)
58 | {
59 | string k = keyStr.ToLower();
60 | if (k == "win")
61 | Windows = true;
62 | else if (k == "ctrl")
63 | Control = true;
64 | else if (k == "shift")
65 | Shift = true;
66 | else if (k == "alt")
67 | Alt = true;
68 | else
69 | Key = (Keys)Enum.Parse(typeof(Keys), keyStr);
70 | }
71 | }
72 | catch
73 | {
74 | throw new ArgumentException("无效的热键");
75 | }
76 | }
77 |
78 | public override string ToString()
79 | {
80 | string str = string.Empty;
81 | if (Key != Keys.None)
82 | {
83 | str = string.Format("{0}{1}{2}{3}{4}",
84 | Windows ? "Win + " : string.Empty,
85 | Control ? "Ctrl + " : string.Empty,
86 | Shift ? "Shift + " : string.Empty,
87 | Alt ? "Alt + " : string.Empty,
88 | Key);
89 | }
90 | return str;
91 | }
92 |
93 | public void Reset()
94 | {
95 | Alt = false;
96 | Control = false;
97 | Shift = false;
98 | Windows = false;
99 | Key = Keys.None;
100 | }
101 |
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Forms/HotKey/HotkeyHook.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Utils;
2 | using System;
3 | using System.Runtime.InteropServices;
4 | using System.Windows.Forms;
5 |
6 | namespace GeniusInvokationAutoToy.Forms.Hotkey
7 | {
8 | ///
9 | /// Code from:
10 | /// https://stackoverflow.com/questions/2450373/set-global-hotkeys-using-c-sharp
11 | ///
12 | public sealed class HotkeyHook : IDisposable
13 | {
14 | ///
15 | /// Represents the window that is used internally to get the messages.
16 | ///
17 | private class Window : NativeWindow, IDisposable
18 | {
19 | private static readonly int WM_HOTKEY = 0x0312;
20 |
21 | public Window()
22 | {
23 | // create the handle for the window.
24 | this.CreateHandle(new CreateParams());
25 | }
26 |
27 | ///
28 | /// Overridden to get the notifications.
29 | ///
30 | ///
31 | protected override void WndProc(ref Message m)
32 | {
33 | base.WndProc(ref m);
34 |
35 | // check if we got a hot key pressed.
36 | if (m.Msg == WM_HOTKEY)
37 | {
38 | // get the keys.
39 | Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
40 | ModifierKeys modifier = (ModifierKeys)((int)m.LParam & 0xFFFF);
41 |
42 | // invoke the event to notify the parent.
43 | if (KeyPressed != null)
44 | KeyPressed(this, new KeyPressedEventArgs(modifier, key));
45 | }
46 | }
47 |
48 | public event EventHandler KeyPressed;
49 |
50 | #region IDisposable Members
51 |
52 | public void Dispose()
53 | {
54 | this.DestroyHandle();
55 | }
56 |
57 | #endregion
58 | }
59 |
60 | private Window _window = new Window();
61 | private int _currentId;
62 |
63 | public HotkeyHook()
64 | {
65 | // register the event of the inner native window.
66 | _window.KeyPressed += delegate (object sender, KeyPressedEventArgs args)
67 | {
68 | if (KeyPressed != null)
69 | KeyPressed(this, args);
70 | };
71 | }
72 |
73 | ///
74 | /// Registers a hot key in the system.
75 | ///
76 | /// The modifiers that are associated with the hot key.
77 | /// The key itself that is associated with the hot key.
78 | public void RegisterHotKey(ModifierKeys modifier, Keys key)
79 | {
80 | // increment the counter.
81 | _currentId = _currentId + 1;
82 |
83 | // register the hot key.
84 | if (!Native.RegisterHotKey(_window.Handle, _currentId, (uint)modifier, (uint)key))
85 | {
86 | if (Marshal.GetLastWin32Error() == 1409)
87 | throw new InvalidOperationException("热键已经被占用");
88 | else
89 | throw new InvalidOperationException("热键注册失败");
90 | }
91 | }
92 |
93 | ///
94 | /// Unregister all hot key.
95 | ///
96 | public void UnregisterHotKey()
97 | {
98 | // unregister all the registered hot keys.
99 | for (int i = _currentId; i > 0; i--)
100 | {
101 | Native.UnregisterHotKey(_window.Handle, i);
102 | }
103 | }
104 |
105 | ///
106 | /// A hot key has been pressed.
107 | ///
108 | public event EventHandler KeyPressed;
109 |
110 | #region IDisposable Members
111 |
112 | public void Dispose()
113 | {
114 | UnregisterHotKey();
115 | // dispose the inner native window.
116 | _window.Dispose();
117 | }
118 |
119 | #endregion
120 | }
121 |
122 | ///
123 | /// Event Args for the event that is fired after the hot key has been pressed.
124 | ///
125 | public class KeyPressedEventArgs : EventArgs
126 | {
127 | public ModifierKeys Modifier { get; }
128 |
129 | public Keys Key { get; }
130 |
131 | internal KeyPressedEventArgs(ModifierKeys modifier, Keys key)
132 | {
133 | Modifier = modifier;
134 | Key = key;
135 | }
136 | }
137 |
138 | ///
139 | /// The enumeration of possible modifiers.
140 | ///
141 | [Flags]
142 | public enum ModifierKeys : uint
143 | {
144 | Alt = 1,
145 | Control = 2,
146 | Shift = 4,
147 | Win = 8
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Forms/HotKey/HotkeyTextBox.cs:
--------------------------------------------------------------------------------
1 |
2 | using GeniusInvokationAutoToy.Utils;
3 | using System;
4 | using System.Collections;
5 | using System.Windows.Forms;
6 |
7 | namespace GeniusInvokationAutoToy.Forms.Hotkey
8 | {
9 | ///
10 | /// A simple control that allows the user to select pretty much any valid hotkey combination
11 | ///
12 | public class HotkeyTextBox : TextBox
13 | {
14 | ///
15 | /// Forces the control to be non-multiline.
16 | ///
17 | public override bool Multiline { get { return false; } }
18 |
19 | // These variables store the current hotkey and modifier(s)
20 | private Hotkey hotkey;
21 |
22 | public bool HasWinKey { get; set; }
23 |
24 | ///
25 | /// Creates a new HotkeyControl
26 | ///
27 | public HotkeyTextBox()
28 | {
29 | hotkey = new Hotkey();
30 |
31 | ContextMenu = new ContextMenu(); // Disable right-clicking
32 | GotFocus += delegate { Native.HideCaret(Handle); };
33 | }
34 |
35 | ///
36 | /// When the hotkey is modified externally, the hotkey string needs to be refreshed.
37 | ///
38 | public void RefreshText(string hotkeyStr = null)
39 | {
40 | if (!string.IsNullOrEmpty(hotkeyStr))
41 | {
42 | hotkey = new Hotkey(hotkeyStr);
43 | }
44 |
45 | hotkey.Windows = HasWinKey;
46 | Text = hotkey.ToString();
47 | }
48 |
49 | ///
50 | /// Update the text in the box to notify the user what combination is currently pressed.
51 | ///
52 | protected override void OnKeyDown(KeyEventArgs e)
53 | {
54 | // Clear the current hotkey
55 | if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
56 | {
57 | hotkey.Reset();
58 | return;
59 | }
60 | else
61 | {
62 | hotkey.Key = e.KeyCode;
63 |
64 | hotkey.Alt = e.Alt;
65 | hotkey.Control = e.Control;
66 | hotkey.Shift = e.Shift;
67 | hotkey.Windows = HasWinKey;
68 | }
69 |
70 | Text = hotkey.ToString();
71 | }
72 |
73 | ///
74 | /// If the current hotkey isn't valid, reset it.
75 | ///
76 | protected override void OnKeyUp(KeyEventArgs e)
77 | {
78 | if (hotkey.Key == Keys.None)
79 | {
80 | Text = "";
81 | }
82 | }
83 |
84 | ///
85 | /// Prevents the whatever entered to show up in the TextBox
86 | ///
87 | protected override void OnKeyPress(KeyPressEventArgs e)
88 | {
89 | e.Handled = true;
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/GeniusInvokationAutoToy.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | AnyCPU
8 | {F17BE4C5-926C-456D-9CC0-606DAE304ED8}
9 | WinExe
10 | GeniusInvokationAutoToy
11 | GeniusInvokationAutoToy
12 | v4.7.2
13 | 512
14 | true
15 | true
16 |
17 |
18 |
19 |
20 |
21 | x64
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE
27 | prompt
28 | 4
29 | true
30 |
31 |
32 | x64
33 | pdbonly
34 | true
35 | bin\Release\
36 | TRACE
37 | prompt
38 | 4
39 | true
40 |
41 |
42 | Raiden.ico
43 |
44 |
45 |
46 | ..\packages\NLog.5.2.0\lib\net46\NLog.dll
47 |
48 |
49 | ..\packages\NLog.Windows.Forms.5.2.0\lib\net35\NLog.Windows.Forms.dll
50 |
51 |
52 | ..\packages\OpenCvSharp4.4.5.3.20210817\lib\net461\OpenCvSharp.dll
53 |
54 |
55 | ..\packages\OpenCvSharp4.4.5.3.20210817\lib\net461\OpenCvSharp.Extensions.dll
56 |
57 |
58 |
59 | ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
60 |
61 |
62 |
63 |
64 | ..\packages\System.Drawing.Common.5.0.2\lib\net461\System.Drawing.Common.dll
65 |
66 |
67 |
68 |
69 | ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
70 |
71 |
72 |
73 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
74 |
75 |
76 | ..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll
77 |
78 |
79 | ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | Form
102 |
103 |
104 | FormMain.cs
105 |
106 |
107 | Form
108 |
109 |
110 | FormMask.cs
111 |
112 |
113 | Form
114 |
115 |
116 | FormMask1.cs
117 |
118 |
119 |
120 |
121 | Component
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | FormMain.cs
150 |
151 |
152 | FormMask.cs
153 |
154 |
155 | FormMask1.cs
156 |
157 |
158 | ResXFileCodeGenerator
159 | Resources.Designer.cs
160 | Designer
161 |
162 |
163 | True
164 | Resources.resx
165 | True
166 |
167 |
168 |
169 | Always
170 |
171 |
172 |
173 | SettingsSingleFileGenerator
174 | Settings.Designer.cs
175 |
176 |
177 | True
178 | Settings.settings
179 | True
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 | 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Nlog.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
14 |
15 |
16 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using System.Windows.Forms;
6 |
7 | namespace GeniusInvokationAutoToy
8 | {
9 | static class Program
10 | {
11 | ///
12 | /// 应用程序的主入口点。
13 | ///
14 | [STAThread]
15 | static void Main()
16 | {
17 | #if DEBUG
18 | Application.EnableVisualStyles();
19 | Application.SetCompatibleTextRenderingDefault(false);
20 | Application.Run(new FormMain());
21 | #else
22 | try
23 | {
24 | Application.EnableVisualStyles();
25 | Application.SetCompatibleTextRenderingDefault(false);
26 | //当前用户是管理员的时候,直接启动应用程序
27 | //如果不是管理员,则使用启动对象启动程序,以确保使用管理员身份运行
28 | //获得当前登录的Windows用户标示
29 | System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
30 | System.Security.Principal.WindowsPrincipal principal = new System.Security.Principal.WindowsPrincipal(identity);
31 | //判断当前登录用户是否为管理员
32 | if (principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator))
33 | {
34 | //如果是管理员,则直接运行
35 | Application.Run(new FormMain());
36 | }
37 | else
38 | {
39 | //创建启动对象
40 | System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
41 | startInfo.UseShellExecute = true;
42 | startInfo.WorkingDirectory = Environment.CurrentDirectory;
43 | startInfo.FileName = Application.ExecutablePath;
44 | //设置启动动作,确保以管理员身份运行
45 | startInfo.Verb = "runas";
46 | try
47 | {
48 | System.Diagnostics.Process.Start(startInfo);
49 | }
50 | catch
51 | {
52 | return;
53 | }
54 | //退出
55 | Application.Exit();
56 | }
57 | }
58 | catch (Exception ex)
59 | {
60 | MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
61 | }
62 | #endif
63 | }
64 |
65 | static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
66 | {
67 | MessageBox.Show(e.Exception.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
68 | }
69 |
70 | static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
71 | {
72 | MessageBox.Show((e.ExceptionObject as Exception).Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // 有关程序集的一般信息由以下
6 | // 控制。更改这些特性值可修改
7 | // 与程序集关联的信息。
8 | [assembly: AssemblyTitle("GeniusInvokationAutoToy")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("GeniusInvokationAutoToy")]
13 | [assembly: AssemblyCopyright("Copyright © 2021")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // 将 ComVisible 设置为 false 会使此程序集中的类型
18 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
19 | //请将此类型的 ComVisible 特性设置为 true。
20 | [assembly: ComVisible(false)]
21 |
22 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
23 | [assembly: Guid("f17be4c5-926c-456d-9cc0-606dae304ed8")]
24 |
25 | // 程序集的版本信息由下列四个值组成:
26 | //
27 | // 主版本
28 | // 次版本
29 | // 生成号
30 | // 修订号
31 | //
32 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
33 | //通过使用 "*",如下所示:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.4.0.0")]
36 | [assembly: AssemblyFileVersion("1.4.0.0")]
37 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace GeniusInvokationAutoToy.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// 一个强类型的资源类,用于查找本地化的字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.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 | /// 返回此类使用的缓存的 ResourceManager 实例。
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("GeniusInvokationAutoToy.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性,对
51 | /// 使用此强类型资源类的所有资源查找执行重写。
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 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/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 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace GeniusInvokationAutoToy.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.6.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.UserScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("False")]
29 | public bool TopMostChecked {
30 | get {
31 | return ((bool)(this["TopMostChecked"]));
32 | }
33 | set {
34 | this["TopMostChecked"] = value;
35 | }
36 | }
37 |
38 | [global::System.Configuration.UserScopedSettingAttribute()]
39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
40 | [global::System.Configuration.DefaultSettingValueAttribute("0")]
41 | public int CboStrategySelectIndex {
42 | get {
43 | return ((int)(this["CboStrategySelectIndex"]));
44 | }
45 | set {
46 | this["CboStrategySelectIndex"] = value;
47 | }
48 | }
49 |
50 | [global::System.Configuration.UserScopedSettingAttribute()]
51 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
52 | [global::System.Configuration.DefaultSettingValueAttribute("0")]
53 | public int CboGameResolutionSelectIndex {
54 | get {
55 | return ((int)(this["CboGameResolutionSelectIndex"]));
56 | }
57 | set {
58 | this["CboGameResolutionSelectIndex"] = value;
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | False
7 |
8 |
9 | 0
10 |
11 |
12 | 0
13 |
14 |
15 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Raiden.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/babalae/genius-invokation-auto-toy/03de89d6f9bbf97c84b58bc27b8e774f1ddf4367/GeniusInvokationAutoToy/Raiden.ico
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Resources/Raiden.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/babalae/genius-invokation-auto-toy/03de89d6f9bbf97c84b58bc27b8e774f1ddf4367/GeniusInvokationAutoToy/Resources/Raiden.ico
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/KeqingRaidenGanyuStrategy.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Core.Model;
2 | using GeniusInvokationAutoToy.Core.MyException;
3 | using GeniusInvokationAutoToy.Core;
4 | using GeniusInvokationAutoToy.Utils;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Text.RegularExpressions;
10 | using System.Threading;
11 | using System.Threading.Tasks;
12 |
13 | namespace GeniusInvokationAutoToy.Strategy
14 | {
15 | [Obsolete]
16 | public class KeqingRaidenGanyuStrategy : BaseStrategy
17 | {
18 | ///
19 | /// 刻晴充能
20 | ///
21 | protected int KeqingEnergyNum;
22 |
23 | ///
24 | /// 莫娜充能
25 | ///
26 | protected int RaidenEnergyNum;
27 |
28 | ///
29 | /// 甘雨充能
30 | ///
31 | protected int GanyuEnergyNum;
32 |
33 | public KeqingRaidenGanyuStrategy(YuanShenWindow window) : base(window)
34 | {
35 | }
36 |
37 |
38 | public override void Run(CancellationTokenSource cts1)
39 | {
40 | cts = cts1;
41 | KeqingRaidenGanyuInit();
42 | try
43 | {
44 | MyLogger.Info("========================================");
45 | MyLogger.Info("对局启动!");
46 | // 对局准备(选择初始手牌、出战角色)
47 | DuelPrepare();
48 |
49 | // 执行回合
50 | MyLogger.Info("--------------第1回合--------------");
51 | Round1();
52 | MyLogger.Info("--------------第2回合--------------");
53 | Round2();
54 | MyLogger.Info("--------------第3回合--------------");
55 | Round3();
56 | MyLogger.Info("--------------第4回合--------------");
57 | Round4();
58 |
59 |
60 | // end
61 | capture.Stop();
62 | MyLogger.Info("没活了,结束自动打牌");
63 | MyLogger.Info("对手还或者的话,麻烦手动终结他吧");
64 | }
65 | catch (TaskCanceledException ex)
66 | {
67 | MyLogger.Info(ex.Message);
68 | }
69 | catch (DuelEndException ex)
70 | {
71 | MyLogger.Info(ex.Message);
72 | }
73 | catch (Exception ex)
74 | {
75 | MyLogger.Error(ex.ToString());
76 | }
77 | finally
78 | {
79 | MyLogger.Info("========================================");
80 | }
81 | }
82 |
83 | public void KeqingRaidenGanyuInit()
84 | {
85 | Init(); // 初始化对局变量
86 | KeqingEnergyNum = 0;
87 | RaidenEnergyNum = 0;
88 | GanyuEnergyNum = 0;
89 | }
90 |
91 | private void DuelPrepare()
92 | {
93 | // 1. 选择初始手牌
94 | Sleep(1000);
95 | MyLogger.Info("开始选择初始手牌");
96 | while (!ClickConfirm())
97 | {
98 | // 循环等待选择卡牌画面
99 | Sleep(1000);
100 | }
101 |
102 | MyLogger.Info("点击确认");
103 |
104 | // 2. 选择出战角色
105 | // 此处选择第2个角色 雷神
106 | MyLogger.Info("等待3s动画...");
107 | Sleep(3000);
108 |
109 | // 是否是再角色出战选择界面
110 | Retry.Do(IsInCharacterPickRetryThrowable, TimeSpan.FromSeconds(1), 5);
111 | MyLogger.Info("识别到已经在角色出战界面,等待1.5s");
112 | Sleep(1500);
113 | // 识别角色所在区域
114 | Retry.Do(() => ChooseCharacterFirst(2), TimeSpan.FromSeconds(1), 5);
115 |
116 | MyLogger.Info("出战雷电将军");
117 |
118 | // 初始化手牌
119 | CurrentCardCount = 5;
120 | }
121 |
122 | ///
123 | /// 第一回合
124 | ///
125 | public void Round1()
126 | {
127 | CurrentDiceCount = 8;
128 | // 0 投骰子
129 | ReRollDice(ElementalType.Electro, ElementalType.Omni);
130 |
131 | // 等待到我的回合 // 投骰子动画时间是不确定的
132 | WaitForMyTurn(1000);
133 |
134 | // 1 回合1 行动1 雷电将军使用1次二技能
135 | MyLogger.Info("回合1 行动1 雷电将军使用1次二技能");
136 | bool useSkillRes = ActionPhaseAutoUseSkill(2, 3, ElementalType.Electro, CurrentDiceCount);
137 | if (!useSkillRes)
138 | {
139 | MyLogger.Warn("没有足够的手牌或元素骰子释放技能,停止自动打牌");
140 | throw new DuelEndException("没有足够的手牌或元素骰子释放技能,停止自动打牌");
141 | }
142 | CurrentDiceCount -=3;
143 |
144 | RaidenEnergyNum++;
145 |
146 | // 等待对方行动完成
147 | WaitForMyTurn(10000);
148 |
149 | // 2 回合1 行动2 雷电将军使用1次一技能
150 | MyLogger.Info("回合1 行动2 雷电将军使用1次一技能");
151 | useSkillRes = ActionPhaseAutoUseSkill(3, 1, ElementalType.Electro, CurrentDiceCount);
152 | if (!useSkillRes)
153 | {
154 | MyLogger.Warn("没有足够的手牌或元素骰子释放技能,停止自动打牌");
155 | throw new DuelEndException("没有足够的手牌或元素骰子释放技能,停止自动打牌");
156 | }
157 | CurrentDiceCount -= 3;
158 | RaidenEnergyNum++;
159 |
160 | // 等待对方行动完成
161 | WaitForMyTurn(10000);
162 |
163 | // 4 回合1 结束 剩下2个骰子
164 | MyLogger.Info("我方点击回合结束");
165 | RoundEnd();
166 |
167 | // 5 等待对方行动+回合结算
168 | WaitOpponentAction();
169 | }
170 |
171 |
172 | ///
173 | /// 第二回合
174 | ///
175 | public void Round2()
176 | {
177 | CurrentDiceCount = 8;
178 | CurrentCardCount += 2;
179 | // 0 投骰子
180 | ReRollDice(ElementalType.Electro, ElementalType.Cryo, ElementalType.Omni);
181 |
182 | // 等待对方行动完成 // 可能是对方先手
183 | WaitForMyTurn(1000);
184 |
185 | MyLogger.Info("回合2 行动1 雷电将军开大");
186 | bool useSkillRes = ActionPhaseAutoUseSkill(1, 4, ElementalType.Electro, CurrentDiceCount);
187 | if (!useSkillRes)
188 | {
189 | // 运气太差直接结束
190 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
191 | throw new DuelEndException("没有足够的手牌或元素骰子释放技能,停止自动打牌");
192 | }
193 | CurrentDiceCount -= 4;
194 |
195 | KeqingEnergyNum += 2;
196 | RaidenEnergyNum = 0;
197 | GanyuEnergyNum += 2;
198 |
199 | // 等待对方行动完成
200 | WaitForMyTurn(15000);
201 |
202 | MyLogger.Info("回合2 行动2 切换甘雨");
203 | SwitchCharacterLater(3);
204 | CurrentDiceCount -= 1;
205 |
206 | // 等待对方行动完成
207 | WaitForMyTurn(10000);
208 |
209 | MyLogger.Info("回合2 行动3 甘雨使用1次二技能");
210 | useSkillRes = ActionPhaseAutoUseSkill(3, 3, ElementalType.Cryo, CurrentDiceCount);
211 | if (!useSkillRes)
212 | {
213 | // 运气太差直接结束
214 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
215 | throw new DuelEndException("没有足够的手牌或元素骰子释放技能,停止自动打牌");
216 | }
217 | CurrentDiceCount -= 3;
218 | GanyuEnergyNum++;
219 |
220 | // 等待对方行动完成
221 | WaitForMyTurn(10000);
222 |
223 | // 4 回合2 结束 剩下0个骰子
224 | MyLogger.Info("我方点击回合结束");
225 | RoundEnd();
226 |
227 | // 5 等待对方行动+回合结算
228 | WaitOpponentAction();
229 | }
230 |
231 |
232 | ///
233 | /// 第三回合
234 | /// 对局可能会胜利
235 | ///
236 | public void Round3()
237 | {
238 | CurrentDiceCount = 8;
239 | CurrentCardCount += 2;
240 | // 0 投骰子
241 | ReRollDice(ElementalType.Electro, ElementalType.Cryo, ElementalType.Omni);
242 |
243 | // 等待对方行动完成 // 可能是对方先手
244 | WaitForMyTurn(1000);
245 |
246 | MyLogger.Info("回合3 行动1 甘雨开大");
247 | bool useSkillRes = ActionPhaseAutoUseSkill(1, 3, ElementalType.Cryo, CurrentDiceCount);
248 | if (!useSkillRes)
249 | {
250 | // 运气太差直接结束
251 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
252 | throw new DuelEndException("没有足够的手牌或元素骰子释放技能,停止自动打牌");
253 | }
254 |
255 | CurrentDiceCount -= 3;
256 | GanyuEnergyNum =0;
257 |
258 | // 等待对方行动完成 // 甘雨大招动画比较长
259 | WaitForMyTurn(15000);
260 |
261 | MyLogger.Info("回合3 行动2 切换刻晴");
262 | SwitchCharacterLater(1);
263 | CurrentDiceCount -= 1;
264 |
265 | // 等待对方行动完成
266 | WaitForMyTurn(10000);
267 |
268 | MyLogger.Info("回合3 行动3 刻晴使用1次二技能");
269 | useSkillRes = ActionPhaseAutoUseSkill(2, 3, ElementalType.Electro, CurrentDiceCount);
270 | if (!useSkillRes)
271 | {
272 | MyLogger.Info("回合3 行动3 二技能无法使用,刻晴尝试使用一技能");
273 | useSkillRes = ActionPhaseAutoUseSkill(3, 1, ElementalType.Electro, CurrentDiceCount);
274 | if (!useSkillRes)
275 | {
276 | // 运气太差直接结束
277 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
278 | throw new DuelEndException("没有足够的手牌或元素骰子释放技能,停止自动打牌");
279 | }
280 | else
281 | {
282 | CurrentDiceCount -= 3;
283 | }
284 | }
285 | else
286 | {
287 | CurrentDiceCount -= 3;
288 | }
289 | KeqingEnergyNum++;
290 |
291 | // 等待对方行动完成
292 | WaitForMyTurn(10000);
293 |
294 | // 4 回合2 结束 剩下0个骰子
295 | MyLogger.Info("我方点击回合结束");
296 | RoundEnd();
297 |
298 | // 5 等待对方行动+回合结算
299 | WaitOpponentAction();
300 | }
301 |
302 | ///
303 | /// 第四回合
304 | /// 对局可能会胜利
305 | ///
306 | public void Round4()
307 | {
308 | CurrentDiceCount = 8;
309 | CurrentCardCount += 2;
310 | // 0 投骰子
311 | ReRollDice(ElementalType.Electro, ElementalType.Omni);
312 |
313 | // 等待对方行动完成 // 可能是对方先手
314 | WaitForMyTurn(1000);
315 |
316 | MyLogger.Info("回合4 行动1 刻晴开大");
317 | bool useSkillRes = ActionPhaseAutoUseSkill(1, 4, ElementalType.Electro, CurrentDiceCount);
318 | if (!useSkillRes)
319 | {
320 | // 运气太差直接结束
321 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
322 | throw new DuelEndException("没有足够的手牌或元素骰子释放技能,停止自动打牌");
323 | }
324 | CurrentDiceCount -= 4;
325 | KeqingEnergyNum = 0;
326 |
327 | // 等待对方行动完成
328 | WaitForMyTurn(10000);
329 |
330 | MyLogger.Info("回合4 行动2 刻晴使用1次二技能");
331 | useSkillRes = ActionPhaseAutoUseSkill(2, 3, ElementalType.Electro, CurrentDiceCount);
332 | if (!useSkillRes)
333 | {
334 | MyLogger.Info("回合4 行动3 二技能无法使用,刻晴尝试使用一技能");
335 | useSkillRes = ActionPhaseAutoUseSkill(3, 1, ElementalType.Electro, CurrentDiceCount);
336 | if (!useSkillRes)
337 | {
338 | // 运气太差直接结束
339 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
340 | throw new DuelEndException("没有足够的手牌或元素骰子释放技能,停止自动打牌");
341 | }
342 | else
343 | {
344 | CurrentDiceCount -= 3;
345 | }
346 | }
347 | else
348 | {
349 | CurrentDiceCount -= 3;
350 | }
351 | KeqingEnergyNum++;
352 | }
353 | }
354 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Model/ActionCommand.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Core.Model;
2 | using GeniusInvokationAutoToy.Utils;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace GeniusInvokationAutoToy.Strategy.Model
10 | {
11 | public class ActionCommand
12 | {
13 | ///
14 | /// 角色
15 | ///
16 | public Character Character { get; set; }
17 |
18 | public ActionEnum Action { get; set; }
19 |
20 | ///
21 | /// 目标编号(技能编号,从右往左)
22 | ///
23 | public int TargetIndex { get; set; }
24 |
25 | public override string ToString()
26 | {
27 | if (Action == ActionEnum.UseSkill)
28 | {
29 | return $"【{Character.Name}】使用【技能{TargetIndex}】";
30 | }
31 | else if (Action == ActionEnum.SwitchLater)
32 | {
33 | return $"【{Character.Name}】切换至【角色{TargetIndex}】";
34 | }
35 | else
36 | {
37 | return base.ToString();
38 | }
39 | }
40 |
41 |
42 | public int GetSpecificElementDiceUseCount()
43 | {
44 | if (Action == ActionEnum.UseSkill)
45 | {
46 | return Character.Skills[TargetIndex].SpecificElementCost;
47 | }
48 | else
49 | {
50 | throw new ArgumentException("未知行动");
51 | }
52 | }
53 |
54 | public int GetAllDiceUseCount()
55 | {
56 | if (Action == ActionEnum.UseSkill)
57 | {
58 | return Character.Skills[TargetIndex].AllCost;
59 | }
60 | else
61 | {
62 | throw new ArgumentException("未知行动");
63 | }
64 | }
65 |
66 | public ElementalType GetDiceUseElementType()
67 | {
68 | if (Action == ActionEnum.UseSkill)
69 | {
70 | return Character.Element;
71 | }
72 | else
73 | {
74 | throw new ArgumentException("未知行动");
75 | }
76 | }
77 |
78 | public bool SwitchLater()
79 | {
80 | return Character.SwitchLater();
81 | }
82 |
83 | public bool UseSkill(Duel duel)
84 | {
85 | return Character.UseSkill(TargetIndex, duel);
86 | }
87 | }
88 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Model/ActionEnum.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Core.Model;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace GeniusInvokationAutoToy.Strategy.Model
9 | {
10 | public enum ActionEnum
11 | {
12 | ChooseFirst, SwitchLater, UseSkill
13 | }
14 |
15 | public static class ActionEnumExtension
16 | {
17 | public static ActionEnum ChineseToActionEnum(this string type)
18 | {
19 | type = type.ToLower();
20 | switch (type)
21 | {
22 | case "出战":
23 | //return ActionEnum.ChooseFirst;
24 | throw new ArgumentOutOfRangeException(nameof(type), type, null);
25 | case "切换":
26 | //return ActionEnum.SwitchLater;
27 | throw new ArgumentOutOfRangeException(nameof(type), type, null);
28 | case "使用":
29 | return ActionEnum.UseSkill;
30 | default:
31 | throw new ArgumentOutOfRangeException(nameof(type), type, null);
32 | }
33 | }
34 |
35 | public static string ToChinese(this ActionEnum type)
36 | {
37 | switch (type)
38 | {
39 | case ActionEnum.ChooseFirst:
40 | return "出战";
41 | case ActionEnum.SwitchLater:
42 | return "切换";
43 | case ActionEnum.UseSkill:
44 | return "使用";
45 | default:
46 | throw new ArgumentOutOfRangeException(nameof(type), type, null);
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Model/Character.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Core.Model;
2 | using GeniusInvokationAutoToy.Utils;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Drawing;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using GeniusInvokationAutoToy.Utils.Extension;
10 | using GeniusInvokationAutoToy.Core.MyException;
11 |
12 | namespace GeniusInvokationAutoToy.Strategy.Model
13 | {
14 | public class Character
15 | {
16 | ///
17 | /// 1-3 所在数组下标一致
18 | ///
19 | public int Index { get; set; }
20 | public string Name { get; set; }
21 | public ElementalType Element { get; set; }
22 | public Skill[] Skills { get; set; }
23 |
24 |
25 | ///
26 | /// 是否被打败
27 | ///
28 | public bool IsDefeated { get; set; }
29 |
30 | ///
31 | /// 充能点
32 | ///
33 | public int Energy { get; set; }
34 |
35 |
36 | ///
37 | /// 充能点来自于图像识别
38 | ///
39 | public int EnergyByRecognition { get; set; }
40 |
41 | ///
42 | /// 角色身上的负面状态
43 | ///
44 | public List StatusList { get; set; } = new List();
45 |
46 | ///
47 | /// 角色区域
48 | ///
49 | public Rectangle Area { get; set; }
50 | ///
51 | /// 血量上方区域,用于判断是否出战
52 | ///
53 | public Rectangle HpUpperArea { get; set; }
54 |
55 | public override string ToString()
56 | {
57 | StringBuilder sb = new StringBuilder();
58 | sb.Append($"角色{Index},");
59 | sb.Append($"充能={EnergyByRecognition},");
60 | if (StatusList?.Count > 0)
61 | {
62 | sb.Append($"状态:{string.Join(",", StatusList)}");
63 | }
64 | return sb.ToString();
65 | }
66 |
67 | public bool ChooseFirst()
68 | {
69 | return MouseUtils.DoubleClick(GameControl.GetInstance().MakeOffset(Area.GetCenterPoint()));
70 | }
71 |
72 | public bool SwitchLater()
73 | {
74 | Point p = GameControl.GetInstance().MakeOffset(Area.GetCenterPoint());
75 | // 选择角色
76 | MouseUtils.Click(p);
77 |
78 | // 点击切人按钮
79 | GameControl.GetInstance().ActionPhasePressSwitchButton();
80 | return true;
81 | }
82 |
83 | ///
84 | /// 角色被打败的时候双击角色牌重新出战
85 | ///
86 | ///
87 | public bool SwitchWhenTakenOut()
88 | {
89 | MyLogger.Info($"有角色被打败,当前选择{Name}出战");
90 | Point p = GameControl.GetInstance().MakeOffset(Area.GetCenterPoint());
91 | // 选择角色
92 | MouseUtils.Click(p);
93 | // 双击切人
94 | GameControl.GetInstance().Sleep(500);
95 | MouseUtils.Click(p);
96 | GameControl.GetInstance().Sleep(300);
97 | return true;
98 | }
99 |
100 | public bool UseSkill(int skillIndex, Duel duel)
101 | {
102 | bool res = GameControl.GetInstance()
103 | .ActionPhaseAutoUseSkill(skillIndex, Skills[skillIndex].SpecificElementCost, Skills[skillIndex].Type, duel);
104 | if (res)
105 | {
106 | return true;
107 | }
108 | else
109 | {
110 | MyLogger.Warn("没有足够的手牌或元素骰子释放技能");
111 | return false;
112 | }
113 | }
114 | }
115 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Model/CharacterStatusEnum.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace GeniusInvokationAutoToy.Strategy.Model
8 | {
9 | public enum CharacterStatusEnum
10 | {
11 | Frozen, Dizziness
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Model/Duel.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Core;
2 | using GeniusInvokationAutoToy.Core.Model;
3 | using GeniusInvokationAutoToy.Core.MyException;
4 | using GeniusInvokationAutoToy.Strategy.Model.Old;
5 | using GeniusInvokationAutoToy.Utils;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Drawing;
9 | using System.Linq;
10 | using System.Runtime.InteropServices;
11 | using System.Text;
12 | using System.Text.RegularExpressions;
13 | using System.Threading;
14 | using System.Threading.Tasks;
15 |
16 | namespace GeniusInvokationAutoToy.Strategy.Model
17 | {
18 | public class Duel
19 | {
20 | public Character CurrentCharacter { get; set; }
21 | public Character[] Characters { get; set; } = new Character[4];
22 |
23 | ///
24 | /// 行动指令队列
25 | ///
26 | public List ActionCommandQueue { get; set; } = new List();
27 |
28 | ///
29 | /// 当前回合数
30 | ///
31 | public int RoundNum { get; set; } = 1;
32 |
33 | ///
34 | /// 角色牌位置
35 | ///
36 | public List CharacterCardRects { get; set; }
37 |
38 | ///
39 | /// 手牌数量
40 | ///
41 | public int CurrentCardCount { get; set; } = 0;
42 |
43 | ///
44 | /// 骰子数量
45 | ///
46 | public int CurrentDiceCount { get; set; } = 0;
47 |
48 |
49 | public CancellationTokenSource Cts { get; set; }
50 |
51 |
52 | public async Task CustomStrategyRunAsync(CancellationTokenSource cts1)
53 | {
54 | await Task.Run(() => { CustomStrategyRun(cts1); });
55 | }
56 |
57 | public void CustomStrategyRun(CancellationTokenSource cts1)
58 | {
59 | Cts = cts1;
60 | try
61 | {
62 | MyLogger.Info("========================================");
63 | MyLogger.Info("对局启动!");
64 |
65 | GameControl.GetInstance().Init(Cts);
66 | GameControl.GetInstance().FocusGameWindow();
67 | Retry.Do(() => GameControl.GetInstance().IsGameFocus(), TimeSpan.FromSeconds(1), 10);
68 | // 对局准备 选择初始手牌
69 | GameControl.GetInstance().CommonDuelPrepare();
70 |
71 |
72 | // 获取角色区域
73 | CharacterCardRects = Retry.Do(() => GameControl.GetInstance().GetCharacterRects(),
74 | TimeSpan.FromSeconds(1.5), 20);
75 | if (CharacterCardRects == null || CharacterCardRects.Count != 3)
76 | {
77 | throw new DuelEndException("未成功获取到角色区域");
78 | }
79 |
80 | for (var i = 1; i < 4; i++)
81 | {
82 | Characters[i].Area = CharacterCardRects[i - 1];
83 | }
84 |
85 | // 出战角色
86 | CurrentCharacter = ActionCommandQueue[0].Character;
87 | CurrentCharacter.ChooseFirst();
88 |
89 | // 开始执行回合
90 | while (true)
91 | {
92 | MyLogger.Info($"--------------第{RoundNum}回合--------------");
93 | ClearCharacterStatus(); // 清空单回合的异常状态
94 | if (RoundNum == 1)
95 | {
96 | CurrentCardCount = 5;
97 | }
98 | else
99 | {
100 | CurrentCardCount += 2;
101 | }
102 |
103 | CurrentDiceCount = 8;
104 |
105 | // 预计算本回合内的所有可能的元素
106 | HashSet elementSet = PredictionDiceType();
107 |
108 | // 0 投骰子
109 | GameControl.GetInstance().ReRollDice(elementSet.ToArray());
110 |
111 | // 等待到我的回合 // 投骰子动画时间是不确定的 // 可能是对方先手
112 | GameControl.GetInstance().WaitForMyTurn(this, 1000);
113 |
114 | // 开始执行行动
115 | while (true)
116 | {
117 | // 没骰子了就结束行动
118 | MyLogger.Info($"行动开始,当前骰子数[{CurrentDiceCount}],当前手牌数[{CurrentCardCount}]");
119 | if (CurrentDiceCount <= 0)
120 | {
121 | MyLogger.Info("骰子已经用完");
122 | GameControl.GetInstance().Sleep(2000);
123 | break;
124 | }
125 |
126 | // 每次行动前都要检查当前角色
127 | CurrentCharacter = GameControl.GetInstance().WhichCharacterActiveWithRetry(this);
128 |
129 | List alreadyExecutedActionIndex = new List();
130 | List alreadyExecutedActionCommand = new List();
131 | var i = 0;
132 | for (i = 0; i < ActionCommandQueue.Count; i++)
133 | {
134 | var actionCommand = ActionCommandQueue[i];
135 | // 指令中的角色未被打败、角色有异常状态 跳过指令
136 | if (actionCommand.Character.IsDefeated || actionCommand.Character.StatusList?.Count > 0)
137 | {
138 | continue;
139 | }
140 |
141 | // 当前出战角色身上存在异常状态的情况下不执行本角色的指令
142 | if (CurrentCharacter.StatusList?.Count > 0 &&
143 | actionCommand.Character.Index == CurrentCharacter.Index)
144 | {
145 | continue;
146 | }
147 |
148 |
149 | // 1. 判断切人
150 | if (CurrentCharacter.Index != actionCommand.Character.Index)
151 | {
152 | if (CurrentDiceCount >= 1)
153 | {
154 | actionCommand.SwitchLater();
155 | CurrentDiceCount--;
156 | alreadyExecutedActionIndex.Add(-actionCommand.Character.Index); // 标记为已执行
157 | var switchAction = new ActionCommand
158 | {
159 | Character = CurrentCharacter,
160 | Action = ActionEnum.SwitchLater,
161 | TargetIndex = actionCommand.Character.Index
162 | };
163 | alreadyExecutedActionCommand.Add(switchAction);
164 | MyLogger.Info("→指令执行完成:" + switchAction);
165 | break;
166 | }
167 | else
168 | {
169 | MyLogger.Info("骰子不足以进行下一步:切换角色" + actionCommand.Character.Index);
170 | break;
171 | }
172 | }
173 |
174 | // 2. 判断使用技能
175 | if (actionCommand.GetAllDiceUseCount() > CurrentDiceCount)
176 | {
177 | MyLogger.Info("骰子不足以进行下一步:" + actionCommand);
178 | break;
179 | }
180 | else
181 | {
182 | bool useSkillRes = actionCommand.UseSkill(this);
183 | if (useSkillRes)
184 | {
185 | CurrentDiceCount -= actionCommand.GetAllDiceUseCount();
186 | alreadyExecutedActionIndex.Add(i);
187 | alreadyExecutedActionCommand.Add(actionCommand);
188 | MyLogger.Info("→指令执行完成:" + actionCommand);
189 | }
190 | else
191 | {
192 | MyLogger.Warn("→指令执行失败(可能是手牌不够):" + actionCommand);
193 | GameControl.GetInstance().Sleep(1000);
194 | GameControl.GetInstance().ClickGameWindowCenter();
195 | }
196 |
197 | break;
198 | }
199 | }
200 |
201 |
202 |
203 | if (alreadyExecutedActionIndex.Count != 0)
204 | {
205 | foreach (var index in alreadyExecutedActionIndex)
206 | {
207 | if (index >= 0)
208 | {
209 | ActionCommandQueue.RemoveAt(index);
210 | }
211 | }
212 |
213 | alreadyExecutedActionIndex.Clear();
214 | // 等待对方行动完成 (开大的时候等待时间久一点)
215 | int sleepTime = ComputeWaitForMyTurnTime(alreadyExecutedActionCommand);
216 | GameControl.GetInstance().WaitForMyTurn(this, sleepTime);
217 | alreadyExecutedActionCommand.Clear();
218 | }
219 | else
220 | {
221 | // 如果没有任何指令可以执行 则跳出循环
222 | // TODO 也有可能是角色死亡/所有角色被冻结导致没有指令可以执行
223 | //if (i >= ActionCommandQueue.Count)
224 | //{
225 | // throw new DuelEndException("策略中所有指令已经执行完毕,结束自动打牌");
226 | //}
227 | GameControl.GetInstance().Sleep(2000);
228 | break;
229 | }
230 |
231 | if (ActionCommandQueue.Count == 0)
232 | {
233 | throw new DuelEndException("策略中所有指令已经执行完毕,结束自动打牌");
234 | }
235 | }
236 |
237 | // 回合结束
238 | GameControl.GetInstance().Sleep(1000);
239 | MyLogger.Info("我方点击回合结束");
240 | GameControl.GetInstance().RoundEnd();
241 |
242 | // 等待对方行动+回合结算
243 | GameControl.GetInstance().WaitOpponentAction(this);
244 | RoundNum++;
245 | }
246 | }
247 | catch (TaskCanceledException ex)
248 | {
249 | MyLogger.Info(ex.Message);
250 | }
251 | catch (DuelEndException ex)
252 | {
253 | MyLogger.Info(ex.Message);
254 | }
255 | catch (Exception ex)
256 | {
257 | MyLogger.Error(ex.ToString());
258 | }
259 | finally
260 | {
261 | MyLogger.Info("========================================");
262 | }
263 | }
264 |
265 | private HashSet PredictionDiceType()
266 | {
267 | int actionUseDiceSum = 0;
268 | HashSet elementSet = new HashSet
269 | {
270 | ElementalType.Omni
271 | };
272 | for (var i = 0; i < ActionCommandQueue.Count; i++)
273 | {
274 | var actionCommand = ActionCommandQueue[i];
275 |
276 | // 角色未被打败的情况下才能执行
277 | if (actionCommand.Character.IsDefeated)
278 | {
279 | continue;
280 | }
281 |
282 | // 通过骰子数量判断是否可以执行
283 |
284 | // 1. 判断切人
285 | if (i > 0 && actionCommand.Character.Index != ActionCommandQueue[i - 1].Character.Index)
286 | {
287 | actionUseDiceSum++;
288 | if (actionUseDiceSum > CurrentDiceCount)
289 | {
290 | break;
291 | }
292 | else
293 | {
294 | elementSet.Add(actionCommand.GetDiceUseElementType());
295 | //executeActionIndex.Add(-actionCommand.Character.Index);
296 | }
297 | }
298 |
299 | // 2. 判断使用技能
300 | actionUseDiceSum += actionCommand.GetAllDiceUseCount();
301 | if (actionUseDiceSum > CurrentDiceCount)
302 | {
303 | break;
304 | }
305 | else
306 | {
307 | elementSet.Add(actionCommand.GetDiceUseElementType());
308 | //executeActionIndex.Add(i);
309 | }
310 | }
311 |
312 | return elementSet;
313 | }
314 |
315 | public void ClearCharacterStatus()
316 | {
317 | foreach (var character in Characters)
318 | {
319 | character?.StatusList?.Clear();
320 | }
321 | }
322 |
323 | ///
324 | /// 根据前面执行的命令计算等待时间
325 | /// 大招等待15秒
326 | /// 快速切换等待3秒
327 | ///
328 | ///
329 | ///
330 | private int ComputeWaitForMyTurnTime(List alreadyExecutedActionCommand)
331 | {
332 | foreach (var command in alreadyExecutedActionCommand)
333 | {
334 | if (command.Action == ActionEnum.UseSkill && command.TargetIndex == 1)
335 | {
336 | return 15000;
337 | }
338 |
339 | // 莫娜切换等待3秒
340 | if (command.Character.Name == "莫娜" && command.Action == ActionEnum.SwitchLater)
341 | {
342 | return 3000;
343 | }
344 | }
345 |
346 | return 10000;
347 | }
348 |
349 | ///
350 | /// 获取角色切换顺序
351 | ///
352 | ///
353 | public List GetCharacterSwitchOrder()
354 | {
355 | List orderList = new List();
356 | for (var i = 0; i < ActionCommandQueue.Count; i++)
357 | {
358 | if (!orderList.Contains(ActionCommandQueue[i].Character.Index))
359 | {
360 | orderList.Add(ActionCommandQueue[i].Character.Index);
361 | }
362 | }
363 |
364 | return orderList;
365 | }
366 |
367 | ///
368 | /// 获取角色存活数量
369 | ///
370 | ///
371 | public int GetCharacterAliveNum()
372 | {
373 | int num = 0;
374 | foreach (var character in Characters)
375 | {
376 | if (character != null && !character.IsDefeated)
377 | {
378 | num++;
379 | }
380 | }
381 |
382 | return num;
383 | }
384 | }
385 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Model/Old/CurrentCharacterStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace GeniusInvokationAutoToy.Strategy.Model.Old
8 | {
9 | public class CurrentCharacterStatus
10 | {
11 | ///
12 | /// 0-2 和所在数组下标一致
13 | ///
14 | public int ArrayIndex { get; set; }
15 | public int EnergyNum { get; set; }
16 |
17 | public List NegativeStatusList { get; set; } = new List();
18 |
19 | public override string ToString()
20 | {
21 | StringBuilder sb = new StringBuilder();
22 | sb.Append($"当前出战角色{ArrayIndex+1},");
23 | sb.Append($"充能={EnergyNum},");
24 | if (NegativeStatusList.Count > 0)
25 | {
26 | sb.Append($"负面状态:{string.Join(",", NegativeStatusList)}");
27 | }
28 | return sb.ToString();
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Model/RoundStrategy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using GeniusInvokationAutoToy.Core.Model;
7 |
8 | namespace GeniusInvokationAutoToy.Strategy.Model
9 | {
10 | public class RoundStrategy
11 | {
12 | public List RawCommandList { get; set; } = new List();
13 |
14 | public List ActionCommands { get; set; } = new List();
15 |
16 | public List MaybeNeedElement(Duel duel)
17 | {
18 | List result = new List();
19 |
20 | for (int i = 0; i < ActionCommands.Count; i++)
21 | {
22 | if (ActionCommands[i].Action == ActionEnum.SwitchLater
23 | && i != ActionCommands.Count-1
24 | && ActionCommands[i+1].Action == ActionEnum.UseSkill)
25 | {
26 | result.Add(duel.Characters[ActionCommands[i].TargetIndex].Element);
27 | }
28 | }
29 | return result;
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Model/Skill.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using GeniusInvokationAutoToy.Core.Model;
7 |
8 | namespace GeniusInvokationAutoToy.Strategy.Model
9 | {
10 | public class Skill
11 | {
12 | ///
13 | /// 1-4 和数组下标一致,游戏中是从右往左开始数的!
14 | ///
15 | public short Index { get; set; }
16 | public ElementalType Type { get; set; }
17 | ///
18 | /// 消耗指定元素骰子数量
19 | ///
20 | public int SpecificElementCost { get; set; }
21 |
22 | ///
23 | /// 消耗杂色骰子数量
24 | ///
25 | public int AnyElementCost { get; set; } = 0;
26 | ///
27 | /// 消耗指定元素骰子数量 + 消耗杂色骰子数量 = 消耗总骰子数量
28 | ///
29 | public int AllCost { get; set; }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/MonaSucroseJeanStrategy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using GeniusInvokationAutoToy.Core;
9 | using GeniusInvokationAutoToy.Core.Model;
10 | using GeniusInvokationAutoToy.Core.MyException;
11 | using GeniusInvokationAutoToy.Strategy.Model.Old;
12 | using GeniusInvokationAutoToy.Utils;
13 | using GeniusInvokationAutoToy.Utils.Extension;
14 | using NLog;
15 |
16 | namespace GeniusInvokationAutoToy.Strategy
17 | {
18 | ///
19 | ///【原神】七圣召唤-史上最无脑PVE牌组!连牌都不用出,暴打NPC!https://www.bilibili.com/video/BV1ZP41197Ws
20 | /// 虽然颠勺队伍早就有了,但是第一次知道PVE也好用
21 | /// 已经弃用
22 | ///
23 | [Obsolete]
24 | public class MonaSucroseJeanStrategy : BaseStrategy
25 | {
26 | ///
27 | /// 莫娜充能
28 | ///
29 | protected int MonaEnergyNum;
30 | ///
31 | /// 砂糖充能
32 | ///
33 | protected int SucroseEnergyNum;
34 | ///
35 | /// 琴充能
36 | ///
37 | protected int JeanEnergyNum;
38 |
39 | public MonaSucroseJeanStrategy(YuanShenWindow window) : base(window)
40 | {
41 | }
42 |
43 |
44 | public override void Run(CancellationTokenSource cts1)
45 | {
46 | cts = cts1;
47 | MonaSucroseJeanInit();
48 | try
49 | {
50 | MyLogger.Info("========================================");
51 | MyLogger.Info("对局启动!");
52 | // 对局准备(选择初始手牌、出战角色)
53 | DuelPrepare();
54 |
55 | // 执行回合
56 | MyLogger.Info("--------------第1回合--------------");
57 | Round1();
58 | MyLogger.Info("--------------第2回合--------------");
59 | Round2();
60 |
61 |
62 | for (int i = 0; i < 3; i++)
63 | {
64 | MyLogger.Info($"--------------第{3 + i}回合--------------");
65 | if (CurrentTakenOutCharacterCount >= 2)
66 | {
67 | RoundMoreForMona();
68 | }
69 | else
70 | {
71 | RoundMore();
72 | }
73 | }
74 |
75 | // end
76 | capture.Stop();
77 | MyLogger.Info("没活了,结束自动打牌");
78 | }
79 | catch (TaskCanceledException ex)
80 | {
81 | MyLogger.Info(ex.Message);
82 | }
83 | catch (DuelEndException ex)
84 | {
85 | MyLogger.Info(ex.Message);
86 | }
87 | catch (Exception ex)
88 | {
89 | MyLogger.Error(ex.ToString());
90 | }
91 | finally
92 | {
93 | MyLogger.Info("========================================");
94 | }
95 | }
96 |
97 | public void MonaSucroseJeanInit()
98 | {
99 | Init(); // 初始化对局变量
100 | MonaEnergyNum = 0;
101 | }
102 |
103 | private void DuelPrepare()
104 | {
105 | // 1. 选择初始手牌
106 | Sleep(1000);
107 | MyLogger.Info("开始选择初始手牌");
108 | while (!ClickConfirm())
109 | {
110 | // 循环等待选择卡牌画面
111 | Sleep(1000);
112 | }
113 |
114 | MyLogger.Info("点击确认");
115 |
116 | // 2. 选择出战角色
117 | // 此处选择第一个角色 莫娜
118 | MyLogger.Info("等待3s动画...");
119 | Sleep(3000);
120 |
121 | // 是否是再角色出战选择界面
122 | Retry.Do(IsInCharacterPickRetryThrowable, TimeSpan.FromSeconds(1), 5);
123 | MyLogger.Info("识别到已经在角色出战界面,等待1.5s");
124 | Sleep(1500);
125 |
126 | // 识别角色所在区域
127 | Retry.Do(() => ChooseCharacterFirst(1), TimeSpan.FromSeconds(1), 5);
128 |
129 | MyLogger.Info("出战莫娜");
130 |
131 | // 初始化手牌
132 | CurrentCardCount = 5;
133 | }
134 |
135 | ///
136 | /// 第一回合 要尽量保证行动
137 | ///
138 | public void Round1()
139 | {
140 | CurrentDiceCount = 8;
141 | // 0 投骰子
142 | ReRollDice(ElementalType.Anemo, ElementalType.Hydro, ElementalType.Omni);
143 |
144 | // 等待到我的回合 // 投骰子动画时间是不确定的
145 | WaitForMyTurn(1000);
146 |
147 | // 1 回合1 行动1 莫娜使用1次二技能
148 | MyLogger.Info("回合1 行动1 莫娜使用1次二技能");
149 | bool useSkillRes = ActionPhaseAutoUseSkill(2, 3, ElementalType.Hydro, CurrentDiceCount);
150 | if (!useSkillRes)
151 | {
152 | MyLogger.Warn("没有足够的手牌或元素骰子释放技能,停止自动打牌");
153 | return;
154 | }
155 | CurrentDiceCount-=3;
156 | MonaEnergyNum++;
157 |
158 | // 等待对方行动完成
159 | WaitForMyTurn(10000);
160 |
161 | CurrentCharacterStatus = WhichCharacterActiveWithRetry();
162 |
163 | if (CurrentCharacterStatus.ArrayIndex != 1)
164 | {
165 | // 2 回合1 行动2 切换砂糖
166 | MyLogger.Info("回合1 行动2 切换砂糖");
167 | SwitchCharacterLater(2);
168 | CurrentDiceCount--;
169 |
170 | // 快速切换无需等待对方 但是有动画,需要延迟一会
171 | WaitForMyTurn(3000);
172 | }
173 | else
174 | {
175 | MyLogger.Warn("回合1 行动2 砂糖已经被切换,无需快速切换");
176 | }
177 |
178 |
179 | // 3 回合1 行动2 砂糖使用1次二技能
180 | MyLogger.Info("回合1 行动3 砂糖使用1次二技能");
181 | ActionPhaseAutoUseSkill(2, 3, ElementalType.Anemo, CurrentDiceCount);
182 | SucroseEnergyNum++;
183 |
184 | // 等待对方行动完成
185 | WaitForMyTurn(10000);
186 |
187 | // 砂糖有可能被超载切走
188 | HoldSwitchCharacter(2);
189 |
190 | // 4 回合1 结束 剩下1个骰子
191 | MyLogger.Info("我方点击回合结束");
192 | RoundEnd();
193 |
194 | // 5 等待对方行动+回合结算
195 | WaitOpponentAction();
196 | }
197 |
198 |
199 | ///
200 | /// 第二回合 要尽量保证行动
201 | ///
202 | public void Round2()
203 | {
204 | CurrentCardCount += 2;
205 | CurrentDiceCount = 8;
206 | // 0 投骰子
207 | ReRollDice(ElementalType.Anemo, ElementalType.Omni);
208 |
209 | // 等待对方行动完成 // 可能是对方先手
210 | WaitForMyTurn(1000);
211 |
212 | HoldSwitchCharacter(2);
213 | // 1 回合2 行动1 砂糖使用1次二技能
214 | MyLogger.Info("回合2 砂糖使用1次二技能");
215 | bool useSkillRes = ActionPhaseAutoUseSkill(2, 3, ElementalType.Anemo, CurrentDiceCount);
216 | if (!useSkillRes)
217 | {
218 | // 运气太差直接结束
219 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
220 | RoundEnd();
221 | WaitOpponentAction();
222 | return;
223 | }
224 | CurrentDiceCount -= 3;
225 | SucroseEnergyNum++;
226 |
227 | // 等待对方行动完成
228 | WaitForMyTurn(10000);
229 |
230 | HoldSwitchCharacter(2);
231 | // 2 回合2 行动2 砂糖充能已满,使用1次三技能
232 | MyLogger.Info("回合2 砂糖充能已满,使用1次三技能");
233 | useSkillRes = ActionPhaseAutoUseSkill(1, 3, ElementalType.Anemo, CurrentDiceCount);
234 | if (!useSkillRes)
235 | {
236 | // 运气太差直接结束
237 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
238 | RoundEnd();
239 | WaitOpponentAction();
240 | return;
241 | }
242 | CurrentDiceCount -= 3;
243 |
244 | // 等待对方行动完成 // 大招久一点
245 | WaitForMyTurn(12000);
246 |
247 | // 4 回合2 结束
248 | MyLogger.Info("我方点击回合结束");
249 | RoundEnd();
250 |
251 | // 5 等待对方行动+回合结算
252 | WaitOpponentAction();
253 | }
254 |
255 |
256 | ///
257 | /// 第三/N回合 出战为砂糖琴
258 | /// 对局可能会胜利
259 | ///
260 | public void RoundMore()
261 | {
262 | CurrentCardCount += 2;
263 | CurrentDiceCount = 8;
264 | // 0 投骰子
265 | ReRollDice(ElementalType.Anemo, ElementalType.Omni);
266 |
267 | // 等待对方行动完成 // 可能是对方先手
268 | WaitForMyTurn(1000);
269 |
270 | // 1 回合2 行动1 使用1次二技能
271 | MyLogger.Info("行动1 使用1次二技能");
272 | bool useSkillRes = ActionPhaseAutoUseSkill(2, 3, ElementalType.Anemo, 8);
273 | if (!useSkillRes)
274 | {
275 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
276 | RoundEnd();
277 | WaitOpponentAction();
278 | return;
279 | }
280 | CurrentDiceCount -= 3;
281 |
282 | // 等待对方行动完成
283 | WaitForMyTurn(10000);
284 |
285 | // 2 回合2 行动2 使用1次二技能
286 | MyLogger.Info("行动2 使用1次二技能");
287 | useSkillRes = ActionPhaseAutoUseSkill(2, 3, ElementalType.Anemo, 5);
288 | if (!useSkillRes)
289 | {
290 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
291 | RoundEnd();
292 | WaitOpponentAction();
293 | return;
294 | }
295 | CurrentDiceCount -= 3;
296 |
297 | // 等待对方行动完成
298 | WaitForMyTurn(10000);
299 |
300 | // 4 回合2 结束 剩下2个骰子
301 | MyLogger.Info("我方点击回合结束");
302 | RoundEnd();
303 |
304 | // 5 等待对方行动+回合结算
305 | WaitOpponentAction();
306 | }
307 |
308 | ///
309 | /// 第三/N回合 出战为莫娜
310 | /// 对局可能会胜利
311 | ///
312 | public void RoundMoreForMona()
313 | {
314 | bool useSkillRes;
315 | CurrentDiceCount = 8;
316 | CurrentCardCount += 2;
317 | // 0 投骰子
318 | ReRollDice(ElementalType.Hydro, ElementalType.Omni);
319 |
320 | // 等待对方行动完成 // 可能是对方先手
321 | WaitForMyTurn(1000);
322 |
323 | if (MonaEnergyNum == 3)
324 | {
325 | CurrentDiceCount = MonaUse3Skill(CurrentDiceCount);
326 | }
327 |
328 | // 1 使用1次二技能
329 | MyLogger.Info("行动1 使用1次二技能");
330 | useSkillRes = ActionPhaseAutoUseSkill(2, 3, ElementalType.Hydro, CurrentDiceCount);
331 | if (!useSkillRes)
332 | {
333 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
334 | RoundEnd();
335 | WaitOpponentAction();
336 | return;
337 | }
338 |
339 | CurrentDiceCount -= 3;
340 | MonaEnergyNum++;
341 |
342 |
343 | if (MonaEnergyNum == 3 && CurrentDiceCount >= 3)
344 | {
345 | CurrentDiceCount = MonaUse3Skill(CurrentDiceCount);
346 | }
347 |
348 | // 等待对方行动完成
349 | WaitForMyTurn(10000);
350 |
351 | // 2 使用1次一技能
352 | if (CurrentDiceCount >= 3)
353 | {
354 | MyLogger.Info("行动2 使用1次一技能");
355 | useSkillRes = ActionPhaseAutoUseSkill(3, 1, ElementalType.Hydro, CurrentDiceCount);
356 | if (!useSkillRes)
357 | {
358 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
359 | RoundEnd();
360 | WaitOpponentAction();
361 | return;
362 | }
363 |
364 | CurrentDiceCount -= 3;
365 | MonaEnergyNum++;
366 | }
367 |
368 |
369 | // 等待对方行动完成
370 | WaitForMyTurn(10000);
371 |
372 | // 4 回合2 结束 剩下2个骰子
373 | MyLogger.Info("我方点击回合结束");
374 | RoundEnd();
375 |
376 | // 5 等待对方行动+回合结算
377 | WaitOpponentAction();
378 | }
379 |
380 | private int MonaUse3Skill(int roundDiceCount)
381 | {
382 | bool useSkillRes;
383 | MyLogger.Info("使用1次三技能");
384 | useSkillRes = ActionPhaseAutoUseSkill(1, 3, ElementalType.Hydro, roundDiceCount);
385 | if (!useSkillRes)
386 | {
387 | MyLogger.Info("没有足够的手牌或元素骰子释放技能,回合结束");
388 | RoundEnd();
389 | WaitOpponentAction();
390 | return roundDiceCount;
391 | }
392 |
393 | roundDiceCount -= 3;
394 | MonaEnergyNum = 0;
395 | return roundDiceCount;
396 | }
397 |
398 | public void HoldSwitchCharacter(int index)
399 | {
400 | // 砂糖有可能被超载切走
401 | CurrentCharacterStatus = WhichCharacterActiveWithRetry();
402 | if (CurrentCharacterStatus.ArrayIndex != index-1)
403 | {
404 | // 2 回合1 行动2 切换砂糖
405 | MyLogger.Info("回合1 行动4 检测到出战角色不是砂糖,可能被超载,切换回砂糖");
406 | SwitchCharacterLater(index); // 刚好还有一个骰子可以用来切人
407 | CurrentDiceCount--;
408 |
409 | // 等待对方行动完成
410 | WaitForMyTurn(10000);
411 | }
412 | else
413 | {
414 | // 冻结、眩晕
415 | if (CurrentCharacterStatus.NegativeStatusList.Count > 0)
416 | {
417 | MyLogger.Warn("当前出战角色因为负面状态无法行动");
418 | throw new DuelEndException("当前出战角色因为负面状态无法行动,暂时无法支持此种情况,请尝试其他卡组或使用自定策略的功能");
419 | }
420 | }
421 | }
422 | }
423 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Strategy/Script/ScriptParser.cs:
--------------------------------------------------------------------------------
1 | using GeniusInvokationAutoToy.Strategy.Model;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using GeniusInvokationAutoToy.Core.Model;
8 | using OpenCvSharp;
9 | using System.Text.RegularExpressions;
10 | using System.Diagnostics;
11 | using System.Windows.Forms;
12 | using GeniusInvokationAutoToy.Utils;
13 |
14 | namespace GeniusInvokationAutoToy.Strategy.Script
15 | {
16 | public class ScriptParser
17 | {
18 | public static Duel Parse(string script)
19 | {
20 | var lines = script.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
21 | var result = new List();
22 | foreach (var line in lines)
23 | {
24 | string l = line.Trim();
25 | //if (l.StartsWith("//"))
26 | //{
27 | // continue;
28 | //}
29 | result.Add(l);
30 | }
31 |
32 | return Parse(result);
33 | }
34 |
35 | public static Duel Parse(List lines)
36 | {
37 | Duel duel = new Duel();
38 | string stage = "";
39 |
40 | int i = 0;
41 | try
42 | {
43 | for (i = 0; i < lines.Count; i++)
44 | {
45 | var line = lines[i];
46 | if (line.Contains(":"))
47 | {
48 | stage = line;
49 | continue;
50 | }
51 |
52 | if (line == "---" || line.StartsWith("//") || string.IsNullOrEmpty(line))
53 | {
54 | continue;
55 | }
56 |
57 | if (stage == "角色定义:")
58 | {
59 | var character = ParseCharacter(line);
60 | duel.Characters[character.Index] = character;
61 | }
62 | else if (stage == "策略定义:")
63 | {
64 | MyAssert(duel.Characters[3] != null, "角色未定义");
65 |
66 | string[] actionParts = line.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
67 | MyAssert(actionParts.Length == 3, "策略中的行动命令解析错误");
68 | MyAssert(actionParts[1] == "使用", "策略中的行动命令解析错误");
69 |
70 | var actionCommand = new ActionCommand();
71 | var action = actionParts[1].ChineseToActionEnum();
72 | actionCommand.Action = action;
73 |
74 | int j = 1;
75 | for (j = 1; j <= 3; j++)
76 | {
77 | var character = duel.Characters[j];
78 | if (character != null && character.Name == actionParts[0])
79 | {
80 | actionCommand.Character = character;
81 | break;
82 | }
83 | }
84 |
85 | MyAssert(j <= 3, "策略中的行动命令解析错误:角色名称无法从角色定义中匹配到");
86 |
87 | int skillNum = int.Parse(Regex.Replace(actionParts[2], @"[^0-9]+", ""));
88 | MyAssert(skillNum < 5, "策略中的行动命令解析错误:技能编号错误");
89 | actionCommand.TargetIndex = skillNum;
90 | duel.ActionCommandQueue.Add(actionCommand);
91 | }
92 | else
93 | {
94 | throw new Exception($"未知的定义字段:{stage}");
95 | }
96 | }
97 |
98 | MyAssert(duel.Characters[3] != null, "角色未定义,请确认策略文本格式是否为UTF-8");
99 | }
100 | catch (Exception ex)
101 | {
102 | MyLogger.Error($"解析脚本错误,行号:{i + 1},错误信息:{ex}");
103 | MessageBox.Show($"解析脚本错误,行号:{i + 1},错误信息:{ex}", "策略解析失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
104 | return null;
105 | }
106 |
107 | return duel;
108 | }
109 |
110 | ///
111 | /// 解析示例
112 | /// 角色1=刻晴|雷{技能3消耗=1雷骰子+2任意,技能2消耗=3雷骰子,技能1消耗=4雷骰子}
113 | /// 角色2=雷神|雷{技能3消耗=1雷骰子+2任意,技能2消耗=3雷骰子,技能1消耗=4雷骰子}
114 | /// 角色3=甘雨|冰{技能4消耗=1冰骰子+2任意,技能3消耗=1冰骰子,技能2消耗=5冰骰子,技能1消耗=3冰骰子}
115 | ///
116 | ///
117 | ///
118 | public static Character ParseCharacter(string line)
119 | {
120 | var character = new Character();
121 |
122 | var characterAndSkill = line.Split('{');
123 |
124 | var parts = characterAndSkill[0].Split('=');
125 | character.Index = int.Parse(Regex.Replace(parts[0], @"[^0-9]+", ""));
126 | MyAssert(character.Index >= 1 && character.Index <= 3, "角色序号必须在1-3之间");
127 | var nameAndElement = parts[1].Split('|');
128 | character.Name = nameAndElement[0];
129 | character.Element = nameAndElement[1].Substring(0, 1).ChineseToElementalType();
130 |
131 | // 技能
132 | string skillStr = characterAndSkill[1].Replace("}", "");
133 | var skillParts = skillStr.Split(',');
134 | var skills = new Skill[skillParts.Length + 1];
135 | for (int i = 0; i < skillParts.Length; i++)
136 | {
137 | var skill = ParseSkill(skillParts[i]);
138 | skills[skill.Index] = skill;
139 | }
140 |
141 | character.Skills = skills.ToArray();
142 | return character;
143 | }
144 |
145 | ///
146 | /// 技能3消耗=1雷骰子+2任意
147 | /// 技能2消耗=3雷骰子
148 | /// 技能1消耗=4雷骰子
149 | ///
150 | ///
151 | ///
152 | public static Skill ParseSkill(string oneSkillStr)
153 | {
154 | var skill = new Skill();
155 | var parts = oneSkillStr.Split('=');
156 | skill.Index = short.Parse(Regex.Replace(parts[0], @"[^0-9]+", ""));
157 | MyAssert(skill.Index >= 1 && skill.Index <= 5, "技能序号必须在1-5之间");
158 | var costStr = parts[1];
159 | var costParts = costStr.Split('+');
160 | skill.SpecificElementCost = int.Parse(costParts[0].Substring(0, 1));
161 | skill.Type = costParts[0].Substring(1, 1).ChineseToElementalType();
162 | // 杂色骰子在+号右边
163 | if (costParts.Length > 1)
164 | {
165 | skill.AnyElementCost = int.Parse(costParts[1].Substring(0, 1));
166 | }
167 |
168 | skill.AllCost = skill.SpecificElementCost + skill.AnyElementCost;
169 | return skill;
170 | }
171 |
172 | private static void MyAssert(bool b, string msg)
173 | {
174 | if (!b)
175 | {
176 | throw new Exception(msg);
177 | }
178 | }
179 | }
180 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/Device.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Management;
5 | using System.Net;
6 | using System.Security.Cryptography;
7 | using System.Text;
8 |
9 | namespace GeniusInvokationAutoToy.Utils
10 | {
11 | public class Device
12 | {
13 | private static string macID = null;
14 | private static string osVersion = null;
15 |
16 | private static string fingerPrint = null;
17 |
18 | #region PROP, get it only once
19 |
20 | public static string MacID
21 | {
22 | get
23 | {
24 | if (macID == null)
25 | {
26 | macID = ObtainMacID();
27 | }
28 | return macID;
29 | }
30 | }
31 |
32 | public static string OSVersion
33 | {
34 | get
35 | {
36 | if (osVersion == null)
37 | {
38 | var name = (from x in new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem").Get().Cast()
39 | select x.GetPropertyValue("Caption")).FirstOrDefault();
40 | osVersion = name != null ? name.ToString() : "Unknown";
41 | }
42 | return osVersion;
43 | }
44 | }
45 | #endregion
46 |
47 | ///
48 | /// Calculate GUID
49 | ///
50 | /// GUID
51 | public static string Value()
52 | {
53 | try
54 | {
55 | if (fingerPrint == null)
56 | {
57 | fingerPrint = GetHash(
58 | "MAC >> " + MacID
59 | );
60 | }
61 | return fingerPrint;
62 | }
63 | catch
64 | {
65 | return Guid.NewGuid().ToString();
66 | }
67 |
68 | }
69 |
70 | private static string GetHash(string s)
71 | {
72 | MD5 sec = new MD5CryptoServiceProvider();
73 | ASCIIEncoding enc = new ASCIIEncoding();
74 | byte[] bt = enc.GetBytes(s);
75 | return GetHexString(sec.ComputeHash(bt));
76 | }
77 |
78 | private static string GetHexString(byte[] bt)
79 | {
80 | string s = string.Empty;
81 | for (int i = 0; i < bt.Length; i++)
82 | {
83 | byte b = bt[i];
84 | int n, n1, n2;
85 | n = (int)b;
86 | n1 = n & 15;
87 | n2 = (n >> 4) & 15;
88 | if (n2 > 9)
89 | s += ((char)(n2 - 10 + (int)'A')).ToString();
90 | else
91 | s += n2.ToString();
92 | if (n1 > 9)
93 | s += ((char)(n1 - 10 + (int)'A')).ToString();
94 | else
95 | s += n1.ToString();
96 | if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
97 | }
98 | return s;
99 | }
100 |
101 |
102 | #region Original Device ID Getting Code
103 |
104 | public static string ObtainMacID()
105 | {
106 | return Identifier("Win32_NetworkAdapterConfiguration", "MACAddress", "IPEnabled");
107 | }
108 |
109 | private static string Identifier(string wmiClass, string wmiProperty, string wmiMustBeTrue)
110 | {
111 | string result = "";
112 | try
113 | {
114 | ManagementClass mc = new ManagementClass(wmiClass);
115 | ManagementObjectCollection moc = mc.GetInstances();
116 | foreach (ManagementObject mo in moc)
117 | {
118 | if (mo[wmiMustBeTrue].ToString() == "True")
119 | {
120 | //Only get the first one
121 | if (result == "")
122 | {
123 | result = mo[wmiProperty].ToString();
124 | break;
125 | }
126 | }
127 | }
128 | }
129 | catch
130 | {
131 | }
132 | return result;
133 | }
134 |
135 | private static string Identifier(string wmiClass, string wmiProperty)
136 | {
137 | string result = "";
138 | try
139 | {
140 | ManagementClass mc = new ManagementClass(wmiClass);
141 | ManagementObjectCollection moc = mc.GetInstances();
142 | foreach (ManagementObject mo in moc)
143 | {
144 | //Only get the first one
145 | if (result == "")
146 | {
147 | result = mo[wmiProperty].ToString();
148 | break;
149 | }
150 | }
151 | }
152 | catch
153 | {
154 | }
155 | return result;
156 | }
157 | #endregion
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/Extension/RectangleExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace GeniusInvokationAutoToy.Utils.Extension
9 | {
10 | public static class RectangleExtension
11 | {
12 | public static OpenCvSharp.Rect ToCvRect(this Rectangle rectangle)
13 | {
14 | return new OpenCvSharp.Rect(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
15 | }
16 |
17 | public static Rectangle ToRectangle(this OpenCvSharp.Rect rectangle)
18 | {
19 | return new Rectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height);
20 | }
21 |
22 | public static Point GetCenterPoint(this Rectangle rectangle)
23 | {
24 | if (rectangle.IsEmpty)
25 | {
26 | throw new ArgumentException("rectangle is empty");
27 | }
28 | return new Point(rectangle.X + rectangle.Width / 2, rectangle.Y + rectangle.Height / 2);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/Extension/RetryExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace GeniusInvokationAutoToy.Utils.Extension
9 | {
10 | public static class RetryExtension
11 | {
12 | public static void InvokeWithRetries(this Action @this, ushort numberOfRetries, TimeSpan sleepPeriod, string throwsMessage)
13 | {
14 | try
15 | {
16 | @this();
17 | }
18 | catch
19 | {
20 | if (numberOfRetries == 0)
21 | {
22 | throw new Exception(throwsMessage);
23 | }
24 |
25 | Thread.Sleep(sleepPeriod);
26 |
27 | InvokeWithRetries(@this, --numberOfRetries, sleepPeriod, throwsMessage);
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/GAHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Web.Script.Serialization;
8 | using System.Windows.Forms;
9 |
10 | namespace GeniusInvokationAutoToy.Utils
11 | {
12 | ///
13 | /// 用于软件的 Google Analytics 实现 By huiyadanli
14 | /// 20230409 更新 GA4 的实现
15 | /// 相关文档:
16 | /// #GA指南(过时) https://developers.google.com/analytics/devguides/collection/protocol/v1/devguide
17 | /// #GA参数(过时) https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters
18 | /// GA4教程 https://firebase.google.com/codelabs/firebase_mp
19 | /// 测试 https://ga-dev-tools.google/ga4/event-builder/
20 | ///
21 | public class GAHelper
22 | {
23 | private static GAHelper instance = null;
24 | private static readonly object obj = new object();
25 |
26 | public static GAHelper Instance
27 | {
28 | get
29 | {
30 | //lock (obj)
31 | //{
32 | if (instance == null)
33 | {
34 | instance = new GAHelper();
35 | }
36 | return instance;
37 | //}
38 | }
39 | }
40 |
41 | // 根据实际情况修改
42 | private static readonly HttpClient client = new HttpClient();
43 |
44 | private const string GAUrl = "https://www.google-analytics.com/mp/collect?api_secret=tMiYgGrJSIeuL5eIV1YCsQ&measurement_id=G-TQYV28WWTX";
45 |
46 | private static readonly string cid = Device.Value(); // Anonymous Client ID. // Guid.NewGuid().ToString()
47 |
48 |
49 | public string UserAgent { get; set; }
50 |
51 | public GAHelper()
52 | {
53 | UserAgent = $"Hui Google Analytics Tracker/1.0 ({Environment.OSVersion.Platform.ToString()}; {Environment.OSVersion.Version.ToString()}; {Environment.OSVersion.VersionString})";
54 | }
55 |
56 | public async Task RequestPageViewAsync(string page, string title = null)
57 | {
58 | try
59 | {
60 | if (page.StartsWith("/"))
61 | {
62 | page = page.Remove(0, 1);
63 | }
64 | page = page.Replace("/", "_").Replace(".", "_");
65 | // 请求参数
66 | var values = new Dictionary
67 | {
68 | { "client_id",UserAgent},
69 | { "user_id", cid },
70 | { "non_personalized_ads", "false" },
71 | { "events", new List>()
72 | {
73 | new Dictionary()
74 | {
75 | { "name",page },
76 | {
77 | "params",
78 | new Dictionary()
79 | {
80 | { "engagement_time_msec", "1"},
81 | }
82 | },
83 | }
84 | }
85 | },
86 | };
87 | var serializer = new JavaScriptSerializer();
88 | var json = serializer.Serialize(values);
89 | var content = new StringContent(json, Encoding.UTF8, "application/json");
90 | var response = await client.PostAsync(GAUrl, content);
91 | Console.WriteLine(response.ToString());
92 | }
93 | catch (Exception ex)
94 | {
95 |
96 | Console.WriteLine("GAHelper:" + ex.Message);
97 | Console.WriteLine(ex.StackTrace);
98 | }
99 | }
100 |
101 | public void RequestPageView(string page, string title = null)
102 | {
103 | Task.Run(() => RequestPageViewAsync(page, title));
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/MouseUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 |
9 | namespace GeniusInvokationAutoToy.Utils
10 | {
11 | public class MouseUtils
12 | {
13 | public static void Move(int x, int y)
14 | {
15 | Native.mouse_event(Native.MouseEventFlag.Absolute | Native.MouseEventFlag.Move,
16 | x * 65535 / PrimaryScreen.DESKTOP.Width, y * 65535 / PrimaryScreen.DESKTOP.Height,
17 | 0, 0);
18 | }
19 |
20 | public static void Move(Point point)
21 | {
22 | Move(point.X, point.Y);
23 | }
24 |
25 | public static void LeftDown()
26 | {
27 | Native.mouse_event(Native.MouseEventFlag.LeftDown, 0, 0, 0, 0);
28 | }
29 |
30 | public static void LeftUp()
31 | {
32 | Native.mouse_event(Native.MouseEventFlag.LeftUp, 0, 0, 0, 0);
33 | }
34 |
35 | public static bool Click(int x, int y)
36 | {
37 | if (x == 0 && y==0)
38 | {
39 | return false;
40 | }
41 | //MyLogger.Info($"Click {x},{y}");
42 | Move(x, y);
43 | LeftDown();
44 | Thread.Sleep(20);
45 | LeftUp();
46 | return true;
47 | }
48 |
49 | public static bool Click(Point point)
50 | {
51 | return Click(point.X, point.Y);
52 | }
53 |
54 | public static bool DoubleClick(Point point)
55 | {
56 | Click(point.X, point.Y);
57 | Thread.Sleep(200);
58 | return Click(point.X, point.Y);
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/MyLogger.cs:
--------------------------------------------------------------------------------
1 | using NLog;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Windows.Forms;
8 |
9 | namespace GeniusInvokationAutoToy.Utils
10 | {
11 |
12 | public class MyLogger
13 | {
14 | static Logger _logger => LogManager.GetCurrentClassLogger();
15 |
16 | public static FormMain formMain;
17 |
18 | public static void Info(string message, params object[] args)
19 | {
20 | _logger.Info(message, args);
21 | }
22 | public static void Trace(string message, params object[] args)
23 | {
24 | _logger.Trace(message, args);
25 | }
26 | public static void Error(string message, params object[] args)
27 | {
28 | _logger.Error(message, args);
29 | }
30 | public static void Debug(string message, params object[] args)
31 | {
32 | _logger.Debug(message, args);
33 | }
34 | public static void Fatal(string message, params object[] args)
35 | {
36 | _logger.Fatal(message, args);
37 | }
38 | public static void Warn(string message, params object[] args)
39 | {
40 | _logger.Warn(message, args);
41 | }
42 | public static void InfoSingleLine(string message, params object[] args)
43 | {
44 | formMain?.RtbConsoleDeleteLine();
45 | _logger.Info(message, args);
46 | }
47 |
48 | public static void WarnSingleLine(string message, params object[] args)
49 | {
50 | formMain?.RtbConsoleDeleteLine();
51 | _logger.Warn(message, args);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/Native.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace GeniusInvokationAutoToy.Utils
9 | {
10 | class Native
11 | {
12 |
13 | [DllImport("GDI32.DLL", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
14 | public static extern bool StretchBlt(IntPtr hdcDest, int nXDest, int nYDest, int nDestWidth, int nDestHeight,
15 | IntPtr hdcSrc, int nXSrc, int nYSrc, int nSrcWidth, int nSrcHeight, CopyPixelOperation dwRop);
16 |
17 | [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
18 | public static extern IntPtr GetDC(IntPtr hWnd);
19 |
20 | [DllImport("user32.dll", ExactSpelling = true)]
21 | public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
22 |
23 | [DllImport("gdi32.dll", ExactSpelling = true)]
24 | public static extern IntPtr BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
25 |
26 | [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
27 | public static extern IntPtr GetDesktopWindow();
28 |
29 | ///
30 | ///Specifies a raster-operation code. These codes define how the color data for the
31 | ///source rectangle is to be combined with the color data for the destination
32 | ///rectangle to achieve the final color.
33 | ///
34 | [Flags]
35 | internal enum CopyPixelOperation
36 | {
37 | NoMirrorBitmap = -2147483648,
38 |
39 | /// dest = BLACK, 0x00000042
40 | Blackness = 66,
41 |
42 | ///dest = (NOT src) AND (NOT dest), 0x001100A6
43 | NotSourceErase = 1114278,
44 |
45 | ///dest = (NOT source), 0x00330008
46 | NotSourceCopy = 3342344,
47 |
48 | ///dest = source AND (NOT dest), 0x00440328
49 | SourceErase = 4457256,
50 |
51 | /// dest = (NOT dest), 0x00550009
52 | DestinationInvert = 5570569,
53 |
54 | /// dest = pattern XOR dest, 0x005A0049
55 | PatInvert = 5898313,
56 |
57 | ///dest = source XOR dest, 0x00660046
58 | SourceInvert = 6684742,
59 |
60 | ///dest = source AND dest, 0x008800C6
61 | SourceAnd = 8913094,
62 |
63 | /// dest = (NOT source) OR dest, 0x00BB0226
64 | MergePaint = 12255782,
65 |
66 | ///dest = (source AND pattern), 0x00C000CA
67 | MergeCopy = 12583114,
68 |
69 | ///dest = source, 0x00CC0020
70 | SourceCopy = 13369376,
71 |
72 | /// dest = source OR dest, 0x00EE0086
73 | SourcePaint = 15597702,
74 |
75 | /// dest = pattern, 0x00F00021
76 | PatCopy = 15728673,
77 |
78 | /// dest = DPSnoo, 0x00FB0A09
79 | PatPaint = 16452105,
80 |
81 | /// dest = WHITE, 0x00FF0062
82 | Whiteness = 16711778,
83 |
84 | ///
85 | /// Capture window as seen on screen. This includes layered windows
86 | /// such as WPF windows with AllowsTransparency="true", 0x40000000
87 | ///
88 | CaptureBlt = 1073741824,
89 | }
90 |
91 |
92 | [DllImport("user32")]
93 | public static extern int mouse_event(MouseEventFlag dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
94 | [Flags]
95 | public enum MouseEventFlag : uint
96 | {
97 | Move = 0x0001,
98 | LeftDown = 0x0002,
99 | LeftUp = 0x0004,
100 | RightDown = 0x0008,
101 | RightUp = 0x0010,
102 | MiddleDown = 0x0020,
103 | MiddleUp = 0x0040,
104 | XDown = 0x0080,
105 | XUp = 0x0100,
106 | Wheel = 0x0800,
107 | VirtualDesk = 0x4000,
108 | Absolute = 0x8000
109 | }
110 | [DllImport("user32.dll")]
111 | public static extern bool SetCursorPos(int X, int Y);
112 |
113 |
114 | [DllImport("user32.dll")]
115 | public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
116 | [DllImport("User32.dll ")]
117 | public static extern IntPtr FindWindowEx(IntPtr parent, IntPtr childe, string strclass, string FrmText);
118 | [DllImport("user32.dll", EntryPoint = "PostMessage")]
119 | public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
120 |
121 | [DllImport("User32.dll", EntryPoint = "SendMessage")]
122 | public static extern int SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
123 |
124 |
125 |
126 | [DllImport("user32.dll")]
127 | [return: MarshalAs(UnmanagedType.Bool)]
128 | public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect);
129 |
130 | [StructLayout(LayoutKind.Sequential)]
131 | public struct RECT
132 | {
133 | public int Left; //最左坐标
134 | public int Top; //最上坐标
135 | public int Right; //最右坐标
136 | public int Bottom; //最下坐标
137 | }
138 |
139 | [DllImport("user32.dll", SetLastError = true)]
140 | public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
141 | [DllImport("user32.dll", SetLastError = true)]
142 | public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
143 |
144 | [DllImport("user32.dll")]
145 | internal static extern bool HideCaret(IntPtr controlHandle);
146 |
147 | [DllImport("user32.dll")]
148 | public static extern int SetForegroundWindow(IntPtr hwnd);
149 |
150 | [DllImport("user32.dll")]
151 | public static extern IntPtr GetForegroundWindow();
152 |
153 | [DllImport("user32.dll")]
154 | public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
155 |
156 | [DllImport("user32.dll")]
157 | public static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint ProcessId);
158 |
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/PrimaryScreen.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace GeniusInvokationAutoToy.Utils
6 | {
7 | class PrimaryScreen
8 | {
9 | #region Win32 API
10 | [DllImport("user32.dll")]
11 | static extern IntPtr GetDC(IntPtr ptr);
12 | [DllImport("gdi32.dll")]
13 | static extern int GetDeviceCaps(
14 | IntPtr hdc, // handle to DC
15 | int nIndex // index of capability
16 | );
17 | [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
18 | static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
19 | #endregion
20 | #region DeviceCaps常量
21 | const int HORZRES = 8;
22 | const int VERTRES = 10;
23 | const int LOGPIXELSX = 88;
24 | const int LOGPIXELSY = 90;
25 | const int DESKTOPVERTRES = 117;
26 | const int DESKTOPHORZRES = 118;
27 | #endregion
28 |
29 | #region 属性
30 | ///
31 | /// 获取屏幕分辨率当前物理大小
32 | ///
33 | public static Size WorkingArea
34 | {
35 | get
36 | {
37 | IntPtr hdc = GetDC(IntPtr.Zero);
38 | Size size = new Size();
39 | size.Width = GetDeviceCaps(hdc, HORZRES);
40 | size.Height = GetDeviceCaps(hdc, VERTRES);
41 | ReleaseDC(IntPtr.Zero, hdc);
42 | return size;
43 | }
44 | }
45 | ///
46 | /// 当前系统DPI_X 大小 一般为96
47 | ///
48 | public static int DpiX
49 | {
50 | get
51 | {
52 | IntPtr hdc = GetDC(IntPtr.Zero);
53 | int DpiX = GetDeviceCaps(hdc, LOGPIXELSX);
54 | ReleaseDC(IntPtr.Zero, hdc);
55 | return DpiX;
56 | }
57 | }
58 | ///
59 | /// 当前系统DPI_Y 大小 一般为96
60 | ///
61 | public static int DpiY
62 | {
63 | get
64 | {
65 | IntPtr hdc = GetDC(IntPtr.Zero);
66 | int DpiX = GetDeviceCaps(hdc, LOGPIXELSY);
67 | ReleaseDC(IntPtr.Zero, hdc);
68 | return DpiX;
69 | }
70 | }
71 | ///
72 | /// 获取真实设置的桌面分辨率大小
73 | ///
74 | public static Size DESKTOP
75 | {
76 | get
77 | {
78 | IntPtr hdc = GetDC(IntPtr.Zero);
79 | Size size = new Size();
80 | size.Width = GetDeviceCaps(hdc, DESKTOPHORZRES);
81 | size.Height = GetDeviceCaps(hdc, DESKTOPVERTRES);
82 | ReleaseDC(IntPtr.Zero, hdc);
83 | return size;
84 | }
85 | }
86 |
87 | ///
88 | /// 获取宽度缩放百分比
89 | ///
90 | public static float ScaleX
91 | {
92 | get
93 | {
94 | IntPtr hdc = GetDC(IntPtr.Zero);
95 | int t = GetDeviceCaps(hdc, DESKTOPHORZRES);
96 | int d = GetDeviceCaps(hdc, HORZRES);
97 | float ScaleX = (float)GetDeviceCaps(hdc, DESKTOPHORZRES) / (float)GetDeviceCaps(hdc, HORZRES);
98 | ReleaseDC(IntPtr.Zero, hdc);
99 | return ScaleX;
100 | }
101 | }
102 | ///
103 | /// 获取高度缩放百分比
104 | ///
105 | public static float ScaleY
106 | {
107 | get
108 | {
109 | IntPtr hdc = GetDC(IntPtr.Zero);
110 | float ScaleY = (float)(float)GetDeviceCaps(hdc, DESKTOPVERTRES) / (float)GetDeviceCaps(hdc, VERTRES);
111 | ReleaseDC(IntPtr.Zero, hdc);
112 | return ScaleY;
113 | }
114 | }
115 | #endregion
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/GeniusInvokationAutoToy/Utils/Retry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 |
8 | namespace GeniusInvokationAutoToy.Utils
9 | {
10 | ///
11 | /// https://stackoverflow.com/questions/1563191/cleanest-way-to-write-retry-logic
12 | ///
13 | public static class Retry
14 | {
15 | public static void Do(
16 | Action action,
17 | TimeSpan retryInterval,
18 | int maxAttemptCount = 3)
19 | {
20 | Do