|
1 | | -using HarmonyLib; |
| 1 | +using Exiled.Events.EventArgs.Interfaces; |
2 | 2 | using System; |
3 | 3 | using System.Collections.Generic; |
4 | 4 | using System.Linq; |
5 | | -using System.Reflection; |
6 | | -using UncomplicatedCustomRoles.API.Enums; |
7 | | -using UncomplicatedCustomRoles.API.Interfaces; |
8 | 5 | using UncomplicatedCustomRoles.Manager; |
9 | 6 |
|
10 | 7 | namespace UncomplicatedCustomRoles.API.Features.CustomModules |
11 | 8 | { |
12 | | -#pragma warning disable IDE1006 |
13 | | - |
14 | | - public abstract class CustomModule : ICustomModule |
| 9 | + public abstract class CustomModule |
15 | 10 | { |
16 | 11 | /// <summary> |
17 | | - /// Gets the <see cref="CustomFlags"/> that represent this module |
| 12 | + /// Gets the display name of the given <see cref="CustomModule"/> |
18 | 13 | /// </summary> |
19 | | - public static CustomFlags Flag => CustomFlags.NotExecutable; |
| 14 | + /// <value>Default one is the class' name</value> |
| 15 | + public virtual string Name |
| 16 | + { |
| 17 | + get |
| 18 | + { |
| 19 | + return GetType().Name; |
| 20 | + } |
| 21 | + } |
20 | 22 |
|
21 | 23 | /// <summary> |
22 | | - /// Gets the <see cref="SummonedCustomRole"/> instance that refers to this specific Module.<br></br> |
23 | | - /// This can be null if the module does not implement anything related to it! |
| 24 | + /// Gets the list of events that this <see cref="CustomModule"/> will listen for. |
24 | 25 | /// </summary> |
25 | | - public SummonedCustomRole Instance { get; } = null; |
| 26 | + /// <remarks>The <see cref="OnEvent(string, IPlayerEvent)"/> will be invoked only for the given events!</remarks> |
| 27 | + public virtual List<string> TriggerOnEvents { get; } = new(); |
26 | 28 |
|
27 | | - public string Name { get; } = string.Empty; |
| 29 | + /// <summary> |
| 30 | + /// Gets the list of required argument names for the current <see cref="CustomModule"/> |
| 31 | + /// </summary> |
| 32 | + public virtual List<string> RequiredArgs { get; } = new(); |
28 | 33 |
|
29 | 34 | /// <summary> |
30 | | - /// Gets whether the given <see cref="CustomModule"/> has it's <see cref="Instance"/> or not |
| 35 | + /// Gets the args of the current <see cref="CustomModule"/> |
31 | 36 | /// </summary> |
32 | | - public bool HasInstance => Instance is not null; |
| 37 | + /// <remarks>Every value is a <see cref="string"/></remarks> |
| 38 | + internal Dictionary<string, string> Args { get; private set; } |
33 | 39 |
|
34 | | - private static IEnumerable<Type> _loadedCache { get; set; } = null; |
| 40 | + /// <summary> |
| 41 | + /// Gets the instance of the <see cref="SummonedCustomRole"/> in which the current <see cref="CustomModule"/> is embedded |
| 42 | + /// </summary> |
| 43 | + internal SummonedCustomRole CustomRole { get; private set; } |
35 | 44 |
|
36 | | - private static IEnumerable<Type> _loaded { get |
37 | | - { |
38 | | - _loadedCache ??= LoadAll(); |
39 | | - return _loadedCache; |
40 | | - } |
| 45 | + internal void Initialize(SummonedCustomRole summonedCustomRole, Dictionary<string, string> args) |
| 46 | + { |
| 47 | + CustomRole = summonedCustomRole; |
| 48 | + Args = args; |
41 | 49 | } |
42 | 50 |
|
43 | 51 | /// <summary> |
44 | | - /// Create a new instance of <see cref="CustomModule"/> without a <see cref="SummonedCustomRole"/> |
| 52 | + /// The added event function |
45 | 53 | /// </summary> |
46 | | - public CustomModule() => Name = GetType().Name; |
| 54 | + /// <remarks>Invoked when the <see cref="CustomModule"/> has been added to the <see cref="SummonedCustomRole"/></remarks> |
| 55 | + public virtual void OnAdded() |
| 56 | + { } |
47 | 57 |
|
48 | 58 | /// <summary> |
49 | | - /// Create a new instance of <see cref="CustomModule"/> |
| 59 | + /// The removed event function |
50 | 60 | /// </summary> |
51 | | - /// <param name="instance"></param> |
52 | | - public CustomModule(SummonedCustomRole instance) |
53 | | - { |
54 | | - Instance = instance; |
55 | | - Name = GetType().Name; |
56 | | - } |
| 61 | + /// <remarks>Invoked when the <see cref="CustomModule"/> has been removed from the <see cref="SummonedCustomRole"/></remarks> |
| 62 | + public virtual void OnRemoved() |
| 63 | + { } |
57 | 64 |
|
58 | 65 | /// <summary> |
59 | | - /// Executen the Custom Module action |
| 66 | + /// The generic event function |
60 | 67 | /// </summary> |
| 68 | + /// <param name="name"></param> |
| 69 | + /// <param name="ev"></param> |
| 70 | + /// <returns>Invoked only for the events listed in <see cref="TriggerOnEvents"/></returns> |
| 71 | + public virtual bool OnEvent(string name, IPlayerEvent ev) => true; |
| 72 | + |
| 73 | + /// <summary> |
| 74 | + /// A generic function |
| 75 | + /// </summary> |
| 76 | + /// <remark>This won't be invoked by UCR</remark> |
61 | 77 | public virtual void Execute() |
62 | 78 | { } |
63 | 79 |
|
64 | | - private static IEnumerable<Type> LoadAll() |
| 80 | +#nullable enable |
| 81 | + internal static List<CustomModule> Load(List<object> modules, SummonedCustomRole summonedCustomRole) |
65 | 82 | { |
66 | | - return Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(typeof(CustomModule)) && !t.IsAbstract); |
| 83 | + LogManager.Silent($"[CM Loader] Initialize loading for {summonedCustomRole}\nPreloaded {YamlFlagsHandler.Modules.Length} modules..."); |
| 84 | + |
| 85 | + Dictionary<string, Dictionary<string, string>?> data = YamlFlagsHandler.Decode(modules) ?? new(); |
| 86 | + |
| 87 | + List<CustomModule> mods = new(); |
| 88 | + |
| 89 | + foreach (KeyValuePair<string, Dictionary<string, string>?> module in data) |
| 90 | + if (InitializeCustomModule(module.Key, module.Value, YamlFlagsHandler.Modules, summonedCustomRole) is CustomModule mod) |
| 91 | + mods.Add(mod); |
| 92 | + |
| 93 | + LogManager.Debug($"Successfully loaded {mods.Count} CustomModules for player {summonedCustomRole.Player.Nickname}!"); |
| 94 | + |
| 95 | + return mods; |
67 | 96 | } |
68 | 97 |
|
69 | | - /// <summary> |
70 | | - /// Load a <see cref="List{T}"/> of <see cref="ICustomModule"/> from the given <see cref="CustomFlags"/> |
71 | | - /// </summary> |
72 | | - /// <param name="flags"></param> |
73 | | - /// <param name="instance"></param> |
74 | | - /// <returns></returns> |
75 | | - public static List<ICustomModule> Load(CustomFlags flags, SummonedCustomRole instance) |
| 98 | + internal static CustomModule? FastAdd(Type type, SummonedCustomRole role, Dictionary<string, string>? args = null) |
76 | 99 | { |
77 | | - LogManager.Debug($"Loading custom modules for {instance.Player} - {instance.Role.Id} -- {flags} -- {_loaded.Count()}"); |
78 | | - List<ICustomModule> result = new(); |
| 100 | + if (Activator.CreateInstance(type) is not CustomModule module) |
| 101 | + { |
| 102 | + LogManager.Error($"Failed to enable CustomModule '{type?.Name}'!\nError: ERR_CUSTOM_MODULE_NULLREFERENCE_OR_NOTMODULE", "CM0003"); |
| 103 | + return null; |
| 104 | + } |
| 105 | + |
| 106 | + module.Initialize(role, args ?? new()); |
| 107 | + module.OnAdded(); // Invoke added event |
79 | 108 |
|
| 109 | + return module; |
| 110 | + } |
| 111 | + |
| 112 | + private static CustomModule? InitializeCustomModule(string name, Dictionary<string, string>? args, Type[] types, SummonedCustomRole summonedCustomRole) |
| 113 | + { |
80 | 114 | try |
81 | 115 | { |
82 | | - foreach (Type type in _loaded) |
| 116 | + LogManager.Silent($"[CM Loader] Initialize loading module '{name}' for {summonedCustomRole}"); |
| 117 | + |
| 118 | + Type type = types.FirstOrDefault(t => t.Name == name); |
| 119 | + |
| 120 | + if (type is null) |
83 | 121 | { |
84 | | - PropertyInfo property = type.GetProperty("Flag", BindingFlags.Public | BindingFlags.Static); |
85 | | - if (property is not null) |
86 | | - { |
87 | | - CustomFlags flag = (CustomFlags)property.GetValue(null, null); |
88 | | - if ((flags & flag) == flag) |
89 | | - if (type.GetConstructors()[0].GetParameters().Length > 0 && type.GetConstructors()[0].GetParameters()[0].ParameterType == typeof(SummonedCustomRole)) |
90 | | - result.Add((CustomModule)Activator.CreateInstance(type, new object[] { instance })); |
91 | | - else |
92 | | - result.Add((CustomModule)Activator.CreateInstance(type)); |
93 | | - |
94 | | - } |
| 122 | + LogManager.Error($"[CM Loader] Failed to enable CustomModule '{name}'!\nError: ERR_CUSTOM_MODULE_NOT_FOUND", "CM0001"); |
| 123 | + return null; |
95 | 124 | } |
| 125 | + |
| 126 | + if (Activator.CreateInstance(type) is not CustomModule module) |
| 127 | + { |
| 128 | + LogManager.Error($"[CM Loader] Failed to enable CustomModule '{name}'!\nError: ERR_CUSTOM_MODULE_NULLREFERENCE_OR_NOTMODULE", "CM0002"); |
| 129 | + return null; |
| 130 | + } |
| 131 | + |
| 132 | + module.Initialize(summonedCustomRole, args ?? new()); |
| 133 | + module.OnAdded(); // Invoke added event |
| 134 | + |
| 135 | + LogManager.Silent($"[CM Loader] CustomModule '{name}' successfully enabled for {summonedCustomRole}!"); |
| 136 | + |
| 137 | + return module; |
96 | 138 | } |
97 | 139 | catch (Exception e) |
98 | 140 | { |
99 | | - LogManager.Error($"Failed to act CustomModule::Load(CustomFlags, SummonedCustomRole) - {e.GetType().FullName}: {e.Message}\n{e.StackTrace}"); |
100 | | - } |
101 | | - |
102 | | - LogManager.Silent($"rff for {flags}: {result.Count}"); |
103 | | - return result; |
104 | | - } |
| 141 | + LogManager.Error(e.ToString()); |
105 | 142 |
|
106 | | - public static ICustomModule Load(Type type, SummonedCustomRole instance) |
107 | | - { |
108 | | - if (type.GetConstructors()[0].GetParameters().Length > 0 && type.GetConstructors()[0].GetParameters()[0].ParameterType == typeof(SummonedCustomRole)) |
109 | | - return (CustomModule)Activator.CreateInstance(type, new object[] { instance }); |
110 | | - return (CustomModule)Activator.CreateInstance(type); |
| 143 | + return null; |
| 144 | + } |
111 | 145 | } |
112 | 146 | } |
113 | 147 | } |
0 commit comments