Elin Decompiled Documentation EA 23.301 Nightly
Loading...
Searching...
No Matches
ModManager.cs
Go to the documentation of this file.
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.IO;
5using System.Linq;
6using HeathenEngineering.SteamworksIntegration;
7using HeathenEngineering.SteamworksIntegration.API;
8using IniParser.Model;
9using Newtonsoft.Json;
10using Steamworks;
11using UnityEngine;
12
13[Serializable]
14public class ModManager : ModManagerCore
15{
16 public static List<object> ListPluginObject = new List<object>();
17
18 public static bool disableMod;
19
21
22 public List<FileInfo> replaceFiles = new List<FileInfo>();
23
24 private Action ImportModGodTalks;
25
26 public static List<string> ListChainLoad => BaseModManager.listChainLoad;
27
28 public static DirectoryInfo DirWorkshop => Instance.dirWorkshop;
29
31
33
34 public override void Init(string path, string defaultPackage = "_Elona")
35 {
36 base.Init(path, defaultPackage);
37 Debug.Log("IsOffline:" + BaseCore.IsOffline);
38 IniData elinIni = Core.GetElinIni();
39 if (elinIni != null)
40 {
42 {
43 string key = elinIni.GetKey("path_workshop");
44 if (!key.IsEmpty())
45 {
46 dirWorkshop = new DirectoryInfo(key);
47 }
48 }
49 else
50 {
51 string path2 = Path.Combine(App.Client.GetAppInstallDirectory(SteamSettings.behaviour.settings.applicationId), "../../workshop/content/2135150");
52 dirWorkshop = new DirectoryInfo(path2);
53 elinIni.Global["path_workshop"] = dirWorkshop.FullName;
54 Core.SaveElinIni(elinIni);
55 }
56 }
57 if (!dirWorkshop.Exists)
58 {
59 dirWorkshop = null;
60 }
61 Debug.Log("Workshop:" + dirWorkshop);
62 Debug.Log("Packages:" + BaseModManager.rootMod);
63 Debug.Log("Core Mod:" + BaseModManager.rootDefaultPacakge);
64 BaseModManager.SubscribeEvent("elin.source.lang_set", delegate(object lang)
65 {
66 if (ModManagerCore.useLocalizations)
67 {
68 ImportSourceLocalizations(lang as string);
69 ModManagerCore.generateLocalizations = false;
70 }
72 BookList.dict = null;
73 });
74 }
75
76 public void SaveLoadOrder()
77 {
78 if (!disableMod)
79 {
80 List<string> contents = (from p in packages
81 where !p.builtin && p.dirInfo.Exists
82 select $"{p.dirInfo.FullName},{(p.willActivate ? 1 : 0)}").ToList();
83 File.WriteAllLines(CorePath.rootExe + "loadorder.txt", contents);
84 }
85 }
86
87 public void LoadLoadOrder()
88 {
89 string path = CorePath.rootExe + "loadorder.txt";
90 if (!File.Exists(path))
91 {
92 return;
93 }
94 Dictionary<string, BaseModPackage> dictionary = new Dictionary<string, BaseModPackage>();
95 foreach (BaseModPackage package in packages)
96 {
97 if (!package.builtin)
98 {
99 dictionary[package.dirInfo.FullName] = package;
100 }
101 }
102 int num = 0;
103 string[] array = File.ReadAllLines(path);
104 for (int i = 0; i < array.Length; i++)
105 {
106 string[] array2 = array[i].Split(',');
107 if (dictionary.TryGetValue(array2[0], out var value))
108 {
109 value.loadPriority = num;
110 value.willActivate = array2[1] == "1";
111 }
112 num++;
113 }
114 }
115
116 public void ImportSourceLocalizations(string lang)
117 {
118 PackageIterator.RebuildAllMappings(lang);
119 SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>();
120 Dictionary<string, SortedDictionary<string, string>> dictionary = new Dictionary<string, SortedDictionary<string, string>>();
121 string value;
122 string key;
123 foreach (string item in FileMapping.FallbackLut[lang].Append(lang).Distinct())
124 {
125 (FileInfo, EMod)[] filesEx = PackageIterator.GetFilesEx(item + "/SourceLocalization.json", useCache: false);
126 for (int i = 0; i < filesEx.Length; i++)
127 {
128 var (fileInfo, eMod) = filesEx[i];
129 try
130 {
131 SortedDictionary<string, string> sortedDictionary2 = IO.LoadFile<SortedDictionary<string, string>>(fileInfo.FullName);
132 foreach (KeyValuePair<string, string> item2 in sortedDictionary2)
133 {
134 item2.Deconstruct(out value, out key);
135 string key2 = value;
136 string value2 = key;
137 sortedDictionary[key2] = value2;
138 }
139 dictionary[eMod.id] = sortedDictionary2;
140 }
141 catch (Exception arg)
142 {
143 Debug.LogError($"#source localization failed to load {fileInfo.ShortPath()}\n{arg}");
144 }
145 }
146 }
147 JsonSerializerSettings setting = new JsonSerializerSettings
148 {
149 PreserveReferencesHandling = PreserveReferencesHandling.None,
150 NullValueHandling = NullValueHandling.Ignore
151 };
152 foreach (BaseModPackage package in packages)
153 {
154 if (!(package is ModPackage modPackage) || package.builtin || !package.activated)
155 {
156 continue;
157 }
158 HashSet<SourceData.BaseRow> sourceRows = modPackage.sourceRows;
159 if (sourceRows == null || sourceRows.Count <= 0)
160 {
161 continue;
162 }
163 modPackage.ImportSourceLocalizations(sortedDictionary);
164 if (!ModManagerCore.generateLocalizations || (!modPackage.isInPackages && !Application.isEditor))
165 {
166 continue;
167 }
168 try
169 {
170 SortedDictionary<string, string> sortedDictionary3 = dictionary.GetValueOrDefault(modPackage.id) ?? new SortedDictionary<string, string>();
171 SortedDictionary<string, string> sortedDictionary4 = modPackage.ExportSourceLocalizations();
172 SortedDictionary<string, string> final = new SortedDictionary<string, string>();
173 foreach (KeyValuePair<string, string> item3 in sortedDictionary4)
174 {
175 item3.Deconstruct(out key, out value);
176 string key3 = key;
177 string defaultValue = value;
178 final[key3] = sortedDictionary3.GetValueOrDefault(key3, defaultValue);
179 }
180 if (sortedDictionary3.Count != final.Count || sortedDictionary3.Any((KeyValuePair<string, string> kv) => !final.ContainsKey(kv.Key)))
181 {
182 string path = Path.Combine(modPackage.dirInfo.FullName, "LangMod/" + lang + "/SourceLocalization.json");
183 IO.SaveFile(path, final, compress: false, setting);
184 Debug.Log($"#source localization updated {path.ShortPath()} / {modPackage}");
185 }
186 }
187 catch (Exception arg2)
188 {
189 Debug.LogError($"#source localization failed to generate {modPackage}\n{arg2}");
190 }
191 }
192 }
193
195 {
196 try
197 {
198 SourceCache.InvalidateCacheVersion();
200 {
202 EClass.sources.materials
203 });
204 List<string> list = new List<string>();
205 foreach (ModPackage item in packages.OfType<ModPackage>())
206 {
207 if (item.builtin || !item.activated)
208 {
209 continue;
210 }
211 foreach (FileInfo sourceSheet in item.Mapping.SourceSheets)
212 {
213 if (!sourceSheet.Name.StartsWith(".") && !sourceSheet.Name.Contains("~"))
214 {
215 ModUtil.sourceImporter.fileProviders[sourceSheet.FullName] = item;
216 list.Add(sourceSheet.FullName);
217 }
218 }
219 }
221 SourceCache.FinalizeCache();
222 SourceCache.InvalidateCacheBlobs();
223 SourceCache.ClearDetail();
224 }
225 catch (Exception message)
226 {
227 Debug.LogError(message);
228 }
229 Debug.Log("#source finished importing workbooks");
230 }
231
233 {
234 Lang.extraExcelDialogs = new HashSet<string>(PathComparer.Default);
235 Lang.excelDialog = null;
236 FileInfo[] files = PackageIterator.GetFiles("Dialog/dialog.xlsx");
237 foreach (FileInfo fileInfo in files)
238 {
239 Lang.extraExcelDialogs.Add(fileInfo.FullName);
240 Debug.Log("#dialog loaded " + fileInfo.ShortPath());
241 }
242 }
243
245 {
246 if (Lang.setting?.dir == null)
247 {
248 return;
249 }
250 Dictionary<string, Dictionary<string, string>> map = EClass.sources.dataGodTalk.sheets["_default"].map;
251 foreach (ExcelData item in from f in PackageIterator.GetFiles("Data/god_talk.xlsx")
252 select new ExcelData(f.FullName, 3))
253 {
254 foreach (KeyValuePair<string, Dictionary<string, string>> item2 in map)
255 {
256 item2.Deconstruct(out var key, out var _);
257 string text = key;
258 if (text.IsEmpty())
259 {
260 continue;
261 }
262 Dictionary<string, string> valueOrDefault = item.sheets["_default"].map.GetValueOrDefault(text);
263 if (valueOrDefault == null)
264 {
265 continue;
266 }
267 foreach (KeyValuePair<string, string> item3 in valueOrDefault)
268 {
269 item3.Deconstruct(out key, out var value2);
270 string text2 = key;
271 string value3 = value2;
272 if (text2 != "id")
273 {
274 map[text][text2] = value3;
275 }
276 }
277 }
278 Debug.Log("#dialog loaded " + item.path.ShortPath());
279 }
280 }
281
282 public IEnumerator RefreshMods(Action onComplete, bool syncMods)
283 {
284 bool flag = !BaseCore.IsOffline && syncMods && UserGeneratedContent.Client.GetNumSubscribedItems() != 0;
285 _loading = Util.Instantiate<LoadingScreen>("LoadingScreen");
286 WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
287 packages.Clear();
288 disableMod |= Application.isEditor && EClass.debug.skipMod;
291 if (!disableMod)
292 {
293 _loading.Log("Loading workshop contents...");
294 if (flag)
295 {
296 yield return LoadWorkshopPackages();
297 }
298 else if (dirWorkshop != null)
299 {
300 DirectoryInfo[] directories = dirWorkshop.GetDirectories();
301 foreach (DirectoryInfo dir in directories)
302 {
303 AddPackage(dir);
304 }
305 }
306 }
309 packages.Sort((BaseModPackage a, BaseModPackage b) => a.loadPriority - b.loadPriority);
310 foreach (BaseModPackage item in packages.Where((BaseModPackage p) => !p.isInPackages && p.willActivate && !p.id.IsEmpty()))
311 {
312 if (mappedPackages.TryGetValue(item.id, out var value) && value.isInPackages)
313 {
314 value.hasPublishedPackage = true;
315 }
316 }
317 _loading.Log($"Total number of mods:{packages.Count}");
318 _loading.Log("Activating Mods...");
319 yield return awaiter;
321 foreach (BaseModPackage package in packages)
322 {
323 if (package.activated)
324 {
325 mappedPackages[package.id] = package as ModPackage;
326 }
327 }
328 BaseModManager.isInitialized = true;
329 yield return awaiter;
330 onComplete?.Invoke();
331 if ((bool)_loading)
332 {
333 UnityEngine.Object.Destroy(_loading.gameObject);
334 }
335 yield return null;
336 }
337
338 public ModPackage AddPackage(DirectoryInfo dir, bool isInPackages = false)
339 {
340 ModPackage modPackage = new ModPackage
341 {
342 dirInfo = dir,
343 installed = true,
344 isInPackages = isInPackages,
345 loadPriority = priorityIndex,
346 Mapping = new FileMapping(dir)
347 };
348 packages.Add(modPackage);
349 priorityIndex++;
350 return modPackage;
351 }
352
353 public ModPackage AddWorkshopPackage(WorkshopItem item, bool isInPackages = false)
354 {
355 ulong sizeOnDisk;
356 string folderPath;
357 DateTime timeStamp;
358 bool itemInstallInfo = UserGeneratedContent.Client.GetItemInstallInfo(item.FileId, out sizeOnDisk, out folderPath, out timeStamp);
359 DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);
360 if (!directoryInfo.Exists)
361 {
362 return null;
363 }
364 ModPackage modPackage = AddPackage(directoryInfo, isInPackages);
365 modPackage.installed = itemInstallInfo;
366 modPackage.banned = item.IsBanned;
367 return modPackage;
368 }
369
370 public int CountUserMod()
371 {
372 return packages.Count((BaseModPackage p) => !p.builtin);
373 }
374
375 public void LoadLocalPackages()
376 {
377 _loading.Log("Loading local Package...");
378 DirectoryInfo[] directories = new DirectoryInfo(BaseModManager.rootMod).GetDirectories();
379 Array.Reverse(directories);
380 DirectoryInfo[] array = directories;
381 foreach (DirectoryInfo directoryInfo in array)
382 {
383 if (!disableMod || !(directoryInfo.Name != "_Elona") || !(directoryInfo.Name != "_Lang_Chinese"))
384 {
385 AddPackage(directoryInfo, isInPackages: true);
386 }
387 }
388 }
389
390 public void LoadCustomPackage()
391 {
392 _loading.Log("Loading user Custom...");
393 DirectoryInfo[] directories = new DirectoryInfo(CorePath.custom).GetDirectories();
394 ModPackage package = new ModPackage();
395 DirectoryInfo[] array = directories;
396 foreach (DirectoryInfo dir in array)
397 {
398 ParseExtra(dir, package);
399 }
400 }
401
402 public IEnumerator LoadWorkshopPackages()
403 {
404 WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
405 UgcQuery activeQuery = UgcQuery.GetSubscribed(withLongDescription: false, withMetadata: false, withKeyValueTags: false, withAdditionalPreviews: false, 0u);
406 activeQuery.Execute(HandleWorkshopQuery);
407 _loading.Log("Fetching subscriptions...(Hit ESC to cancel)");
408 while (activeQuery.handle != UGCQueryHandle_t.Invalid && !UnityEngine.Input.GetKey(KeyCode.Escape))
409 {
410 yield return awaiter;
411 }
412 yield return UpdateWorkshopPackages();
413 void HandleWorkshopQuery(UgcQuery query)
414 {
415 foreach (WorkshopItem results in query.ResultsList)
416 {
417 AddWorkshopPackage(results);
418 }
419 }
420 }
421
422 private IEnumerator UpdateWorkshopPackages()
423 {
424 _loading?.Log("Updating subscriptions...");
425 WaitForEndOfFrame awaiter = new WaitForEndOfFrame();
426 while (true)
427 {
428 bool flag = false;
429 foreach (BaseModPackage item in packages.Where((BaseModPackage p) => !p.installed))
430 {
431 if (!(item.item is WorkshopItem { IsBanned: false } workshopItem))
432 {
433 continue;
434 }
435 flag = true;
436 string text = "Downloading " + workshopItem.Title + ": ";
437 BaseModPackage baseModPackage = item;
438 if ((object)baseModPackage.progressText == null)
439 {
440 baseModPackage.progressText = _loading?.Log(text);
441 }
442 if (item.downloadStarted && workshopItem.DownloadCompletion >= 1f)
443 {
444 item.installed = true;
445 if ((bool)item.progressText)
446 {
447 item.progressText.text = text + "Done!";
448 }
449 }
450 else if (workshopItem.IsDownloading || workshopItem.IsDownloadPending)
451 {
452 int num = Mathf.FloorToInt(workshopItem.DownloadCompletion * 100f);
453 if ((bool)item.progressText)
454 {
455 item.progressText.text = text + num + "%";
456 }
457 }
458 else if (!item.downloadStarted)
459 {
460 item.downloadStarted = true;
461 workshopItem.DownloadItem(highPriority: true);
462 Debug.Log("Start downloading: " + workshopItem.Title + " | " + $"Installed={workshopItem.IsInstalled}, " + $"Downloading={workshopItem.IsDownloading}, " + $"Pending={workshopItem.IsDownloadPending}");
463 }
464 }
465 if (!flag)
466 {
467 yield break;
468 }
469 if (UnityEngine.Input.GetKey(KeyCode.Escape))
470 {
471 break;
472 }
473 yield return awaiter;
474 }
475 Debug.Log("Workshop updating cancelled");
476 }
477
478 public void InitPackagesMeta()
479 {
480 foreach (BaseModPackage package in packages)
481 {
482 try
483 {
484 if (package.Init())
485 {
486 mappedPackages[package.id] = package as ModPackage;
487 }
488 _loading?.Log(package.ToString());
489 }
490 catch (Exception ex)
491 {
492 package.willActivate = false;
493 _loading?.Log("Mod " + package.title + "/" + package.id + " has failed to initialize, reason: " + ex.Message);
494 }
495 }
496 }
497
498 public void ActivatePackages()
499 {
501 ListPluginObject.Clear();
502 foreach (ModPackage package in packages)
503 {
504 if ((disableMod && !package.builtin) || !package.IsValidVersion())
505 {
506 continue;
507 }
508 try
509 {
510 package.Activate();
511 if (package.activated)
512 {
513 BaseModManager.listChainLoad.Add(package.dirInfo.FullName);
514 }
515 }
516 catch (Exception ex)
517 {
518 _loading.Log("Failed to activate mod: " + package.title + ", reason: " + ex.Message);
519 }
520 }
523 }
524
525 public override void ParseExtra(DirectoryInfo dir, BaseModPackage package)
526 {
527 ModPackage modPackage = (ModPackage)package;
528 switch (dir.Name)
529 {
530 case "TalkText":
531 modPackage.ParseTalkText(dir);
532 break;
533 case "Map":
534 if (!package.builtin)
535 {
536 modPackage.ParseMap(dir);
537 }
538 break;
539 case "Map Piece":
540 if (!package.builtin)
541 {
542 modPackage.ParseMapPiece(dir);
543 }
544 break;
545 case "Texture Replace":
546 replaceFiles.AddRange(modPackage.ParseTextureReplace(dir));
547 break;
548 case "Texture":
549 modPackage.ParseTexture(dir);
550 break;
551 case "Portrait":
552 modPackage.ParsePortrait(dir);
553 break;
554 case "LangMod":
555 modPackage.ParseLangMod(dir);
556 break;
557 case "Sound":
558 modPackage.ParseSound(dir);
559 break;
560 case "Lang":
561 modPackage.AddOrUpdateLang(dir);
562 break;
563 }
564 }
565}
$
Definition: ModManager.cs:87
static bool IsOffline
Definition: BaseCore.cs:9
static bool isInitialized
static string rootDefaultPacakge
static BaseModManager Instance
static string rootMod
static List< string > listChainLoad
static void SubscribeEvent(string eventId, Action< object > handler)
DirectoryInfo dirInfo
bool skipMod
Definition: CoreDebug.cs:149
static string custom
Definition: CorePath.cs:159
static string rootExe
Definition: CorePath.cs:168
Definition: Core.cs:14
static void SaveElinIni(IniData ini)
Definition: Core.cs:813
static IniData GetElinIni()
Definition: Core.cs:779
Definition: EClass.cs:6
static SourceManager sources
Definition: EClass.cs:43
static CoreDebug debug
Definition: EClass.cs:49
Dictionary< string, Sheet > sheets
Definition: ExcelData.cs:25
string dir
Definition: LangSetting.cs:28
Definition: Lang.cs:6
static LangSetting setting
Definition: Lang.cs:54
static HashSet< string > extraExcelDialogs
Definition: Lang.cs:62
Text Log(string s)
void ImportAllModSourceSheets()
Definition: ModManager.cs:194
static new ModManager Instance
Definition: ModManager.cs:30
override void ParseExtra(DirectoryInfo dir, BaseModPackage package)
Definition: ModManager.cs:525
LoadingScreen _loading
Definition: ModManager.cs:20
void ImportAllModDialogs()
Definition: ModManager.cs:232
static bool IsInitialized
Definition: ModManager.cs:32
void ImportSourceLocalizations(string lang)
Definition: ModManager.cs:116
Action ImportModGodTalks
Definition: ModManager.cs:24
static List< string > ListChainLoad
Definition: ModManager.cs:26
void ActivatePackages()
Definition: ModManager.cs:498
List< FileInfo > replaceFiles
Definition: ModManager.cs:22
void ImportAllModGodTalks()
Definition: ModManager.cs:244
void LoadLoadOrder()
Definition: ModManager.cs:87
ModPackage AddWorkshopPackage(WorkshopItem item, bool isInPackages=false)
Definition: ModManager.cs:353
IEnumerator UpdateWorkshopPackages()
Definition: ModManager.cs:422
override void Init(string path, string defaultPackage="_Elona")
Definition: ModManager.cs:34
void LoadCustomPackage()
Definition: ModManager.cs:390
IEnumerator RefreshMods(Action onComplete, bool syncMods)
Definition: ModManager.cs:282
static bool disableMod
Definition: ModManager.cs:18
IEnumerator LoadWorkshopPackages()
Definition: ModManager.cs:402
void LoadLocalPackages()
Definition: ModManager.cs:375
ModPackage AddPackage(DirectoryInfo dir, bool isInPackages=false)
Definition: ModManager.cs:338
static List< object > ListPluginObject
Definition: ModManager.cs:16
int CountUserMod()
Definition: ModManager.cs:370
void SaveLoadOrder()
Definition: ModManager.cs:76
static DirectoryInfo DirWorkshop
Definition: ModManager.cs:28
void InitPackagesMeta()
Definition: ModManager.cs:478
IReadOnlyList< FileInfo > ParseTalkText(DirectoryInfo dir)
Definition: ModPackage.cs:18
void ParseLangMod(DirectoryInfo dir)
Definition: ModPackage.cs:153
IReadOnlyList< FileInfo > ParseTexture(DirectoryInfo dir)
Definition: ModPackage.cs:95
void AddOrUpdateLang(DirectoryInfo dir)
Definition: ModPackage.cs:237
IReadOnlyList< FileInfo > ParseMapPiece(DirectoryInfo dir, bool addToList=true)
Definition: ModPackage.cs:57
IReadOnlyList< FileInfo > ParseTextureReplace(DirectoryInfo dir)
Definition: ModPackage.cs:78
IReadOnlyList< FileInfo > ParsePortrait(DirectoryInfo dir)
Definition: ModPackage.cs:115
IReadOnlyList< FileInfo > ParseMap(DirectoryInfo dir, bool addToList=true)
Definition: ModPackage.cs:36
IReadOnlyList< FileInfo > ParseSound(DirectoryInfo dir)
Definition: ModPackage.cs:168
static SourceImporter sourceImporter
Definition: ModUtil.cs:15
static void OnModsActivated()
Definition: ModUtil.cs:23
static void LoadTypeFallback()
Definition: ModUtil.cs:37
IEnumerable< SourceData > ImportFilesCached(IEnumerable< string > imports, bool resetData=true)
static void HotInit(IEnumerable< SourceData > sourceData)
Dictionary< string, EMod > fileProviders
ExcelData dataGodTalk
SourceElement elements