+EA 23.283 Nightly - Plugin.BaseCore
March 4, 2026
10 files modified.
Important Changes
None.
BaseModManager
cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
public class BaseModManagerpublic void Parse<T>(ModItemList<T> list) where T : UnityEngine.Object
cs
public static List<string> listChainLoad = new List<string>();
private static readonly Dictionary<string, HashSet<Action<object>>> _eventHandlers = new Dictionary<string, HashSet<Action<object>>>();
public DirectoryInfo dirWorkshop;
public int priorityIndex;cs
public virtual void ParseExtra(DirectoryInfo dir, BaseModPackage package)
{
}
public static void SubscribeEvent(string eventId, Action<object> handler)
{
if (!_eventHandlers.TryGetValue(eventId, out var value))
{
value = new HashSet<Action<object>>();
_eventHandlers[eventId] = value;
}
value.Add(handler);
}
public static void UnsubscribeEvent(string eventId, Action<object> handler)
{
if (_eventHandlers.TryGetValue(eventId, out var value))
{
value.Remove(handler);
if (value.Count == 0)
{
_eventHandlers.Remove(eventId);
}
}
}
public static void PublishEvent(string eventId, object data = null)
{
if (!_eventHandlers.TryGetValue(eventId, out var value))
{
return;
}
foreach (Action<object> item in value.ToList())
{
try
{
item(data);
}
catch (Exception arg)
{
Debug.LogError($"#event '{eventId}' throws error in one of the handlers\n{arg}");
}
}
}
public static bool HasEventSubscriber(string eventId)
{
int? num = _eventHandlers.GetValueOrDefault(eventId)?.Count;
if (num.HasValue)
{
return num.GetValueOrDefault() > 0;
}
return false;
}
}BaseModPackage
cs
{
if (!hasPublishedPackage && installed && dirInfo.Exists && willActivate)
{
Debug.Log("Activating(" + loadPriority + ") :" + title + "/" + id);
Debug.Log("Activating(" + loadPriority + ") : " + title + "/" + id);
activated = true;
Parse();
}ClassCache
public T Create<T2>(Type type)
cs
public T Create<T2>(string id, string assembly)
{
Func<T> func = dict.TryGetValue(id);
if (func != null)
{
return func();
}
Type type = Type.GetType(id + ", " + assembly);
if (type == null)
{ClassExtension
cs
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using Pluralize.NET;
using UnityEngine;
using UnityEngine.Events;public static void Set<T1, T2>(this Dictionary<T1, T2> dic, Dictionary<T1, T2> f
cs
}
}
public static string[] SplitByNewline(this string text)
{
if (string.IsNullOrEmpty(text))
{
return new string[0];
}
return text.Split(new string[3] { "\r\n", "\n", "\r" }, StringSplitOptions.None);
}
public static string RemoveNewline(this string text)
{
if (string.IsNullOrEmpty(text))
{
return text;
}
return text.Replace("\r", "").Replace("\n", "");
}
public static string RemoveAllTags(this string text)
{
if (string.IsNullOrEmpty(text))
{
return text;
}
return Regex.Replace(text, "<.*?>", "");
}
public static int Calc(this string str, int power = 0, int ele = 0, int p2 = 0)
{
return Cal.Calcuate(str.Replace("p2", p2.ToString() ?? "").Replace("p", power.ToString() ?? "").Replace("e", ele.ToString() ?? "")EAction
cs
CancelUI = 53,
Dump = 54,
Mute = 55,
Meditate = 56
Meditate = 56,
Console = 57
}EInput
cs
action = EAction.Chat
};
public KeyMap console = new KeyMap
{
action = EAction.Console
};
public List<KeyMap> List()
{
return new List<KeyMap>
{
axisUp, axisDown, axisLeft, axisRight, axisUpLeft, axisUpRight, axisDownLeft, axisDownRight, journal, chara,
inventory, ability, log, fire, chat, wait, mouseLeft, mouseMiddle, mouseRight, report,
quickSave, quickLoad, autoCombat, emptyHand, switchHotbar, examine, getAll, dump, mute, meditate,
search
inventory, ability, log, fire, chat, console, wait, mouseLeft, mouseMiddle, mouseRight,
report, quickSave, quickLoad, autoCombat, emptyHand, switchHotbar, examine, getAll, dump, mute,
meditate, search
};
}
}private static EAction GetAction()
cs
{
return EAction.Chat;
}
if (Input.GetKeyDown(keys.console.key))
{
return EAction.Console;
}
if (keyFire.Update())
{
return keyFire.Action;ExcelParser
cs
using System;
using System.Text;
using NPOI.SS.UserModel;
using UnityEngine;
public class ExcelParser
{
public static string path;
public static IRow row;
public static IRow rowDefault;public static bool IsNull(ICell cell)
cs
public static int GetInt(int id)
{
if (int.TryParse(GetStr(id), out var result))
string str = GetStr(id);
if (str.IsEmpty())
{
return 0;
}
if (!int.TryParse(str, out var result))
{
return result;
ReportIllFormat<int>(id);
}
return 0;
return result;
}
public static int GetInt(int col, IRow _row)public static int GetInt(int col, IRow _row)
cs
public static bool GetBool(int id)
{
string str = GetStr(id);
bool result;
return str switch
{
"0" => false,
"1" => true,
null => false,
_ => bool.Parse(str),
"1" => true,
"0" => false,
_ => bool.TryParse(str, out result) && result,
};
}public static bool GetBool(int col, IRow _row)
cs
public static double GetDouble(int id)
{
string str = GetStr(id);
if (str != null)
if (str.IsEmpty())
{
return 0.0;
}
if (!double.TryParse(str, out var result))
{
return double.Parse(str);
ReportIllFormat<double>(id);
}
return 0.0;
return result;
}
public static float GetFloat(int id)
{
string str = GetStr(id);
if (str != null)
if (str.IsEmpty())
{
return float.Parse(str);
return 0f;
}
return 0f;
if (!float.TryParse(str, out var result))
{
ReportIllFormat<float>(id);
}
return result;
}
public static float[] GetFloatArray(int id)
{
string str = GetStr(id);
if (str != null)
if (str.IsEmpty())
{
return Array.Empty<float>();
}
string[] array = str.Split(',');
float[] array2 = new float[array.Length];
for (int i = 0; i < array.Length; i++)
{
return Array.ConvertAll(str.Split(','), float.Parse);
if (!float.TryParse(array[i], out array2[i]))
{
ReportIllFormat<float>(id);
array2[i] = 0f;
}
}
return new float[0];
return array2;
}
public static int[] GetIntArray(int id)
{
string str = GetStr(id);
if (str != null)
if (str.IsEmpty())
{
return Array.ConvertAll(str.Split(','), int.Parse);
return Array.Empty<int>();
}
string[] array = str.Split(',');
int[] array2 = new int[array.Length];
for (int i = 0; i < array.Length; i++)
{
if (!int.TryParse(array[i], out array2[i]))
{
ReportIllFormat<int>(id);
array2[i] = 0;
}
}
return new int[0];
return array2;
}
public static string[] GetStringArray(int id)public static string[] GetStringArray(int id)
cs
{
return str.Split(',');
}
return new string[0];
return Array.Empty<string>();
}
public static string GetString(int id)public static string GetStr(int id, bool useDefault = false)
cs
}
return cell.StringCellValue;
}
public static string ToLetterId(int id)
{
string text = "";
while (id >= 0)
{
text = (char)(id % 26 + 65) + text;
id /= 26;
id--;
}
return text;
}
public static void ReportIllFormat<T>(int id)
{
StringBuilder stringBuilder = new StringBuilder();
string name = typeof(T).Name;
ICell cell = row.Cells.TryGet(id, returnNull: true);
string value = ((row.RowNum < 3) ? ", SourceData begins at the 4th row. 3rd row is the default value row." : $", default:'{rowDefault.Cells.TryGet(id, returnNull: true)}'");
stringBuilder.AppendLine("$source ill-format file: " + path);
stringBuilder.Append($"row#{row.RowNum + 1}, cell'{id + 1}'/'{ToLetterId(id)}', expected:'{name}', read:'{cell}'");
stringBuilder.AppendLine(value);
Debug.LogError(stringBuilder);
}
}Lang
cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Langcs
public static ExcelData excelDialog;
public static HashSet<string> extraExcelDialogs = new HashSet<string>();
public static bool IsBuiltin(string id)
{
if (!(id == "JP"))public static ExcelData.Sheet GetDialogSheet(string idSheet)
cs
{
if (excelDialog == null)
{
string path = CorePath.CorePackage.TextDialog + "dialog.xlsx";
excelDialog = new ExcelData();
excelDialog.path = path;
excelDialog = new ExcelData(CorePath.CorePackage.TextDialog + "dialog.xlsx");
excelDialog.LoadBook();
for (int i = 0; i < excelDialog.book.NumberOfSheets; i++)
{
string sheetName = excelDialog.book.GetSheetAt(i).SheetName;
excelDialog.BuildMap(sheetName);
foreach (ExcelData item in extraExcelDialogs.Select((string f) => new ExcelData(f)))
{
item.BuildMap(sheetName);
ExcelData.Sheet sheet = item.sheets[sheetName];
if (item.book.GetSheet(sheetName) == null)
{
sheet.list.Clear();
sheet.map.Clear();
}
foreach (var (text2, value) in sheet.map)
{
if (!text2.IsEmpty())
{
excelDialog.sheets[sheetName].map[text2] = value;
}
}
}
}
}
excelDialog.BuildMap(idSheet);
return excelDialog.sheets[idSheet];
}
public static string[] GetDialog(string idSheet, string idTopic)
{
ExcelData.Sheet dialogSheet = GetDialogSheet(idSheet);
string key = "text" + (isBuiltin ? ("_" + langCode) : "");
Dictionary<string, string> dictionary = dialogSheet.map.TryGetValue(idTopic);
if (dictionary == null || !dictionary.ContainsKey(key))
Dictionary<string, string> dictionary = GetDialogSheet(idSheet).map.TryGetValue(idTopic);
if (dictionary == null)
{
return new string[1] { idTopic };
}
string text = dictionary[key];
string key = "text_" + langCode;
string text = dictionary.GetValueOrDefault(key) ?? dictionary.GetValueOrDefault("text");
if (text.IsEmpty())
{
text = dictionary["text_EN"];MOD
cs
public static List<FileInfo> listMaps = new List<FileInfo>();
public static List<FileInfo> listPartialMaps = new List<FileInfo>();
public static Dictionary<string, FileInfo> sounds = new Dictionary<string, FileInfo>();
}SourceData
cs
public override void Init()
{
Debug.Log("Initializing:" + base.name);
if (initialized)
{
Debug.Log("#init Skipping sourceData.Init:" + base.name);cs
}
initialized = true;
editorListString.Clear();
RemoveDuplicateRows();
int num = 0;
foreach (T row in rows)
{cs
return null;
}
public override int ImportRows(IEnumerable<BaseRow> sourceRows)
{
int num = 0;
foreach (BaseRow sourceRow in sourceRows)
{
if (sourceRow is T val)
{
val.OnImportData(this);
rows.Add(val);
num++;
}
}
OnAfterImportData();
initialized = false;
return num;
}
public virtual void RemoveDuplicateRows()
{
HashSet<T2> hashSet = new HashSet<T2>();
List<T> list = new List<T>(rows.Count);
bool flag = typeof(T).DeclaringType.Name.Contains("Lang");
string arg = GetType().Name;
System.Reflection.FieldInfo field = typeof(T).GetField("id");
if (field.FieldType != typeof(T2))
{
Debug.LogError($"#source override: {arg} id field mismatch {field.FieldType} != {typeof(T2)}");
}
for (int num = rows.Count - 1; num >= 0; num--)
{
T val = rows[num];
T2 val2 = (T2)field.GetValue(val);
if (hashSet.Add(val2))
{
list.Add(val);
}
else if (!flag)
{
Debug.Log($"#source override: {arg} {val2}");
}
}
if (rows.Count != list.Count)
{
Debug.Log($"#source override: {arg} total/{rows.Count} -> unique/{list.Count}");
list.Reverse();
rows = list;
}
}
public override void BackupSource()
{
_backupRows = rows;cs
[Serializable]
public class BaseRow
{
private static readonly Dictionary<Type, Dictionary<string, FieldInfo>> _fieldCache = new Dictionary<Type, Dictionary<string, FieldInfo>>();
public int _index;
public virtual bool UseAlias => false;
public virtual string GetAlias => "";
public Dictionary<string, FieldInfo> GetRowFields()
{
Type type = GetType();
if (_fieldCache.TryGetValue(type, out var value))
{
return value;
}
value = new Dictionary<string, FieldInfo>();
FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (FieldInfo fieldInfo in fields)
{
value[fieldInfo.Name] = fieldInfo;
}
return _fieldCache[type] = value;
}
public virtual string GetName()
{
return GetText();public virtual string GetEditorListName()
cs
public string GetText(string id = "name", bool returnNull = false)
{
FieldInfo field = GetType().GetField(id + LangSuffix);
if (!Lang.isBuiltin && (field == null || (field.GetValue(this) as string).IsEmpty()))
Dictionary<string, FieldInfo> rowFields = GetRowFields();
if (rowFields.TryGetValue(id + LangSuffix, out var value))
{
FieldInfo field2 = GetType().GetField(id);
if (field2 != null && !(field2.GetValue(this) as string).IsEmpty())
string text = value.GetValue(this) as string;
if (!text.IsEmpty())
{
return field2.GetValue(this) as string;
return text;
}
}
if (field != null)
if (!Lang.isBuiltin && rowFields.TryGetValue(id, out var value2))
{
return (field.GetValue(this) as string).IsEmpty(returnNull ? null : "");
string text2 = value2.GetValue(this) as string;
if (!text2.IsEmpty())
{
return text2;
}
}
return "";
if (!returnNull)
{
return "";
}
return null;
}
public string[] GetTextArray(string id)
{
if (!Lang.isBuiltin)
Dictionary<string, FieldInfo> rowFields = GetRowFields();
if (rowFields.TryGetValue(id + LangSuffix, out var value) && value.GetValue(this) is string[] { Length: >0 } array)
{
FieldInfo field = GetType().GetField(id + Lang.suffix);
if (field != null && field.GetValue(this) is string[] array && array.Length != 0)
{
return array;
}
return GetType().GetField(id).GetValue(this) as string[];
return array;
}
return GetType().GetField(id + Lang.suffix).GetValue(this) as string[];
if (!Lang.isBuiltin && rowFields.TryGetValue(id, out var value2) && value2.GetValue(this) is string[] { Length: >0 } array2)
{
return array2;
}
return Array.Empty<string>();
}
public virtual void SetID(ref int count)public virtual void SetID(ref int count)
cs
public virtual void OnImportData(SourceData data)
{
}
public virtual IDictionary<string, string> ExportTexts(string idField = "id")
{
Dictionary<string, FieldInfo> rowFields = GetRowFields();
object obj = rowFields.GetValueOrDefault(idField)?.GetValue(this);
SortedDictionary<string, string> sortedDictionary = new SortedDictionary<string, string>();
if (obj == null)
{
return sortedDictionary;
}
string name = GetType().DeclaringType.Name;
foreach (var (text2, jp2) in rowFields)
{
if (!text2.EndsWith("_JP"))
{
continue;
}
string text3 = text2[..^3];
if (rowFields.TryGetValue(text3, out var value) && rowFields.ContainsKey(text3 + "_L"))
{
string text4 = GetFieldText(jp2, value);
if (!text4.IsEmpty())
{
sortedDictionary[$"{name}.{obj}.{text3}"] = text4;
}
}
}
return sortedDictionary;
string GetFieldText(FieldInfo jp, FieldInfo en)
{
object obj2 = jp.GetValue(this);
object obj3 = en.GetValue(this);
if (!Lang.isJP)
{
object obj4 = obj2;
object obj5 = obj3;
obj3 = obj4;
obj2 = obj5;
}
if (obj2 is string str)
{
return str.IsEmpty(obj3 as string);
}
if (obj2 is string[] array)
{
return string.Join(',', (array.Length != 0) ? array : (obj3 as string[]));
}
return null;
}
}
public virtual void ImportTexts(IReadOnlyDictionary<string, string> texts, string idField = "id")
{
Dictionary<string, FieldInfo> rowFields = GetRowFields();
object obj = rowFields.GetValueOrDefault(idField)?.GetValue(this);
if (obj == null)
{
return;
}
string name = GetType().DeclaringType.Name;
foreach (var (text2, fieldInfo2) in rowFields)
{
if (!text2.EndsWith("_L"))
{
continue;
}
string text3 = text2[..^2];
if (rowFields.ContainsKey(text3) && rowFields.ContainsKey(text3 + "_JP"))
{
fieldInfo2.SetValue(this, null);
if (texts.TryGetValue($"{name}.{obj}.{text3}", out var value2) && !value2.IsEmpty())
{
SetFieldText(fieldInfo2, value2);
}
}
}
void SetFieldText(FieldInfo l, string value)
{
if (l.FieldType == typeof(string))
{
l.SetValue(this, value);
}
else if (l.FieldType == typeof(string[]))
{
l.SetValue(this, value.IsEmpty() ? Array.Empty<string>() : value.Split(','));
}
}
}
}
public static string LangSuffix;public virtual bool ImportData(ISheet sheet, string bookname, bool overwrite = f
cs
return false;
}
public virtual int ImportRows(IEnumerable<BaseRow> sourceRows)
{
return 0;
}
public virtual void BackupSource()
{
}