Skip to content

+EA 23.283 Nightly - Plugin.BaseCore

March 4, 2026

10 files modified.

Important Changes

None.

BaseModManager

using System;

cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq; 
using UnityEngine;

public class BaseModManager

public 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;

public void InitLang()

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

public void Activate()

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

using System.Linq;

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

public enum EAction

cs
	CancelUI = 53,
	Dump = 54,
	Mute = 55,
	Meditate = 56
	Meditate = 56, 
	Console = 57
}

EInput

public class KeyMapManager

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

using System;

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

using System;

cs
using System;
using System.Collections.Generic;
using System.Linq; 
using System.Text;

public class Lang

public class Words

cs

	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

public class 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

public class FieldMap

cs

	public override void Init()
	{
		Debug.Log("Initializing:" + base.name); 
		if (initialized)
		{
			Debug.Log("#init Skipping sourceData.Init:" + base.name);

public override void Init()

cs
	}
	initialized = true;
	editorListString.Clear();
	RemoveDuplicateRows(); 
	int num = 0;
	foreach (T row in rows)
	{

public virtual T CreateRow()

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;

public enum AutoID

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()
	{
	}