Elin Decompiled Documentation EA 23.319 Nightly Patch 1
Loading...
Searching...
No Matches
ModUtil.cs
Go to the documentation of this file.
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Diagnostics;
5using System.Diagnostics.CodeAnalysis;
6using System.IO;
7using System.Linq;
8using System.Reflection;
9using System.Text;
10using System.Text.RegularExpressions;
11using System.Threading;
12using NPOI.SS.UserModel;
13using NPOI.XSSF.UserModel;
14using Newtonsoft.Json;
15using ReflexCLI;
16using ReflexCLI.Attributes;
17using UnityEngine;
18using UnityEngine.Networking;
19
20[ConsoleCommandClassCustomizer("Mod")]
21public class ModUtil : EClass
22{
23 public static Dictionary<string, string> fallbackTypes = new Dictionary<string, string>();
24
25 private static readonly Dictionary<string, ICustomContent> _customContent = new Dictionary<string, ICustomContent>();
26
27 private static readonly List<Func<string, object, int>> _customCalcEvaluator = new List<Func<string, object, int>>();
28
29 private static readonly HashSet<Type> _checkedAttributedTypes = new HashSet<Type>();
30
31 private static readonly Dictionary<string, Texture2D> _cachedTextures = new Dictionary<string, Texture2D>();
32
33 private static Effect _rodTemplate;
34
35 public static SourceImporter sourceImporter = new SourceImporter(SourceMapping);
36
37 public static readonly List<ContextMenuProxy> contextMenuProxies = new List<ContextMenuProxy>();
38
39 public static IReadOnlyDictionary<string, SourceData> SourceMapping => (from f in typeof(SourceManager).GetFields()
40 where typeof(SourceData).IsAssignableFrom(f.FieldType)
41 select f).ToDictionary((FieldInfo f) => f.FieldType.Name, (FieldInfo f) => f.GetValue(EClass.sources) as SourceData);
42
43 public static void LoadTypeFallback()
44 {
45 string text = "type_resolver.txt";
46 string[] array = Array.Empty<string>();
47 if (File.Exists(CorePath.RootData + text))
48 {
49 array = IO.LoadTextArray(CorePath.RootData + text);
50 }
51 else
52 {
53 array = new string[2] { "TrueArena,ArenaWaveEvent,ZoneEvent", "Elin-GeneRecombinator,Elin_GeneRecombinator.IncubationSacrifice,Chara" };
54 IO.SaveTextArray(CorePath.RootData + text, array);
55 }
56 string[] array2 = array;
57 for (int i = 0; i < array2.Length; i++)
58 {
59 string[] array3 = array2[i].Split(',');
60 if (array3.Length >= 2)
61 {
62 RegisterSerializedTypeFallback(array3[0], array3[1], array3[2]);
63 }
64 }
65 }
66
67 public static void RegisterSerializedTypeFallback(string nameAssembly, string nameType, string nameFallbackType)
68 {
69 fallbackTypes[nameType] = nameFallbackType;
70 }
71
72 public static void LogModError(string message, BaseModPackage package = null)
73 {
74 string text = "#mod/" + package?.title + " (" + package?.id + ")\n" + message;
75 UnityEngine.Debug.LogWarning(text.RemoveAllTags());
76 if ((package?.isInPackages ?? false) || Application.isEditor)
77 {
78 EGui.CreatePopup(text);
79 }
80 }
81
82 public static void LogModError(string message, SourceData.BaseRow row)
83 {
84 LogModError(message, FindSourceRowPackage(row));
85 }
86
87 public static void LogModError(string message, Type type)
88 {
89 LogModError(message, FindFileProviderPackage(new FileInfo(type.Assembly.Location)));
90 }
91
92 public static void LogModError(string message, FileInfo file)
93 {
94 LogModError(message, FindFileProviderPackage(file));
95 }
96
97 public static void LogModError(string message, DirectoryInfo dir)
98 {
99 LogModError(message, FindDirectoryProviderPackage(dir));
100 }
101
102 public static ModPackage GetModPackage(string modId)
103 {
104 return ModManagerCore.Instance.MappedPackages.GetValueOrDefault(modId) as ModPackage;
105 }
106
107 public static ModPackage FindFileProviderPackage(FileInfo file)
108 {
109 string path = file.FullName.NormalizePath();
110 return ModManager.Instance.packages.LastOrDefault((BaseModPackage p) => path.StartsWith(p.dirInfo.FullName.NormalizePath())) as ModPackage;
111 }
112
113 public static ModPackage FindDirectoryProviderPackage(DirectoryInfo dir)
114 {
115 string path = dir.FullName.NormalizePath();
116 return ModManager.Instance.packages.LastOrDefault((BaseModPackage p) => path.StartsWith(p.dirInfo.FullName.NormalizePath())) as ModPackage;
117 }
118
119 public static ModPackage FindSourceRowPackage(SourceData.BaseRow row)
120 {
121 return ModManagerCore.Instance.packages.OfType<ModPackage>().LastOrDefault((ModPackage p) => p.sourceRows.Contains(row));
122 }
123
124 public static Zone FindZoneByFullName(string zoneFullName = "ntyris/0", bool useRandomFallback = false)
125 {
126 if (zoneFullName.IsEmpty())
127 {
128 return null;
129 }
130 var (zoneType, zoneId, destLv) = Zone.ParseZoneFullName(zoneFullName);
131 if (zoneId.IsEmpty())
132 {
133 return null;
134 }
135 Zone zone = EClass.game.spatials.Find((Zone z) => z.GetType().Name == zoneType || z.id == zoneId)?.FindOrCreateLevel(destLv);
136 if (zone == null && (zoneId == "*" || useRandomFallback))
137 {
138 zone = (from z in EClass.game.spatials.map.Values.OfType<Zone>()
139 where z.CanSpawnAdv
140 select z).RandomItem();
141 }
142 return zone;
143 }
144
145 public static void OnModsActivated()
146 {
147 CommandRegistry.assemblies.Add(typeof(EScript).Assembly);
148 SoundManager.current.soundLoaders.Add(LoadSoundData);
149 UIBook.topicLoaders.Add(LoadTopicFiles);
150 BookList.booklistLoaders.Add(LoadBookList);
151 Lang.excelDialogLoaders.Add(LoadExcelDialog);
152 LoadEffectTemplate();
153 DynamicAsset<Effect>.assetLoaders.Add(LoadEffect);
154 BaseModManager.SubscribeEvent<string>("elin.source.lang_set", OnSetLang);
155 BaseModManager.SubscribeEvent<List<Religion>>("elin.religion_importing", OnReligionImporting);
156 BaseModManager.SubscribeEvent("elin.source.importing", OnSourceImporting);
157 BaseModManager.SubscribeEvent("elin.source.imported", OnSourceImported);
158 BaseModManager.PublishEvent("elin.mods.activated");
159 RegisterElinEventAttributes();
160 CoroutineHelper.Deferred(RegisterElinEventAttributes);
161 }
162
163 private static void OnSourceImporting()
164 {
165 ExcelParser.allowTrimming = true;
166 ImportAllModSourceSheets();
167 }
168
169 private static void OnSourceImported()
170 {
171 _customContent.Clear();
172 foreach (EMod activatedUserMod in ModManager.Instance.ActivatedUserMods)
173 {
174 try
175 {
176 activatedUserMod.GenerateCustomContentProfiles();
177 foreach (ICustomContent item in activatedUserMod.customContent)
178 {
179 AddContent(item);
180 }
181 }
182 catch (Exception ex)
183 {
184 LogModError("exception while generating custom source profiles\n" + ex.Message, activatedUserMod);
185 UnityEngine.Debug.LogException(ex);
186 }
187 }
188 ImportAllGunEffectSettings();
189 CustomReligionContent.managed.Clear();
190 foreach (CustomReligionContent item2 in _customContent.Values.OfType<CustomReligionContent>())
191 {
192 item2.RegisterCustomReligion();
193 }
194 CustomReligionContent.Init();
195 SourceCache.FinalizeCache();
196 SourceCache.InvalidateCacheBlobs();
197 SourceCache.ClearDetail();
199 if (EClass.core.launchArgs.Contains("EXPORTSOURCE"))
200 {
201 string text = CorePath.rootExe + "/SourceExport/" + EClass.core.version.GetText();
202 ExportAllSourceDataCsv(text);
203 UnityEngine.Debug.Log("#source exported current version to " + text);
204 }
205 }
206
207 [ElinPreLoad]
208 private static void OnPreLoadInit(GameIOContext context)
209 {
210 }
211
212 [ElinPostLoad]
213 private static void OnPostLoadInit(GameIOContext context)
214 {
215 EClass.player.knownBGMs.RemoveWhere((int id) => !EClass.core.refs.dictBGM.ContainsKey(id));
216 KeyValuePair<int, Spatial>[] array = EClass.game.spatials.map.ToArray();
217 for (int i = 0; i < array.Length; i++)
218 {
219 KeyValuePair<int, Spatial> keyValuePair = array[i];
220 var (num2, spatial2) = (KeyValuePair<int, Spatial>)(ref keyValuePair);
221 if (spatial2.source == null)
222 {
223 spatial2.Destroy();
224 UnityEngine.Debug.LogWarning($"#mod-content removed invalid zone '{num2}', '{spatial2.id}', '{(spatial2 as Zone)?.ZoneFullName}'");
225 }
226 }
227 List<ICustomContent> contents = new List<ICustomContent>();
228 CustomReligionContent.LoadReligionData(context);
229 LoadCustomContent<CustomZoneContent>();
230 LoadCustomContent<CustomCharaContent>();
231 LoadOtherCustomContent();
232 void LoadCustomContent<T>() where T : class, ICustomContent
233 {
234 UnityEngine.Debug.Log("#mod-content loading " + typeof(T).Name + "...");
235 foreach (T item in _customContent.Values.OfType<T>())
236 {
237 try
238 {
239 item.OnGameLoad(context);
240 contents.Add(item);
241 }
242 catch (Exception ex2)
243 {
244 LogModError("exception while loading custom content '" + item.ContentId + "'\n" + ex2.Message, item.Owner);
245 UnityEngine.Debug.LogException(ex2);
246 }
247 }
248 }
249 void LoadOtherCustomContent()
250 {
251 foreach (ICustomContent item2 in _customContent.Values.Except(contents))
252 {
253 try
254 {
255 item2.OnGameLoad(context);
256 }
257 catch (Exception ex)
258 {
259 LogModError("exception while loading custom content '" + item2.ContentId + "'\n" + ex.Message, item2.Owner);
260 UnityEngine.Debug.LogException(ex);
261 }
262 }
263 }
264 }
265
266 [ElinPreSave]
267 private static void OnPreSaveInit(GameIOContext context)
268 {
269 }
270
271 [ElinPostSave]
272 private static void OnPostSaveInit(GameIOContext context)
273 {
274 CustomReligionContent.SaveReligionData(context);
275 foreach (ICustomContent value in _customContent.Values)
276 {
277 try
278 {
279 value.OnGameSave(context);
280 }
281 catch (Exception ex)
282 {
283 LogModError("exception while saving custom content '" + value.ContentId + "'\n" + ex.Message, value.Owner);
284 UnityEngine.Debug.LogException(ex);
285 }
286 }
287 }
288
289 private static void OnReligionImporting(List<Religion> list)
290 {
291 list.AddRange(CustomReligionContent.GetCustomReligions());
292 }
293
294 [ElinCharaOnCreate]
295 private static void OnCharaCreated(Chara chara)
296 {
297 if (TryGetContent<CustomCharaContent>("Chara/" + chara.id, out var content))
298 {
299 content.OnCharaCreated(chara);
300 }
301 if (TryGetContent<CustomBiographyContent>("Biography/" + chara.id, out var content2))
302 {
303 content2.RefreshCharaBio(chara);
304 }
305 }
306
307 [ElinThingOnCreate]
308 private static void OnThingCreated(Thing thing)
309 {
310 if (TryGetContent<CustomThingContent>("Thing/" + thing.id, out var content))
311 {
312 content.OnThingCreated(thing);
313 }
314 }
315
316 [ElinActPerform]
317 private static void OnActPerformed(Act act)
318 {
319 if (act.HasTag("godAbility"))
320 {
321 CustomReligionContent.managed.Values.FirstOrDefault((ReligionCustom r) => r.content.godAbilities.Contains(act.ID))?.Talk("ability");
322 }
323 }
324
325 private static void OnSetLang(string lang)
326 {
327 PackageIterator.ClearCache();
328 PackageIterator.RebuildAllMappings(lang);
329 SourceLocalization.SetLang(lang);
330 foreach (EMod activatedUserMod in ModManager.Instance.ActivatedUserMods)
331 {
332 if (activatedUserMod.IsSourceLocalizable && (activatedUserMod.isInPackages || Application.isEditor))
333 {
334 activatedUserMod.UpdateSourceLocalizationFile(lang);
335 }
336 }
337 AliasGen.list = null;
338 AliasGen.listMix.Clear();
339 AliasGen.listBuiltin.Clear();
340 WordGen.listMix.Clear();
341 WordGen.listBuiltin.Clear();
342 foreach (string item in LoadAlias())
343 {
345 }
346 NameGen.list = null;
347 foreach (string item2 in LoadName())
348 {
349 MOD.listName.Add(new ExcelData(item2));
350 }
351 foreach (string item3 in LoadGodTalk())
352 {
353 MOD.listGodTalk.Add(new ExcelData(item3));
354 }
355 foreach (string item4 in LoadCharaTalk())
356 {
357 MOD.listTalk.Add(new ExcelData(item4));
358 }
359 foreach (string item5 in LoadCharaTone())
360 {
361 MOD.tones.Add(new ExcelData(item5));
362 }
363 BookList.dict = null;
364 BottleMessageList.list = null;
365 Lang.excelDialog = null;
366 foreach (CustomFileContent item6 in _customContent.Values.OfType<CustomFileContent>())
367 {
368 item6.OnSetLang(lang);
369 }
370 }
371
372 public static bool TryGetContent<T>(string contentId, [NotNullWhen(true)] out T content) where T : class, ICustomContent
373 {
374 ICustomContent value;
375 bool num = _customContent.TryGetValue(contentId, out value);
376 content = value as T;
377 if (num)
378 {
379 return content != null;
380 }
381 return false;
382 }
383
384 public static bool HasContent(string contentId)
385 {
386 return _customContent.ContainsKey(contentId);
387 }
388
389 public static void AddContent(ICustomContent content)
390 {
391 UnityEngine.Debug.Log(_customContent.Remove(content.ContentId, out var value) ? ("#mod-content override '" + content.ContentId + "' from '" + value.Owner.id + "' to '" + content.Owner.id + "'") : ("#mod-content added '" + content.ContentId + "' from '" + content.Owner.id + "'"));
392 _customContent[content.ContentId] = content;
393 }
394
395 public static bool FixDefaultRenderRowPref(RenderRow r, string id)
396 {
397 FileInfo fileInfo = PackageIterator.GetFiles("Texture/" + id + ".pref").LastOrDefault();
398 if (fileInfo == null)
399 {
400 return false;
401 }
402 r.pref = SourcePref.ReadFromIni(fileInfo.FullName);
403 return true;
404 }
405
406 public static void FixDefaultCharaRowPref(SourceChara.Row r)
407 {
408 if (!r.tag.Contains("usePref") || !FixDefaultRenderRowPref(r, r.id))
409 {
410 r.pref = new SourcePref
411 {
412 pivotY = -10
413 };
414 }
415 }
416
417 public static void FixDefaultThingRowPref(SourceThing.Row r)
418 {
419 if (!r.tag.Contains("usePref") || !FixDefaultRenderRowPref(r, r.id))
420 {
421 r.pref = new SourcePref
422 {
423 shadow = 1
424 };
425 }
426 }
427
428 public static List<Thing> GenerateMerchantStock(Card owner, string stockId = null, bool forceRestock = false)
429 {
430 List<Thing> list = new List<Thing>();
431 if (stockId.IsEmpty())
432 {
433 stockId = owner.GetStr("merchant_override");
434 }
435 if (stockId.IsEmpty())
436 {
437 return list;
438 }
439 string[] array = stockId.Split('|');
440 HashSet<string> orCreate = EClass.player.noRestocks.GetOrCreate(owner.trait.IdNoRestock, () => new HashSet<string>());
441 string[] array2 = array;
442 foreach (string text in array2)
443 {
444 if (!TryGetContent<CustomMerchantStock>("MerchantStock/" + text, out var content))
445 {
446 continue;
447 }
448 foreach (Thing item in content.Generate(owner))
449 {
450 bool @bool = item.GetBool(101);
451 if (!(!forceRestock && @bool) || !orCreate.Contains(item.trait.IdNoRestock))
452 {
453 if (@bool)
454 {
455 orCreate.Add(item.trait.IdNoRestock);
456 }
457 list.Add(item);
458 }
459 }
460 }
461 return list;
462 }
463
464 public static void RegisterElinEventAttributes()
465 {
466 ClassCache.modTypes.Add(typeof(ModUtil));
468 foreach (var item3 in ClassCache.modTypes.Except(_checkedAttributedTypes).MembersWith<ElinEventBaseAttribute>())
469 {
470 MemberInfo item = item3.member;
471 ElinEventBaseAttribute[] item2 = item3.attrs;
472 foreach (ElinEventBaseAttribute elinEventBaseAttribute in item2)
473 {
474 try
475 {
476 if (!(item is PropertyInfo property))
477 {
478 if (item is MethodInfo method)
479 {
480 elinEventBaseAttribute.Register(method);
481 }
482 }
483 else
484 {
485 elinEventBaseAttribute.Register(property);
486 }
487 }
488 catch (Exception ex)
489 {
490 LogModError("exception while registering attribute '" + elinEventBaseAttribute.GetType().Name + "' from '" + item.TryToString() + "'\n" + ex.Message, item.DeclaringType);
491 UnityEngine.Debug.LogException(ex);
492 }
493 }
494 }
495 _checkedAttributedTypes.UnionWith(ClassCache.modTypes);
496 }
497
498 public static List<string> LoadBookList()
499 {
500 List<string> list = new List<string>();
501 DirectoryInfo[] directories = PackageIterator.GetDirectories("Text");
502 foreach (DirectoryInfo directoryInfo in directories)
503 {
504 list.AddRange(Directory.GetDirectories(directoryInfo.FullName));
505 UnityEngine.Debug.Log("#mod-content loaded book list " + directoryInfo.ShortPath());
506 }
507 return list;
508 }
509
510 public static List<string> LoadTopicFiles()
511 {
512 List<string> list = new List<string>();
513 FileInfo[] files = PackageIterator.GetFiles("Text/Help/_topics.txt");
514 foreach (FileInfo fileInfo in files)
515 {
516 list.AddRange(IO.LoadTextArray(fileInfo.FullName));
517 UnityEngine.Debug.Log("#mod-content loaded book topics " + fileInfo.ShortPath());
518 }
519 return list;
520 }
521
522 public static List<string> LoadExcelDialog()
523 {
524 List<string> list = new List<string>();
525 FileInfo[] files = PackageIterator.GetFiles("Dialog/dialog.xlsx");
526 foreach (FileInfo fileInfo in files)
527 {
528 list.Add(fileInfo.FullName);
529 UnityEngine.Debug.Log("#mod-content loaded dialog " + fileInfo.ShortPath());
530 }
531 return list;
532 }
533
534 public static List<string> LoadAlias()
535 {
536 List<string> list = new List<string>();
537 FileInfo[] files = PackageIterator.GetFiles(Lang.langCode + "/Data/Alias.xlsx");
538 foreach (FileInfo fileInfo in files)
539 {
540 list.Add(fileInfo.FullName);
541 UnityEngine.Debug.Log("#mod-content loaded Alias " + fileInfo.ShortPath());
542 }
543 return list;
544 }
545
546 public static List<string> LoadName()
547 {
548 List<string> list = new List<string>();
549 FileInfo[] files = PackageIterator.GetFiles(Lang.langCode + "/Data/Name.xlsx");
550 foreach (FileInfo fileInfo in files)
551 {
552 list.Add(fileInfo.FullName);
553 UnityEngine.Debug.Log("#mod-content loaded Name " + fileInfo.ShortPath());
554 }
555 return list;
556 }
557
558 public static List<string> LoadCharaTalk()
559 {
560 List<string> list = new List<string>();
561 FileInfo[] files = PackageIterator.GetFiles("Data/chara_talk.xlsx");
562 foreach (FileInfo fileInfo in files)
563 {
564 list.Add(fileInfo.FullName);
565 UnityEngine.Debug.Log("#mod-content loaded chara tone " + fileInfo.ShortPath());
566 }
567 return list;
568 }
569
570 public static List<string> LoadCharaTone()
571 {
572 List<string> list = new List<string>();
573 FileInfo[] files = PackageIterator.GetFiles("Data/chara_tone.xlsx");
574 foreach (FileInfo fileInfo in files)
575 {
576 list.Add(fileInfo.FullName);
577 UnityEngine.Debug.Log("#mod-content loaded chara talk " + fileInfo.ShortPath());
578 }
579 return list;
580 }
581
582 public static Sprite LoadSprite(string spritePath, Vector2? pivot = null, string name = null, int resizeWidth = 0, int resizeHeight = 0)
583 {
584 if (spritePath.IsEmpty())
585 {
586 return null;
587 }
588 if (!spritePath.EndsWith(".png"))
589 {
590 if (SpriteReplacer.dictModItems.TryGetValue(spritePath, out var value))
591 {
592 spritePath = value;
593 }
594 spritePath += ".png";
595 }
596 if (!File.Exists(spritePath))
597 {
598 FileInfo[] files = PackageIterator.GetFiles(Path.Combine("Texture", spritePath));
599 if (files.IsEmpty())
600 {
601 return null;
602 }
603 spritePath = files[^1].FullName;
604 }
605 Vector2 valueOrDefault = pivot.GetValueOrDefault();
606 if (!pivot.HasValue)
607 {
608 valueOrDefault = new Vector2(0.5f, 0.5f);
609 pivot = valueOrDefault;
610 }
611 string text = $"{spritePath}/{pivot}/{resizeWidth}/{resizeHeight}";
612 if (name == null)
613 {
614 name = text;
615 }
616 try
617 {
618 if (!_cachedTextures.TryGetValue(text, out var value2))
619 {
620 value2 = IO.LoadPNG(spritePath);
621 if (value2 == null)
622 {
623 return null;
624 }
625 if (resizeWidth != 0 && resizeHeight != 0 && value2.width != resizeWidth && value2.height != resizeHeight)
626 {
627 Texture2D texture2D = value2.Rescale(resizeWidth, resizeHeight);
628 UnityEngine.Object.Destroy(value2);
629 value2 = texture2D;
630 value2.name = text;
631 }
632 }
633 _cachedTextures[text] = value2;
634 }
635 catch (Exception arg)
636 {
637 UnityEngine.Debug.LogError($"#mod-content failed to load sprite {spritePath.ShortPath()}\n{arg}");
638 return null;
639 }
640 Texture2D texture2D2 = _cachedTextures[text];
641 Sprite sprite = Sprite.Create(texture2D2, new Rect(0f, 0f, texture2D2.width, texture2D2.height), pivot.Value, 100f, 0u, SpriteMeshType.FullRect);
642 sprite.name = name;
643 return sprite;
644 }
645
646 public static Sprite AppendSpriteSheet(string id, int resizeWidth = 0, int resizeHeight = 0, string pattern = "@")
647 {
648 Dictionary<string, string> dictModItems = SpriteReplacer.dictModItems;
649 if (!dictModItems.TryGetValue(id, out var value) && pattern != "")
650 {
651 value = dictModItems.Where((KeyValuePair<string, string> kv) => kv.Key.StartsWith(pattern)).FirstOrDefault((KeyValuePair<string, string> kv) => id.StartsWith(kv.Key[pattern.Length..])).Value;
652 }
653 string spritePath = value;
654 string name = id;
655 Sprite sprite = LoadSprite(spritePath, null, name, resizeWidth, resizeHeight);
656 if (sprite == null)
657 {
658 return null;
659 }
660 if (SpriteSheet.dict.TryGetValue(id, out var value2) && value2.texture.width == sprite.texture.width && value2.texture.height == sprite.texture.height)
661 {
662 return value2;
663 }
664 return SpriteSheet.dict[sprite.name] = sprite;
665 }
666
667 public static List<string> LoadGodTalk()
668 {
669 List<string> list = new List<string>();
670 FileInfo[] files = PackageIterator.GetFiles("Data/god_talk.xlsx");
671 foreach (FileInfo fileInfo in files)
672 {
673 list.Add(fileInfo.FullName);
674 UnityEngine.Debug.Log("#mod-content loaded god talk " + fileInfo.ShortPath());
675 }
676 return list;
677 }
678
679 public static Dictionary<string, CustomGunEffectData> LoadGunEffects()
680 {
681 Dictionary<string, CustomGunEffectData> dictionary = new Dictionary<string, CustomGunEffectData>();
682 (FileInfo, EMod)[] filesEx = PackageIterator.GetFilesEx("Data/EffectSetting.guns.json");
683 for (int i = 0; i < filesEx.Length; i++)
684 {
685 (FileInfo, EMod) tuple = filesEx[i];
686 FileInfo item = tuple.Item1;
687 EMod item2 = tuple.Item2;
689 _customContent[customGunEffectSetting.ContentId] = customGunEffectSetting;
690 }
691 foreach (CustomGunEffectSetting item3 in _customContent.Values.OfType<CustomGunEffectSetting>())
692 {
693 item3.Load();
694 dictionary.Merge(item3.items);
695 UnityEngine.Debug.Log($"#mod-content loaded {item3}");
696 }
697 return dictionary;
698 }
699
700 public static void ImportAllGunEffectSettings()
701 {
702 foreach (KeyValuePair<string, CustomGunEffectData> item in LoadGunEffects())
703 {
704 item.Deconstruct(out var key, out var value);
705 string key2 = key;
706 GameSetting.EffectData value2 = value.CreateEffectData();
707 EClass.setting.effect.guns[key2] = value2;
708 }
709 }
710
711 public static string ExportAllGunEffectSettings()
712 {
714 string text = CorePath.rootExe + "/guns.json";
715 Dictionary<string, CustomGunEffectData> dictionary = new Dictionary<string, CustomGunEffectData>();
716 foreach (string key in guns.Keys)
717 {
719 dictionary[key] = value;
720 }
721 File.WriteAllText(text, JsonConvert.SerializeObject(dictionary, Formatting.Indented, GameIOContext.Settings));
722 return $"dumped {dictionary.Count} guns data to {text}";
723 }
724
725 private static Effect LoadEffect(string id)
726 {
727 if (id.IsEmpty())
728 {
729 return null;
730 }
731 if (!_rodTemplate)
732 {
733 return null;
734 }
735 string effectId = id.Split('/')[^1];
736 Sprite sprite = LoadSprite(effectId);
737 if (!sprite)
738 {
739 return null;
740 }
741 Effect effect = UnityEngine.Object.Instantiate(_rodTemplate);
742 effect.name = effectId;
743 effect.sprites = Slice().ToArray();
744 UnityEngine.Object.DontDestroyOnLoad(effect);
745 UnityEngine.Debug.Log("#mod-content loaded custom effect '" + effectId + "'");
746 return effect;
747 IEnumerable<Sprite> Slice()
748 {
749 int height = (int)sprite.rect.height;
750 float frames = sprite.rect.width / (float)height;
751 if (frames != 0f)
752 {
753 int i = 0;
754 while ((float)i < frames)
755 {
756 Sprite sprite2 = Sprite.Create(rect: new Rect(i * height, 0f, height, height), texture: sprite.texture, pivot: new Vector2(0.5f, 0.5f * (128f / (float)height)), pixelsPerUnit: 100f, extrude: 0u, meshType: SpriteMeshType.FullRect);
757 sprite2.name = $"{effectId}{i:D4}";
758 yield return sprite2;
759 int num = i + 1;
760 i = num;
761 }
762 }
763 }
764 }
765
766 private static void LoadEffectTemplate()
767 {
768 _rodTemplate = Resources.Load<Effect>("Media/Effect/General/rod");
769 if (!_rodTemplate)
770 {
771 UnityEngine.Debug.LogWarning("#mod-content cannot initialize rod effect template");
772 }
773 }
774
775 public static SerializableSoundData GetSoundMeta(string soundPath)
776 {
777 string path = Path.ChangeExtension(soundPath, ".json");
778 SerializableSoundData serializableSoundData;
779 if (File.Exists(path))
780 {
781 try
782 {
783 serializableSoundData = IO.LoadFile<SerializableSoundData>(path);
784 if (serializableSoundData.dataVersion == SerializableSoundData.SoundDataMetaVersion.V1)
785 {
786 return serializableSoundData;
787 }
788 }
789 catch
790 {
791 }
792 }
793 serializableSoundData = new SerializableSoundData();
794 if (soundPath.NormalizePath().Contains("/Sound/BGM/"))
795 {
796 serializableSoundData.type = SoundData.Type.BGM;
797 serializableSoundData.bgmDataOptional = new SerializableBGMData
798 {
799 parts = new List<BGMData.Part>
800 {
801 new BGMData.Part()
802 }
803 };
804 }
805 IO.SaveFile(path, serializableSoundData);
806 return serializableSoundData;
807 }
808
809 public static AudioType GetAudioType(string extension)
810 {
811 return extension.ToLowerInvariant().Trim() switch
812 {
813 ".acc" => AudioType.ACC,
814 ".mp3" => AudioType.MPEG,
815 ".ogg" => AudioType.OGGVORBIS,
816 ".wav" => AudioType.WAV,
817 _ => AudioType.UNKNOWN,
818 };
819 }
820
821 public static SoundData LoadSoundData(string soundId)
822 {
823 if (!MOD.sounds.TryGetValue(soundId, out var value) || !value.Exists)
824 {
825 return null;
826 }
827 return LoadSoundData(value);
828 }
829
830 public static SoundData LoadSoundData(FileInfo soundFile)
831 {
832 string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(soundFile.FullName);
833 string fullName = soundFile.FullName;
834 AudioType audioType = GetAudioType(soundFile.Extension);
835 bool stream = fullName.NormalizePath().Contains("/BGM/") && audioType == AudioType.OGGVORBIS;
836 using UnityWebRequest unityWebRequest = AudioClipStream.GetAudioClip("file://" + fullName, audioType, compressed: false, stream);
837 unityWebRequest.SendWebRequest();
838 Stopwatch stopwatch = Stopwatch.StartNew();
839 while (!unityWebRequest.isDone && stopwatch.ElapsedMilliseconds < 5000)
840 {
841 Thread.Sleep(1);
842 }
843 if (unityWebRequest.result != UnityWebRequest.Result.Success)
844 {
845 UnityEngine.Debug.LogError("#sound '" + fileNameWithoutExtension + "' failed to load: " + unityWebRequest.error.IsEmpty("timeout"));
846 return null;
847 }
848 AudioClip content = DownloadHandlerAudioClip.GetContent(unityWebRequest);
849 int? num = content?.samples;
850 if (!num.HasValue || num.GetValueOrDefault() <= 0)
851 {
852 UnityEngine.Debug.LogError($"#sound '{fileNameWithoutExtension}' sample is null: {audioType}");
853 return null;
854 }
855 content.name = fileNameWithoutExtension;
856 SoundData soundData = GetSoundMeta(fullName).ToSoundData();
857 if (soundData is BGMData bGMData)
858 {
859 bGMData._name = Path.GetFileNameWithoutExtension(fullName);
860 if (bGMData.song == null)
861 {
862 bGMData.song = new BGMData.SongData();
863 bGMData.song.parts.Add(new BGMData.Part());
864 }
865 }
866 soundData.clip = content;
867 soundData.name = fileNameWithoutExtension;
868 UnityEngine.Debug.Log($"#sound '{fileNameWithoutExtension}' loaded: {audioType}/{content.length}s");
869 SoundManager.current.dictData[fileNameWithoutExtension] = soundData;
870 return soundData;
871 }
872
873 public static void AddOrReplaceBGM(string bgmId)
874 {
875 List<BGMData> bgms = Core.Instance.refs.bgms;
876 Dictionary<int, BGMData> dictBGM = Core.Instance.refs.dictBGM;
877 BGMData bGMData = LoadSoundData(bgmId) as BGMData;
878 if (bGMData == null)
879 {
880 return;
881 }
882 bGMData.name = bgmId.Replace("BGM/", "");
883 if (bGMData.id <= 0)
884 {
885 Match match = Regex.Match(bGMData.name, "^(\\d+)(?:_(.*))?$");
886 if (match.Success)
887 {
888 int id = match.Groups[1].Value.ToInt();
889 string text = (match.Groups[2].Success ? match.Groups[2].Value : null);
890 bGMData.id = id;
891 if (!text.IsEmpty())
892 {
893 bGMData.name = text;
894 }
895 }
896 else
897 {
898 bGMData.id = bgms.Count + 1;
899 UnityEngine.Debug.Log($"#sound bgm unassigned/{bGMData.id}/{bGMData.name}");
900 }
901 }
902 if (dictBGM.TryGetValue(bGMData.id, out var value))
903 {
904 value.clip = bGMData.clip;
905 UnityEngine.Debug.Log($"#sound bgm replace/{bGMData.id}/{value.name}/>/{bGMData.name}");
906 }
907 else
908 {
909 bgms.Add(bGMData);
910 dictBGM[bGMData.id] = bGMData;
911 UnityEngine.Debug.Log($"#sound bgm addon/{bGMData.id}/{bGMData.name}");
912 }
913 }
914
915 public static ModPackage FindSoundPackage(string soundId)
916 {
917 return ModManagerCore.Instance.packages.OfType<ModPackage>().LastOrDefault((ModPackage p) => p.sounds.Keys.Contains(soundId));
918 }
919
920 public static Playlist CreatePlaylist(ref List<int> bgmIds, Playlist mold = null)
921 {
922 Playlist playlist = EClass.Sound.plBlank.Instantiate();
923 if (bgmIds.Count == 0 && (bool)mold)
924 {
925 bgmIds = mold.ToInts();
926 playlist.shuffle = mold.shuffle;
927 playlist.minSwitchTime = mold.minSwitchTime;
928 playlist.nextBGMOnSwitch = mold.nextBGMOnSwitch;
929 playlist.ignoreLoop = mold.ignoreLoop;
930 playlist.keepBGMifSamePlaylist = mold.keepBGMifSamePlaylist;
931 playlist.name = mold.name;
932 }
933 foreach (int bgmId in bgmIds)
934 {
935 if (EClass.core.refs.dictBGM.TryGetValue(bgmId, out var value))
936 {
937 playlist.list.Add(new Playlist.Item
938 {
939 data = value
940 });
941 }
942 }
943 return playlist;
944 }
945
946 public static void SetBGMKnown(int bgmId, bool known = true)
947 {
948 known &= EClass.core.refs.dictBGM.ContainsKey(bgmId);
949 if (known)
950 {
951 EClass.player.knownBGMs.Add(bgmId);
952 }
953 else
954 {
955 EClass.player.knownBGMs.Remove(bgmId);
956 }
957 }
958
959 [Obsolete("use ImportModSourceSheets for proper caching and localizaiton support")]
960 public static void ImportExcel(string pathToExcelFile, string sheetName, SourceData source)
961 {
962 UnityEngine.Debug.Log("ImportExcel source:" + source?.ToString() + " Path:" + pathToExcelFile);
963 using FileStream @is = File.Open(pathToExcelFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
964 XSSFWorkbook xSSFWorkbook = new XSSFWorkbook((Stream)@is);
965 for (int i = 0; i < xSSFWorkbook.NumberOfSheets; i++)
966 {
967 ISheet sheetAt = xSSFWorkbook.GetSheetAt(i);
968 if (sheetAt.SheetName != sheetName)
969 {
970 continue;
971 }
972 UnityEngine.Debug.Log("Importing Sheet:" + sheetName);
973 try
974 {
975 ExcelParser.path = pathToExcelFile;
976 if (!source.ImportData(sheetAt, new FileInfo(pathToExcelFile).Name, overwrite: true))
977 {
978 UnityEngine.Debug.LogError(ERROR.msg);
979 break;
980 }
981 UnityEngine.Debug.Log("Imported " + sheetAt.SheetName);
982 source.Reset();
983 }
984 catch (Exception ex)
985 {
986 UnityEngine.Debug.LogError("[Error] Skipping import " + sheetAt.SheetName + " :" + ex.Message + "/" + ex.Source + "/" + ex.StackTrace);
987 break;
988 }
989 }
990 }
991
992 public static SourceData FindSourceByName(string sourceData)
993 {
994 return sourceImporter.FindSourceByName(sourceData);
995 }
996
997 public static void ImportModSourceSheets(string modId)
998 {
999 try
1000 {
1001 SourceCache.InvalidateCacheVersion();
1002 EMod valueOrDefault = ModManager.Instance.MappedPackages.GetValueOrDefault(modId);
1003 if (valueOrDefault == null)
1004 {
1005 return;
1006 }
1007 List<string> list = new List<string>();
1008 foreach (FileInfo sourceSheet in valueOrDefault.Mapping.SourceSheets)
1009 {
1010 sourceImporter.fileProviders[sourceSheet.FullName] = valueOrDefault;
1011 list.Add(sourceSheet.FullName);
1012 }
1013 sourceImporter.ImportFilesCached(list);
1014 UnityEngine.Debug.Log("#source finished importing workbooks from " + modId);
1015 }
1016 catch (Exception exception)
1017 {
1018 UnityEngine.Debug.LogException(exception);
1019 }
1020 }
1021
1022 public static void ImportAllModSourceSheets()
1023 {
1024 try
1025 {
1026 SourceCache.InvalidateCacheVersion();
1028 {
1030 EClass.sources.materials
1031 });
1032 List<string> list = new List<string>();
1033 foreach (BaseModPackage package in ModManager.Instance.packages)
1034 {
1035 if (!(package is ModPackage modPackage) || !package.activated || package.id == null)
1036 {
1037 continue;
1038 }
1039 foreach (FileInfo sourceSheet in modPackage.Mapping.SourceSheets)
1040 {
1041 if (!sourceSheet.Name.StartsWith(".") && !sourceSheet.Name.Contains('~'))
1042 {
1043 sourceImporter.fileProviders[sourceSheet.FullName] = modPackage;
1044 list.Add(sourceSheet.FullName);
1045 }
1046 }
1047 }
1048 sourceImporter.ImportFilesCached(list);
1049 }
1050 catch (Exception exception)
1051 {
1052 UnityEngine.Debug.LogException(exception);
1053 }
1054 UnityEngine.Debug.Log("#source finished importing workbooks");
1055 }
1056
1057 public static string ExportSourceDataCsv(string sourceData, string delimiter = ",")
1058 {
1059 SourceData sourceData2 = FindSourceByName(sourceData);
1060 if (sourceData2 == null)
1061 {
1062 return "";
1063 }
1064 IReadOnlyDictionary<string, string> typeMapping = sourceData2.GetTypeMapping();
1065 (string, string)[] array = (from kv in sourceData2.GetRowMapping()
1066 orderby kv.Value
1067 select (column: kv.Key, type: typeMapping[kv.Key])).ToArray();
1068 StringBuilder stringBuilder = new StringBuilder();
1069 stringBuilder.AppendLine(string.Join(delimiter, array.Select(((string column, string type) p) => p.column)));
1070 stringBuilder.AppendLine(string.Join(delimiter, array.Select(((string column, string type) p) => p.type)));
1071 SourceData.BaseRow[] array2 = sourceData2.ExportRows();
1072 foreach (SourceData.BaseRow baseRow in array2)
1073 {
1074 List<string> list = new List<string>();
1075 (string, string)[] array3 = array;
1076 for (int j = 0; j < array3.Length; j++)
1077 {
1078 (string, string) tuple = array3[j];
1079 string item = tuple.Item1;
1080 string item2 = tuple.Item2;
1081 object value = baseRow.GetRowFields()[item].GetValue(baseRow);
1082 object obj = value;
1083 IEnumerable enumerable;
1084 if (!(obj is int[] array4))
1085 {
1086 if (!(obj is int key))
1087 {
1088 if (obj is string item3)
1089 {
1090 list.Add(item3);
1091 continue;
1092 }
1093 enumerable = obj as IEnumerable;
1094 if (enumerable != null)
1095 {
1096 goto IL_024a;
1097 }
1098 }
1099 else if (item2 == "element_id")
1100 {
1101 list.Add(EClass.sources.elements.map[key].alias);
1102 continue;
1103 }
1104 list.Add(value.ToString());
1105 continue;
1106 }
1107 if (!(item2 == "elements"))
1108 {
1109 enumerable = (IEnumerable)obj;
1110 goto IL_024a;
1111 }
1112 List<string> list2 = new List<string>();
1113 for (int k = 0; k < array4.Length - 1; k += 2)
1114 {
1115 string alias = EClass.sources.elements.map[array4[k]].alias;
1116 string text = array4[k + 1].ToString();
1117 list2.Add(alias + "/" + text);
1118 }
1119 string item4 = string.Join(',', list2);
1120 list.Add(item4);
1121 continue;
1122 IL_024a:
1123 string item5 = string.Join(',', enumerable.OfType<object>());
1124 list.Add(item5);
1125 }
1126 IEnumerable<string> values = list.Select(delegate(string f)
1127 {
1128 string text2 = f.Replace("\r", "").Replace("\n", "\\n").Replace("\"", "\"\"");
1129 return (!text2.IsEmpty()) ? ("\"" + text2 + "\"") : "";
1130 });
1131 stringBuilder.AppendLine(string.Join(delimiter, values));
1132 }
1133 return stringBuilder.ToString();
1134 }
1135
1136 public static void ExportAllSourceDataCsv(string dir)
1137 {
1138 IO.CreateDirectory(dir);
1139 foreach (string key in SourceMapping.Keys)
1140 {
1141 File.WriteAllText(Path.Combine(dir, key + ".csv"), ExportSourceDataCsv(key));
1142 }
1143 }
1144
1145 public static string ExportSourceDataJson(string sourceData, Formatting format = Formatting.Indented)
1146 {
1147 SourceData sourceData2 = FindSourceByName(sourceData);
1148 if (sourceData2 == null)
1149 {
1150 return "";
1151 }
1152 return JsonConvert.SerializeObject(sourceData2.ExportRows(), format, GameIOContext.Settings);
1153 }
1154
1155 public static void ExportAllSourceDataJson(string dir)
1156 {
1157 IO.CreateDirectory(dir);
1158 foreach (string key in SourceMapping.Keys)
1159 {
1160 File.WriteAllText(Path.Combine(dir, key + ".json"), ExportSourceDataJson(key));
1161 }
1162 }
1163
1164 public static void AddContextMenuEntry(Action onClick, string menuEntry, string displayName = "")
1165 {
1166 if (onClick == null || menuEntry.IsEmpty())
1167 {
1168 return;
1169 }
1170 string[] array = menuEntry.Split('/', StringSplitOptions.RemoveEmptyEntries);
1171 List<ContextMenuProxy> children = contextMenuProxies;
1172 for (int i = 0; i < array.Length; i++)
1173 {
1174 bool flag = i < array.Length - 1;
1175 string part = array[i];
1176 ContextMenuProxy contextMenuProxy = children.Find((ContextMenuProxy p) => p.MenuEntry == part);
1177 if (contextMenuProxy == null)
1178 {
1179 contextMenuProxy = new ContextMenuProxy(flag ? part : displayName, part)
1180 {
1181 onClick = ((i == array.Length - 1 && flag) ? null : new Action(SafeInvoke)),
1182 isMenu = flag
1183 };
1184 children.Add(contextMenuProxy);
1185 }
1186 else if (contextMenuProxy.isMenu != flag)
1187 {
1188 UnityEngine.Debug.LogWarning("#mod-content attempt to add context menu entry with same name but different types\n" + part + " -> " + (contextMenuProxy.isMenu ? "submenu" : "button"));
1189 return;
1190 }
1191 children = contextMenuProxy.children;
1192 }
1193 UnityEngine.Debug.Log("#mod-content added context menu entry '" + menuEntry + "' from '" + onClick.Method.TryToString() + "'");
1194 void SafeInvoke()
1195 {
1196 try
1197 {
1198 onClick();
1199 }
1200 catch (Exception exception)
1201 {
1202 UnityEngine.Debug.LogException(exception);
1203 }
1204 }
1205 }
1206
1207 public static void RemoveContextMenuEntry(string entry)
1208 {
1209 string[] array = entry.Split('/', StringSplitOptions.RemoveEmptyEntries);
1210 if (array.Length == 0)
1211 {
1212 return;
1213 }
1214 List<ContextMenuProxy> children = contextMenuProxies;
1215 ContextMenuProxy contextMenuProxy = null;
1216 List<ContextMenuProxy> list = null;
1217 string[] array2 = array;
1218 foreach (string part in array2)
1219 {
1220 contextMenuProxy = children.Find((ContextMenuProxy p) => p.MenuEntry == part);
1221 if (contextMenuProxy == null)
1222 {
1223 return;
1224 }
1225 list = children;
1226 children = contextMenuProxy.children;
1227 }
1228 list?.Remove(contextMenuProxy);
1229 }
1230}
Definition: ACT.cs:62
virtual string ID
Definition: ACT.cs:99
Version version
Definition: BaseCore.cs:17
static void PublishEvent(string eventId, object data=null)
static void SubscribeEvent(string eventId, Action< object > handler)
DirectoryInfo dirInfo
static List< Func< List< string > > > booklistLoaders
Definition: BookList.cs:28
Definition: Card.cs:11
string id
Definition: Card.cs:36
string GetStr(string id, string defaultStr=null)
Definition: Card.cs:2579
Trait trait
Definition: Card.cs:54
Definition: Chara.cs:10
static HashSet< Type > modTypes
Definition: ClassCache.cs:58
readonly List< ContextMenuProxy > children
static string RootData
Definition: CorePath.cs:200
Dictionary< int, BGMData > dictBGM
Definition: CoreRef.cs:386
List< BGMData > bgms
Definition: CoreRef.cs:382
Definition: Core.cs:14
CoreRef refs
Definition: Core.cs:51
static new Core Instance
Definition: Core.cs:15
string[] launchArgs
Definition: Core.cs:78
string ContentId
Definition: CustomContent.cs:6
virtual void OnSetLang(string lang)
static CustomGunEffectData CreateFromId(string id)
Dictionary< string, CustomGunEffectData > items
static CustomGunEffectSetting CreateFromFile(FileInfo file, ModPackage owner=null)
static List< Func< string, T > > assetLoaders
Definition: DynamicAsset.cs:9
Definition: EClass.cs:6
static Game game
Definition: EClass.cs:9
static Core core
Definition: EClass.cs:7
static SourceManager sources
Definition: EClass.cs:43
static Player player
Definition: EClass.cs:13
static SoundManager Sound
Definition: EClass.cs:47
static GameSetting setting
Definition: EClass.cs:35
Definition: ERROR.cs:2
static string msg
Definition: ERROR.cs:3
Definition: Effect.cs:7
bool HasTag(string tag)
Definition: ELEMENT.cs:480
virtual void Register(MethodInfo method)
void Add(ExcelData data)
static void ClearStaticRows()
Definition: ExcelParser.cs:264
UD_String_EffectData guns
Definition: GameSetting.cs:278
EffectSetting effect
Definition: GameSetting.cs:301
SpatialManager spatials
Definition: Game.cs:153
Definition: IO.cs:10
static string[] LoadTextArray(string _path)
Definition: IO.cs:483
static void SaveTextArray(string path, string[] text)
Definition: IO.cs:110
static void CreateDirectory(string path)
Definition: IO.cs:384
static void SaveFile(string path, object obj, bool compress=false, JsonSerializerSettings setting=null)
Definition: IO.cs:88
static Texture2D LoadPNG(string _path, FilterMode filter=FilterMode.Point)
Definition: IO.cs:473
Definition: Lang.cs:7
static List< Func< List< string > > > excelDialogLoaders
Definition: Lang.cs:59
static string langCode
Definition: Lang.cs:29
Definition: MOD.cs:7
static TalkDataList listTalk
Definition: MOD.cs:14
static GodTalkDataList listGodTalk
Definition: MOD.cs:16
static ToneDataList tones
Definition: MOD.cs:18
static ExcelDataList listAlias
Definition: MOD.cs:10
static Dictionary< string, FileInfo > sounds
Definition: MOD.cs:30
static ExcelDataList listName
Definition: MOD.cs:12
static new ModManager Instance
Definition: ModManager.cs:27
HashSet< int > knownBGMs
Definition: Player.cs:1131
Dictionary< string, HashSet< string > > noRestocks
Definition: Player.cs:1194
CustomReligionContent content
string[] tag
Definition: RenderRow.cs:58
override bool ImportData(ISheet sheet, string bookname, bool overwrite=false)
Definition: SourceData.cs:137
virtual IReadOnlyDictionary< string, int > GetRowMapping()
Definition: SourceData.cs:962
override BaseRow[] ExportRows()
Definition: SourceData.cs:233
override void Reset()
Definition: SourceData.cs:116
virtual IReadOnlyDictionary< string, string > GetTypeMapping()
Definition: SourceData.cs:967
IEnumerable< SourceData > ImportFilesCached(IEnumerable< string > imports, bool resetData=true)
static void HotInit(IEnumerable< SourceData > sourceData)
Dictionary< string, EMod > fileProviders
SourceData FindSourceByName(string name)
SourceElement elements
static SourcePref ReadFromIni(string path)
Definition: SourcePref.cs:395
Zone Find(string id)
GlobalSpatialList map
virtual bool CanSpawnAdv
Definition: Spatial.cs:505
virtual string Name
Definition: Spatial.cs:509
string id
Definition: Spatial.cs:13
static Dictionary< string, string > dictModItems
static Dictionary< string, Sprite > dict
Definition: SpriteSheet.cs:6
Definition: Thing.cs:8
virtual string IdNoRestock
Definition: Trait.cs:373
ICollection< TKey > Keys
Definition: UDictionary.cs:25
Definition: UIBook.cs:9
static List< Func< List< string > > > topicLoaders
Definition: UIBook.cs:332
Definition: Zone.cs:12
static string string int zoneLv ParseZoneFullName(string zoneFullName)
Definition: Zone.cs:548
Zone FindOrCreateLevel(int destLv, string subId="")
Definition: Zone.cs:531
string GetText()
Definition: Version.cs:16