Skip to content

Commit c140fbc

Browse files
committed
Action mods integration & python checks
1 parent a223cd8 commit c140fbc

25 files changed

+545
-102
lines changed
1.67 KB
Binary file not shown.
1.68 KB
Binary file not shown.
Binary file not shown.
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using System.Windows;
9+
using Microsoft.Win32;
10+
using Newtonsoft.Json;
11+
12+
namespace AssistantComputerControl {
13+
class ActionMods {
14+
private static Dictionary<string, string> modActions = null;
15+
private static string validateErrMsg = "";
16+
17+
//Check mod folder and init mods
18+
public static void CheckMods() {
19+
try {
20+
modActions = new Dictionary<string, string>();
21+
string[] dirs = Directory.GetDirectories(MainProgram.actionModsPath, "*", SearchOption.TopDirectoryOnly);
22+
23+
foreach (string dir in dirs) {
24+
string theFile = Path.Combine(dir, "info.json");
25+
if (File.Exists(theFile)) {
26+
//Info file exists - read it
27+
string fileContent = ReadInfoFile(theFile);
28+
if (fileContent != null) {
29+
ValidateAddMod(fileContent, dir);
30+
} else {
31+
MainProgram.DoDebug("Failed to read info.json file at; " + dir);
32+
}
33+
} else {
34+
MainProgram.DoDebug("Invalid folder in action mods; '" + dir + "'. Doesn't contain an info.json file.");
35+
}
36+
}
37+
} catch (Exception e) {
38+
Console.WriteLine("The process failed: {0}", e.ToString());
39+
}
40+
}
41+
42+
//Validate & init
43+
private static bool ValidateAddMod(string fileContent, string dir) {
44+
try {
45+
dynamic jsonTest = JsonConvert.DeserializeObject<dynamic>(fileContent);
46+
if (ValidateInfoJson(jsonTest)) {
47+
string scriptFile = jsonTest["options"]["file_name"], scriptFileLocation = Path.Combine(dir, scriptFile);
48+
if (File.Exists(scriptFileLocation)) {
49+
string actionName = jsonTest["action_name"];
50+
if (!ModActionExists(actionName)) {
51+
MainProgram.DoDebug("[Mod loaded] " + jsonTest["title"] + " v" + jsonTest["version"] + " (" + actionName + ")");
52+
53+
modActions.Add(actionName, new DirectoryInfo(dir).Name);
54+
55+
ExecuteModAction(actionName); //Test
56+
} else {
57+
MainProgram.DoDebug("[Mod init error] A mod with this name (" + actionName + ") is already loaded (no dublicates allowed)");
58+
}
59+
} else {
60+
MainProgram.DoDebug("[Mod init error] Action mod script doesn't exist at; " + scriptFileLocation);
61+
}
62+
} else {
63+
MainProgram.DoDebug("[Mod init error] " + validateErrMsg);
64+
}
65+
} catch (Exception e) {
66+
MainProgram.DoDebug("[Mod init error] Failed parse JSON from info.json file at; " + dir + ". Exception; " + e.Message);
67+
}
68+
69+
return false;
70+
}
71+
72+
//Validate the JSON
73+
private static bool ValidateInfoJson(dynamic theJson) {
74+
if (theJson["action_name"] != null && theJson["options"] != null && theJson["title"] != null && theJson["version"] != null) {
75+
if (theJson["options"]["file_name"] != null && theJson["options"]["requires_param"] != null && theJson["options"]["require_second_param"] != null) {
76+
string scriptFile = theJson["options"]["file_name"];
77+
if (!scriptFile.Contains("/") && !scriptFile.Contains(@"\") && !scriptFile.Contains("..")) {
78+
return true;
79+
} else {
80+
validateErrMsg = "Invalid info.json action mod script; file has to be located within the action mod folder";
81+
}
82+
} else {
83+
validateErrMsg = "Invalid info.json action mod file; " + (theJson) + ". Missing some required options.";
84+
}
85+
} else {
86+
validateErrMsg = "Invalid info.json action mod file; " + (theJson) + ". Missing some required settings.";
87+
}
88+
return false;
89+
}
90+
91+
public static bool ModActionExists(string name) {
92+
return modActions.ContainsKey(name);
93+
}
94+
95+
//Get python path & compare versions
96+
private static string GetPythonPath(string requiredVersion = "", string maxVersion = "") {
97+
string[] possiblePythonLocations = new string[3] {
98+
@"HKLM\SOFTWARE\Python\PythonCore\",
99+
@"HKCU\SOFTWARE\Python\PythonCore\",
100+
@"HKLM\SOFTWARE\Wow6432Node\Python\PythonCore\"
101+
};
102+
//Version number, install path
103+
Dictionary<string, string> pythonLocations = new Dictionary<string, string>();
104+
105+
foreach (string possibleLocation in possiblePythonLocations) {
106+
string regKey = possibleLocation.Substring(0, 4), actualPath = possibleLocation.Substring(5);
107+
RegistryKey theKey = (regKey == "HKLM" ? Registry.LocalMachine : Registry.CurrentUser);
108+
RegistryKey theValue = theKey.OpenSubKey(actualPath);
109+
110+
foreach (var v in theValue.GetSubKeyNames()) {
111+
RegistryKey productKey = theValue.OpenSubKey(v);
112+
if (productKey != null) {
113+
try {
114+
string pythonExePath = productKey.OpenSubKey("InstallPath").GetValue("ExecutablePath").ToString();
115+
if (pythonExePath != null && pythonExePath != "") {
116+
//Console.WriteLine("Got python version; " + v + " at path; " + pythonExePath);
117+
pythonLocations.Add(v.ToString(), pythonExePath);
118+
}
119+
} catch {
120+
//Install path doesn't exist
121+
}
122+
}
123+
}
124+
}
125+
126+
if (pythonLocations.Count > 0) {
127+
System.Version desiredVersion = new System.Version(requiredVersion == "" ? "0.0.1" : requiredVersion),
128+
maxPVersion = new System.Version(maxVersion == "" ? "999.999.999" : maxVersion);
129+
130+
string highestVersion = "", highestVersionPath = "";
131+
132+
foreach (KeyValuePair<string, string> pVersion in pythonLocations) {
133+
//TODO; if on 64-bit machine, prefer the 64 bit version over 32 and vice versa
134+
int index = pVersion.Key.IndexOf("-"); //For x-32 and x-64 in version numbers
135+
string formattedVersion = index > 0 ? pVersion.Key.Substring(0, index) : pVersion.Key;
136+
137+
System.Version thisVersion = new System.Version(formattedVersion);
138+
int comparison = desiredVersion.CompareTo(thisVersion),
139+
maxComparison = maxPVersion.CompareTo(thisVersion);
140+
141+
if (comparison <= 0) {
142+
//Version is greater or equal
143+
if (maxComparison >= 0) {
144+
desiredVersion = thisVersion;
145+
146+
highestVersion = pVersion.Key;
147+
highestVersionPath = pVersion.Value;
148+
} else {
149+
//Console.WriteLine("Version is too high; " + maxComparison.ToString());
150+
}
151+
} else {
152+
//Console.WriteLine("Version (" + pVersion.Key + ") is not within the spectrum.");
153+
}
154+
}
155+
156+
//Console.WriteLine(highestVersion);
157+
//Console.WriteLine(highestVersionPath);
158+
return highestVersionPath;
159+
}
160+
161+
return "";
162+
}
163+
164+
//Execute mod
165+
public static void ExecuteModAction(string name, string parameter = "", string secondaryParameter = "") {
166+
MainProgram.DoDebug("\nRunning MOD ACTION!\n");
167+
168+
string modLocation = Path.Combine(MainProgram.actionModsPath, modActions[name]), infoJsonFile = Path.Combine(modLocation, "info.json");
169+
if (File.Exists(infoJsonFile)) {
170+
string modFileContent = ReadInfoFile(infoJsonFile);
171+
if (modFileContent != null) {
172+
try {
173+
dynamic jsonTest = JsonConvert.DeserializeObject<dynamic>(modFileContent);
174+
if (jsonTest != null) {
175+
if (ValidateInfoJson(jsonTest)) {
176+
//JSON is valid - get script file
177+
string scriptFile = jsonTest["options"]["file_name"], scriptFileLocation = Path.Combine(modLocation, scriptFile);
178+
if (File.Exists(scriptFileLocation)) {
179+
try {
180+
ProcessStartInfo p = new ProcessStartInfo {
181+
UseShellExecute = false,
182+
CreateNoWindow = true,
183+
RedirectStandardOutput = true,
184+
RedirectStandardError = true
185+
};
186+
187+
string theExtension = Path.GetExtension(scriptFile);
188+
189+
if (theExtension == ".ps1") {
190+
//Is powershell - open it correctly
191+
p.FileName = "powershell.exe";
192+
p.Arguments = $"-WindowStyle Hidden -file \"{scriptFileLocation}\" \"{Path.Combine(MainProgram.CheckPath(), "*")}\" \"*.{Properties.Settings.Default.ActionFileExtension}\"";
193+
} else if (theExtension == ".py") {
194+
//Python - open it correctly
195+
MainProgram.DoDebug("Is python!");
196+
197+
string minPythonVersion = (jsonTest["options"]["min_python_version"] != null ? jsonTest["options"]["min_python_version"] : ""),
198+
maxPythonVersion = (jsonTest["options"]["max_python_version"] != null ? jsonTest["options"]["max_python_version"] : ""),
199+
pythonPath = GetPythonPath(minPythonVersion, maxPythonVersion);
200+
201+
if (pythonPath != "") {
202+
MainProgram.DoDebug("Python path; " + pythonPath);
203+
p.FileName = GetPythonPath();
204+
p.Arguments = scriptFileLocation;
205+
} else {
206+
//No python version (or one with the min-max requirements) not found.
207+
if (minPythonVersion == "" && maxPythonVersion == "") {
208+
//Python just not found
209+
MessageBox.Show("We could not locate Python on your computer. Please either download Python or specify its path in the ACC settings if it's already installed.", MainProgram.messageBoxTitle);
210+
} else {
211+
if (minPythonVersion != "" && maxPythonVersion != "") {
212+
//Both min & max set
213+
MessageBox.Show("We could not locate a version of Python between v" + minPythonVersion + " and v" + maxPythonVersion + ". Please either download a version of Python in between the specified versions, or specify its path in the ACC settings if it's already installed.", MainProgram.messageBoxTitle);
214+
} else {
215+
if (minPythonVersion != "") {
216+
//Min only
217+
MessageBox.Show("We could not locate a version of Python greater than v" + minPythonVersion + ". Please either download Python (min version " + minPythonVersion + ") or specify its path in the ACC settings if it's already installed.", MainProgram.messageBoxTitle);
218+
} else {
219+
//Max only
220+
MessageBox.Show("We could not locate a version of Python lower than v" + maxPythonVersion + ". Please either download Python (max version " + maxPythonVersion + ") or specify its path in the ACC settings if it's already installed.", MainProgram.messageBoxTitle);
221+
}
222+
}
223+
}
224+
225+
return;
226+
}
227+
} else {
228+
//"Other" filetype. Simply open file.
229+
p.FileName = scriptFileLocation;
230+
p.Arguments = "how to do dis?";
231+
}
232+
233+
Process theP = Process.Start(p);
234+
235+
string output = theP.StandardOutput.ReadToEnd();
236+
theP.WaitForExit();
237+
238+
Console.WriteLine(output);
239+
} catch (Exception e) {
240+
//Process init failed - it shouldn't, but better safe than sorry
241+
MainProgram.DoDebug("6");
242+
Console.WriteLine(e);
243+
}
244+
} else {
245+
//Script file doesn't exist
246+
MainProgram.DoDebug("5");
247+
}
248+
} else {
249+
//JSON is not valid; validateErrMsg
250+
MainProgram.DoDebug("4");
251+
}
252+
} else {
253+
//JSON is invalid or failed
254+
MainProgram.DoDebug("3");
255+
}
256+
} catch (Exception e) {
257+
//Failed to parse
258+
MainProgram.DoDebug("2");
259+
Console.WriteLine(e.Message);
260+
}
261+
} else {
262+
//Couldn't read file
263+
MainProgram.DoDebug("1");
264+
}
265+
} else {
266+
MainProgram.DoDebug("0; " + modLocation);
267+
}
268+
269+
MainProgram.DoDebug("\n\n");
270+
}
271+
272+
private static string ReadInfoFile(string file) {
273+
try {
274+
return File.ReadAllText(file);
275+
} catch {
276+
return null;
277+
}
278+
}
279+
}
280+
}

0 commit comments

Comments
 (0)