MOD!
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5240790581fdac4aa3b2a4db00e0e9a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,247 @@
|
||||
#if UNITY_EDITOR
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace SLSFramework.UModAssistance
|
||||
{
|
||||
#region List<string>选择器,通过类型查找资产,将其名称存储在列表中
|
||||
|
||||
public partial class DataEditor : Editor
|
||||
{
|
||||
private string _pickerTargetListName;
|
||||
|
||||
private Dictionary<string, Object> _assetCache;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
// 每次选中新对象时,都清空缓存
|
||||
_assetCache = new Dictionary<string, Object>();
|
||||
}
|
||||
|
||||
|
||||
protected void DrawCharacterListGUI<T>(SerializedProperty listProperty, string searchFilter = "") where T : Object
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchFilter))
|
||||
{
|
||||
searchFilter = $"t:{typeof(T).Name}";
|
||||
}
|
||||
|
||||
listProperty.isExpanded = EditorGUILayout.Foldout(listProperty.isExpanded, listProperty.displayName, false);
|
||||
|
||||
if (listProperty.isExpanded)
|
||||
{
|
||||
EditorGUI.indentLevel++;
|
||||
|
||||
for (int i = 0; i < listProperty.arraySize; i++)
|
||||
{
|
||||
SerializedProperty elementNameProp = listProperty.GetArrayElementAtIndex(i);
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(elementNameProp, GUIContent.none);
|
||||
bool valueChanged = EditorGUI.EndChangeCheck();
|
||||
string assetName = elementNameProp.stringValue;
|
||||
|
||||
if (valueChanged || !_assetCache.TryGetValue(assetName, out Object foundAsset))
|
||||
{
|
||||
foundAsset = FindObjectData<T>(assetName, searchFilter);
|
||||
_assetCache[assetName] = foundAsset; // 将搜索结果(即使是null)存入缓存
|
||||
}
|
||||
|
||||
if (foundAsset != null)
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
EditorGUILayout.ObjectField(foundAsset, typeof(T), false, GUILayout.Width(150));
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField(new GUIContent(EditorGUIUtility.IconContent("console.warnicon").image, "资产未找到或名称不匹配"),
|
||||
GUILayout.Width(20));
|
||||
}
|
||||
|
||||
if (GUILayout.Button("-", GUILayout.Width(20)))
|
||||
{
|
||||
_assetCache.Remove(elementNameProp.stringValue);
|
||||
listProperty.DeleteArrayElementAtIndex(i);
|
||||
i--;
|
||||
}
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Add by Search..."))
|
||||
{
|
||||
_pickerTargetListName = listProperty.propertyPath;
|
||||
EditorGUIUtility.ShowObjectPicker<T>(null, false, searchFilter, GUI.skin.GetHashCode());
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
protected T FindObjectData<T>(string assetName, string searchFilter) where T : Object
|
||||
{
|
||||
if (string.IsNullOrEmpty(assetName)) return null;
|
||||
|
||||
string[] guids = AssetDatabase.FindAssets($"{assetName} {searchFilter}");
|
||||
if (guids.Length > 0)
|
||||
{
|
||||
return AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(guids[0]));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void HandleObjectPicker()
|
||||
{
|
||||
if (Event.current.commandName == "ObjectSelectorUpdated" && EditorGUIUtility.GetObjectPickerControlID() == GUI.skin.GetHashCode())
|
||||
{
|
||||
Object pickedObject = EditorGUIUtility.GetObjectPickerObject();
|
||||
if (pickedObject != null)
|
||||
{
|
||||
SerializedProperty targetListProp = serializedObject.FindProperty(_pickerTargetListName);
|
||||
if (targetListProp != null)
|
||||
{
|
||||
bool exists = false;
|
||||
for (int i = 0; i < targetListProp.arraySize; i++)
|
||||
{
|
||||
if (targetListProp.GetArrayElementAtIndex(i).stringValue == pickedObject.name)
|
||||
{
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
targetListProp.InsertArrayElementAtIndex(targetListProp.arraySize);
|
||||
targetListProp.GetArrayElementAtIndex(targetListProp.arraySize - 1).stringValue = pickedObject.name;
|
||||
}
|
||||
}
|
||||
|
||||
_pickerTargetListName = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Type选择器,将获取的类型名存入一个string中
|
||||
|
||||
public partial class DataEditor
|
||||
{
|
||||
private static Dictionary<Tuple<Type, string>, (string[] paths, Type[] types)> _typeCache =
|
||||
new Dictionary<Tuple<Type, string>, (string[], Type[])>();
|
||||
|
||||
/// <summary>
|
||||
/// 绘制一个用于选择指定基类的所有子类的下拉菜单
|
||||
/// </summary>
|
||||
/// <param name="classNameProp">存储类名的字符串属性</param>
|
||||
/// <param name="label">在Inspector中显示的标签</param>
|
||||
/// <param name="baseType">要查找的基类 (例如 typeof(CardLogicBase))</param>
|
||||
/// <param name="namespaceToRemove">可选参数,用于从路径中移除特定的命名空间部分 (例如 ".Cards")</param>
|
||||
/// <returns>如果值被用户改变,则返回true</returns>
|
||||
protected bool DrawTypeSelectorGUI(SerializedProperty classNameProp, string label, Type baseType,
|
||||
string namespacePrefix = null, string namespaceToRemove = null)
|
||||
{
|
||||
// --- 核心修改 2:使用包含 namespaceToRemove 的复合键 ---
|
||||
var cacheKey = new Tuple<Type, string>(baseType, namespaceToRemove ?? string.Empty);
|
||||
|
||||
if (!_typeCache.ContainsKey(cacheKey))
|
||||
{
|
||||
CacheDerivedTypes(baseType, namespacePrefix, namespaceToRemove, cacheKey);
|
||||
}
|
||||
|
||||
var (paths, types) = _typeCache[cacheKey];
|
||||
|
||||
int currentIndex = -1;
|
||||
for (int i = 0; i < types.Length; i++)
|
||||
{
|
||||
if (types[i].Name == classNameProp.stringValue)
|
||||
{
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int newIndex = EditorGUILayout.Popup(label, currentIndex, paths);
|
||||
|
||||
if (newIndex != currentIndex)
|
||||
{
|
||||
classNameProp.stringValue = (newIndex >= 0 && newIndex < types.Length)
|
||||
? types[newIndex].Name
|
||||
: string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CacheDerivedTypes(Type baseType, string namespacePrefix, string namespaceToRemove, Tuple<Type, string> cacheKey)
|
||||
{
|
||||
List<(string path, Type type)> typeList = new List<(string, Type)>();
|
||||
|
||||
IEnumerable<Type> types = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(assembly => assembly.GetTypes())
|
||||
.Where(t => baseType.IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface && t != baseType);
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
string path = "Uncategorized/" + type.Name;
|
||||
if (type.Namespace != null && type.Namespace.StartsWith(namespacePrefix))
|
||||
{
|
||||
string formattedNamespace = type.Namespace.Substring(namespacePrefix.Length);
|
||||
|
||||
// --- 核心修改 3:使用传入的参数来替换硬编码 ---
|
||||
if (!string.IsNullOrEmpty(namespaceToRemove))
|
||||
{
|
||||
formattedNamespace = formattedNamespace.Replace("." + namespaceToRemove, "");
|
||||
}
|
||||
|
||||
formattedNamespace = formattedNamespace.Replace('.', '/');
|
||||
if (formattedNamespace.StartsWith("/")) formattedNamespace = formattedNamespace.Substring(1);
|
||||
path = formattedNamespace + "/" + type.Name;
|
||||
}
|
||||
|
||||
typeList.Add((path, type));
|
||||
}
|
||||
|
||||
typeList.Sort((a, b) => a.path.CompareTo(b.path));
|
||||
|
||||
_typeCache[cacheKey] = (typeList.Select(t => t.path).ToArray(), typeList.Select(t => t.type).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 绘制一个按钮,点击后调用指定方法
|
||||
public partial class DataEditor
|
||||
{
|
||||
protected void DrawMethodButton<T>(string buttonLabel, string functionName) where T : Object
|
||||
{
|
||||
if (GUILayout.Button(buttonLabel))
|
||||
{
|
||||
T invoker = target as T;
|
||||
MethodInfo method = typeof(T).GetMethod(functionName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (method != null)
|
||||
{
|
||||
method.Invoke(invoker, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Method '{functionName}' not found in type '{typeof(T).Name}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cc91a8081a9a9f44ab0df9fe725a089
|
||||
95
Assets/Scripts/ScriptExtensions/UModAssistance/ModBrowser.cs
Normal file
95
Assets/Scripts/ScriptExtensions/UModAssistance/ModBrowser.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Continentis.MainGame;
|
||||
using Continentis.MainGame.Card;
|
||||
using Continentis.MainGame.Character;
|
||||
using Continentis.MainGame.Equipment;
|
||||
using Continentis.MainGame.Rules;
|
||||
using Continentis.Mods;
|
||||
using I2.Loc;
|
||||
using SLSFramework.General;
|
||||
using UMod;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace SLSFramework.UModAssistance
|
||||
{
|
||||
public partial class ModBrowser : MonoBehaviour
|
||||
{
|
||||
// Public
|
||||
public bool persistent = true;
|
||||
public Button loadButton;
|
||||
public RectTransform modButtonContainer;
|
||||
public GameObject modLoadTabPrefab;
|
||||
public List<ModLoadTab> modTabs = new List<ModLoadTab>();
|
||||
public List<IModInfo> selectedMods = new List<IModInfo>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Mod.DefaultDirectory = new ModDirectory(Application.dataPath + "/ExportedMods");
|
||||
#else
|
||||
Mod.DefaultDirectory = new ModDirectory(Application.dataPath + "/Mods");
|
||||
#endif
|
||||
loadButton.onClick.AddListener(OnLoadClicked);
|
||||
GenerateUIList();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ModBrowser
|
||||
{
|
||||
private void OnLoadClicked()
|
||||
{
|
||||
GetAllSelectedMods();
|
||||
|
||||
foreach (IModInfo mod in selectedMods)
|
||||
{
|
||||
ModHost host = ModManager.LoadMod(mod);
|
||||
ModManager.RegisterTypesFromMod(host, typeof(CharacterBase));
|
||||
ModManager.RegisterTypesFromMod(host, typeof(CardLogicBase));
|
||||
ModManager.RegisterTypesFromMod(host, typeof(EquipmentBase));
|
||||
ModManager.RegisterTypesFromMod(host,typeof(Continentis.MainGame.Card.CombatBuffBase));
|
||||
ModManager.RegisterTypesFromMod(host,typeof(Continentis.MainGame.Character.CombatBuffBase));
|
||||
ModManager.RegisterTypesFromMod(host, typeof(RulesCollectionBase));
|
||||
|
||||
string manifestName = host.CurrentMod.NameInfo.ModName + "_Manifest";
|
||||
ModManifest manifest = host.Assets.Load<ModManifest>(manifestName);
|
||||
manifest.SaveToDatabase(host);
|
||||
List<TextAsset> localizationFiles = manifest.localizationFiles;
|
||||
|
||||
foreach (TextAsset localizationFile in localizationFiles)
|
||||
{
|
||||
LanguageSourceData sourceData = new LanguageSourceData();
|
||||
sourceData.Import_CSV(string.Empty, localizationFile.text, eSpreadsheetUpdateMode.Merge, ',');
|
||||
LocalizationManager.AddSource(sourceData);
|
||||
}
|
||||
}
|
||||
|
||||
LocalizationManager.LocalizeAll();
|
||||
}
|
||||
|
||||
private void GenerateUIList()
|
||||
{
|
||||
// Destroy all cells
|
||||
modButtonContainer.DestroyAllChildren();
|
||||
|
||||
// Create new cells
|
||||
foreach (IModInfo info in Mod.DefaultDirectory.GetMods())// ModDirectory.GetMods())
|
||||
{
|
||||
CreateUICell(info, modButtonContainer);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateUICell(IModInfo mod, RectTransform container)
|
||||
{
|
||||
ModLoadTab modTab = Instantiate(modLoadTabPrefab, container).GetComponent<ModLoadTab>();
|
||||
modTab.Initialize(mod);
|
||||
modTabs.Add(modTab);
|
||||
}
|
||||
|
||||
private void GetAllSelectedMods()
|
||||
{
|
||||
selectedMods = modTabs.FindAll(t => t.isSelected).ConvertAll(t => t.modInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 222420d8b6807ad458d012a439512436
|
||||
31
Assets/Scripts/ScriptExtensions/UModAssistance/ModLoadTab.cs
Normal file
31
Assets/Scripts/ScriptExtensions/UModAssistance/ModLoadTab.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using TMPro;
|
||||
using UMod;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace SLSFramework.UModAssistance
|
||||
{
|
||||
public class ModLoadTab : MonoBehaviour
|
||||
{
|
||||
public IModInfo modInfo;
|
||||
public string path;
|
||||
public bool isSelected => loadToggle.isOn;
|
||||
|
||||
public TMP_Text nameText;
|
||||
public TMP_Text versionText;
|
||||
public TMP_Text pathText;
|
||||
public Toggle loadToggle;
|
||||
|
||||
public void Initialize(IModInfo modInfo)
|
||||
{
|
||||
this.modInfo = modInfo;
|
||||
string relative = Mod.DefaultDirectory.GetModPath(modInfo.NameInfo.ModName).ToString();
|
||||
path = relative.Replace(Application.dataPath + "/", "");
|
||||
|
||||
nameText.text = modInfo.NameInfo.ModName;
|
||||
versionText.text = modInfo.NameInfo.ModVersion;
|
||||
pathText.text = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0ea9bf78368bff43b7f5145f22492c3
|
||||
199
Assets/Scripts/ScriptExtensions/UModAssistance/ModManager.cs
Normal file
199
Assets/Scripts/ScriptExtensions/UModAssistance/ModManager.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using SLSFramework.General;
|
||||
using UMod;
|
||||
using UMod.Scripting;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace SLSFramework.UModAssistance
|
||||
{
|
||||
public static partial class ModManager
|
||||
{
|
||||
public static ModHost LoadMod(IModInfo modInfo)
|
||||
{
|
||||
string modName = modInfo.NameInfo.ModName;
|
||||
ModHost host = Mod.Load(Mod.DefaultDirectory.GetModPath(modName));
|
||||
LoadedMods.Add(modName, host);
|
||||
Debug.Log($"Mod '{modName}' loaded successfully.");
|
||||
return host;
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class ModManager
|
||||
{
|
||||
public static readonly SerializableDictionary<string, ModHost> LoadedMods = new SerializableDictionary<string, ModHost>();
|
||||
public static readonly Dictionary<Type, Dictionary<string, ScriptableObject>> Database = new Dictionary<Type, Dictionary<string, ScriptableObject>>();
|
||||
public static bool IsValidAssetName(string assetName) => Regex.IsMatch(assetName, @"^\w+_\w+_.+$");
|
||||
|
||||
/// <summary>
|
||||
/// Get asset by its name, automatically determining which mod it belongs to.
|
||||
/// </summary>
|
||||
/// <param name="assetName">Name of the asset <b>MUST</b> in the format "Type_ModName_AssetName"</param>
|
||||
public static T GetAsset<T>(string assetName) where T : Object
|
||||
{
|
||||
//命名符合“Type_ModName_AssetName”格式规范
|
||||
if (IsValidAssetName(assetName))
|
||||
{
|
||||
string assumeModName = assetName.Split('_')[1];
|
||||
|
||||
if (LoadedMods.TryGetValue(assumeModName, out ModHost host))
|
||||
{
|
||||
T asset = host.Assets.Load<T>(assetName);
|
||||
if (asset != null)
|
||||
{
|
||||
return asset;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Mod '{assumeModName}' is not loaded, or cannot get asset '{assetName}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Please check the name format (Type_ModName_AssetName) of this asset, '{assetName}'.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get asset from specified mod.
|
||||
/// </summary>
|
||||
/// <param name="modName">Name of the mod</param>
|
||||
/// <param name="assetName">Name of the asset, recommend name format "Type_ModName_AssetName"</param>
|
||||
public static T GetAsset<T>(string modName, string assetName) where T : Object
|
||||
{
|
||||
if (!IsValidAssetName(assetName))
|
||||
{
|
||||
Debug.LogWarning($"Asset name '{assetName}' does not follow the 'Type_ModName_AssetName' format.");
|
||||
}
|
||||
|
||||
if (LoadedMods.TryGetValue(modName, out ModHost host))
|
||||
{
|
||||
return host.Assets.Load<T>(assetName);
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Mod '{modName}' is not loaded, or cannot get asset '{assetName}'.");
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool TryGetData<T>(string assetName, out T data) where T : ScriptableObject
|
||||
{
|
||||
return (data = GetData<T>(assetName)) != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get data (Scriptable Objects, loaded by data manifest) from the database by its name and type.
|
||||
/// </summary>
|
||||
/// <param name="assetName">Name of the asset</param>
|
||||
public static T GetData<T>(string assetName) where T : ScriptableObject
|
||||
{
|
||||
if (!IsValidAssetName(assetName))
|
||||
{
|
||||
Debug.LogWarning($"Asset name '{assetName}' does not follow the 'Type_ModName_AssetName' format.");
|
||||
}
|
||||
|
||||
Type assetType = typeof(T);
|
||||
if (Database.TryGetValue(assetType, out Dictionary<string, ScriptableObject> assets))
|
||||
{
|
||||
if (assets.TryGetValue(assetName, out ScriptableObject asset))
|
||||
{
|
||||
return asset as T;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Data Asset '{assetName}' of type '{assetType}' not found in database.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"No assets of type '{assetType}' found in database.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class ModManager
|
||||
{
|
||||
public static readonly Dictionary<string, Type> TypeRegistry = new Dictionary<string, Type>();
|
||||
|
||||
/// <summary>
|
||||
/// 从一个已加载的Mod中,查找所有指定基类的子类,并将其注册到全局字典中。
|
||||
/// </summary>
|
||||
/// <param name="host">已加载的ModHost对象</param>
|
||||
/// <param name="baseType">要查找的基类,例如 typeof(CardLogicBase)</param>
|
||||
public static void RegisterTypesFromMod(ModHost host, Type baseType)
|
||||
{
|
||||
if (host?.ScriptDomain == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int countBefore = TypeRegistry.Count;
|
||||
|
||||
// 遍历Mod包含的所有程序集(DLLs)
|
||||
foreach (ScriptAssembly assembly in host.ScriptDomain.Assemblies)
|
||||
{
|
||||
// assembly.RawAssembly 是 uMod 封装的真实 System.Reflection.Assembly 对象
|
||||
var typesInAssembly = assembly.RawAssembly.GetTypes()
|
||||
.Where(t => baseType.IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface);
|
||||
|
||||
foreach (var type in typesInAssembly)
|
||||
{
|
||||
if (!TypeRegistry.ContainsKey(type.Name))
|
||||
{
|
||||
TypeRegistry.Add(type.Name, type);
|
||||
Debug.Log($"Registered script type '{type.FullName}' from mod '{host.CurrentMod.NameInfo.ModName}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理命名冲突:如果不同Mod中存在同名的类,后加载的会被忽略
|
||||
Debug.LogWarning($"Duplicate script type name found: '{type.Name}'. The existing type from assembly '{TypeRegistry[type.Name].Assembly.FullName}' will be kept.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int countAfter = TypeRegistry.Count;
|
||||
if (countAfter > countBefore)
|
||||
{
|
||||
Debug.Log($"Registered {countAfter - countBefore} new script types deriving from '{baseType.Name}' from mod '{host.CurrentMod.NameInfo.ModName}'.");
|
||||
}
|
||||
}
|
||||
|
||||
public static Type GetType(string typeName)
|
||||
{
|
||||
if (TypeRegistry.TryGetValue(typeName, out Type type))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
Debug.LogWarning($"Type '{typeName}' not found in TypeRegistry.");
|
||||
return null;
|
||||
}
|
||||
|
||||
public static T CreateInstance<T>(string typeName) where T : class
|
||||
{
|
||||
Type type = GetType(typeName);
|
||||
if (type != null && typeof(T).IsAssignableFrom(type))
|
||||
{
|
||||
return Activator.CreateInstance(type) as T;
|
||||
}
|
||||
Debug.LogWarning($"Cannot create instance of type '{typeName}' as it is not found or not assignable to '{typeof(T).Name}'.");
|
||||
return null;
|
||||
}
|
||||
|
||||
public static T CreateInstance<T>(string typeName, params object[] parameters) where T : class
|
||||
{
|
||||
Type type = GetType(typeName);
|
||||
if (type != null && typeof(T).IsAssignableFrom(type))
|
||||
{
|
||||
return Activator.CreateInstance(type, parameters) as T;
|
||||
}
|
||||
Debug.LogWarning($"Cannot create instance of type '{typeName}' as it is not found or not assignable to '{typeof(T).Name}'.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d2fb7a334e649f4ba61fc074840774d
|
||||
Reference in New Issue
Block a user