csharp/0x0ade/CelesteNet/CelesteNet.Server/CelesteNetServerModuleWrapper.Core.cs

CelesteNetServerModuleWrapper.Core.cs
#if NETCORE
using Celeste.Mod.CelesteNet.DataTypes;
using Mono.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Celeste.Mod.CelesteNet.Server {
    public partial clast CelesteNetServerModuleWrapper {

        private astemblyLoadContext? ALC;

        private void Loadastembly() {
            long stamp = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;

            string dir = Path.Combine(Path.GetTempPath(), $"CelesteNetServerModuleCache.{Server.Timestamp}");
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);

            string path = Path.Combine(dir, $"{Path.GetFileNameWithoutExtension(astemblyPath)}.{stamp}.dll");
            File.Copy(astemblyPath, path);

            if (File.Exists(Path.ChangeExtension(astemblyPath, "pdb")))
                File.Copy(Path.ChangeExtension(astemblyPath, "pdb"), Path.ChangeExtension(path, "pdb"));

            ALC = new ModuleastemblyLoadContext($"ModCtx.{stamp}.{ID}");
            ALC.Resolving += (ctx, name) => {
                foreach (CelesteNetServerModuleWrapper wrapper in Server.ModuleWrappers)
                    if (wrapper.ID == name.Name)
                        return wrapper.astembly;
                astemblyLoadContext? parent = astemblyLoadContext.GetLoadContext(typeof(CelesteNetServerModuleWrapper).astembly);
                if (parent != null)
                    foreach (astembly asm in parent.astemblies)
                        if (asm.GetName().Name == name.Name)
                            return asm;
                return null;
            };

            astembly = ALC.LoadFromastemblyPath(path);
        }

        private void Unloadastembly() {
            ALC?.Unload();
            ALC = null;
        }

        public clast ModuleastemblyLoadContext : astemblyLoadContext {

            public ModuleastemblyLoadContext(string name)
                : base(name, isCollectible: true) {
            }

            protected override astembly? Load(astemblyName name) {
                return null;
            }

        }

    }
}
#endif