#nullable enable using System; using System.IO; using System.Linq; using System.Reflection; using ShrinkCommand; using ShrinkEventBus; using ShrinkModFramework.Godot; if (args.Length != 1 || !File.Exists(args[0])) throw new ArgumentException("Pass the woven mod assembly path."); using var loader = new ShrinkGodotModLoader(); var instances = loader.Load(args[0]); if (instances.Count != 1) throw new InvalidOperationException("Mod entry was not discovered."); var mod = instances[0]; var type = mod.GetType(); if (type.GetProperty("Ready")?.GetValue(mod) is not true) throw new InvalidOperationException("Mod lifecycle did not reach OnReady."); var assembly = type.Assembly; if (assembly.GetCustomAttributes(typeof(ShrinkCommandStaticRegistryAttribute), false).Length != 1) throw new InvalidOperationException("Mod command registry metadata is missing."); var eventType = assembly.GetType("ModFixtureEvent") ?? throw new InvalidOperationException("Mod event is missing."); var post = typeof(EventBus).GetMethods(BindingFlags.Public | BindingFlags.Static) .Single(method => method.Name == "Post" && method.IsGenericMethodDefinition && method.GetParameters().Length == 1) .MakeGenericMethod(eventType); post.Invoke(null, new[] { Activator.CreateInstance(eventType) }); var eventSubscriber = assembly.GetType("ModFixtureEvents") ?? throw new InvalidOperationException("Mod static subscriber is missing."); if ((int?)eventSubscriber.GetProperty("Calls", BindingFlags.Public | BindingFlags.Static)?.GetValue(null) != 1) throw new InvalidOperationException("Mod static EventBus binding did not run."); if (!loader.Unload(args[0])) throw new InvalidOperationException("Mod unload failed."); if ((int?)type.GetProperty("UnloadCalls")?.GetValue(mod) != 1) throw new InvalidOperationException("Mod OnUnload was not called."); if (loader.LoadedAssemblyPaths.Count != 0) throw new InvalidOperationException("Mod remained registered after unload."); Console.WriteLine("PASS external netstandard2.1 mod CodeGen + Godot AssemblyLoadContext lifecycle");