├── .gitignore
├── Console
├── App.config
├── Config.cs
├── Console.csproj
├── Log.cs
├── Main.cs
├── Marks.cs
├── Starter.cs
└── Utils.cs
├── LICENSE
├── README.md
├── Repository.json
├── Repository_beta_13.json
├── UnityModManager.sln
├── UnityModManager
├── Config.cs
├── Doorstop.cs
├── Fixes.cs
├── Games.cs
├── Graphics.cs
├── Injector.cs
├── Json.cs
├── KeyBinding.cs
├── Log.cs
├── ModEntry.cs
├── ModInfo.cs
├── ModManager.cs
├── ModSettings.cs
├── Properties
│ ├── Resources.Designer.cs
│ └── Resources.resx
├── Repository.cs
├── TextureReplacer.cs
├── ToggleGroup.cs
├── UI.cs
├── UIDraw.cs
├── UnityModManager.csproj
├── Updates.cs
├── Utils.cs
├── VectorsInt.cs
└── Window_GUI.cs
├── UnityModManagerApp
├── DownloadExtraFiles.Designer.cs
├── DownloadExtraFiles.cs
├── DownloadExtraFiles.resx
├── DownloadMod.Designer.cs
├── DownloadMod.cs
├── DownloadMod.resx
├── Form.Designer.cs
├── Form.cs
├── Form.resx
├── Log.cs
├── Mods.cs
├── Program.cs
├── Properties
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── SetFolder.Designer.cs
├── SetFolder.cs
├── SetFolder.resx
├── Tools
│ └── SteamHelper.cs
├── UnityModManagerApp.csproj
├── Updates.cs
├── Utils.cs
├── app.config
├── icon.ico
└── images
│ └── dragdropfiles.png
├── Updater
├── Config.cs
├── Form.Designer.cs
├── Form.cs
├── Form.resx
├── Program.cs
├── Properties
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Updater.csproj
├── Utils.cs
└── app.config
└── lib
├── Harmony
├── 1.2
│ ├── 0Harmony-1.2.dll
│ └── 0Harmony12.dll
└── 2.2
│ └── 0Harmony.dll
├── Ionic.Zip.dll
├── Newtonsoft.Json.dll
├── System.Xml.dll
├── dnlib.dll
├── libraries
├── winhttp_x64.dll
└── winhttp_x86.dll
/.gitignore:
--------------------------------------------------------------------------------
1 | */UnityEngine*
2 | */obj
3 | */bin
4 | .vs
5 | */*.csproj.user
--------------------------------------------------------------------------------
/Console/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Console/Config.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Xml.Serialization;
7 | using Newtonsoft.Json;
8 |
9 | namespace UnityModManagerNet.ConsoleInstaller
10 | {
11 | public enum ModStatus { NotInstalled, Installed }
12 | public enum InstallType { Assembly, DoorstopProxy, /*Config,*/ Count }
13 |
14 | public enum UpdateCheckingMode { Manually, OnceDay, Everytime, Count }
15 |
16 | public class ModInfo : UnityModManager.ModInfo
17 | {
18 | [JsonIgnore]
19 | public ModStatus Status;
20 |
21 | [JsonIgnore]
22 | public Dictionary AvailableVersions = new Dictionary();
23 |
24 | [JsonIgnore]
25 | public Version ParsedVersion;
26 |
27 | [JsonIgnore]
28 | public string Path;
29 |
30 | public bool IsValid()
31 | {
32 | if (string.IsNullOrEmpty(Id))
33 | {
34 | return false;
35 | }
36 | if (string.IsNullOrEmpty(DisplayName))
37 | {
38 | DisplayName = Id;
39 | }
40 | if (ParsedVersion == null)
41 | {
42 | ParsedVersion = Utils.ParseVersion(Version);
43 | }
44 |
45 | return true;
46 | }
47 |
48 | public bool EqualsVersion(ModInfo other)
49 | {
50 | return other != null && Id.Equals(other.Id) && Version.Equals(other.Version);
51 | }
52 | }
53 |
54 | [XmlRoot("Config")]
55 | public class GameInfo
56 | {
57 | [XmlAttribute]
58 | public string Name;
59 | public string Folder;
60 | public string ModsDirectory;
61 | public string ModInfo;
62 | public string GameExe;
63 | public string EntryPoint;
64 | public string StartingPoint;
65 | public string UIStartingPoint;
66 | public string TextureReplacingPoint;
67 | public string SessionStartPoint;
68 | public string SessionStopPoint;
69 | public string GameVersionPoint;
70 | public string MinimalManagerVersion;
71 | public string OldPatchTarget;
72 | ///
73 | /// [0.21.8]
74 | ///
75 | public string Comment;
76 | //public string MachineConfig;
77 | public string ExtraFilesUrl;
78 | public string HarmonyVersion;
79 |
80 | public override string ToString()
81 | {
82 | return Name;
83 | }
84 |
85 | public static string filepathInGame;
86 |
87 | public void ExportToGame()
88 | {
89 | try
90 | {
91 | using (var writer = new StreamWriter(filepathInGame))
92 | {
93 | new XmlSerializer(typeof(GameInfo)).Serialize(writer, this);
94 | }
95 | }
96 | catch (Exception e)
97 | {
98 | Log.Print($"Error file creating '{filepathInGame}'.");
99 | throw e;
100 | }
101 | }
102 |
103 | public static GameInfo ImportFromGame()
104 | {
105 | try
106 | {
107 | using (var stream = File.OpenRead(filepathInGame))
108 | {
109 | return new XmlSerializer(typeof(GameInfo)).Deserialize(stream) as GameInfo;
110 | }
111 | }
112 | catch (Exception e)
113 | {
114 | Log.Print(e.ToString());
115 | Log.Print($"Can't read file '{filepathInGame}'.");
116 | return null;
117 | }
118 | }
119 | }
120 |
121 | public sealed class Config
122 | {
123 | public const string filename = "UnityModManagerConfig.xml";
124 |
125 | public string Repository;
126 | public string HomePage;
127 |
128 | [XmlElement]
129 | public GameInfo[] GameInfo;
130 |
131 | public static void Create()
132 | {
133 | var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename);
134 | try
135 | {
136 | using (var writer = new StreamWriter(filepath))
137 | {
138 | var config = new Config()
139 | {
140 | GameInfo = new GameInfo[]
141 | {
142 | new GameInfo
143 | {
144 | Name = "Game",
145 | Folder = "Folder",
146 | ModsDirectory = "Mods",
147 | ModInfo = "Info.json",
148 | EntryPoint = "[Assembly-CSharp.dll]App.Awake",
149 | GameExe = "Game.exe"
150 | }
151 | }
152 | };
153 | var serializer = new XmlSerializer(typeof(Config));
154 | serializer.Serialize(writer, config);
155 | }
156 |
157 | Log.Print($"'{filename}' auto created.");
158 | }
159 | catch (Exception e)
160 | {
161 | Log.Print(e.ToString());
162 | }
163 | }
164 |
165 | public static Config Load()
166 | {
167 | var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename);
168 | if (File.Exists(filepath))
169 | {
170 | try
171 | {
172 | using (var stream = File.OpenRead(filepath))
173 | {
174 | var serializer = new XmlSerializer(typeof(Config));
175 | var result = serializer.Deserialize(stream) as Config;
176 |
177 | foreach(var file in new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).GetFiles("UnityModManagerConfig*.xml", SearchOption.TopDirectoryOnly))
178 | {
179 | if (file.Name != filename)
180 | {
181 | try
182 | {
183 | using (var localStream = File.OpenRead(file.FullName))
184 | {
185 | var localResult = serializer.Deserialize(localStream) as Config;
186 | if (localResult.GameInfo == null)
187 | continue;
188 | var concatanatedArray = new GameInfo[result.GameInfo.Length + localResult.GameInfo.Length];
189 | result.GameInfo.CopyTo(concatanatedArray, 0);
190 | localResult.GameInfo.CopyTo(concatanatedArray, result.GameInfo.Length);
191 | result.GameInfo = concatanatedArray;
192 | }
193 | }
194 | catch (Exception e)
195 | {
196 | Log.Print(e.ToString());
197 | }
198 | }
199 | }
200 |
201 | OnDeserialize(result);
202 | return result;
203 | }
204 | }
205 | catch (Exception e)
206 | {
207 | Log.Print(e.ToString() + Environment.NewLine + filename);
208 | }
209 | }
210 | else
211 | {
212 | Log.Print($"'{filename}' not found.");
213 | }
214 | return null;
215 | }
216 |
217 | private static void OnDeserialize(Config value)
218 | {
219 |
220 | }
221 | }
222 |
223 | public sealed class Param
224 | {
225 | [Serializable]
226 | public class GameParam
227 | {
228 | [XmlAttribute]
229 | public string Name;
230 | public string Path;
231 | public InstallType InstallType = InstallType.DoorstopProxy;
232 | public DateTime LastUpdateCheck;
233 | }
234 |
235 | public string APIkey;
236 | public UpdateCheckingMode UpdateCheckingMode = UpdateCheckingMode.OnceDay;
237 | public string LastSelectedGame;
238 | public int WindowHeight;
239 | public List GameParams = new List();
240 |
241 | public const string filename = "Params.xml";
242 |
243 | static GameParam CreateGameParam(GameInfo gameInfo)
244 | {
245 | return new GameParam { Name = gameInfo.Name };
246 | }
247 |
248 | public GameParam GetGameParam(GameInfo gameInfo)
249 | {
250 | var result = GameParams.FirstOrDefault(x => x.Name == gameInfo.Name);
251 | if (result == null)
252 | {
253 | result = CreateGameParam(gameInfo);
254 | GameParams.Add(result);
255 | }
256 | return result;
257 | }
258 |
259 | public void Sync(GameInfo[] gameInfos)
260 | {
261 | int i = 0;
262 | while (i < GameParams.Count)
263 | {
264 | if (gameInfos.Any(x => x.Name == GameParams[i].Name))
265 | {
266 | i++;
267 | }
268 | else
269 | {
270 | GameParams.RemoveAt(i);
271 | }
272 | }
273 | }
274 |
275 | public void Save()
276 | {
277 | var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "UnityModManagerNet");
278 | if (!Directory.Exists(dir))
279 | {
280 | Directory.CreateDirectory(dir);
281 | }
282 | var path = Path.Combine(dir, filename);
283 | try
284 | {
285 | using (var writer = new StreamWriter(path))
286 | {
287 | var serializer = new XmlSerializer(typeof(Param));
288 | serializer.Serialize(writer, this);
289 | }
290 | }
291 | catch (Exception e)
292 | {
293 | Log.Print(e.ToString() + Environment.NewLine + path);
294 | }
295 | }
296 |
297 | public static Param Load()
298 | {
299 | var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "UnityModManagerNet", filename);
300 | if (File.Exists(path))
301 | {
302 | try
303 | {
304 | using (var stream = File.OpenRead(path))
305 | {
306 | var serializer = new XmlSerializer(typeof(Param));
307 | return serializer.Deserialize(stream) as Param;
308 | }
309 | }
310 | catch (Exception e)
311 | {
312 | Log.Print(e.ToString() + Environment.NewLine + path);
313 | }
314 | }
315 | return new Param();
316 | }
317 | }
318 |
319 |
320 | }
321 |
--------------------------------------------------------------------------------
/Console/Console.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Exe
7 | net48
8 | latest
9 |
10 | UnityModManager
11 | Console
12 | UnityModManagerNet
13 | Copyright © 2021-$([System.DateTime]::Now.ToString('yyyy'))
14 |
15 |
16 |
17 | true
18 | en-001
19 | True
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | $(Pkgdnlib)\lib\net35\dnlib.dll
32 |
33 |
34 | $(PkgLib_Harmony)\lib\net48\0Harmony.dll
35 |
36 |
37 |
38 |
39 |
40 | ..\lib\UnityEngine.dll
41 |
42 |
43 | ..\lib\UnityEngine.UI.dll
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Console/Log.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace UnityModManagerNet.ConsoleInstaller
5 | {
6 | public class Log
7 | {
8 | public static Log Instance { get; set; }
9 | protected static bool firstLine = true;
10 | public const string fileLog = "Log.txt";
11 | protected static StreamWriter stream;
12 |
13 | public static void Print(string str, bool append = false)
14 | {
15 | Instance.Write(str, append);
16 | }
17 |
18 | public static void Append(string str)
19 | {
20 | Print(str, true);
21 | }
22 |
23 | public static void Init() where T: Log
24 | {
25 | try
26 | {
27 | Instance = Activator.CreateInstance();
28 | File.Delete(fileLog);
29 | stream = new StreamWriter(new FileStream(fileLog, FileMode.OpenOrCreate, FileAccess.Write));
30 | stream.AutoFlush = true;
31 | }
32 | catch (UnauthorizedAccessException)
33 | {
34 | Print("Write error, insufficient permissions. Try to run app as administrator.");
35 | }
36 | }
37 |
38 | public virtual void Write(string str, bool append = false)
39 | {
40 | if (append)
41 | {
42 | Console.Write(str);
43 | }
44 | else
45 | {
46 | if (firstLine)
47 | {
48 | firstLine = false;
49 | str = $"[{DateTime.Now.ToShortTimeString()}] {str}";
50 | }
51 | else
52 | {
53 | str = $"\r\n[{DateTime.Now.ToShortTimeString()}] {str}";
54 | }
55 | Console.Write(str);
56 | }
57 |
58 | stream?.Write(str);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Console/Marks.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace UnityModManagerNet.Marks
7 | {
8 | public static class IsDirty
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Console/Starter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Reflection;
4 |
5 | namespace UnityModManagerNet.Injection
6 | {
7 | public class UnityModManagerStarter
8 | {
9 | public static void Start()
10 | {
11 | //Injector.Run();
12 |
13 | try
14 | {
15 | var file = Path.Combine(Path.Combine(Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath), "UnityModManager"), "UnityModManager.dll");
16 | Console.WriteLine("[Assembly] Loading UnityModManager by " + file);
17 |
18 | var assembly = Assembly.LoadFrom(file);
19 | var injector = assembly.GetType("UnityModManagerNet.Injector");
20 | injector.GetMethod("Run", BindingFlags.Static | BindingFlags.Public).Invoke(null, new object[] { false });
21 | }
22 | catch (Exception e)
23 | {
24 | Console.WriteLine(e.ToString());
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 newman55
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # unity-mod-manager
2 | This mod adds modding support for games created on Unity engine.
3 |
4 | [**Home page**](https://www.nexusmods.com/site/mods/21)
5 |
6 | [**Dropbox**](https://www.dropbox.com/s/wz8x8e4onjdfdbm/UnityModManager.zip?dl=1)
7 |
8 | ### Libraries used in the project.
9 | - [Harmony](https://github.com/pardeike/Harmony/wiki/Utilities)
10 | - [HarmonyProxy](https://github.com/spacehamster/HarmonyProxy)
11 | - [UnityDoorstop](https://github.com/NeighTools/UnityDoorstop)
12 | - [dnlib](https://github.com/0xd4d/dnlib)
13 | - [Json.NET](https://www.newtonsoft.com/json)
14 | - [TinyJson](https://github.com/zanders3/json)
15 | - [Ionic.Zip](https://archive.codeplex.com/?p=dotnetzip)
16 |
--------------------------------------------------------------------------------
/Repository.json:
--------------------------------------------------------------------------------
1 | {
2 | "Releases":
3 | [
4 | {"Id": "UnityModManager", "Version": "0.12.7", "DownloadUrl": "https://www.dropbox.com/s/2fipc0zhp0q4z7m/umm_update.zip?dl=1"}
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/Repository_beta_13.json:
--------------------------------------------------------------------------------
1 | {
2 | "Releases":
3 | [
4 | {"Id": "UnityModManager", "Version": "0.32.4", "DownloadUrl": "https://www.dropbox.com/s/wt18wcq5six02ku/umm_update.zip?dl=1"}
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/UnityModManager.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31912.275
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Updater", "Updater\Updater.csproj", "{0EEC949D-BF5C-4F12-9743-0A635ABC8DE4}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityModManagerApp", "UnityModManagerApp\UnityModManagerApp.csproj", "{6E8F8B45-2A2D-4E5A-8573-3559337E68F3}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnityModManager", "UnityModManager\UnityModManager.csproj", "{A1FCAE3E-523E-4E33-8860-DD39DDDF0F62}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Console", "Console\Console.csproj", "{7151CE06-904E-485D-8BC3-A7174A9D5D29}"
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {0EEC949D-BF5C-4F12-9743-0A635ABC8DE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {0EEC949D-BF5C-4F12-9743-0A635ABC8DE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {0EEC949D-BF5C-4F12-9743-0A635ABC8DE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {0EEC949D-BF5C-4F12-9743-0A635ABC8DE4}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {6E8F8B45-2A2D-4E5A-8573-3559337E68F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {6E8F8B45-2A2D-4E5A-8573-3559337E68F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {6E8F8B45-2A2D-4E5A-8573-3559337E68F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {6E8F8B45-2A2D-4E5A-8573-3559337E68F3}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {A1FCAE3E-523E-4E33-8860-DD39DDDF0F62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {A1FCAE3E-523E-4E33-8860-DD39DDDF0F62}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {A1FCAE3E-523E-4E33-8860-DD39DDDF0F62}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {A1FCAE3E-523E-4E33-8860-DD39DDDF0F62}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {7151CE06-904E-485D-8BC3-A7174A9D5D29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {7151CE06-904E-485D-8BC3-A7174A9D5D29}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {7151CE06-904E-485D-8BC3-A7174A9D5D29}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {7151CE06-904E-485D-8BC3-A7174A9D5D29}.Release|Any CPU.Build.0 = Release|Any CPU
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | GlobalSection(ExtensibilityGlobals) = postSolution
41 | SolutionGuid = {5BE2057F-67FB-4E45-B83B-E3225C71C644}
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/UnityModManager/Config.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Xml.Serialization;
5 | using UnityEngine;
6 |
7 | namespace UnityModManagerNet
8 | {
9 | public partial class UnityModManager
10 | {
11 | public sealed class Param
12 | {
13 | [Serializable]
14 | public class Mod
15 | {
16 | [XmlAttribute]
17 | public string Id;
18 | [XmlAttribute]
19 | public bool Enabled = true;
20 | public KeyBinding Hotkey = new KeyBinding();
21 | }
22 |
23 | public static KeyBinding DefaultHotkey = new KeyBinding { keyCode = KeyCode.F10, modifiers = 1 };
24 | public static KeyBinding EscapeHotkey = new KeyBinding { keyCode = KeyCode.Escape };
25 | public KeyBinding Hotkey = new KeyBinding();
26 | public int CheckUpdates = 1;
27 | public int ShowOnStart = 1;
28 | public float WindowWidth;
29 | public float WindowHeight;
30 | public float UIScale = 1f;
31 | public string UIFont = null;
32 | public DateTime LastUpdateCheck;
33 |
34 | public List ModParams = new List();
35 |
36 | static readonly string filepath = Path.Combine(Path.GetDirectoryName(typeof(Param).Assembly.Location), "Params.xml");
37 |
38 | public void Save()
39 | {
40 | try
41 | {
42 | ModParams.Clear();
43 | foreach (var mod in modEntries)
44 | {
45 | ModParams.Add(new Mod { Id = mod.Info.Id, Enabled = mod.Enabled, Hotkey = mod.Hotkey });
46 | }
47 | using (var writer = new StreamWriter(filepath))
48 | {
49 | var serializer = new XmlSerializer(typeof(Param));
50 | serializer.Serialize(writer, this);
51 | }
52 | }
53 | catch (Exception e)
54 | {
55 | Logger.Error($"Can't write file '{filepath}'.");
56 | Debug.LogException(e);
57 | }
58 | }
59 |
60 | public static Param Load()
61 | {
62 | if (File.Exists(filepath))
63 | {
64 | try
65 | {
66 | using (var stream = File.OpenRead(filepath))
67 | {
68 | var serializer = new XmlSerializer(typeof(Param));
69 | var result = serializer.Deserialize(stream) as Param;
70 |
71 | return result;
72 | }
73 | }
74 | catch (Exception e)
75 | {
76 | Logger.Error($"Can't read file '{filepath}'.");
77 | Debug.LogException(e);
78 | }
79 | }
80 | return new Param();
81 | }
82 |
83 | internal void ReadModParams()
84 | {
85 | foreach (var item in ModParams)
86 | {
87 | var mod = FindMod(item.Id);
88 | if (mod != null)
89 | {
90 | mod.Enabled = item.Enabled;
91 | mod.Hotkey = item.Hotkey != null ? item.Hotkey : new KeyBinding();
92 | }
93 | }
94 | }
95 | }
96 |
97 | [XmlRoot("Param")]
98 | public sealed class InstallerParam
99 | {
100 | public string APIkey;
101 |
102 | public static InstallerParam Load()
103 | {
104 | var filepath = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "UnityModManagerNet"), "Params.xml");
105 | if (File.Exists(filepath))
106 | {
107 | try
108 | {
109 | using (var stream = File.OpenRead(filepath))
110 | {
111 | var serializer = new XmlSerializer(typeof(InstallerParam));
112 | var result = serializer.Deserialize(stream) as InstallerParam;
113 |
114 | return result;
115 | }
116 | }
117 | catch (Exception e)
118 | {
119 | Logger.Error($"Can't read file '{filepath}'.");
120 | Debug.LogException(e);
121 | }
122 | }
123 | return new InstallerParam();
124 | }
125 | }
126 |
127 | [XmlRoot("Config")]
128 | public class GameInfo
129 | {
130 | [XmlAttribute]
131 | public string Name;
132 | public string Folder;
133 | public string ModsDirectory;
134 | public string ModInfo;
135 | public string EntryPoint;
136 | public string StartingPoint;
137 | public string UIStartingPoint;
138 | public string TextureReplacingPoint;
139 | public string SessionStartPoint;
140 | public string SessionStopPoint;
141 | public string GameExe;
142 | public string GameVersionPoint;
143 | public string MinimalManagerVersion;
144 |
145 | static readonly string filepath = Path.Combine(Path.GetDirectoryName(typeof(GameInfo).Assembly.Location), "Config.xml");
146 |
147 | public static GameInfo Load()
148 | {
149 | try
150 | {
151 | using (var stream = File.OpenRead(filepath))
152 | {
153 | var obj = new XmlSerializer(typeof(GameInfo)).Deserialize(stream) as GameInfo;
154 | if (!string.IsNullOrEmpty(obj.Name))
155 | {
156 | obj.Name = obj.Name.Replace("&", "&");
157 | }
158 | if (!string.IsNullOrEmpty(obj.Folder))
159 | {
160 | obj.Folder = obj.Folder.Replace("&", "&");
161 | }
162 | if (!string.IsNullOrEmpty(obj.GameExe))
163 | {
164 | obj.GameExe = obj.GameExe.Replace("&", "&");
165 | }
166 |
167 | return obj;
168 | }
169 | }
170 | catch (Exception e)
171 | {
172 | Logger.Error($"Can't read file '{filepath}'.");
173 | Debug.LogException(e);
174 | return null;
175 | }
176 | }
177 | }
178 | }
179 | }
--------------------------------------------------------------------------------
/UnityModManager/Doorstop.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace Doorstop
5 | {
6 | public class Entrypoint
7 | {
8 | public static void Start()
9 | {
10 | UnityModManagerNet.UnityModManager.Main();
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/UnityModManager/Fixes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using HarmonyLib;
4 |
5 | namespace UnityModManagerNet
6 | {
7 | static class Fixes
8 | {
9 | public static void Apply()
10 | {
11 | if (Environment.Version < new Version(4, 0))
12 | {
13 | var harmony = new HarmonyLib.Harmony(nameof(UnityModManager));
14 | var original = typeof(Assembly).GetMethod(nameof(Assembly.GetTypes), BindingFlags.Instance | BindingFlags.Public, null, new Type[0], new ParameterModifier[0]);
15 | var prefix = typeof(Fixes).GetMethod(nameof(Prefix_GetTypes), BindingFlags.Static | BindingFlags.NonPublic);
16 | harmony.Patch(original, new HarmonyMethod(prefix));
17 | //UnityModManager.Logger.Log("");
18 | }
19 | }
20 |
21 | static bool Prefix_GetTypes(Assembly __instance, ref Type[] __result)
22 | {
23 | if (__instance.FullName.StartsWith("UnityModManager"))
24 | {
25 | __result = new Type[0];
26 | return false;
27 | }
28 | return true;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/UnityModManager/Games.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using UnityEngine;
6 |
7 | namespace UnityModManagerNet
8 | {
9 | public partial class UnityModManager
10 | {
11 | class GameScripts
12 | {
13 | readonly static List scripts = new List();
14 |
15 | public static void Init()
16 | {
17 | var currentGame = Config.Name.Replace(" ", "").Replace(":", "");
18 | foreach (var t in typeof(GameScripts).GetNestedTypes(BindingFlags.NonPublic))
19 | {
20 | if (t.IsClass && t.IsSubclassOf(typeof(GameScript)) && t.Name == currentGame)
21 | {
22 | var script = (GameScript)Activator.CreateInstance(t);
23 | scripts.Add(script);
24 | Logger.Log($"Initialize game script {t.Name}");
25 | }
26 | }
27 | }
28 |
29 | public static void OnBeforeLoadMods()
30 | {
31 | foreach (var o in scripts)
32 | {
33 | try
34 | {
35 | o.OnBeforeLoadMods();
36 | }
37 | catch (Exception e)
38 | {
39 | Logger.LogException("OnBeforeLoadMods", e);
40 | }
41 | }
42 | }
43 |
44 | public static void OnAfterLoadMods()
45 | {
46 | foreach (var o in scripts)
47 | {
48 | try
49 | {
50 | o.OnAfterLoadMods();
51 | }
52 | catch (Exception e)
53 | {
54 | Logger.LogException("OnAfterLoadMods", e);
55 | }
56 | }
57 | }
58 |
59 | public static void OnModToggle(ModEntry modEntry, bool value)
60 | {
61 | foreach(var o in scripts)
62 | {
63 | try
64 | {
65 | o.OnModToggle(modEntry, value);
66 | }
67 | catch (Exception e)
68 | {
69 | Logger.LogException("OnModToggle", e);
70 | }
71 | }
72 | }
73 |
74 | public static void OnToggleWindow(bool value)
75 | {
76 | foreach (var o in scripts)
77 | {
78 | try
79 | {
80 | o.OnToggleWindow(value);
81 | }
82 | catch (Exception e)
83 | {
84 | Logger.LogException("OnToggleWindow", e);
85 | }
86 | }
87 | }
88 |
89 | class GameScript
90 | {
91 | public virtual void OnModToggle(ModEntry modEntry, bool value) { }
92 | public virtual void OnBeforeLoadMods() { }
93 | public virtual void OnAfterLoadMods() { }
94 | ///
95 | /// [0.21.3]
96 | ///
97 | public virtual void OnToggleWindow(bool value) { }
98 | }
99 |
100 | // Insert here a class named as game to execute custom script for a game.
101 |
102 | /*
103 | class RiskofRain2 : GameScript
104 | {
105 | public override void OnModToggle(ModEntry modEntry, bool value)
106 | {
107 | if (modEntry.Info.IsCheat)
108 | {
109 | if (value)
110 | {
111 | SetModded(true);
112 | }
113 | else if (modEntries.All(x => x == modEntry || !x.Info.IsCheat))
114 | {
115 | SetModded(false);
116 | }
117 | }
118 | }
119 |
120 | public override void OnBeforeLoadMods()
121 | {
122 | forbidDisableMods = true;
123 | }
124 |
125 | private static FieldInfo mFieldModded;
126 | public static FieldInfo FieldModded
127 | {
128 | get
129 | {
130 | if (mFieldModded == null)
131 | {
132 | foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
133 | {
134 | if (assembly.ManifestModule.Name == "Assembly-CSharp.dll")
135 | {
136 | mFieldModded = assembly.GetType("RoR2.RoR2Application").GetField("isModded", BindingFlags.Public | BindingFlags.Static);
137 | break;
138 | }
139 | }
140 | }
141 | return mFieldModded;
142 | }
143 | }
144 |
145 | public static bool GetModded()
146 | {
147 | return (bool)FieldModded.GetValue(null);
148 | }
149 |
150 | public static void SetModded(bool value)
151 | {
152 | FieldModded.SetValue(null, value);
153 | }
154 | }
155 | */
156 |
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/UnityModManager/Injector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Runtime.InteropServices;
4 | using System.Security.Cryptography;
5 | using System.Text.RegularExpressions;
6 | using UnityEngine;
7 | using HarmonyLib;
8 |
9 | namespace UnityModManagerNet
10 | {
11 | public class Injector
12 | {
13 | public static void Run(bool doorstop = false)
14 | {
15 | if (UnityModManager.initialized)
16 | return;
17 |
18 | try
19 | {
20 | _Run(doorstop);
21 | }
22 | catch (Exception e)
23 | {
24 | Debug.LogException(e);
25 | UnityModManager.OpenUnityFileLog();
26 | }
27 | }
28 |
29 | private static bool startUiWithManager;
30 |
31 | private static void _Run(bool doorstop)
32 | {
33 | Console.WriteLine();
34 | Console.WriteLine();
35 | UnityModManager.Logger.Log("Injection...");
36 |
37 | if (!UnityModManager.Initialize())
38 | {
39 | UnityModManager.Logger.Log($"Cancel start due to an error.");
40 | UnityModManager.OpenUnityFileLog();
41 | return;
42 | }
43 |
44 | Fixes.Apply();
45 |
46 | if (!string.IsNullOrEmpty(UnityModManager.Config.UIStartingPoint) && UnityModManager.Config.UIStartingPoint != UnityModManager.Config.StartingPoint)
47 | {
48 | if (TryGetEntryPoint(UnityModManager.Config.UIStartingPoint, out var @class, out var method, out var place))
49 | {
50 | var usePrefix = (place == "before");
51 | var harmony = new HarmonyLib.Harmony(nameof(UnityModManager));
52 | var prefix = typeof(Injector).GetMethod(nameof(Prefix_Show), BindingFlags.Static | BindingFlags.NonPublic);
53 | var postfix = typeof(Injector).GetMethod(nameof(Postfix_Show), BindingFlags.Static | BindingFlags.NonPublic);
54 | harmony.Patch(method, usePrefix ? new HarmonyMethod(prefix) : null, !usePrefix ? new HarmonyMethod(postfix) : null);
55 | }
56 | else
57 | {
58 | UnityModManager.OpenUnityFileLog();
59 | return;
60 | }
61 | }
62 | else
63 | {
64 | startUiWithManager = true;
65 | }
66 |
67 | if (!string.IsNullOrEmpty(UnityModManager.Config.StartingPoint))
68 | {
69 | if (!doorstop && UnityModManager.Config.StartingPoint == UnityModManager.Config.EntryPoint)
70 | {
71 | UnityModManager.Start();
72 | if (startUiWithManager)
73 | {
74 | RunUI();
75 | }
76 | }
77 | else
78 | {
79 | if (TryGetEntryPoint(UnityModManager.Config.StartingPoint, out var @class, out var method, out var place))
80 | {
81 | var usePrefix = (place == "before");
82 | var harmony = new HarmonyLib.Harmony(nameof(UnityModManager));
83 | var prefix = typeof(Injector).GetMethod(nameof(Prefix_Start), BindingFlags.Static | BindingFlags.NonPublic);
84 | var postfix = typeof(Injector).GetMethod(nameof(Postfix_Start), BindingFlags.Static | BindingFlags.NonPublic);
85 | harmony.Patch(method, usePrefix ? new HarmonyMethod(prefix) : null, !usePrefix ? new HarmonyMethod(postfix) : null);
86 | UnityModManager.Logger.Log("Injection successful.");
87 | }
88 | else
89 | {
90 | UnityModManager.Logger.Log("Injection canceled.");
91 | UnityModManager.OpenUnityFileLog();
92 | return;
93 | }
94 | }
95 | }
96 | else
97 | {
98 | if (startUiWithManager)
99 | {
100 | UnityModManager.Logger.Error($"Can't start UI. UIStartingPoint is not defined.");
101 | UnityModManager.OpenUnityFileLog();
102 | return;
103 | }
104 | UnityModManager.Start();
105 | }
106 |
107 | if (!string.IsNullOrEmpty(UnityModManager.Config.TextureReplacingPoint))
108 | {
109 | if (TryGetEntryPoint(UnityModManager.Config.TextureReplacingPoint, out var @class, out var method, out var place))
110 | {
111 | var usePrefix = (place == "before");
112 | var harmony = new HarmonyLib.Harmony(nameof(UnityModManager));
113 | var prefix = typeof(Injector).GetMethod(nameof(Prefix_TextureReplacing), BindingFlags.Static | BindingFlags.NonPublic);
114 | var postfix = typeof(Injector).GetMethod(nameof(Postfix_TextureReplacing), BindingFlags.Static | BindingFlags.NonPublic);
115 | harmony.Patch(method, usePrefix ? new HarmonyMethod(prefix) : null, !usePrefix ? new HarmonyMethod(postfix) : null);
116 | }
117 | else
118 | {
119 | UnityModManager.OpenUnityFileLog();
120 | }
121 | }
122 |
123 | if (!string.IsNullOrEmpty(UnityModManager.Config.SessionStartPoint))
124 | {
125 | if (TryGetEntryPoint(UnityModManager.Config.SessionStartPoint, out var @class, out var method, out var place))
126 | {
127 | var usePrefix = (place == "before");
128 | var harmony = new HarmonyLib.Harmony(nameof(UnityModManager));
129 | var prefix = typeof(Injector).GetMethod(nameof(Prefix_SessionStart), BindingFlags.Static | BindingFlags.NonPublic);
130 | var postfix = typeof(Injector).GetMethod(nameof(Postfix_SessionStart), BindingFlags.Static | BindingFlags.NonPublic);
131 | harmony.Patch(method, usePrefix ? new HarmonyMethod(prefix) : null, !usePrefix ? new HarmonyMethod(postfix) : null);
132 | }
133 | else
134 | {
135 | UnityModManager.Config.SessionStartPoint = null;
136 | UnityModManager.OpenUnityFileLog();
137 | }
138 | }
139 |
140 | if (!string.IsNullOrEmpty(UnityModManager.Config.SessionStopPoint))
141 | {
142 | if (TryGetEntryPoint(UnityModManager.Config.SessionStopPoint, out var @class, out var method, out var place))
143 | {
144 | var usePrefix = (place == "before");
145 | var harmony = new HarmonyLib.Harmony(nameof(UnityModManager));
146 | var prefix = typeof(Injector).GetMethod(nameof(Prefix_SessionStop), BindingFlags.Static | BindingFlags.NonPublic);
147 | var postfix = typeof(Injector).GetMethod(nameof(Postfix_SessionStop), BindingFlags.Static | BindingFlags.NonPublic);
148 | harmony.Patch(method, usePrefix ? new HarmonyMethod(prefix) : null, !usePrefix ? new HarmonyMethod(postfix) : null);
149 | }
150 | else
151 | {
152 | UnityModManager.Config.SessionStopPoint = null;
153 | UnityModManager.OpenUnityFileLog();
154 | }
155 | }
156 | }
157 |
158 | static void RunUI()
159 | {
160 | if (!UnityModManager.UI.Load())
161 | {
162 | UnityModManager.Logger.Error($"Can't load UI.");
163 | }
164 | UnityModManager.UI.Instance.FirstLaunch();
165 | }
166 |
167 | static void Prefix_Start()
168 | {
169 | UnityModManager.Start();
170 | if (startUiWithManager)
171 | {
172 | RunUI();
173 | }
174 | }
175 |
176 | static void Postfix_Start()
177 | {
178 | UnityModManager.Start();
179 | if (startUiWithManager)
180 | {
181 | RunUI();
182 | }
183 | }
184 |
185 | static void Prefix_Show()
186 | {
187 | if (!UnityModManager.UI.Load())
188 | {
189 | UnityModManager.Logger.Error($"Can't load UI.");
190 | }
191 | if (!UnityModManager.UI.Instance)
192 | {
193 | UnityModManager.Logger.Error("UnityModManager.UI does not exist.");
194 | return;
195 | }
196 | UnityModManager.UI.Instance.FirstLaunch();
197 | }
198 |
199 | static void Postfix_Show()
200 | {
201 | if (!UnityModManager.UI.Load())
202 | {
203 | UnityModManager.Logger.Error($"Can't load UI.");
204 | }
205 | if (!UnityModManager.UI.Instance)
206 | {
207 | UnityModManager.Logger.Error("UnityModManager.UI does not exist.");
208 | return;
209 | }
210 | UnityModManager.UI.Instance.FirstLaunch();
211 | }
212 |
213 | static void Prefix_TextureReplacing()
214 | {
215 | //UnityModManager.ApplySkins();
216 | }
217 |
218 | static void Postfix_TextureReplacing()
219 | {
220 | //UnityModManager.ApplySkins();
221 | }
222 |
223 | static void Prefix_SessionStart()
224 | {
225 | foreach (var mod in UnityModManager.modEntries)
226 | {
227 | if (mod.Active && mod.OnSessionStart != null)
228 | {
229 | try
230 | {
231 | mod.OnSessionStart.Invoke(mod);
232 | }
233 | catch (Exception e)
234 | {
235 | mod.Logger.LogException("OnSessionStart", e);
236 | }
237 | }
238 | }
239 | }
240 |
241 | static void Postfix_SessionStart()
242 | {
243 | Prefix_SessionStart();
244 | }
245 |
246 | static void Prefix_SessionStop()
247 | {
248 | foreach (var mod in UnityModManager.modEntries)
249 | {
250 | if (mod.Active && mod.OnSessionStop != null)
251 | {
252 | try
253 | {
254 | mod.OnSessionStop.Invoke(mod);
255 | }
256 | catch (Exception e)
257 | {
258 | mod.Logger.LogException("OnSessionStop", e);
259 | }
260 | }
261 | }
262 | }
263 |
264 | static void Postfix_SessionStop()
265 | {
266 | Prefix_SessionStop();
267 | }
268 |
269 | internal static bool TryGetEntryPoint(string str, out Type foundClass, out MethodInfo foundMethod, out string insertionPlace)
270 | {
271 | foundClass = null;
272 | foundMethod = null;
273 | insertionPlace = null;
274 |
275 | if (TryParseEntryPoint(str, out string assemblyName, out _, out _, out _))
276 | {
277 | foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
278 | {
279 | if (assembly.ManifestModule.Name == assemblyName)
280 | {
281 | return TryGetEntryPoint(assembly, str, out foundClass, out foundMethod, out insertionPlace);
282 | }
283 | }
284 | try
285 | {
286 | var asm = Assembly.Load(assemblyName);
287 | return TryGetEntryPoint(asm, str, out foundClass, out foundMethod, out insertionPlace);
288 | }
289 | catch (Exception e)
290 | {
291 | UnityModManager.Logger.Error($"File '{assemblyName}' cant't be loaded.");
292 | UnityModManager.Logger.LogException(e);
293 | }
294 |
295 | return false;
296 | }
297 |
298 | return false;
299 | }
300 |
301 | internal static bool TryGetEntryPoint(Assembly assembly, string str, out Type foundClass, out MethodInfo foundMethod, out string insertionPlace)
302 | {
303 | foundClass = null;
304 | foundMethod = null;
305 |
306 | if (!TryParseEntryPoint(str, out _, out var className, out var methodName, out insertionPlace))
307 | {
308 | return false;
309 | }
310 |
311 | foundClass = assembly.GetType(className);
312 | if (foundClass == null)
313 | {
314 | UnityModManager.Logger.Error($"Class '{className}' not found.");
315 | return false;
316 | }
317 |
318 | foundMethod = foundClass.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
319 | if (foundMethod == null)
320 | {
321 | UnityModManager.Logger.Error($"Method '{methodName}' not found.");
322 | return false;
323 | }
324 |
325 | return true;
326 | }
327 |
328 | internal static bool TryParseEntryPoint(string str, out string assembly, out string @class, out string method, out string insertionPlace)
329 | {
330 | assembly = string.Empty;
331 | @class = string.Empty;
332 | method = string.Empty;
333 | insertionPlace = string.Empty;
334 |
335 | var regex = new Regex(@"(?:(?<=\[)(?'assembly'.+(?>\.dll))(?=\]))|(?:(?'class'[\w|\.]+)(?=\.))|(?:(?<=\.)(?'func'\w+))|(?:(?<=\:)(?'mod'\w+))", RegexOptions.IgnoreCase);
336 | var matches = regex.Matches(str);
337 | var groupNames = regex.GetGroupNames();
338 |
339 | if (matches.Count > 0)
340 | {
341 | foreach (Match match in matches)
342 | {
343 | foreach (var group in groupNames)
344 | {
345 | if (match.Groups[group].Success)
346 | {
347 | switch (group)
348 | {
349 | case "assembly":
350 | assembly = match.Groups[group].Value;
351 | break;
352 | case "class":
353 | @class = match.Groups[group].Value;
354 | break;
355 | case "func":
356 | method = match.Groups[group].Value;
357 | if (method == "ctor")
358 | method = ".ctor";
359 | else if (method == "cctor")
360 | method = ".cctor";
361 | break;
362 | case "mod":
363 | insertionPlace = match.Groups[group].Value.ToLower();
364 | break;
365 | }
366 | }
367 | }
368 | }
369 | }
370 |
371 | var hasError = false;
372 |
373 | if (string.IsNullOrEmpty(assembly))
374 | {
375 | hasError = true;
376 | UnityModManager.Logger.Error("Assembly name not found.");
377 | }
378 |
379 | if (string.IsNullOrEmpty(@class))
380 | {
381 | hasError = true;
382 | UnityModManager.Logger.Error("Class name not found.");
383 | }
384 |
385 | if (string.IsNullOrEmpty(method))
386 | {
387 | hasError = true;
388 | UnityModManager.Logger.Error("Method name not found.");
389 | }
390 |
391 | if (hasError)
392 | {
393 | UnityModManager.Logger.Error($"Error parsing EntryPoint '{str}'.");
394 | return false;
395 | }
396 |
397 | return true;
398 | }
399 | }
400 | }
401 |
--------------------------------------------------------------------------------
/UnityModManager/Log.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using UnityEngine;
6 |
7 | namespace UnityModManagerNet
8 | {
9 | public partial class UnityModManager
10 | {
11 | public partial class ModEntry
12 | {
13 | public class ModLogger
14 | {
15 | protected readonly string Prefix;
16 | protected readonly string PrefixError;
17 | protected readonly string PrefixCritical;
18 | protected readonly string PrefixWarning;
19 | protected readonly string PrefixException;
20 |
21 | public ModLogger(string Id)
22 | {
23 | Prefix = $"[{Id}] ";
24 | PrefixError = $"[{Id}] [Error] ";
25 | PrefixCritical = $"[{Id}] [Critical] ";
26 | PrefixWarning = $"[{Id}] [Warning] ";
27 | PrefixException = $"[{Id}] [Exception] ";
28 | }
29 |
30 | public void Log(string str)
31 | {
32 | UnityModManager.Logger.Log(str, Prefix);
33 | }
34 |
35 | public void Error(string str)
36 | {
37 | UnityModManager.Logger.Log(str, PrefixError);
38 | }
39 |
40 | public void Critical(string str)
41 | {
42 | UnityModManager.Logger.Log(str, PrefixCritical);
43 | }
44 |
45 | public void Warning(string str)
46 | {
47 | UnityModManager.Logger.Log(str, PrefixWarning);
48 | }
49 |
50 | public void NativeLog(string str)
51 | {
52 | UnityModManager.Logger.NativeLog(str, Prefix);
53 | }
54 |
55 | ///
56 | /// [0.17.0]
57 | ///
58 | public void LogException(string key, Exception e)
59 | {
60 | UnityModManager.Logger.LogException(key, e, PrefixException);
61 | }
62 |
63 | ///
64 | /// [0.17.0]
65 | ///
66 | public void LogException(Exception e)
67 | {
68 | UnityModManager.Logger.LogException(null, e, PrefixException);
69 | }
70 | }
71 | }
72 |
73 | public static class Logger
74 | {
75 | const string Prefix = "[Manager] ";
76 | const string PrefixError = "[Manager] [Error] ";
77 | const string PrefixException = "[Manager] [Exception] ";
78 |
79 | public static readonly string filepath = Path.Combine(Path.GetDirectoryName(typeof(GameInfo).Assembly.Location), "Log.txt");
80 |
81 | public static void NativeLog(string str)
82 | {
83 | NativeLog(str, Prefix);
84 | }
85 |
86 | public static void NativeLog(string str, string prefix)
87 | {
88 | Write(prefix + str, true);
89 | }
90 |
91 | public static void Log(string str)
92 | {
93 | Log(str, Prefix);
94 | }
95 |
96 | public static void Log(string str, string prefix)
97 | {
98 | Write(prefix + str);
99 | }
100 |
101 | public static void Error(string str)
102 | {
103 | Error(str, PrefixError);
104 | }
105 |
106 | public static void Error(string str, string prefix)
107 | {
108 | Write(prefix + str);
109 | }
110 |
111 | ///
112 | /// [0.17.0]
113 | ///
114 | public static void LogException(Exception e)
115 | {
116 | LogException(null, e, PrefixException);
117 | }
118 |
119 | ///
120 | /// [0.17.0]
121 | ///
122 | public static void LogException(string key, Exception e)
123 | {
124 | LogException(key, e, PrefixException);
125 | }
126 |
127 | ///
128 | /// [0.17.0]
129 | ///
130 | public static void LogException(string key, Exception e, string prefix)
131 | {
132 | if (string.IsNullOrEmpty(key))
133 | Write($"{prefix}{e.GetType().Name} - {e.Message}");
134 | else
135 | Write($"{prefix}{key}: {e.GetType().Name} - {e.Message}");
136 | Console.WriteLine(e.ToString());
137 | }
138 |
139 | private static bool hasErrors;
140 | private static int bufferCapacity = 100;
141 | private static List buffer = new List(bufferCapacity);
142 | internal static int historyCapacity = 200;
143 | internal static List history = new List(historyCapacity * 2);
144 |
145 | private static void Write(string str, bool onlyNative = false)
146 | {
147 | if (str == null)
148 | return;
149 |
150 | Console.WriteLine(str);
151 |
152 | if (onlyNative)
153 | return;
154 |
155 | buffer.Add(str);
156 | history.Add(str);
157 |
158 | if (history.Count >= historyCapacity * 2)
159 | {
160 | var result = history.Skip(historyCapacity).ToArray();
161 | history.Clear();
162 | history.AddRange(result);
163 | }
164 | }
165 |
166 | private static float timer;
167 |
168 | internal static void Watcher(float dt)
169 | {
170 | if (buffer.Count >= bufferCapacity || timer > 0.5f)
171 | {
172 | WriteBuffers();
173 | }
174 | else
175 | {
176 | timer += dt;
177 | }
178 | }
179 |
180 | internal static void WriteBuffers()
181 | {
182 | try
183 | {
184 | if (buffer.Count > 0 && !hasErrors)
185 | {
186 | if (!File.Exists(filepath))
187 | {
188 | using (File.Create(filepath))
189 | {; }
190 | }
191 | using (StreamWriter writer = File.AppendText(filepath))
192 | {
193 | foreach (var str in buffer)
194 | {
195 | writer.WriteLine(str);
196 | }
197 | }
198 | }
199 | }
200 | catch (UnauthorizedAccessException e)
201 | {
202 | hasErrors = true;
203 | Console.WriteLine(PrefixException + e.ToString());
204 | Console.WriteLine(Prefix + "Uncheck the read-only box from the UnityModManager folder.");
205 | history.Add(PrefixException + e.ToString());
206 | history.Add(Prefix + "Uncheck the read-only box from the UnityModManager folder.");
207 | }
208 | catch (Exception e)
209 | {
210 | hasErrors = true;
211 | Console.WriteLine(PrefixException + e.ToString());
212 | history.Add(PrefixException + e.ToString());
213 | }
214 |
215 | buffer.Clear();
216 | timer = 0;
217 | }
218 |
219 | public static void Clear()
220 | {
221 | buffer.Clear();
222 | history.Clear();
223 | if (File.Exists(filepath) && !hasErrors)
224 | {
225 | try
226 | {
227 | File.Delete(filepath);
228 | }
229 | catch (UnauthorizedAccessException e)
230 | {
231 | hasErrors = true;
232 | Console.WriteLine(PrefixException + e.ToString());
233 | Console.WriteLine(Prefix + "Uncheck the read-only box from the UnityModManager folder.");
234 | history.Add(PrefixException + e.ToString());
235 | history.Add(Prefix + "Uncheck the read-only box from the UnityModManager folder.");
236 | }
237 | catch (Exception e)
238 | {
239 | hasErrors = true;
240 | Console.WriteLine(PrefixException + e.ToString());
241 | history.Add(PrefixException + e.ToString());
242 | }
243 | }
244 | }
245 | }
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/UnityModManager/ModInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace UnityModManagerNet
7 | {
8 | public partial class UnityModManager
9 | {
10 | public class ModInfo : IEquatable
11 | {
12 | public string Id;
13 |
14 | public string DisplayName;
15 |
16 | public string Author;
17 |
18 | public string Version;
19 |
20 | public string ManagerVersion;
21 |
22 | public string GameVersion;
23 |
24 | public string[] Requirements;
25 |
26 | public string[] LoadAfter;
27 |
28 | public string AssemblyName;
29 |
30 | public string EntryMethod;
31 |
32 | public string HomePage;
33 |
34 | public string Repository;
35 |
36 | public string ContentType;
37 |
38 | ///
39 | /// Used for RoR2 game [0.17.0]
40 | ///
41 | [NonSerialized]
42 | public bool IsCheat = true;
43 |
44 | public static implicit operator bool(ModInfo exists)
45 | {
46 | return exists != null;
47 | }
48 |
49 | public bool Equals(ModInfo other)
50 | {
51 | return Id.Equals(other.Id);
52 | }
53 |
54 | public override bool Equals(object obj)
55 | {
56 | if (ReferenceEquals(null, obj))
57 | {
58 | return false;
59 | }
60 | return obj is ModInfo modInfo && Equals(modInfo);
61 | }
62 |
63 | public override int GetHashCode()
64 | {
65 | return Id.GetHashCode();
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/UnityModManager/ModSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Xml.Serialization;
7 |
8 | namespace UnityModManagerNet
9 | {
10 | public partial class UnityModManager
11 | {
12 | public class ModSettings
13 | {
14 | ///
15 | /// By default, it will save the data to the Mods/%Name%/Settings.xml [0.31.1]
16 | ///
17 | ///
18 | /// Before version [0.31.1] it was necessary to override
19 | ///
20 | public virtual void Save(ModEntry modEntry)
21 | {
22 | Save(this, modEntry);
23 | }
24 |
25 | public virtual string GetPath(ModEntry modEntry)
26 | {
27 | return Path.Combine(modEntry.Path, "Settings.xml");
28 | }
29 |
30 | public static void Save(T data, ModEntry modEntry) where T : ModSettings, new()
31 | {
32 | Save(data, modEntry, null);
33 | }
34 |
35 | ///
36 | /// [0.20.0]
37 | ///
38 | public static void Save(T data, ModEntry modEntry, XmlAttributeOverrides attributes) where T : ModSettings, new()
39 | {
40 | var filepath = data.GetPath(modEntry);
41 | try
42 | {
43 | using (var writer = new StreamWriter(filepath))
44 | {
45 | var serializer = new XmlSerializer(data.GetType(), attributes);
46 | serializer.Serialize(writer, data);
47 | }
48 | }
49 | catch (Exception e)
50 | {
51 | modEntry.Logger.Error($"Can't save {filepath}.");
52 | modEntry.Logger.LogException(e);
53 | }
54 | }
55 |
56 | public static T Load(ModEntry modEntry) where T : ModSettings, new()
57 | {
58 | var t = new T();
59 | var filepath = t.GetPath(modEntry);
60 | if (File.Exists(filepath))
61 | {
62 | try
63 | {
64 | using (var stream = File.OpenRead(filepath))
65 | {
66 | var serializer = new XmlSerializer(typeof(T));
67 | var result = (T)serializer.Deserialize(stream);
68 | return result;
69 | }
70 | }
71 | catch (Exception e)
72 | {
73 | modEntry.Logger.Error($"Can't read {filepath}.");
74 | modEntry.Logger.LogException(e);
75 | }
76 | }
77 |
78 | return t;
79 | }
80 |
81 | public static T Load(ModEntry modEntry, XmlAttributeOverrides attributes) where T : ModSettings, new()
82 | {
83 | var t = new T();
84 | var filepath = t.GetPath(modEntry);
85 | if (File.Exists(filepath))
86 | {
87 | try
88 | {
89 | using (var stream = File.OpenRead(filepath))
90 | {
91 | var serializer = new XmlSerializer(typeof(T), attributes);
92 | var result = (T)serializer.Deserialize(stream);
93 | return result;
94 | }
95 | }
96 | catch (Exception e)
97 | {
98 | modEntry.Logger.Error($"Can't read {filepath}.");
99 | modEntry.Logger.LogException(e);
100 | }
101 | }
102 |
103 | return t;
104 | }
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/UnityModManager/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace UnityModManagerNet.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", "16.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("UnityModManagerNet.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性
51 | /// 重写当前线程的 CurrentUICulture 属性。
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 |
--------------------------------------------------------------------------------
/UnityModManager/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=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/UnityModManager/Repository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace UnityModManagerNet
7 | {
8 | public partial class UnityModManager
9 | {
10 | public class Repository
11 | {
12 | [Serializable]
13 | public class Release : IEquatable
14 | {
15 | public string Id;
16 | public string Version;
17 | public string DownloadUrl;
18 |
19 | public bool Equals(Release other)
20 | {
21 | return Id.Equals(other.Id);
22 | }
23 |
24 | public override bool Equals(object obj)
25 | {
26 | if (ReferenceEquals(null, obj))
27 | {
28 | return false;
29 | }
30 | return obj is Release obj2 && Equals(obj2);
31 | }
32 |
33 | public override int GetHashCode()
34 | {
35 | return Id.GetHashCode();
36 | }
37 | }
38 |
39 | public Release[] Releases;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/UnityModManager/TextureReplacer.cs:
--------------------------------------------------------------------------------
1 | using HarmonyLib;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Text;
8 | using System.Xml.Serialization;
9 | using TinyJson;
10 | using UnityEngine;
11 | using static UnityModManagerNet.UnityModManager.TextureReplacer;
12 |
13 | namespace UnityModManagerNet
14 | {
15 | public partial class UnityModManager
16 | {
17 | internal class TextureReplacer
18 | {
19 | public class Skin
20 | {
21 | public struct conditions
22 | {
23 | public string MaterialName;
24 | public string ObjectName;
25 | public string ObjectComponent;
26 | public string Custom;
27 | [IgnoreJson] public bool IsEmpty => string.IsNullOrEmpty(MaterialName) && string.IsNullOrEmpty(ObjectName) && string.IsNullOrEmpty(ObjectComponent) && string.IsNullOrEmpty(Custom);
28 | }
29 | public class texture
30 | {
31 | public string Path;
32 | public Texture2D Texture;
33 | public Texture2D Previous;
34 | }
35 |
36 | [IgnoreJson] public ModEntry modEntry;
37 | public string Name;
38 | public string Tags;
39 | public conditions Conditions;
40 | [IgnoreJson] public Dictionary textures;
41 |
42 | public override string ToString()
43 | {
44 | return $"{Name} ({modEntry.Info.DisplayName})";
45 | }
46 |
47 | public void WriteFile(string filePath)
48 | {
49 | try
50 | {
51 | File.WriteAllText(filePath, JSONWriter.ToJson(this));
52 | }
53 | catch (Exception e)
54 | {
55 | Logger.Error(e.ToString());
56 | Logger.Error($"Error file creating '{filePath}'.");
57 | }
58 | }
59 |
60 | public static Skin ReadFile(string filePath)
61 | {
62 | try
63 | {
64 | return JSONParser.FromJson(File.ReadAllText(filePath));
65 | }
66 | catch (Exception e)
67 | {
68 | Logger.Error(e.ToString());
69 | Logger.Error($"Can't read file '{filePath}'.");
70 | return null;
71 | }
72 | }
73 |
74 | public static implicit operator bool(Skin exists)
75 | {
76 | return exists != null;
77 | }
78 |
79 | public bool Equals(Skin other)
80 | {
81 | return Name.Equals(other.Name) && modEntry.Info.Equals(other.modEntry.Info);
82 | }
83 |
84 | public override bool Equals(object obj)
85 | {
86 | if (ReferenceEquals(null, obj))
87 | {
88 | return false;
89 | }
90 | return obj is Skin skin && Equals(skin);
91 | }
92 |
93 | public override int GetHashCode()
94 | {
95 | return Name.GetHashCode() + modEntry.Info.GetHashCode();
96 | }
97 | }
98 |
99 | public static void Start()
100 | {
101 | }
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/UnityModManager/UnityModManager.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Library
7 | net35
8 | latest
9 |
10 | UnityModManager
11 | UnityModManagerNet
12 | Copyright © 2019-$([System.DateTime]::Now.ToString('yyyy'))
13 | 0.32.4
14 |
15 |
16 |
17 | true
18 | $(SolutionDir)\UnityModManager\bin\$(Configuration)\
19 | en-001
20 | 0.32.4
21 | 0.32.4
22 | True
23 | UnityModManager
24 | newman55
25 | Mod manager for Unity games.
26 | https://www.nexusmods.com/site/mods/21
27 | https://github.com/newman55/unity-mod-manager/
28 | unity3d mod manager
29 | MIT
30 | git
31 |
32 |
33 |
34 |
35 |
36 |
37 | all
38 | runtime; build; native; contentfiles; analyzers; buildtransitive
39 |
40 |
41 |
42 |
43 |
44 | ..\lib\UnityEngine.dll
45 |
46 |
47 | ..\lib\UnityEngine.UI.dll
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/UnityModManager/Updates.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Net;
8 | using System.Net.NetworkInformation;
9 | using System.Reflection;
10 | using System.Text;
11 | using System.Threading;
12 | using UnityEngine;
13 | using UnityEngine.Events;
14 | using UnityEngine.Networking;
15 | using static UnityModManagerNet.UnityModManager;
16 |
17 | namespace UnityModManagerNet
18 | {
19 | public partial class UnityModManager
20 | {
21 | public class NexusModInfo
22 | {
23 | public string name;
24 | public int mod_id;
25 | public string domain_name;
26 | public string version;
27 | }
28 |
29 | private static void CheckModUpdates()
30 | {
31 | Logger.Log("Checking updates.");
32 |
33 | if (!HasNetworkConnection())
34 | {
35 | Logger.Log("No network connection or firewall blocked.");
36 | return;
37 | }
38 |
39 | Params.LastUpdateCheck = DateTime.Now;
40 |
41 | var urls = new HashSet();
42 | var nexusUrls = new HashSet();
43 |
44 | foreach (var modEntry in modEntries)
45 | {
46 | if (!string.IsNullOrEmpty(modEntry.Info.Repository))
47 | {
48 | urls.Add(modEntry.Info.Repository);
49 | }
50 |
51 | if (!string.IsNullOrEmpty(modEntry.Info.HomePage) && ParseNexusUrl(modEntry.Info.HomePage, out string nexusGame, out string nexusModId))
52 | {
53 | nexusUrls.Add(modEntry.Info.HomePage);
54 | }
55 | }
56 |
57 | if (urls.Count > 0)
58 | {
59 | foreach (var url in urls)
60 | {
61 | if (unityVersion < new Version(5, 4))
62 | {
63 | UI.Instance.StartCoroutine(DownloadString_5_3(url, ParseRepository));
64 | }
65 | else
66 | {
67 | UI.Instance.StartCoroutine(DownloadString(url, ParseRepository));
68 | }
69 | }
70 | }
71 |
72 | if (nexusUrls.Count > 0)
73 | {
74 | foreach (var url in nexusUrls)
75 | {
76 | if (unityVersion >= new Version(5, 4))
77 | {
78 | UI.Instance.StartCoroutine(DownloadString(url, ParseNexus));
79 | }
80 | }
81 | }
82 | }
83 |
84 | private static void ParseRepository(string json, string url)
85 | {
86 | if (string.IsNullOrEmpty(json))
87 | {
88 | return;
89 | }
90 |
91 | try
92 | {
93 | var repository = TinyJson.JSONParser.FromJson(json);
94 | if (repository != null && repository.Releases != null && repository.Releases.Length > 0)
95 | {
96 | foreach (var release in repository.Releases)
97 | {
98 | if (!string.IsNullOrEmpty(release.Id) && !string.IsNullOrEmpty(release.Version))
99 | {
100 | var modEntry = FindMod(release.Id);
101 | if (modEntry != null)
102 | {
103 | var ver = ParseVersion(release.Version);
104 | if (modEntry.Version < ver && (modEntry.NewestVersion == null || modEntry.NewestVersion < ver))
105 | {
106 | modEntry.NewestVersion = ver;
107 | }
108 | }
109 | }
110 | }
111 | }
112 | }
113 | catch (Exception e)
114 | {
115 | Logger.Log(string.Format("Error checking mod updates on '{0}'.", url));
116 | Logger.Log(e.Message);
117 | }
118 | }
119 |
120 | private static void ParseNexus(string json, string url)
121 | {
122 | if (string.IsNullOrEmpty(json))
123 | {
124 | return;
125 | }
126 |
127 | try
128 | {
129 | var result = TinyJson.JSONParser.FromJson(json);
130 | if (result != null && !string.IsNullOrEmpty(result.version))
131 | {
132 | var mod = modEntries.Find((x) => x.Info.HomePage == url);
133 | if (mod != null)
134 | {
135 | var ver = ParseVersion(result.version);
136 | if (mod.Version < ver && (mod.NewestVersion == null || mod.NewestVersion < ver))
137 | {
138 | mod.NewestVersion = ver;
139 | }
140 | }
141 | }
142 | }
143 | catch (Exception e)
144 | {
145 | Logger.Log(string.Format("Error checking mod updates on '{0}'.", url));
146 | Logger.Log(e.Message);
147 | }
148 | }
149 |
150 | public static bool HasNetworkConnection()
151 | {
152 | //try
153 | //{
154 | // using (var ping = new System.Net.NetworkInformation.Ping())
155 | // {
156 | // return ping.Send("8.8.8.8", 3000).Status == IPStatus.Success;
157 | // }
158 | //}
159 | //catch (Exception e)
160 | //{
161 | // Console.WriteLine(e.Message);
162 | //}
163 |
164 | try
165 | {
166 | var timeout = 2000;
167 | var ping = new UnityEngine.Ping("8.8.8.8");
168 | while (!ping.isDone)
169 | {
170 | Thread.Sleep(10);
171 | timeout -= 10;
172 | if (timeout <= 0)
173 | {
174 | return false;
175 | }
176 | }
177 | return true;
178 | }
179 | catch (Exception e)
180 | {
181 | Console.WriteLine(e.Message);
182 | }
183 |
184 | return false;
185 | }
186 |
187 | private static bool nexusApiSupportLogged;
188 |
189 | private static IEnumerator DownloadString(string url, UnityAction handler)
190 | {
191 | var orgUrl = url;
192 | var www = UnityWebRequest.Get(url);
193 | if (ParseNexusUrl(url, out string nexusGame, out string nexusModId))
194 | {
195 | if (string.IsNullOrEmpty(InstallerParams.APIkey))
196 | {
197 | if (!nexusApiSupportLogged)
198 | {
199 | nexusApiSupportLogged = true;
200 | Logger.Log($"The nexus api key is missing. Without it, you won't be able to check for updates. You can configure it via the UnityModManager Installer. If you don't need it, just ignore.");
201 | }
202 | yield break;
203 | }
204 | url = $"https://api.nexusmods.com/v1/games/{nexusGame}/mods/{nexusModId}.json";
205 | www = UnityWebRequest.Get(url);
206 | www.SetRequestHeader("Content-Type", "application/json");
207 | www.SetRequestHeader("apikey", InstallerParams.APIkey);
208 | www.SetRequestHeader("Application-Version", version.ToString());
209 | www.SetRequestHeader("Application-Name", "UnityModManager");
210 | }
211 | yield return www.Send();
212 |
213 | MethodInfo isError;
214 | var ver = ParseVersion(Application.unityVersion);
215 | if (ver.Major >= 2017)
216 | {
217 | isError = typeof(UnityWebRequest).GetMethod("get_isNetworkError");
218 | }
219 | else
220 | {
221 | isError = typeof(UnityWebRequest).GetMethod("get_isError");
222 | }
223 |
224 | if (isError == null || (bool)isError.Invoke(www, null))
225 | {
226 | Logger.Log(www.error);
227 | Logger.Log(string.Format("Error downloading '{0}'.", url));
228 | yield break;
229 | }
230 | handler(www.downloadHandler.text, orgUrl);
231 | }
232 |
233 | private static IEnumerator DownloadString_5_3(string url, UnityAction handler)
234 | {
235 | var www = new WWW(url);
236 | yield return www;
237 |
238 | if (!string.IsNullOrEmpty(www.error))
239 | {
240 | Logger.Log(www.error);
241 | Logger.Log(string.Format("Error downloading '{0}'.", url));
242 | yield break;
243 | }
244 |
245 | handler(www.text, url);
246 | }
247 | }
248 | }
249 |
--------------------------------------------------------------------------------
/UnityModManager/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text.RegularExpressions;
4 | using System.Threading;
5 | using UnityEngine;
6 |
7 | namespace UnityModManagerNet
8 | {
9 | public partial class UnityModManager
10 | {
11 | public static void OpenUnityFileLog()
12 | {
13 | new Thread(() =>
14 | {
15 | Thread.CurrentThread.IsBackground = true;
16 | var folders = new string[] { Application.persistentDataPath, Application.dataPath };
17 | var files = new string[] { "Player.log", "output_log.txt" };
18 | foreach (var folder in folders)
19 | {
20 | foreach (var file in files)
21 | {
22 | var filepath = Path.Combine(folder, file);
23 | if (File.Exists(filepath))
24 | {
25 | Thread.Sleep(500);
26 | Application.OpenURL(filepath);
27 | return;
28 | }
29 | }
30 | }
31 | }).Start();
32 | }
33 |
34 | public static Version ParseVersion(string str)
35 | {
36 | var array = str.Split('.');
37 | if (array.Length >= 4)
38 | {
39 | var regex = new Regex(@"\D");
40 | return new Version(int.Parse(regex.Replace(array[0], "")), int.Parse(regex.Replace(array[1], "")), int.Parse(regex.Replace(array[2], "")), int.Parse(regex.Replace(array[3], "")));
41 | }
42 | else if (array.Length >= 3)
43 | {
44 | var regex = new Regex(@"\D");
45 | return new Version(int.Parse(regex.Replace(array[0], "")), int.Parse(regex.Replace(array[1], "")), int.Parse(regex.Replace(array[2], "")));
46 | }
47 | else if (array.Length >= 2)
48 | {
49 | var regex = new Regex(@"\D");
50 | return new Version(int.Parse(regex.Replace(array[0], "")), int.Parse(regex.Replace(array[1], "")));
51 | }
52 | else if (array.Length >= 1)
53 | {
54 | var regex = new Regex(@"\D");
55 | return new Version(int.Parse(regex.Replace(array[0], "")), 0);
56 | }
57 |
58 | Logger.Error($"Error parsing version {str}");
59 | return new Version();
60 | }
61 |
62 | public static bool ParseNexusUrl(string url, out string game, out string id)
63 | {
64 | game = null;
65 | id = null;
66 | var regex = new Regex(@"https:\/\/www\.nexusmods\.com\/(\w+)\/mods\/(\d+)", RegexOptions.IgnoreCase);
67 | var matches = regex.Matches(url);
68 | foreach (Match match in matches)
69 | {
70 | game = match.Groups[1].Value;
71 | id = match.Groups[2].Value;
72 | return true;
73 | }
74 | return false;
75 | }
76 |
77 | public static bool IsUnixPlatform()
78 | {
79 | int p = (int)Environment.OSVersion.Platform;
80 | return (p == 4) || (p == 6) || (p == 128);
81 | }
82 |
83 | public static bool IsMacPlatform()
84 | {
85 | int p = (int)Environment.OSVersion.Platform;
86 | return (p == 6);
87 | }
88 |
89 | public static bool IsLinuxPlatform()
90 | {
91 | int p = (int)Environment.OSVersion.Platform;
92 | return (p == 4) || (p == 128);
93 | }
94 | }
95 |
96 | ///
97 | /// [0.18.0]
98 | ///
99 | public interface ICopyable
100 | {
101 | }
102 |
103 | ///
104 | /// [0.18.0]
105 | ///
106 | [Flags]
107 | public enum CopyFieldMask { Any = 0, Matching = 1, Public = 2, Serialized = 4, SkipNotSerialized = 8, OnlyCopyAttr = 16 };
108 |
109 | ///
110 | /// [0.18.0]
111 | ///
112 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)]
113 | public class CopyFieldsAttribute : Attribute
114 | {
115 | public CopyFieldMask Mask;
116 |
117 | public CopyFieldsAttribute(CopyFieldMask Mask)
118 | {
119 | this.Mask = Mask;
120 | }
121 | }
122 |
123 | ///
124 | /// [0.18.0]
125 | ///
126 | [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
127 | public class CopyAttribute : Attribute
128 | {
129 | public string Alias;
130 |
131 | public CopyAttribute()
132 | {
133 | }
134 |
135 | public CopyAttribute(string Alias)
136 | {
137 | this.Alias = Alias;
138 | }
139 | }
140 |
141 | public static partial class Extensions
142 | {
143 | ///
144 | /// [0.18.0]
145 | ///
146 | public static void CopyFieldsTo(this T1 from, ref T2 to)
147 | where T1 : ICopyable, new()
148 | where T2 : new()
149 | {
150 | object obj = to;
151 | Utils.CopyFields(from, obj, CopyFieldMask.OnlyCopyAttr);
152 | to = (T2)obj;
153 | }
154 | }
155 |
156 | public static partial class Utils
157 | {
158 | ///
159 | /// [0.18.0]
160 | ///
161 | public static void CopyFields(object from, object to, CopyFieldMask defaultMask)
162 | where T1 : new()
163 | where T2 : new()
164 | {
165 | CopyFieldMask mask = defaultMask;
166 | foreach (CopyFieldsAttribute attr in typeof(T1).GetCustomAttributes(typeof(CopyFieldsAttribute), false))
167 | {
168 | mask = attr.Mask;
169 | }
170 |
171 | var fields = typeof(T1).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
172 | foreach (var f in fields)
173 | {
174 | CopyAttribute a = new CopyAttribute();
175 | var attributes = f.GetCustomAttributes(typeof(CopyAttribute), false);
176 | if (attributes.Length > 0)
177 | {
178 | foreach (CopyAttribute a_ in attributes)
179 | {
180 | a = a_;
181 | }
182 | }
183 | else
184 | {
185 | if ((mask & CopyFieldMask.OnlyCopyAttr) == 0 && ((mask & CopyFieldMask.SkipNotSerialized) == 0 || !f.IsNotSerialized)
186 | && ((mask & CopyFieldMask.Public) > 0 && f.IsPublic
187 | || (mask & CopyFieldMask.Serialized) > 0 && f.GetCustomAttributes(typeof(SerializeField), false).Length > 0
188 | || (mask & CopyFieldMask.Public) == 0 && (mask & CopyFieldMask.Serialized) == 0))
189 | {
190 | }
191 | else
192 | {
193 | continue;
194 | }
195 | }
196 |
197 | if (string.IsNullOrEmpty(a.Alias))
198 | a.Alias = f.Name;
199 |
200 | var f2 = typeof(T2).GetField(a.Alias, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
201 | if (f2 == null)
202 | {
203 | if ((mask & CopyFieldMask.Matching) == 0)
204 | UnityModManager.Logger.Error($"Field '{typeof(T2).Name}.{a.Alias}' not found");
205 | continue;
206 | }
207 | if (f.FieldType != f2.FieldType)
208 | {
209 | UnityModManager.Logger.Error($"Fields '{typeof(T1).Name}.{f.Name}' and '{typeof(T2).Name}.{f2.Name}' have different types");
210 | continue;
211 | }
212 | f2.SetValue(to, f.GetValue(from));
213 | }
214 | }
215 | }
216 | }
217 |
--------------------------------------------------------------------------------
/UnityModManager/Window_GUI.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using UnityEngine;
6 |
7 | namespace UnityModManagerNet
8 | {
9 | public partial class UnityModManager
10 | {
11 | public partial class UI
12 | {
13 | internal class WindowParams
14 | {
15 | public int? Width { get; set; }
16 | public int? Height { get; set; }
17 | }
18 |
19 | internal class Window_GUI
20 | {
21 | internal static readonly List mList = new List();
22 | internal readonly HashSet mDestroyCounter = new HashSet();
23 |
24 | private const int MARGIN = 50;
25 |
26 | private int mId;
27 | private Rect mWindowRect;
28 | private Vector2 mScrollPosition;
29 | private int mWidth;
30 | private int mHeight;
31 | private int mRecalculateFrame;
32 |
33 | private bool Recalculating
34 | {
35 | get { return mRecalculateFrame == Time.frameCount; }
36 | }
37 |
38 | private bool mOpened;
39 | public bool Opened
40 | {
41 | get { return mOpened; }
42 | internal set
43 | {
44 | mOpened = value;
45 | if (value)
46 | {
47 | Reset();
48 | }
49 | }
50 | }
51 |
52 | public WindowParams Params { get; internal set; }
53 |
54 | internal string title;
55 | internal int unique;
56 | internal Action onGui;
57 | internal Action onClose;
58 |
59 | public Window_GUI(Action onGui, Action onClose, string title, int unique, WindowParams @params = null)
60 | {
61 | mId = GetNextWindowId();
62 | mList.Add(this);
63 | this.onGui = onGui;
64 | this.onClose = onClose;
65 | this.unique = unique;
66 | this.title = title;
67 | Params = @params ?? new WindowParams();
68 | }
69 |
70 | public void Render()
71 | {
72 | if (Recalculating)
73 | {
74 | mWindowRect = GUILayout.Window(mId, mWindowRect, WindowFunction, "", window);
75 | if (mWindowRect.width > 0)
76 | {
77 | mWidth = (int)(Math.Min(Params.Width ?? mWindowRect.width, Screen.width - MARGIN * 2));
78 | mHeight = (int)(Math.Min(Params.Height ?? mWindowRect.height, Screen.height - MARGIN * 2));
79 | mWindowRect.x = (int)(Math.Max(Screen.width - mWidth, 0) / 2);
80 | mWindowRect.y = (int)(Math.Max(Screen.height - mHeight, 0) / 2);
81 | }
82 | }
83 | else
84 | {
85 | mWindowRect = GUILayout.Window(mId, mWindowRect, WindowFunction, "", window, GUILayout.Width(mWidth), GUILayout.Height(mHeight + 10));
86 | GUI.BringWindowToFront(mId);
87 | }
88 | }
89 |
90 | private void WindowFunction(int windowId)
91 | {
92 | if (title != null)
93 | GUILayout.Label(title, h1);
94 | if (!Recalculating)
95 | mScrollPosition = GUILayout.BeginScrollView(mScrollPosition);
96 | onGui.Invoke(this);
97 | if (!Recalculating)
98 | GUILayout.EndScrollView();
99 | //if (GUILayout.Button("Close", button))
100 | // Opened = false;
101 | }
102 |
103 | internal void Reset()
104 | {
105 | mRecalculateFrame = Time.frameCount;
106 | mWindowRect = new Rect(-9000, 0, 0, 0);
107 | }
108 |
109 | ///
110 | /// []
111 | ///
112 | public void Close()
113 | {
114 | if (!Opened) return;
115 |
116 | Opened = false;
117 |
118 | if (onClose != null)
119 | {
120 | try
121 | {
122 | onClose();
123 | }
124 | catch (Exception e)
125 | {
126 | Logger.Error("Window.OnClose: " + e.GetType() + " - " + e.Message);
127 | Console.WriteLine(e.ToString());
128 | }
129 | }
130 | }
131 | }
132 |
133 | ///
134 | /// Creates and displays window. Caches by title or unique. (deferred) []
135 | ///
136 | internal static void ShowWindow(Action onGui, string title, int unique, WindowParams windowParams = null)
137 | {
138 | ShowWindow(onGui, null, title, unique, windowParams);
139 | }
140 |
141 | ///
142 | /// Creates and displays window. Caches by title or unique saving window parameters. (deferred) []
143 | ///
144 | internal static void ShowWindow(Action onGui, Action onClose, string title, int unique, WindowParams windowParams = null)
145 | {
146 | if (onGui == null)
147 | {
148 | throw new ArgumentNullException("onGui");
149 | }
150 |
151 | Window_GUI obj = null;
152 | foreach (var item in Window_GUI.mList)
153 | {
154 | if (unique == 0 && item.title == title || unique != 0 && item.unique == unique)
155 | {
156 | item.Close();
157 | obj = item;
158 | obj.title = title;
159 | obj.onGui = onGui;
160 | obj.onClose = onClose;
161 | break;
162 | }
163 | }
164 | if (obj == null)
165 | {
166 | obj = new Window_GUI(onGui, onClose, title, unique, windowParams);
167 | }
168 | obj.Opened = true;
169 | }
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/UnityModManagerApp/DownloadExtraFiles.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace UnityModManagerNet.Installer
2 | {
3 | partial class DownloadExtraFiles
4 | {
5 | ///
6 | /// Обязательная переменная конструктора.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Освободить все используемые ресурсы.
12 | ///
13 | /// истинно, если управляемый ресурс должен быть удален; иначе ложно.
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
24 |
25 | ///
26 | /// Требуемый метод для поддержки конструктора — не изменяйте
27 | /// содержимое этого метода с помощью редактора кода.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.status = new System.Windows.Forms.Label();
32 | this.progressBar1 = new System.Windows.Forms.ProgressBar();
33 | this.SuspendLayout();
34 | //
35 | // status
36 | //
37 | this.status.Location = new System.Drawing.Point(12, 9);
38 | this.status.Name = "status";
39 | this.status.Size = new System.Drawing.Size(306, 43);
40 | this.status.TabIndex = 2;
41 | this.status.Text = "Downloading...";
42 | this.status.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
43 | //
44 | // progressBar1
45 | //
46 | this.progressBar1.Location = new System.Drawing.Point(12, 55);
47 | this.progressBar1.Name = "progressBar1";
48 | this.progressBar1.Size = new System.Drawing.Size(306, 23);
49 | this.progressBar1.TabIndex = 3;
50 | //
51 | // DownloadExtraFiles
52 | //
53 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
54 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
55 | this.ClientSize = new System.Drawing.Size(330, 94);
56 | this.Controls.Add(this.progressBar1);
57 | this.Controls.Add(this.status);
58 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
59 | this.MaximizeBox = false;
60 | this.MinimizeBox = false;
61 | this.Name = "DownloadExtraFiles";
62 | this.Text = "Extra Files";
63 | this.ResumeLayout(false);
64 |
65 | }
66 |
67 | #endregion
68 |
69 | public System.Windows.Forms.Label status;
70 | private System.Windows.Forms.ProgressBar progressBar1;
71 | }
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/UnityModManagerApp/DownloadExtraFiles.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Net;
9 | using System.Text;
10 | using System.Windows.Forms;
11 | using Ionic.Zip;
12 |
13 | namespace UnityModManagerNet.Installer
14 | {
15 | public partial class DownloadExtraFiles : System.Windows.Forms.Form
16 | {
17 | const string downloadFile = "extrafiles.zip";
18 | string gamePath;
19 |
20 | public DownloadExtraFiles()
21 | {
22 | InitializeComponent();
23 | }
24 |
25 | public DownloadExtraFiles(string url, string gamePath)
26 | {
27 | this.gamePath = gamePath;
28 | InitializeComponent();
29 | Start(url);
30 | }
31 |
32 | public void Start(string url)
33 | {
34 | if (string.IsNullOrEmpty(gamePath))
35 | {
36 | status.Text = "Before select game folder.";
37 | Log.Print("Before select game folder.");
38 | return;
39 | }
40 |
41 | try
42 | {
43 | status.Text = $"Downloading ...";
44 | Log.Print($"Downloading ...");
45 | using (var wc = new WebClient())
46 | {
47 | wc.Encoding = Encoding.UTF8;
48 | wc.DownloadProgressChanged += Wc_DownloadProgressChanged;
49 | wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
50 | wc.DownloadFileAsync(new Uri(url), downloadFile);
51 | }
52 | }
53 | catch (Exception e)
54 | {
55 | status.Text = e.Message;
56 | }
57 | }
58 |
59 | private void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
60 | {
61 | progressBar1.Value = e.ProgressPercentage;
62 | }
63 |
64 | private void Wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
65 | {
66 | if (e.Error != null)
67 | {
68 | status.Text = e.Error.Message;
69 | Log.Print(e.Error.Message);
70 | return;
71 | }
72 | if (!e.Cancelled)
73 | {
74 | var success = false;
75 | try
76 | {
77 | using (var zip = ZipFile.Read(downloadFile))
78 | {
79 | foreach (var entry in zip.EntriesSorted)
80 | {
81 | if (entry.IsDirectory)
82 | {
83 | Directory.CreateDirectory(Path.Combine(gamePath, entry.FileName));
84 | }
85 | else
86 | {
87 | Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(gamePath, entry.FileName)));
88 | using (FileStream fs = new FileStream(Path.Combine(gamePath, entry.FileName), FileMode.Create, FileAccess.Write))
89 | {
90 | entry.Extract(fs);
91 | }
92 | }
93 | }
94 | }
95 |
96 | status.Text = "Done.";
97 | Log.Print("Done.");
98 | success = true;
99 | }
100 | catch (Exception ex)
101 | {
102 | status.Text = ex.Message;
103 | Log.Print(ex.Message);
104 | }
105 |
106 | if (File.Exists(downloadFile))
107 | {
108 | File.Delete(downloadFile);
109 | }
110 |
111 | if (success)
112 | {
113 | DialogResult = DialogResult.OK;
114 | Close();
115 | }
116 | }
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/UnityModManagerApp/DownloadExtraFiles.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 |
--------------------------------------------------------------------------------
/UnityModManagerApp/DownloadMod.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace UnityModManagerNet.Installer
2 | {
3 | partial class DownloadMod
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.progressBar = new System.Windows.Forms.ProgressBar();
32 | this.status = new System.Windows.Forms.Label();
33 | this.SuspendLayout();
34 | //
35 | // progressBar
36 | //
37 | this.progressBar.Location = new System.Drawing.Point(12, 68);
38 | this.progressBar.Name = "progressBar";
39 | this.progressBar.Size = new System.Drawing.Size(310, 29);
40 | this.progressBar.TabIndex = 0;
41 | //
42 | // status
43 | //
44 | this.status.Location = new System.Drawing.Point(12, 7);
45 | this.status.Name = "status";
46 | this.status.RightToLeft = System.Windows.Forms.RightToLeft.No;
47 | this.status.Size = new System.Drawing.Size(310, 54);
48 | this.status.TabIndex = 1;
49 | this.status.Text = "Downloading";
50 | this.status.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
51 | //
52 | // DownloadMod
53 | //
54 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
55 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
56 | this.ClientSize = new System.Drawing.Size(334, 111);
57 | this.Controls.Add(this.status);
58 | this.Controls.Add(this.progressBar);
59 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
60 | this.MaximizeBox = false;
61 | this.MinimizeBox = false;
62 | this.Name = "DownloadMod";
63 | this.ShowIcon = false;
64 | this.ShowInTaskbar = false;
65 | this.Text = "Mod";
66 | this.TopMost = true;
67 | this.ResumeLayout(false);
68 |
69 | }
70 |
71 | #endregion
72 |
73 | private System.Windows.Forms.ProgressBar progressBar;
74 | private System.Windows.Forms.Label status;
75 | }
76 | }
--------------------------------------------------------------------------------
/UnityModManagerApp/DownloadMod.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Net;
9 | using System.Text;
10 | using System.Windows.Forms;
11 |
12 | namespace UnityModManagerNet.Installer
13 | {
14 | public partial class DownloadMod : Form
15 | {
16 | public UnityModManager.Repository.Release release;
17 | public string tempFilepath { get; private set; }
18 |
19 | public DownloadMod()
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | public DownloadMod(UnityModManager.Repository.Release release)
25 | {
26 | this.release = release;
27 | InitializeComponent();
28 | Start();
29 | }
30 |
31 | private void Start()
32 | {
33 | try
34 | {
35 | var dir = Path.Combine(Path.GetTempPath(), "UnityModManager");
36 | if (!Directory.Exists(dir))
37 | Directory.CreateDirectory(dir);
38 |
39 | tempFilepath = Path.Combine(dir, $"{release.Id}.zip");
40 |
41 | status.Text = $"Downloading {release.Id} {release.Version} ...";
42 |
43 | using (var wc = new WebClient())
44 | {
45 | wc.Encoding = Encoding.UTF8;
46 | wc.DownloadProgressChanged += Wc_DownloadProgressChanged;
47 | wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
48 | wc.DownloadFileAsync(new Uri(release.DownloadUrl), tempFilepath);
49 | }
50 | }
51 | catch (Exception e)
52 | {
53 | status.Text = e.Message;
54 | Log.Print(e.Message);
55 | }
56 | }
57 |
58 | private void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
59 | {
60 | progressBar.Value = e.ProgressPercentage;
61 | }
62 |
63 | private void Wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
64 | {
65 | if (e.Error != null)
66 | {
67 | status.Text = e.Error.Message;
68 | Log.Print(e.Error.Message);
69 | return;
70 | }
71 | if (!e.Cancelled)
72 | {
73 | DialogResult = DialogResult.OK;
74 | Close();
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/UnityModManagerApp/DownloadMod.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 |
--------------------------------------------------------------------------------
/UnityModManagerApp/Form.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 |
121 | 213, 11
122 |
123 |
124 | 329, 11
125 |
126 |
127 | 50, 11
128 |
129 |
130 | 510, 11
131 |
132 |
--------------------------------------------------------------------------------
/UnityModManagerApp/Log.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace UnityModManagerNet.Installer
5 | {
6 | class Log : ConsoleInstaller.Log
7 | {
8 | public override void Write(string str, bool append = false)
9 | {
10 | if (append)
11 | {
12 | UnityModManagerForm.instance.statusLabel.Text += str;
13 | UnityModManagerForm.instance.statusLabel.ToolTipText += str;
14 | }
15 | else
16 | {
17 | UnityModManagerForm.instance.statusLabel.Text = str;
18 | UnityModManagerForm.instance.statusLabel.ToolTipText = str;
19 | if (firstLine)
20 | {
21 | firstLine = false;
22 | str = $"[{DateTime.Now.ToShortTimeString()}] {str}";
23 | }
24 | else
25 | {
26 | str = $"\r\n[{DateTime.Now.ToShortTimeString()}] {str}";
27 | }
28 | }
29 |
30 | UnityModManagerForm.instance.inputLog.AppendText(str);
31 | stream?.Write(str);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/UnityModManagerApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Windows.Forms;
5 |
6 | namespace UnityModManagerNet.Installer
7 | {
8 | static class Program
9 | {
10 | ///
11 | /// Главная точка входа для приложения.
12 | ///
13 | [STAThread]
14 | static void Main()
15 | {
16 | Application.EnableVisualStyles();
17 | Application.SetCompatibleTextRenderingDefault(false);
18 | Application.Run(new UnityModManagerForm());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/UnityModManagerApp/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Этот код создан программой.
4 | // Исполняемая версия:4.0.30319.42000
5 | //
6 | // Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
7 | // повторной генерации кода.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace UnityModManagerNet.Installer.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("UnityModManagerNet.Installer.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 | /// Поиск локализованного ресурса типа System.Drawing.Bitmap.
65 | ///
66 | internal static System.Drawing.Bitmap dragdropfiles {
67 | get {
68 | object obj = ResourceManager.GetObject("dragdropfiles", resourceCulture);
69 | return ((System.Drawing.Bitmap)(obj));
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/UnityModManagerApp/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=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\images\dragdropfiles.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
--------------------------------------------------------------------------------
/UnityModManagerApp/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Этот код создан программой.
4 | // Исполняемая версия:4.0.30319.42000
5 | //
6 | // Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
7 | // повторной генерации кода.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace UnityModManagerNet.Installer.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.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 | }
27 |
--------------------------------------------------------------------------------
/UnityModManagerApp/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/UnityModManagerApp/SetFolder.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace UnityModManagerNet.Installer
2 | {
3 | partial class SetFolder
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.textBox1 = new System.Windows.Forms.TextBox();
32 | this.button1 = new System.Windows.Forms.Button();
33 | this.SuspendLayout();
34 | //
35 | // textBox1
36 | //
37 | this.textBox1.Location = new System.Drawing.Point(12, 13);
38 | this.textBox1.Name = "textBox1";
39 | this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
40 | this.textBox1.Size = new System.Drawing.Size(621, 20);
41 | this.textBox1.TabIndex = 0;
42 | //
43 | // button1
44 | //
45 | this.button1.Location = new System.Drawing.Point(285, 39);
46 | this.button1.Name = "button1";
47 | this.button1.Size = new System.Drawing.Size(75, 23);
48 | this.button1.TabIndex = 1;
49 | this.button1.Text = "Change";
50 | this.button1.UseVisualStyleBackColor = true;
51 | this.button1.Click += new System.EventHandler(this.button1_Click);
52 | //
53 | // SetFolder
54 | //
55 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
56 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
57 | this.ClientSize = new System.Drawing.Size(645, 69);
58 | this.Controls.Add(this.button1);
59 | this.Controls.Add(this.textBox1);
60 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
61 | this.MaximizeBox = false;
62 | this.MinimizeBox = false;
63 | this.Name = "SetFolder";
64 | this.Text = "Game folder";
65 | this.TopMost = true;
66 | this.ResumeLayout(false);
67 | this.PerformLayout();
68 |
69 | }
70 |
71 | #endregion
72 | private System.Windows.Forms.Button button1;
73 | public System.Windows.Forms.TextBox textBox1;
74 | }
75 | }
--------------------------------------------------------------------------------
/UnityModManagerApp/SetFolder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Data;
5 | using System.Drawing;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 | using System.Windows.Forms;
11 |
12 | namespace UnityModManagerNet.Installer
13 | {
14 | public partial class SetFolder : Form
15 | {
16 | public SetFolder()
17 | {
18 | InitializeComponent();
19 | }
20 |
21 | public SetFolder(string path)
22 | {
23 | InitializeComponent();
24 | textBox1.Text = path;
25 | }
26 |
27 | private void button1_Click(object sender, EventArgs e)
28 | {
29 | DialogResult = DialogResult.OK;
30 | Close();
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/UnityModManagerApp/SetFolder.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 |
--------------------------------------------------------------------------------
/UnityModManagerApp/Tools/SteamHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text.RegularExpressions;
6 | using JetBrains.Annotations;
7 | using Microsoft.Win32;
8 |
9 | namespace UnityModManagerNet.Installer.Tools
10 | {
11 | ///
12 | /// Base on: https://stackoverflow.com/questions/54767662/finding-game-launcher-executables-in-directory-c-sharp
13 | ///
14 | public static class SteamHelper
15 | {
16 | private static ICollection RegistryKeys = new[] { "SOFTWARE\\Wow6432Node\\Valve\\", "SOFTWARE\\VALVE\\" };
17 | private static ICollection _steamGameDirs = new List();
18 |
19 | static SteamHelper()
20 | {
21 | if (!Utils.IsWindowsPlatform())
22 | {
23 | return;
24 | }
25 | UpdateSteamGameDirectories();
26 | }
27 |
28 | private static void UpdateSteamGameDirectories()
29 | {
30 | _steamGameDirs = RegistryKeys
31 | .Select(v => Registry.LocalMachine.OpenSubKey(v))
32 | .Where(registryKey => registryKey != null)
33 | .SelectMany(
34 | registryKey =>
35 | {
36 | using (registryKey)
37 | {
38 | return GetDirectories(registryKey).ToArray();
39 | }
40 | }
41 | )
42 | .Distinct()
43 | .ToList();
44 | }
45 |
46 | private static IEnumerable GetDirectories(RegistryKey registryKey)
47 | {
48 | foreach (var subKeyName in registryKey.GetSubKeyNames())
49 | {
50 | using (var subKey = registryKey.OpenSubKey(subKeyName))
51 | {
52 | if (subKey == null)
53 | {
54 | continue;
55 | }
56 |
57 | var installPath = subKey.GetValue("InstallPath");
58 | if (installPath == null)
59 | {
60 | continue;
61 | }
62 |
63 | var steamPath = installPath.ToString();
64 | var configPath = $"{steamPath}/steamapps/libraryfolders.vdf";
65 | const string driveRegex = @"[A-Z]:\\";
66 | if (!File.Exists(configPath))
67 | {
68 | continue;
69 | }
70 |
71 | var configLines = File.ReadAllLines(configPath);
72 | foreach (var item in configLines)
73 | {
74 | var match = Regex.Match(item, driveRegex);
75 | if (item == string.Empty || !match.Success)
76 | {
77 | continue;
78 | }
79 |
80 | var matched = match.ToString();
81 | var item2 = item.Substring(item.IndexOf(matched, StringComparison.Ordinal));
82 | item2 = item2.Replace("\\\\", "\\");
83 | item2 = item2.Replace("\"", "\\steamapps\\common\\");
84 | yield return item2;
85 | }
86 |
87 | yield return $"{steamPath}\\steamapps\\common\\";
88 | }
89 | }
90 | }
91 |
92 | public static IEnumerable GetGameDirectories(string gameFolderName)
93 | {
94 | return _steamGameDirs
95 | .Select(v => Path.Combine(v, gameFolderName))
96 | .Where(v => Directory.Exists(v));
97 | }
98 |
99 | public static string? GetGameDirectory(string gameFolderName)
100 | {
101 | return GetGameDirectories(gameFolderName).FirstOrDefault();
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/UnityModManagerApp/UnityModManagerApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WinExe
7 | net48
8 | true
9 | false
10 | latest
11 | enable
12 |
13 | UnityModManagerApp
14 | UnityModManagerNet.Installer
15 | Copyright © 2019-$([System.DateTime]::Now.ToString('yyyy'))
16 |
17 |
18 |
19 | true
20 | AnyCPU
21 | en-001
22 | icon.ico
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | ..\lib\UnityEngine.dll
44 |
45 |
46 | ..\lib\UnityEngine.UI.dll
47 |
48 |
49 | $(Pkgdnlib)\lib\net35\dnlib.dll
50 |
51 |
52 | $(PkgLib_Harmony)\lib\net48\0Harmony.dll
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | True
64 | True
65 | Settings.settings
66 |
67 |
68 |
69 |
70 |
71 | SettingsSingleFileGenerator
72 | Settings.Designer.cs
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/UnityModManagerApp/Updates.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Windows.Forms;
6 | using Newtonsoft.Json;
7 | using System.Net;
8 | using System.Net.NetworkInformation;
9 | using UnityModManagerNet.ConsoleInstaller;
10 |
11 | namespace UnityModManagerNet.Installer
12 | {
13 | public partial class UnityModManagerForm : Form
14 | {
15 | public class NexusModInfo
16 | {
17 | public string name;
18 | public int mod_id;
19 | public string domain_name;
20 | public string version;
21 | }
22 |
23 | readonly Dictionary> repositories = new Dictionary>();
24 | readonly Dictionary nexusUpdates = new Dictionary();
25 |
26 | private void CheckModUpdates()
27 | {
28 | if (selectedGame == null)
29 | return;
30 |
31 | Log.Print("Checking mod updates");
32 | tabPage2.Enabled = false;
33 |
34 | if (!HasNetworkConnection())
35 | {
36 | return;
37 | }
38 |
39 | selectedGameParams.LastUpdateCheck = DateTime.Now;
40 |
41 | if (!repositories.ContainsKey(selectedGame))
42 | repositories.Add(selectedGame, new HashSet());
43 |
44 | var urls = new HashSet();
45 | foreach (var mod in mods)
46 | {
47 | if (!string.IsNullOrEmpty(mod.Repository))
48 | {
49 | urls.Add(mod.Repository);
50 | }
51 |
52 | if (!string.IsNullOrEmpty(param.APIkey) && !string.IsNullOrEmpty(mod.HomePage))
53 | {
54 | CheckNexus(mod);
55 | }
56 | }
57 |
58 | if (urls.Count > 0)
59 | {
60 | foreach (var url in urls)
61 | {
62 | try
63 | {
64 | using (var wc = new WebClient())
65 | {
66 | wc.Encoding = System.Text.Encoding.UTF8;
67 | wc.DownloadStringCompleted += (sender, e) => { ModUpdates_DownloadStringCompleted(sender, e, selectedGame, url); };
68 | wc.DownloadStringAsync(new Uri(url));
69 | }
70 | }
71 | catch (Exception e)
72 | {
73 | Log.Print(e.Message);
74 | Log.Print($"Error checking mod updates on '{url}' for [{string.Join(",", mods.Where(x => x.Repository == url).Select(x => x.DisplayName).ToArray())}].");
75 | }
76 | }
77 | }
78 |
79 | RefreshModList();
80 | tabPage2.Enabled = true;
81 | }
82 |
83 | private void ModUpdates_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e, GameInfo game, string url)
84 | {
85 | if (e.Error != null)
86 | {
87 | Log.Print(e.Error.Message);
88 | return;
89 | }
90 |
91 | if (!e.Cancelled && !string.IsNullOrEmpty(e.Result) && repositories.ContainsKey(game))
92 | {
93 | try
94 | {
95 | var repository = JsonConvert.DeserializeObject(e.Result);
96 | if (repository == null || repository.Releases == null || repository.Releases.Length == 0)
97 | return;
98 |
99 | listMods.Invoke((MethodInvoker)delegate
100 | {
101 | foreach(var v in repository.Releases)
102 | {
103 | repositories[game].Add(v);
104 | }
105 | if (selectedGame == game)
106 | RefreshModList();
107 | });
108 | }
109 | catch (Exception ex)
110 | {
111 | Log.Print(ex.Message);
112 | Log.Print($"Error checking mod updates on '{url}' for [{string.Join(",", mods.Where(x => x.Repository == url).Select(x => x.DisplayName).ToArray())}].");
113 | }
114 | }
115 | }
116 |
117 | private void CheckNexus(ModInfo modInfo)
118 | {
119 | if (modInfo && Utils.ParseNexusUrl(modInfo.HomePage, out string nexusGame, out string nexusModId))
120 | {
121 | try
122 | {
123 | var request = WebRequest.Create($"https://api.nexusmods.com/v1/games/{nexusGame}/mods/{nexusModId}.json");
124 | request.ContentType = "application/json";
125 | request.Headers.Add("apikey", param.APIkey);
126 | request.Headers.Add("Application-Version", version.ToString());
127 | request.Headers.Add("Application-Name", "UnityModManager");
128 | var response = request.GetResponse();
129 | var reader = new StreamReader(response.GetResponseStream());
130 | string result = reader.ReadToEnd();
131 |
132 | NexusModInfo nexusModInfo = JsonConvert.DeserializeObject(result);
133 | if (nexusModInfo != null)
134 | {
135 | nexusUpdates[modInfo] = Utils.ParseVersion(nexusModInfo.version);
136 | }
137 |
138 | reader.Close();
139 | response.Close();
140 | }
141 | catch (Exception ex)
142 | {
143 | Log.Print(ex.Message);
144 | }
145 | }
146 | }
147 |
148 | private void CheckLastVersion()
149 | {
150 | if (string.IsNullOrEmpty(config.Repository))
151 | return;
152 |
153 | Log.Print("Checking for updates.");
154 |
155 | if (!HasNetworkConnection())
156 | {
157 | Log.Print("No network connection or firewall blocked.");
158 | return;
159 | }
160 |
161 | try
162 | {
163 | using (var wc = new WebClient())
164 | {
165 | wc.Encoding = System.Text.Encoding.UTF8;
166 | wc.DownloadStringCompleted += LastVersion_DownloadStringCompleted;
167 | wc.DownloadStringAsync(new Uri(config.Repository));
168 | }
169 | }
170 | catch (Exception e)
171 | {
172 | Log.Print(e.Message);
173 | Log.Print($"Error checking update.");
174 | }
175 | }
176 |
177 | private void LastVersion_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
178 | {
179 | if (e.Error != null)
180 | {
181 | Log.Print(e.Error.Message);
182 | return;
183 | }
184 |
185 | if (!e.Cancelled && !string.IsNullOrEmpty(e.Result))
186 | {
187 | try
188 | {
189 | var repository = JsonConvert.DeserializeObject(e.Result);
190 | if (repository == null || repository.Releases == null || repository.Releases.Length == 0)
191 | return;
192 |
193 | var release = repository.Releases.FirstOrDefault(x => x.Id == nameof(UnityModManager));
194 | if (release != null && !string.IsNullOrEmpty(release.Version))
195 | {
196 | var ver = Utils.ParseVersion(release.Version);
197 | if (version < ver)
198 | {
199 | //btnDownloadUpdate.Visible = true;
200 | btnDownloadUpdate.Text = $"Download {release.Version}";
201 | Log.Print($"Update is available.");
202 | }
203 | else
204 | {
205 | Log.Print($"No updates.");
206 | }
207 | }
208 | }
209 | catch (Exception ex)
210 | {
211 | Log.Print(ex.Message);
212 | Log.Print($"Error checking update.");
213 | }
214 | }
215 | }
216 |
217 | public static bool HasNetworkConnection()
218 | {
219 | try
220 | {
221 | using (var ping = new Ping())
222 | {
223 | return ping.Send("8.8.8.8", 3000).Status == IPStatus.Success;
224 | }
225 | }
226 | catch (Exception e)
227 | {
228 | Log.Print(e.Message);
229 | }
230 |
231 | return false;
232 | }
233 | }
234 | }
--------------------------------------------------------------------------------
/UnityModManagerApp/Utils.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Text.RegularExpressions;
3 |
4 | namespace UnityModManagerNet.Installer
5 | {
6 | public class Utils : ConsoleInstaller.Utils
7 | {
8 | public static bool ParseNexusUrl(string url, out string game, out string id)
9 | {
10 | game = null;
11 | id = null;
12 | var regex = new Regex(@"https:\/\/www\.nexusmods\.com\/(\w+)\/mods\/(\d+)", RegexOptions.IgnoreCase);
13 | var matches = regex.Matches(url);
14 | foreach (Match match in matches)
15 | {
16 | game = match.Groups[1].Value;
17 | id = match.Groups[2].Value;
18 | return true;
19 | }
20 | return false;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/UnityModManagerApp/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/UnityModManagerApp/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/UnityModManagerApp/icon.ico
--------------------------------------------------------------------------------
/UnityModManagerApp/images/dragdropfiles.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/UnityModManagerApp/images/dragdropfiles.png
--------------------------------------------------------------------------------
/Updater/Config.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Windows.Forms;
7 | using System.Xml.Serialization;
8 |
9 | namespace UnityModManagerNet.Downloader
10 | {
11 | public class Config
12 | {
13 | public string Repository;
14 | }
15 |
16 | public class Repository
17 | {
18 | [Serializable]
19 | public class Release
20 | {
21 | public string Id;
22 | public string Version;
23 | public string DownloadUrl;
24 | }
25 |
26 | public Release[] Releases;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Updater/Form.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace UnityModManagerNet.Downloader
2 | {
3 | partial class DownloaderForm
4 | {
5 | ///
6 | /// Обязательная переменная конструктора.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Освободить все используемые ресурсы.
12 | ///
13 | /// истинно, если управляемый ресурс должен быть удален; иначе ложно.
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
24 |
25 | ///
26 | /// Требуемый метод для поддержки конструктора — не изменяйте
27 | /// содержимое этого метода с помощью редактора кода.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.progressBar1 = new System.Windows.Forms.ProgressBar();
32 | this.status = new System.Windows.Forms.Label();
33 | this.SuspendLayout();
34 | //
35 | // progressBar1
36 | //
37 | this.progressBar1.Location = new System.Drawing.Point(12, 55);
38 | this.progressBar1.Name = "progressBar1";
39 | this.progressBar1.Size = new System.Drawing.Size(306, 23);
40 | this.progressBar1.TabIndex = 0;
41 | //
42 | // status
43 | //
44 | this.status.Location = new System.Drawing.Point(12, 9);
45 | this.status.Name = "status";
46 | this.status.Size = new System.Drawing.Size(306, 43);
47 | this.status.TabIndex = 1;
48 | this.status.Text = "Downloading...";
49 | this.status.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
50 | //
51 | // DownloaderForm
52 | //
53 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
54 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
55 | this.ClientSize = new System.Drawing.Size(330, 94);
56 | this.Controls.Add(this.status);
57 | this.Controls.Add(this.progressBar1);
58 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
59 | this.MaximizeBox = false;
60 | this.MinimizeBox = false;
61 | this.Name = "DownloaderForm";
62 | this.Text = "Updates";
63 | this.ResumeLayout(false);
64 |
65 | }
66 |
67 | #endregion
68 |
69 | private System.Windows.Forms.ProgressBar progressBar1;
70 | public System.Windows.Forms.Label status;
71 | }
72 | }
73 |
74 |
--------------------------------------------------------------------------------
/Updater/Form.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Drawing;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Net;
8 | using System.Reflection;
9 | using System.Runtime.InteropServices;
10 | using System.Text;
11 | using System.Windows.Forms;
12 | using System.Xml.Serialization;
13 | using Ionic.Zip;
14 | using Newtonsoft.Json;
15 |
16 | namespace UnityModManagerNet.Downloader
17 | {
18 | public partial class DownloaderForm : Form
19 | {
20 | const string updateFile = "update.zip";
21 | const string configFile = "UnityModManagerConfig.xml";
22 | const string managerName = "UnityModManager";
23 | const string managerFile = "UnityModManager.dll";
24 | const string managerAppName = "UnityModManager";
25 | const string managerAppFile = "UnityModManager.exe";
26 |
27 | public DownloaderForm()
28 | {
29 | InitializeComponent();
30 | Start();
31 | }
32 |
33 | public void Start()
34 | {
35 | var rewrite = false;
36 | string[] args = Environment.GetCommandLineArgs();
37 | if (args.Length > 0)
38 | {
39 | rewrite = args.Contains("-rewrite");
40 | }
41 |
42 | ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
43 |
44 | if (!Utils.HasNetworkConnection())
45 | {
46 | status.Text = $"No network connection.";
47 | return;
48 | }
49 |
50 | try
51 | {
52 | Config config;
53 | using (var stream = File.OpenRead(configFile))
54 | {
55 | var serializer = new XmlSerializer(typeof(Config));
56 | config = serializer.Deserialize(stream) as Config;
57 | }
58 | if (config == null || string.IsNullOrEmpty(config.Repository))
59 | {
60 | status.Text = $"Error parsing '{configFile}'.";
61 | return;
62 | }
63 | if (File.Exists(updateFile))
64 | {
65 | File.Delete(updateFile);
66 | }
67 |
68 | string result = null;
69 | using (var wc = new WebClient())
70 | {
71 | wc.Encoding = Encoding.UTF8;
72 | result = wc.DownloadString(new Uri(config.Repository));
73 | }
74 | var repository = JsonConvert.DeserializeObject(result);
75 | if (repository == null || repository.Releases.Length == 0)
76 | {
77 | status.Text = $"Error parsing '{config.Repository}'.";
78 | return;
79 | }
80 | var release = repository.Releases.FirstOrDefault(x => x.Id == managerName);
81 | if (!rewrite && File.Exists(managerFile))
82 | {
83 | var managerAssembly = Assembly.ReflectionOnlyLoad(File.ReadAllBytes(managerFile));
84 | if (Utils.ParseVersion(release.Version) <= managerAssembly.GetName().Version)
85 | {
86 | status.Text = $"No updates.";
87 | return;
88 | }
89 | }
90 | status.Text = $"Downloading {release.Version} ...";
91 | using (var wc = new WebClient())
92 | {
93 | wc.Encoding = Encoding.UTF8;
94 | wc.DownloadProgressChanged += Wc_DownloadProgressChanged;
95 | wc.DownloadFileCompleted += Wc_DownloadFileCompleted;
96 | wc.DownloadFileAsync(new Uri(release.DownloadUrl), updateFile);
97 | }
98 | }
99 | catch (Exception e)
100 | {
101 | status.Text = e.Message;
102 | }
103 | }
104 |
105 | private void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
106 | {
107 | progressBar1.Value = e.ProgressPercentage;
108 | }
109 |
110 | private void Wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
111 | {
112 | if (e.Error != null)
113 | {
114 | status.Text = e.Error.Message;
115 | return;
116 | }
117 | if (!e.Cancelled)
118 | {
119 | var success = false;
120 | try
121 | {
122 | foreach (var p in Process.GetProcessesByName(managerAppName))
123 | {
124 | status.Text = "Waiting for the UnityModManager to close.";
125 | p.CloseMainWindow();
126 | p.WaitForExit();
127 | }
128 | using (var zip = ZipFile.Read(updateFile))
129 | {
130 | foreach (var entry in zip.EntriesSorted)
131 | {
132 | if (entry.IsDirectory)
133 | {
134 | Directory.CreateDirectory(Path.Combine(Environment.CurrentDirectory, entry.FileName));
135 | }
136 | else
137 | {
138 | Directory.CreateDirectory(Path.GetDirectoryName(Path.Combine(Environment.CurrentDirectory, entry.FileName)));
139 | using (FileStream fs = new FileStream(Path.Combine(Environment.CurrentDirectory, entry.FileName), FileMode.Create, FileAccess.Write))
140 | {
141 | entry.Extract(fs);
142 | }
143 | }
144 | }
145 | }
146 | status.Text = "Done.";
147 | success = true;
148 | }
149 | catch (Exception ex)
150 | {
151 | status.Text = ex.Message;
152 | }
153 |
154 | if (File.Exists(updateFile))
155 | {
156 | File.Delete(updateFile);
157 | }
158 |
159 | if (success)
160 | {
161 | if (!Utils.IsUnixPlatform() && Process.GetProcessesByName(managerAppName).Length == 0)
162 | {
163 | if (File.Exists(managerAppFile))
164 | {
165 | SetForegroundWindow(Process.Start(managerAppFile).MainWindowHandle);
166 | }
167 | }
168 | Application.Exit();
169 | }
170 | }
171 | }
172 |
173 | [DllImport("user32.dll", SetLastError = true)]
174 | private static extern bool SetForegroundWindow(IntPtr hwnd);
175 | }
176 | }
177 |
--------------------------------------------------------------------------------
/Updater/Form.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 |
--------------------------------------------------------------------------------
/Updater/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Windows.Forms;
5 |
6 | namespace UnityModManagerNet.Downloader
7 | {
8 | static class Program
9 | {
10 | [STAThread]
11 | static void Main()
12 | {
13 | Application.EnableVisualStyles();
14 | Application.SetCompatibleTextRenderingDefault(false);
15 | Application.Run(new DownloaderForm());
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Updater/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Этот код создан программой.
4 | // Исполняемая версия:4.0.30319.42000
5 | //
6 | // Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
7 | // повторной генерации кода.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace UnityModManagerNet.Downloader.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("UnityModManagerNet.Downloader.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 |
--------------------------------------------------------------------------------
/Updater/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 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Updater/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // Этот код создан программой.
4 | // Исполняемая версия:4.0.30319.42000
5 | //
6 | // Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае
7 | // повторной генерации кода.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace UnityModManagerNet.Downloader.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.0.3.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 | }
27 |
--------------------------------------------------------------------------------
/Updater/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Updater/Updater.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WinExe
7 | net48
8 | true
9 | false
10 | latest
11 |
12 | Downloader
13 | UnityModManagerNet.Downloader
14 | Copyright © 2019-$([System.DateTime]::Now.ToString('yyyy'))
15 |
16 |
17 |
18 | true
19 | en-001
20 | AnyCPU
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ..\lib\UnityEngine.dll
33 |
34 |
35 | ..\lib\UnityEngine.UI.dll
36 |
37 |
38 | $(Pkgdnlib)\lib\net35\dnlib.dll
39 |
40 |
41 | $(PkgLib_Harmony)\lib\net48\0Harmony.dll
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Updater/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net.NetworkInformation;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace UnityModManagerNet.Downloader
9 | {
10 | static class Utils
11 | {
12 | public static Version ParseVersion(string str)
13 | {
14 | var array = str.Split('.', ',');
15 | if (array.Length >= 3)
16 | {
17 | var regex = new Regex(@"\D");
18 | return new Version(int.Parse(regex.Replace(array[0], "")), int.Parse(regex.Replace(array[1], "")), int.Parse(regex.Replace(array[2], "")));
19 | }
20 |
21 | return new Version();
22 | }
23 |
24 | public static bool HasNetworkConnection()
25 | {
26 | try
27 | {
28 | using (var ping = new Ping())
29 | {
30 | return ping.Send("8.8.8.8", 2000).Status == IPStatus.Success;
31 | }
32 | }
33 | catch (Exception)
34 | {
35 | }
36 |
37 | return false;
38 | }
39 |
40 | public static bool IsUnixPlatform()
41 | {
42 | int p = (int)Environment.OSVersion.Platform;
43 | return (p == 4) || (p == 6) || (p == 128);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Updater/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/lib/Harmony/1.2/0Harmony-1.2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/Harmony/1.2/0Harmony-1.2.dll
--------------------------------------------------------------------------------
/lib/Harmony/1.2/0Harmony12.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/Harmony/1.2/0Harmony12.dll
--------------------------------------------------------------------------------
/lib/Harmony/2.2/0Harmony.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/Harmony/2.2/0Harmony.dll
--------------------------------------------------------------------------------
/lib/Ionic.Zip.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/Ionic.Zip.dll
--------------------------------------------------------------------------------
/lib/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/lib/System.Xml.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/System.Xml.dll
--------------------------------------------------------------------------------
/lib/dnlib.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/dnlib.dll
--------------------------------------------------------------------------------
/lib/libraries:
--------------------------------------------------------------------------------
1 | https://www.dropbox.com/s/dng4xkf24qzh2cc/UnityEngine.zip?dl=1
--------------------------------------------------------------------------------
/lib/winhttp_x64.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/winhttp_x64.dll
--------------------------------------------------------------------------------
/lib/winhttp_x86.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/newman55/unity-mod-manager/b566410fbce72db2bdb2eaf16293d9e1b50d516f/lib/winhttp_x86.dll
--------------------------------------------------------------------------------