int UnloadModule(ILua lua) { try { string module_name = lua.GetString(1); if (String.IsNullOrEmpty(module_name)) { throw new Exception("Module name is empty or null"); } if (!module_contexts.ContainsKey(module_name)) { throw new Exception($"There is no loaded module with name { module_name }"); } lua.PrintToConsole($"Unloading module { module_name } ..."); WeakReference <GmodNetModuleAssemblyLoadContext> context_weak_reference = UnloadHelper(module_name); for (int i = 0; context_weak_reference.TryGetTarget(out _); i++) { lua.PushSpecial(SPECIAL_TABLES.SPECIAL_GLOB); lua.GetField(-1, "collectgarbage"); lua.MCall(0, 0); lua.Pop(1); GC.Collect(); GC.WaitForPendingFinalizers(); if (i >= 300) { throw new Exception($"Module {module_name} can't be unloaded: there are remaining references or background threads still executing. " + $"Module resources can't be freed. Memory leak could occur. Game restart may be required."); } } lua.PrintToConsole($"Module {module_name} was unloaded."); lua.PushBool(true); return(1); } catch (Exception e) { lua.PrintToConsole("Unable to unload module: exception was thrown"); lua.PrintToConsole(e.ToString()); lua.PushBool(false); return(1); } }
internal void OnNativeUnload(ILua lua) { try { List <string> module_names = new List <string>(); foreach (var p in module_contexts) { module_names.Add(p.Key); } foreach (string name in module_names) { try { WeakReference <GmodNetModuleAssemblyLoadContext> weak_reference = UnloadHelper(name); for (int i = 0; weak_reference.TryGetTarget(out _); i++) { lua.PushSpecial(SPECIAL_TABLES.SPECIAL_GLOB); lua.GetField(-1, "collectgarbage"); lua.MCall(0, 0); lua.Pop(1); GC.Collect(); GC.WaitForPendingFinalizers(); if (i >= 300) { throw new Exception($"Module {name} can't be unloaded: there are remaining references or background threads still executing. " + $"Module resources can't be freed. Memory leak could occur. Game restart may be required."); } } } catch (Exception e) { lua.PrintToConsole($"Exception was thrown while unloading .NET module {name}"); lua.PrintToConsole(e.ToString()); } } } catch (Exception e) { lua.PrintToConsole("Critiacal error occured on .NET modules unload"); lua.PrintToConsole(e.ToString()); } }
int LoadModule(ILua lua) { try { string module_name = lua.GetString(1); lua.Pop(lua.Top()); if (String.IsNullOrEmpty(module_name)) { throw new Exception("Module name is null or empty"); } if (module_contexts.ContainsKey(module_name)) { throw new Exception($"Module with name {module_name} is already loaded"); } GmodNetModuleAssemblyLoadContext module_context = new GmodNetModuleAssemblyLoadContext(module_name); Assembly module_assembly = module_context.LoadFromAssemblyPath(Path.GetFullPath("garrysmod/lua/bin/Modules/" + module_name + "/" + module_name + ".dll")); Type[] module_types = module_assembly.GetTypes().Where(t => typeof(IModule).IsAssignableFrom(t)).ToArray(); List <IModule> modules = new List <IModule>(); List <GCHandle> gc_handles = new List <GCHandle>(); foreach (Type t in module_types) { IModule current_module = (IModule)Activator.CreateInstance(t); modules.Add(current_module); gc_handles.Add(GCHandle.Alloc(current_module)); } if (modules.Count == 0) { throw new Exception($"Module {module_name} does not contain any implementations of the IModule interface."); } lua.PrintToConsole("Loading modules from " + module_name + "."); lua.PrintToConsole("Number of the IModule interface implementations: " + modules.Count); foreach (IModule m in modules) { lua.PrintToConsole("Loading class-module " + m.ModuleName + " version " + m.ModuleVersion + "..."); m.Load(lua, isServerSide, module_context); lua.PrintToConsole("Class-module " + m.ModuleName + " was loaded."); } module_contexts.Add(module_name, Tuple.Create(module_context, gc_handles)); lua.PushBool(true); return(1); } catch (Exception e) { lua.PrintToConsole("Unable to load module: exception was thrown"); lua.PrintToConsole(e.ToString()); lua.PushBool(false); return(1); } }