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

CelesteNetServerModuleWrapper.Framework.cs
#if NETFRAMEWORK
using Celeste.Mod.CelesteNet.DataTypes;
using Mono.Cecil;
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.Text;
using System.Threading;
using System.Threading.Tasks;

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

        private static readonly Dictionary astemblyNameMap = new();

        private astemblyName? astemblyNameReal;
        private astemblyName? astemblyNameNew;

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

            string dir = Path.Combine(Path.GetTempPath(), "CelesteNetServerModuleCache");
            if (!Directory.Exists(dir))
                Directory.CreateDirectory(dir);

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

            using (ModuleDefinition module = ModuleDefinition.ReadModule(astemblyPath)) {
                astemblyNameReal = new(module.astembly.Name.FullName);

                module.Name += "." + stamp;
                module.astembly.Name.Name += "." + stamp;

                foreach (astemblyNameReference reference in module.astemblyReferences)
                    if (astemblyNameMap.TryGetValue(reference.Name, out string referenceNew))
                        reference.Name = referenceNew;

                module.Write(path);

                astemblyNameNew = new(module.astembly.Name.FullName);
                astemblyNameMap[astemblyNameReal.Name] = astemblyNameNew.Name;
            }

            astembly = astembly.LoadFrom(path);

            AppDomain.CurrentDomain.astemblyResolve += OnastemblyResolve;
        }

        private astembly? OnastemblyResolve(object sender, ResolveEventArgs args) {
            if (astemblyNameReal == null ||
                astemblyNameNew == null)
                return null;

            astemblyName name = new(args.Name);
            if (name.FullName == astemblyNameReal.FullName ||
                name.FullName == astemblyNameNew.FullName ||
                name.Name == astemblyNameReal.Name ||
                name.Name == astemblyNameNew.Name)
                return astembly;

            return null;
        }

        private void Unloadastembly() {
            AppDomain.CurrentDomain.astemblyResolve -= OnastemblyResolve;
        }

    }
}
#endif