Skip to content

Commit 7a9889f

Browse files
add method name checking during compilation
1 parent 71c84c3 commit 7a9889f

File tree

3 files changed

+133
-105
lines changed

3 files changed

+133
-105
lines changed

Code/MethodSystem/BaseMethods/Method.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ protected Method()
2626
Subgroup = type.Namespace?
2727
.Split('.')
2828
.LastOrDefault()?
29-
.WithCurrent(name => name.Substring(0, name.Length - "Methods".Length))
29+
.WithCurrent(name => name[..^"Methods".Length])
3030
?? "Unknown";
3131

3232
var name = type.Name;
@@ -35,7 +35,7 @@ protected Method()
3535
throw new AndrzejFuckedUpException($"Method class name '{name}' must end with 'Method'.");
3636
}
3737

38-
Name = name.Substring(0, name.Length - "Method".Length);
38+
Name = name[..^"Method".Length];
3939
Args = new(this);
4040
}
4141

Code/MethodSystem/MethodIndex.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ public static Method[] GetMethods()
4747
public static void AddAllDefinedMethodsInAssembly(Assembly? assembly = null)
4848
{
4949
assembly ??= Assembly.GetCallingAssembly();
50-
var definedMethods = assembly.GetTypes()
51-
.Where(t => t.IsClass && !t.IsAbstract && typeof(Method).IsAssignableFrom(t))
50+
var definedMethods = GetDefinedMethods(assembly)
5251
.Where(t =>
5352
{
5453
if (!typeof(IExiledMethod).IsAssignableFrom(t)) return true;
@@ -104,6 +103,23 @@ public static TryGet<Method> TryGetMethod(string name)
104103
return $"There is no method with name '{name}'. Did you mean '{closestMethod ?? "<error>"}'?";
105104
}
106105

106+
public static string? AreMethodsNamedCorrectly(Assembly assembly)
107+
{
108+
var methods = GetDefinedMethods(assembly);
109+
var invalidMethods = methods.Where(m => !m.Name.EndsWith("Method")).ToList();
110+
111+
return invalidMethods.Any()
112+
? $"The following methods do not end with 'Method': {string.Join(", ", invalidMethods)}"
113+
: null;
114+
}
115+
116+
private static Type[] GetDefinedMethods(Assembly assembly)
117+
{
118+
return assembly.GetTypes()
119+
.Where(t => t.IsClass && !t.IsAbstract && typeof(Method).IsAssignableFrom(t))
120+
.ToArray();
121+
}
122+
107123
/// <summary>
108124
/// Calculates the Levenshtein distance between two strings, which represents the minimum number of
109125
/// single-character edits (insertions, deletions, or substitutions) required to transform one string to another.

SER.csproj

Lines changed: 113 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -130,108 +130,120 @@
130130
<Using Namespace="System.Reflection" />
131131
<Code Type="Fragment" Language="cs">
132132
<![CDATA[
133-
// 1. Resolver for SCP:SL Dependencies
134-
ResolveEventHandler resolver = (sender, args) => {
135-
try {
136-
// Parse the requested assembly name
137-
var nameObj = new AssemblyName(args.Name);
138-
string fileName = nameObj.Name + ".dll";
133+
// 1. Resolver for SCP:SL Dependencies
134+
ResolveEventHandler resolver = (sender, args) => {
135+
try {
136+
// Parse the requested assembly name
137+
var nameObj = new AssemblyName(args.Name);
138+
string fileName = nameObj.Name + ".dll";
139+
140+
// Look in the game references folder
141+
string fullPath = Path.Combine(ReferencePath, fileName);
142+
143+
if (File.Exists(fullPath)) {
144+
return Assembly.LoadFrom(fullPath);
145+
}
146+
}
147+
catch { /* Safe verify, ignore errors */ }
148+
return null;
149+
};
150+
151+
AppDomain.CurrentDomain.AssemblyResolve += resolver;
152+
153+
try
154+
{
155+
if (!File.Exists(AssemblyPath)) {
156+
Log.LogError("Target DLL not found: " + AssemblyPath);
157+
return false;
158+
}
159+
160+
// 3. Load the DLL
161+
// LoadFrom allows dependencies to be resolved via the event handler
162+
Assembly assembly = Assembly.LoadFrom(AssemblyPath);
163+
164+
{
165+
Type targetType = assembly.GetType("SER.Code.MethodSystem.MethodIndex");
166+
if (targetType == null)
167+
{
168+
Log.LogError("Validation Error: Type 'SER.Code.MethodSystem.MethodIndex' not found.");
169+
return false;
170+
}
171+
172+
MethodInfo verifyMethod = targetType.GetMethod("AreMethodsNamedCorrectly", BindingFlags.Public | BindingFlags.Static);
173+
if (verifyMethod == null)
174+
{
175+
Log.LogError("Validation Error: Static method 'AreMethodsNamedCorrectly()' not found.");
176+
return false;
177+
}
178+
179+
var error = (string)verifyMethod.Invoke(null, [assembly]);
180+
if (error != null)
181+
{
182+
Log.LogError(error);
183+
return false;
184+
}
139185
140-
// Look in the game references folder
141-
string fullPath = Path.Combine(ReferencePath, fileName);
142-
143-
if (File.Exists(fullPath)) {
144-
return Assembly.LoadFrom(fullPath);
145-
}
146-
}
147-
catch { /* Safe verify, ignore errors */ }
148-
return null;
149-
};
150-
151-
AppDomain.CurrentDomain.AssemblyResolve += resolver;
152-
153-
try
154-
{
155-
if (!File.Exists(AssemblyPath)) {
156-
Log.LogError("Target DLL not found: " + AssemblyPath);
157-
return false;
158-
}
159-
160-
// 3. Load the DLL
161-
// LoadFrom allows dependencies to be resolved via the event handler
162-
Assembly assembly = Assembly.LoadFrom(AssemblyPath);
163-
164-
{
165-
// 4. Find the class (Namespace.ClassName)
166-
Type targetType = assembly.GetType("SER.Code.MethodSystem.MethodIndex");
167-
if (targetType == null)
168-
{
169-
Log.LogError("Validation Error: Type 'SER.Code.MethodSystem.MethodIndex' not found.");
170-
return false;
171-
}
172-
173-
// 5. Find the method
174-
MethodInfo method = targetType.GetMethod("AddAllDefinedMethodsInAssembly", BindingFlags.Public | BindingFlags.Static);
175-
if (method == null)
176-
{
177-
Log.LogError("Validation Error: Static method 'AddAllDefinedMethodsInAssembly()' not found.");
178-
return false;
179-
}
180-
181-
method.Invoke(null, [assembly]);
182-
Log.LogMessage(MessageImportance.High, ">>> Loaded methods.");
183-
}
184-
185-
{
186-
// 4. Find the class (Namespace.ClassName)
187-
Type targetType = assembly.GetType("SER.Code.Examples.Example");
188-
if (targetType == null)
189-
{
190-
Log.LogError("Validation Error: Type 'SER.Code.Examples.Example' not found.");
191-
return false;
192-
}
193-
194-
// 5. Find the method
195-
MethodInfo method = targetType.GetMethod("Verify", BindingFlags.Public | BindingFlags.Static);
196-
if (method == null)
197-
{
198-
Log.LogError("Validation Error: Static method 'Verify()' not found.");
199-
return false;
200-
}
201-
202-
Log.LogMessage(MessageImportance.High, ">>> Validating Scripts...");
203-
204-
// 6. Invoke
205-
string result = (string)method.Invoke(null, null);
206-
207-
if (!string.IsNullOrEmpty(result))
208-
{
209-
Log.LogError("SCRIPT ERROR: " + result);
210-
return false;
211-
}
212-
213-
Log.LogMessage(MessageImportance.High, ">>> Validation Passed.");
214-
return true;
215-
}
216-
}
217-
catch (Exception ex)
218-
{
219-
if (ex is ReflectionTypeLoadException re) {
220-
foreach (var loaderEx in re.LoaderExceptions) {
221-
Log.LogError("Loader Error: " + loaderEx.Message);
222-
}
223-
}
224-
else if (ex.InnerException != null) {
225-
Log.LogError("Runtime Error: " + ex.InnerException.Message);
226-
}
227-
else {
228-
Log.LogError("Task Error: " + ex.ToString());
229-
}
230-
}
231-
finally {
232-
// 7. Detach Resolver to keep build process clean
233-
AppDomain.CurrentDomain.AssemblyResolve -= resolver;
234-
}
186+
MethodInfo method = targetType.GetMethod("AddAllDefinedMethodsInAssembly", BindingFlags.Public | BindingFlags.Static);
187+
if (method == null)
188+
{
189+
Log.LogError("Validation Error: Static method 'AddAllDefinedMethodsInAssembly()' not found.");
190+
return false;
191+
}
192+
193+
method.Invoke(null, [assembly]);
194+
Log.LogMessage(MessageImportance.High, ">>> Loaded methods.");
195+
}
196+
197+
{
198+
// 4. Find the class (Namespace.ClassName)
199+
Type targetType = assembly.GetType("SER.Code.Examples.Example");
200+
if (targetType == null)
201+
{
202+
Log.LogError("Validation Error: Type 'SER.Code.Examples.Example' not found.");
203+
return false;
204+
}
205+
206+
// 5. Find the method
207+
MethodInfo method = targetType.GetMethod("Verify", BindingFlags.Public | BindingFlags.Static);
208+
if (method == null)
209+
{
210+
Log.LogError("Validation Error: Static method 'Verify()' not found.");
211+
return false;
212+
}
213+
214+
Log.LogMessage(MessageImportance.High, ">>> Validating Scripts...");
215+
216+
// 6. Invoke
217+
string result = (string)method.Invoke(null, null);
218+
219+
if (!string.IsNullOrEmpty(result))
220+
{
221+
Log.LogError("SCRIPT ERROR: " + result);
222+
return false;
223+
}
224+
225+
Log.LogMessage(MessageImportance.High, ">>> Validation Passed.");
226+
return true;
227+
}
228+
}
229+
catch (Exception ex)
230+
{
231+
if (ex is ReflectionTypeLoadException re) {
232+
foreach (var loaderEx in re.LoaderExceptions) {
233+
Log.LogError("Loader Error: " + loaderEx.Message);
234+
}
235+
}
236+
else if (ex.InnerException != null) {
237+
Log.LogError("Runtime Error: " + ex.InnerException.Message);
238+
}
239+
else {
240+
Log.LogError("Task Error: " + ex.ToString());
241+
}
242+
}
243+
finally {
244+
// 7. Detach Resolver to keep build process clean
245+
AppDomain.CurrentDomain.AssemblyResolve -= resolver;
246+
}
235247
]]>
236248
</Code>
237249
</Task>

0 commit comments

Comments
 (0)