2using System.Collections;
3using System.Collections.Generic;
4using System.Diagnostics;
5using System.Diagnostics.CodeAnalysis;
8using System.Reflection;
10using System.Text.RegularExpressions;
11using System.Threading;
12using NPOI.SS.UserModel;
13using NPOI.XSSF.UserModel;
16using ReflexCLI.Attributes;
18using UnityEngine.Networking;
20[ConsoleCommandClassCustomizer(
"Mod")]
21public class ModUtil :
EClass
23 public static Dictionary<string, string> fallbackTypes =
new Dictionary<string, string>();
25 private static readonly Dictionary<string, ICustomContent> _customContent =
new Dictionary<string, ICustomContent>();
27 private static readonly List<Func<string, object, int>> _customCalcEvaluator =
new List<Func<string, object, int>>();
29 private static readonly HashSet<Type> _checkedAttributedTypes =
new HashSet<Type>();
31 private static readonly Dictionary<string, Texture2D> _cachedTextures =
new Dictionary<string, Texture2D>();
33 private static Effect _rodTemplate;
37 public static readonly List<ContextMenuProxy> contextMenuProxies =
new List<ContextMenuProxy>();
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);
43 public static void LoadTypeFallback()
45 string text =
"type_resolver.txt";
46 string[] array = Array.Empty<
string>();
53 array =
new string[2] {
"TrueArena,ArenaWaveEvent,ZoneEvent",
"Elin-GeneRecombinator,Elin_GeneRecombinator.IncubationSacrifice,Chara" };
56 string[] array2 = array;
57 for (
int i = 0; i < array2.Length; i++)
59 string[] array3 = array2[i].Split(
',');
60 if (array3.Length >= 2)
62 RegisterSerializedTypeFallback(array3[0], array3[1], array3[2]);
67 public static void RegisterSerializedTypeFallback(
string nameAssembly,
string nameType,
string nameFallbackType)
69 fallbackTypes[nameType] = nameFallbackType;
72 public static void LogModError(
string message,
BaseModPackage package =
null)
74 string text =
"#mod/" + package?.title +
" (" + package?.id +
")\n" + message;
75 UnityEngine.Debug.LogWarning(text.RemoveAllTags());
76 if ((package?.isInPackages ??
false) || Application.isEditor)
78 EGui.CreatePopup(text);
84 LogModError(message, FindSourceRowPackage(row));
87 public static void LogModError(
string message, Type type)
89 LogModError(message, FindFileProviderPackage(
new FileInfo(type.Assembly.Location)));
92 public static void LogModError(
string message, FileInfo file)
94 LogModError(message, FindFileProviderPackage(file));
97 public static void LogModError(
string message, DirectoryInfo dir)
99 LogModError(message, FindDirectoryProviderPackage(dir));
102 public static ModPackage GetModPackage(
string modId)
104 return ModManagerCore.Instance.MappedPackages.GetValueOrDefault(modId) as
ModPackage;
107 public static ModPackage FindFileProviderPackage(FileInfo file)
109 string path = file.FullName.NormalizePath();
113 public static ModPackage FindDirectoryProviderPackage(DirectoryInfo dir)
115 string path = dir.FullName.NormalizePath();
121 return ModManagerCore.Instance.packages.OfType<
ModPackage>().LastOrDefault((
ModPackage p) => p.sourceRows.Contains(row));
124 public static Zone FindZoneByFullName(
string zoneFullName =
"ntyris/0",
bool useRandomFallback =
false)
126 if (zoneFullName.IsEmpty())
131 if (zoneId.IsEmpty())
136 if (zone ==
null && (zoneId ==
"*" || useRandomFallback))
140 select z).RandomItem();
145 public static void OnModsActivated()
147 CommandRegistry.assemblies.Add(typeof(EScript).Assembly);
148 SoundManager.current.soundLoaders.Add(LoadSoundData);
152 LoadEffectTemplate();
159 RegisterElinEventAttributes();
160 CoroutineHelper.Deferred(RegisterElinEventAttributes);
163 private static void OnSourceImporting()
165 ExcelParser.allowTrimming =
true;
166 ImportAllModSourceSheets();
169 private static void OnSourceImported()
171 _customContent.Clear();
176 activatedUserMod.GenerateCustomContentProfiles();
177 foreach (ICustomContent
item in activatedUserMod.customContent)
184 LogModError(
"exception while generating custom source profiles\n" + ex.Message, activatedUserMod);
185 UnityEngine.Debug.LogException(ex);
188 ImportAllGunEffectSettings();
189 CustomReligionContent.managed.Clear();
190 foreach (CustomReligionContent item2
in _customContent.Values.OfType<CustomReligionContent>())
192 item2.RegisterCustomReligion();
194 CustomReligionContent.Init();
195 SourceCache.FinalizeCache();
196 SourceCache.InvalidateCacheBlobs();
197 SourceCache.ClearDetail();
202 ExportAllSourceDataCsv(text);
203 UnityEngine.Debug.Log(
"#source exported current version to " + text);
208 private static void OnPreLoadInit(GameIOContext context)
213 private static void OnPostLoadInit(GameIOContext context)
217 for (
int i = 0; i < array.Length; i++)
219 KeyValuePair<int, Spatial> keyValuePair = array[i];
220 var (num2, spatial2) = (KeyValuePair<int, Spatial>)(ref keyValuePair);
221 if (spatial2.source ==
null)
224 UnityEngine.Debug.LogWarning(
$"#mod-content removed invalid zone '{num2}', '{spatial2.id}', '{(spatial2 as Zone)?.ZoneFullName}'");
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
234 UnityEngine.Debug.Log(
"#mod-content loading " + typeof(T).Name +
"...");
235 foreach (T
item in _customContent.Values.OfType<T>())
239 item.OnGameLoad(context);
242 catch (Exception ex2)
244 LogModError(
"exception while loading custom content '" +
item.ContentId +
"'\n" + ex2.Message,
item.Owner);
245 UnityEngine.Debug.LogException(ex2);
249 void LoadOtherCustomContent()
251 foreach (ICustomContent item2
in _customContent.Values.Except(contents))
255 item2.OnGameLoad(context);
259 LogModError(
"exception while loading custom content '" + item2.ContentId +
"'\n" + ex.Message, item2.Owner);
260 UnityEngine.Debug.LogException(ex);
267 private static void OnPreSaveInit(GameIOContext context)
272 private static void OnPostSaveInit(GameIOContext context)
274 CustomReligionContent.SaveReligionData(context);
275 foreach (ICustomContent value
in _customContent.Values)
279 value.OnGameSave(context);
283 LogModError(
"exception while saving custom content '" + value.ContentId +
"'\n" + ex.Message, value.Owner);
284 UnityEngine.Debug.LogException(ex);
289 private static void OnReligionImporting(List<Religion> list)
291 list.AddRange(CustomReligionContent.GetCustomReligions());
295 private static void OnCharaCreated(
Chara chara)
297 if (TryGetContent<CustomCharaContent>(
"Chara/" + chara.
id, out var content))
299 content.OnCharaCreated(chara);
301 if (TryGetContent<CustomBiographyContent>(
"Biography/" + chara.
id, out var content2))
303 content2.RefreshCharaBio(chara);
308 private static void OnThingCreated(
Thing thing)
310 if (TryGetContent<CustomThingContent>(
"Thing/" + thing.
id, out var content))
312 content.OnThingCreated(thing);
317 private static void OnActPerformed(
Act act)
319 if (act.
HasTag(
"godAbility"))
321 CustomReligionContent.managed.Values.FirstOrDefault((
ReligionCustom r) => r.
content.godAbilities.Contains(act.
ID))?.Talk(
"ability");
325 private static void OnSetLang(
string lang)
327 PackageIterator.ClearCache();
328 PackageIterator.RebuildAllMappings(lang);
329 SourceLocalization.SetLang(lang);
332 if (activatedUserMod.IsSourceLocalizable && (activatedUserMod.isInPackages || Application.isEditor))
334 activatedUserMod.UpdateSourceLocalizationFile(lang);
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())
347 foreach (
string item2
in LoadName())
351 foreach (
string item3
in LoadGodTalk())
355 foreach (
string item4
in LoadCharaTalk())
359 foreach (
string item5
in LoadCharaTone())
363 BookList.dict =
null;
364 BottleMessageList.list =
null;
365 Lang.excelDialog =
null;
372 public static bool TryGetContent<T>(
string contentId, [NotNullWhen(
true)] out T content) where T :
class, ICustomContent
374 ICustomContent value;
375 bool num = _customContent.TryGetValue(contentId, out value);
376 content = value as T;
379 return content !=
null;
384 public static bool HasContent(
string contentId)
386 return _customContent.ContainsKey(contentId);
389 public static void AddContent(ICustomContent content)
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;
395 public static bool FixDefaultRenderRowPref(
RenderRow r,
string id)
397 FileInfo fileInfo = PackageIterator.GetFiles(
"Texture/" +
id +
".pref").LastOrDefault();
398 if (fileInfo ==
null)
408 if (!r.
tag.Contains(
"usePref") || !FixDefaultRenderRowPref(r, r.id))
419 if (!r.
tag.Contains(
"usePref") || !FixDefaultRenderRowPref(r, r.id))
428 public static List<Thing> GenerateMerchantStock(
Card owner,
string stockId =
null,
bool forceRestock =
false)
430 List<Thing> list =
new List<Thing>();
431 if (stockId.IsEmpty())
433 stockId = owner.
GetStr(
"merchant_override");
435 if (stockId.IsEmpty())
439 string[] array = stockId.Split(
'|');
441 string[] array2 = array;
442 foreach (
string text
in array2)
444 if (!TryGetContent<CustomMerchantStock>(
"MerchantStock/" + text, out var content))
448 foreach (
Thing item in content.Generate(owner))
450 bool @
bool =
item.GetBool(101);
451 if (!(!forceRestock && @
bool) || !orCreate.Contains(
item.trait.IdNoRestock))
455 orCreate.Add(
item.trait.IdNoRestock);
464 public static void RegisterElinEventAttributes()
470 MemberInfo
item = item3.member;
476 if (!(
item is PropertyInfo property))
478 if (
item is MethodInfo method)
480 elinEventBaseAttribute.
Register(method);
485 elinEventBaseAttribute.
Register(property);
490 LogModError(
"exception while registering attribute '" + elinEventBaseAttribute.GetType().Name +
"' from '" +
item.TryToString() +
"'\n" + ex.Message,
item.DeclaringType);
491 UnityEngine.Debug.LogException(ex);
498 public static List<string> LoadBookList()
500 List<string> list =
new List<string>();
501 DirectoryInfo[] directories = PackageIterator.GetDirectories(
"Text");
502 foreach (DirectoryInfo directoryInfo
in directories)
504 list.AddRange(Directory.GetDirectories(directoryInfo.FullName));
505 UnityEngine.Debug.Log(
"#mod-content loaded book list " + directoryInfo.ShortPath());
510 public static List<string> LoadTopicFiles()
512 List<string> list =
new List<string>();
513 FileInfo[] files = PackageIterator.GetFiles(
"Text/Help/_topics.txt");
514 foreach (FileInfo fileInfo
in files)
517 UnityEngine.Debug.Log(
"#mod-content loaded book topics " + fileInfo.ShortPath());
522 public static List<string> LoadExcelDialog()
524 List<string> list =
new List<string>();
525 FileInfo[] files = PackageIterator.GetFiles(
"Dialog/dialog.xlsx");
526 foreach (FileInfo fileInfo
in files)
528 list.Add(fileInfo.FullName);
529 UnityEngine.Debug.Log(
"#mod-content loaded dialog " + fileInfo.ShortPath());
534 public static List<string> LoadAlias()
536 List<string> list =
new List<string>();
537 FileInfo[] files = PackageIterator.GetFiles(
Lang.
langCode +
"/Data/Alias.xlsx");
538 foreach (FileInfo fileInfo
in files)
540 list.Add(fileInfo.FullName);
541 UnityEngine.Debug.Log(
"#mod-content loaded Alias " + fileInfo.ShortPath());
546 public static List<string> LoadName()
548 List<string> list =
new List<string>();
549 FileInfo[] files = PackageIterator.GetFiles(
Lang.
langCode +
"/Data/Name.xlsx");
550 foreach (FileInfo fileInfo
in files)
552 list.Add(fileInfo.FullName);
553 UnityEngine.Debug.Log(
"#mod-content loaded Name " + fileInfo.ShortPath());
558 public static List<string> LoadCharaTalk()
560 List<string> list =
new List<string>();
561 FileInfo[] files = PackageIterator.GetFiles(
"Data/chara_talk.xlsx");
562 foreach (FileInfo fileInfo
in files)
564 list.Add(fileInfo.FullName);
565 UnityEngine.Debug.Log(
"#mod-content loaded chara tone " + fileInfo.ShortPath());
570 public static List<string> LoadCharaTone()
572 List<string> list =
new List<string>();
573 FileInfo[] files = PackageIterator.GetFiles(
"Data/chara_tone.xlsx");
574 foreach (FileInfo fileInfo
in files)
576 list.Add(fileInfo.FullName);
577 UnityEngine.Debug.Log(
"#mod-content loaded chara talk " + fileInfo.ShortPath());
582 public static Sprite LoadSprite(
string spritePath, Vector2? pivot =
null,
string name =
null,
int resizeWidth = 0,
int resizeHeight = 0)
584 if (spritePath.IsEmpty())
588 if (!spritePath.EndsWith(
".png"))
594 spritePath +=
".png";
596 if (!File.Exists(spritePath))
598 FileInfo[] files = PackageIterator.GetFiles(Path.Combine(
"Texture", spritePath));
603 spritePath = files[^1].FullName;
605 Vector2 valueOrDefault = pivot.GetValueOrDefault();
608 valueOrDefault =
new Vector2(0.5f, 0.5f);
609 pivot = valueOrDefault;
611 string text =
$"{spritePath}/{pivot}/{resizeWidth}/{resizeHeight}";
618 if (!_cachedTextures.TryGetValue(text, out var value2))
625 if (resizeWidth != 0 && resizeHeight != 0 && value2.width != resizeWidth && value2.height != resizeHeight)
627 Texture2D texture2D = value2.Rescale(resizeWidth, resizeHeight);
628 UnityEngine.Object.Destroy(value2);
633 _cachedTextures[text] = value2;
635 catch (Exception arg)
637 UnityEngine.Debug.LogError(
$"#mod-content failed to load sprite {spritePath.ShortPath()}\n{arg}");
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);
646 public static Sprite AppendSpriteSheet(
string id,
int resizeWidth = 0,
int resizeHeight = 0,
string pattern =
"@")
649 if (!dictModItems.TryGetValue(
id, out var value) && pattern !=
"")
651 value = dictModItems.Where((KeyValuePair<string, string> kv) => kv.Key.StartsWith(pattern)).FirstOrDefault((KeyValuePair<string, string> kv) =>
id.StartsWith(kv.Key[pattern.Length..])).Value;
653 string spritePath = value;
655 Sprite sprite = LoadSprite(spritePath,
null, name, resizeWidth, resizeHeight);
660 if (
SpriteSheet.
dict.TryGetValue(
id, out var value2) && value2.texture.width == sprite.texture.width && value2.texture.height == sprite.texture.height)
667 public static List<string> LoadGodTalk()
669 List<string> list =
new List<string>();
670 FileInfo[] files = PackageIterator.GetFiles(
"Data/god_talk.xlsx");
671 foreach (FileInfo fileInfo
in files)
673 list.Add(fileInfo.FullName);
674 UnityEngine.Debug.Log(
"#mod-content loaded god talk " + fileInfo.ShortPath());
679 public static Dictionary<string, CustomGunEffectData> LoadGunEffects()
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++)
685 (FileInfo, EMod) tuple = filesEx[i];
686 FileInfo
item = tuple.Item1;
687 EMod item2 = tuple.Item2;
689 _customContent[customGunEffectSetting.
ContentId] = customGunEffectSetting;
694 dictionary.Merge(item3.
items);
695 UnityEngine.Debug.Log(
$"#mod-content loaded {item3}");
700 public static void ImportAllGunEffectSettings()
702 foreach (KeyValuePair<string, CustomGunEffectData>
item in LoadGunEffects())
704 item.Deconstruct(out var key, out var value);
711 public static string ExportAllGunEffectSettings()
714 string text = CorePath.rootExe +
"/guns.json";
715 Dictionary<string, CustomGunEffectData> dictionary =
new Dictionary<string, CustomGunEffectData>();
716 foreach (
string key
in guns.
Keys)
719 dictionary[key] = value;
721 File.WriteAllText(text, JsonConvert.SerializeObject(dictionary, Formatting.Indented, GameIOContext.Settings));
722 return $"dumped {dictionary.Count} guns data to {text}";
725 private static Effect LoadEffect(
string id)
735 string effectId =
id.Split(
'/')[^1];
736 Sprite sprite = LoadSprite(effectId);
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 +
"'");
747 IEnumerable<Sprite> Slice()
749 int height = (int)sprite.rect.height;
750 float frames = sprite.rect.width / (
float)height;
754 while ((
float)i < frames)
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;
766 private static void LoadEffectTemplate()
768 _rodTemplate = Resources.Load<
Effect>(
"Media/Effect/General/rod");
771 UnityEngine.Debug.LogWarning(
"#mod-content cannot initialize rod effect template");
775 public static SerializableSoundData GetSoundMeta(
string soundPath)
777 string path = Path.ChangeExtension(soundPath,
".json");
778 SerializableSoundData serializableSoundData;
779 if (File.Exists(path))
783 serializableSoundData =
IO.LoadFile<SerializableSoundData>(path);
784 if (serializableSoundData.dataVersion == SerializableSoundData.SoundDataMetaVersion.V1)
786 return serializableSoundData;
793 serializableSoundData =
new SerializableSoundData();
794 if (soundPath.NormalizePath().Contains(
"/Sound/BGM/"))
796 serializableSoundData.type = SoundData.Type.BGM;
797 serializableSoundData.bgmDataOptional =
new SerializableBGMData
799 parts =
new List<BGMData.Part>
806 return serializableSoundData;
809 public static AudioType GetAudioType(
string extension)
811 return extension.ToLowerInvariant().Trim()
switch
813 ".acc" => AudioType.ACC,
814 ".mp3" => AudioType.MPEG,
815 ".ogg" => AudioType.OGGVORBIS,
816 ".wav" => AudioType.WAV,
817 _ => AudioType.UNKNOWN,
821 public static SoundData LoadSoundData(
string soundId)
823 if (!
MOD.
sounds.TryGetValue(soundId, out var value) || !value.Exists)
827 return LoadSoundData(value);
830 public static SoundData LoadSoundData(FileInfo soundFile)
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)
843 if (unityWebRequest.result != UnityWebRequest.Result.Success)
845 UnityEngine.Debug.LogError(
"#sound '" + fileNameWithoutExtension +
"' failed to load: " + unityWebRequest.error.IsEmpty(
"timeout"));
848 AudioClip content = DownloadHandlerAudioClip.GetContent(unityWebRequest);
849 int? num = content?.samples;
850 if (!num.HasValue || num.GetValueOrDefault() <= 0)
852 UnityEngine.Debug.LogError(
$"#sound '{fileNameWithoutExtension}' sample is null: {audioType}");
855 content.name = fileNameWithoutExtension;
856 SoundData soundData = GetSoundMeta(fullName).ToSoundData();
857 if (soundData is BGMData bGMData)
859 bGMData._name = Path.GetFileNameWithoutExtension(fullName);
860 if (bGMData.song ==
null)
862 bGMData.song =
new BGMData.SongData();
863 bGMData.song.parts.Add(
new BGMData.Part());
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;
873 public static void AddOrReplaceBGM(
string bgmId)
877 BGMData bGMData = LoadSoundData(bgmId) as BGMData;
882 bGMData.name = bgmId.Replace(
"BGM/",
"");
885 Match match = Regex.Match(bGMData.name,
"^(\\d+)(?:_(.*))?$");
888 int id = match.Groups[1].Value.ToInt();
889 string text = (match.Groups[2].Success ? match.Groups[2].Value :
null);
898 bGMData.id = bgms.Count + 1;
899 UnityEngine.Debug.Log(
$"#sound bgm unassigned/{bGMData.id}/{bGMData.name}");
902 if (dictBGM.TryGetValue(bGMData.id, out var value))
904 value.clip = bGMData.clip;
905 UnityEngine.Debug.Log(
$"#sound bgm replace/{bGMData.id}/{value.name}/>/{bGMData.name}");
910 dictBGM[bGMData.id] = bGMData;
911 UnityEngine.Debug.Log(
$"#sound bgm addon/{bGMData.id}/{bGMData.name}");
915 public static ModPackage FindSoundPackage(
string soundId)
917 return ModManagerCore.Instance.packages.OfType<
ModPackage>().LastOrDefault((
ModPackage p) => p.sounds.Keys.Contains(soundId));
920 public static Playlist CreatePlaylist(ref List<int> bgmIds, Playlist mold =
null)
922 Playlist playlist =
EClass.
Sound.plBlank.Instantiate();
923 if (bgmIds.Count == 0 && (
bool)mold)
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;
933 foreach (
int bgmId
in bgmIds)
937 playlist.list.Add(
new Playlist.Item
946 public static void SetBGMKnown(
int bgmId,
bool known =
true)
959 [Obsolete(
"use ImportModSourceSheets for proper caching and localizaiton support")]
960 public static void ImportExcel(
string pathToExcelFile,
string sheetName,
SourceData source)
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++)
967 ISheet sheetAt = xSSFWorkbook.GetSheetAt(i);
968 if (sheetAt.SheetName != sheetName)
972 UnityEngine.Debug.Log(
"Importing Sheet:" + sheetName);
975 ExcelParser.path = pathToExcelFile;
976 if (!source.
ImportData(sheetAt,
new FileInfo(pathToExcelFile).Name, overwrite:
true))
978 UnityEngine.Debug.LogError(
ERROR.
msg);
981 UnityEngine.Debug.Log(
"Imported " + sheetAt.SheetName);
986 UnityEngine.Debug.LogError(
"[Error] Skipping import " + sheetAt.SheetName +
" :" + ex.Message +
"/" + ex.Source +
"/" + ex.StackTrace);
992 public static SourceData FindSourceByName(
string sourceData)
997 public static void ImportModSourceSheets(
string modId)
1001 SourceCache.InvalidateCacheVersion();
1003 if (valueOrDefault ==
null)
1007 List<string> list =
new List<string>();
1008 foreach (FileInfo sourceSheet
in valueOrDefault.Mapping.SourceSheets)
1010 sourceImporter.
fileProviders[sourceSheet.FullName] = valueOrDefault;
1011 list.Add(sourceSheet.FullName);
1014 UnityEngine.Debug.Log(
"#source finished importing workbooks from " + modId);
1016 catch (Exception exception)
1018 UnityEngine.Debug.LogException(exception);
1022 public static void ImportAllModSourceSheets()
1026 SourceCache.InvalidateCacheVersion();
1030 EClass.sources.materials
1032 List<string> list =
new List<string>();
1039 foreach (FileInfo sourceSheet
in modPackage.Mapping.SourceSheets)
1041 if (!sourceSheet.Name.StartsWith(
".") && !sourceSheet.Name.Contains(
'~'))
1043 sourceImporter.
fileProviders[sourceSheet.FullName] = modPackage;
1044 list.Add(sourceSheet.FullName);
1050 catch (Exception exception)
1052 UnityEngine.Debug.LogException(exception);
1054 UnityEngine.Debug.Log(
"#source finished importing workbooks");
1057 public static string ExportSourceDataCsv(
string sourceData,
string delimiter =
",")
1059 SourceData sourceData2 = FindSourceByName(sourceData);
1060 if (sourceData2 ==
null)
1064 IReadOnlyDictionary<string, string> typeMapping = sourceData2.
GetTypeMapping();
1065 (string, string)[] array = (from kv in sourceData2.
GetRowMapping()
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)));
1074 List<string> list =
new List<string>();
1075 (string, string)[] array3 = array;
1076 for (
int j = 0; j < array3.Length; j++)
1078 (string, string) tuple = array3[j];
1079 string item = tuple.Item1;
1080 string item2 = tuple.Item2;
1081 object value = baseRow.GetRowFields()[
item].GetValue(baseRow);
1083 IEnumerable enumerable;
1084 if (!(obj is
int[] array4))
1086 if (!(obj is
int key))
1088 if (obj is
string item3)
1093 enumerable = obj as IEnumerable;
1094 if (enumerable !=
null)
1099 else if (item2 ==
"element_id")
1104 list.Add(value.ToString());
1107 if (!(item2 ==
"elements"))
1109 enumerable = (IEnumerable)obj;
1112 List<string> list2 =
new List<string>();
1113 for (
int k = 0; k < array4.Length - 1; k += 2)
1116 string text = array4[k + 1].ToString();
1117 list2.Add(alias +
"/" + text);
1119 string item4 =
string.Join(
',', list2);
1123 string item5 =
string.Join(
',', enumerable.OfType<
object>());
1126 IEnumerable<string> values = list.Select(delegate(
string f)
1128 string text2 = f.Replace(
"\r",
"").Replace(
"\n",
"\\n").Replace(
"\"",
"\"\"");
1129 return (!text2.IsEmpty()) ? (
"\"" + text2 +
"\"") :
"";
1131 stringBuilder.AppendLine(
string.Join(delimiter, values));
1133 return stringBuilder.ToString();
1136 public static void ExportAllSourceDataCsv(
string dir)
1139 foreach (
string key
in SourceMapping.Keys)
1141 File.WriteAllText(Path.Combine(dir, key +
".csv"), ExportSourceDataCsv(key));
1145 public static string ExportSourceDataJson(
string sourceData, Formatting format = Formatting.Indented)
1147 SourceData sourceData2 = FindSourceByName(sourceData);
1148 if (sourceData2 ==
null)
1152 return JsonConvert.SerializeObject(sourceData2.
ExportRows(), format, GameIOContext.Settings);
1155 public static void ExportAllSourceDataJson(
string dir)
1158 foreach (
string key
in SourceMapping.Keys)
1160 File.WriteAllText(Path.Combine(dir, key +
".json"), ExportSourceDataJson(key));
1164 public static void AddContextMenuEntry(Action onClick,
string menuEntry,
string displayName =
"")
1166 if (onClick ==
null || menuEntry.IsEmpty())
1170 string[] array = menuEntry.Split(
'/', StringSplitOptions.RemoveEmptyEntries);
1171 List<ContextMenuProxy> children = contextMenuProxies;
1172 for (
int i = 0; i < array.Length; i++)
1174 bool flag = i < array.Length - 1;
1175 string part = array[i];
1177 if (contextMenuProxy ==
null)
1181 onClick = ((i == array.Length - 1 && flag) ?
null :
new Action(SafeInvoke)),
1184 children.Add(contextMenuProxy);
1186 else if (contextMenuProxy.
isMenu != flag)
1188 UnityEngine.Debug.LogWarning(
"#mod-content attempt to add context menu entry with same name but different types\n" + part +
" -> " + (contextMenuProxy.
isMenu ?
"submenu" :
"button"));
1191 children = contextMenuProxy.
children;
1193 UnityEngine.Debug.Log(
"#mod-content added context menu entry '" + menuEntry +
"' from '" + onClick.Method.TryToString() +
"'");
1200 catch (Exception exception)
1202 UnityEngine.Debug.LogException(exception);
1207 public static void RemoveContextMenuEntry(
string entry)
1209 string[] array = entry.Split(
'/', StringSplitOptions.RemoveEmptyEntries);
1210 if (array.Length == 0)
1214 List<ContextMenuProxy> children = contextMenuProxies;
1216 List<ContextMenuProxy> list =
null;
1217 string[] array2 = array;
1218 foreach (
string part
in array2)
1221 if (contextMenuProxy ==
null)
1226 children = contextMenuProxy.
children;
1228 list?.Remove(contextMenuProxy);
static void PublishEvent(string eventId, object data=null)
static void SubscribeEvent(string eventId, Action< object > handler)
static List< Func< List< string > > > booklistLoaders
string GetStr(string id, string defaultStr=null)
static HashSet< Type > modTypes
Dictionary< int, BGMData > dictBGM
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
static SourceManager sources
static SoundManager Sound
static GameSetting setting
virtual void Register(MethodInfo method)
static void ClearStaticRows()
UD_String_EffectData guns
static string[] LoadTextArray(string _path)
static void SaveTextArray(string path, string[] text)
static void CreateDirectory(string path)
static void SaveFile(string path, object obj, bool compress=false, JsonSerializerSettings setting=null)
static Texture2D LoadPNG(string _path, FilterMode filter=FilterMode.Point)
static List< Func< List< string > > > excelDialogLoaders
static TalkDataList listTalk
static GodTalkDataList listGodTalk
static ToneDataList tones
static ExcelDataList listAlias
static Dictionary< string, FileInfo > sounds
static ExcelDataList listName
static new ModManager Instance
Dictionary< string, HashSet< string > > noRestocks
CustomReligionContent content
override bool ImportData(ISheet sheet, string bookname, bool overwrite=false)
virtual IReadOnlyDictionary< string, int > GetRowMapping()
override BaseRow[] ExportRows()
virtual IReadOnlyDictionary< string, string > GetTypeMapping()
IEnumerable< SourceData > ImportFilesCached(IEnumerable< string > imports, bool resetData=true)
static void HotInit(IEnumerable< SourceData > sourceData)
Dictionary< string, EMod > fileProviders
SourceData FindSourceByName(string name)
static SourcePref ReadFromIni(string path)
static Dictionary< string, string > dictModItems
static Dictionary< string, Sprite > dict
virtual string IdNoRestock
static List< Func< List< string > > > topicLoaders
static string string int zoneLv ParseZoneFullName(string zoneFullName)
Zone FindOrCreateLevel(int destLv, string subId="")