XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
UTF-8
using ParallelTasks;
using Sandbox;
using Sandbox.Definitions;
using Sandbox.Engine.Utils;
using Sandbox.Game;
using Sandbox.Game.Entities;
using Sandbox.Game.Entities.Planet;
using Sandbox.Game.GameSystems;
using Sandbox.Game.World;
using SpaceEngineers.Game;
using SpaceEngineersBlueprintEditor.SpaceEngineersCore.InnerModel;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using VRage;
using VRage.Collections;
using VRage.FileSystem;
using VRage.Game;
using VRage.Game.ObjectBuilder;
using VRage.ObjectBuilders;
using VRage.Plugins;
using VRage.Utils;
using VRageMath;
using VRageRender;

namespace SpaceEngineersBlueprintEditor.SpaceEngineersCore;

public class Initializer
{
    public static bool IsDefinitionsLoadComplete { get; private set; }
    private static object GetUninitializedObject(Type type)
    {
        return FormatterServices.GetUninitializedObject(type);
    }
    public static void Initialize(string gameContentPath, string userDataPath)
    {
        MyFileSystem.ExePath = Path.GetDirectoryName(Assembly.GetAssembly(typeof(FastResourceLock))!.Location);
        MyLog.Default = MySandboxGame.Log;
        SpaceEngineersGame.SetupBasicGameInfo();
        _ = new MyCommonProgramStartup([]);
        MyFileSystem.Reset();
        MyFileSystem.Init(gameContentPath, userDataPath);
        MyVRage.Init(new CorePlatform());
        MyVRage.Platform.Init();
        MySandboxGame.Config = new MyConfig("SpaceEngineers.cfg");
        MySandboxGame.Config.Load();
        SpaceEngineersGame.SetupPerGameSettings();
        MyPerGameSettings.UpdateOrchestratorType = null;
        InitMultithreading();
        MyRenderProxy.Initialize(new MyNullRender());
        InitSandboxGame();
        MySession obj = (MySession)GetUninitializedObject(typeof(MySession));
        ConstructField(obj, "CreativeTools");
        ConstructField(obj, "m_sessionComponents");
        ConstructField(obj, "m_sessionComponentsForUpdate");
        obj.Settings = new MyObjectBuilder_SessionSettings
        {
            EnableVoxelDestruction = true
        };
        MySession.Static = obj;
        var myHeightMapLoadingSystem = new MyHeightMapLoadingSystem();
        obj.RegisterComponent(myHeightMapLoadingSystem, myHeightMapLoadingSystem.UpdateOrder, myHeightMapLoadingSystem.Priority);
        myHeightMapLoadingSystem.LoadData();
        var myPlanets = new MyPlanets();
        obj.RegisterComponent(myPlanets, myHeightMapLoadingSystem.UpdateOrder, myHeightMapLoadingSystem.Priority);
        myPlanets.LoadData();
        MyDefinitionManager.Static.PreloadDefinitions();
        MyDefinitionManager.Static.LoadData([]);
        MyTexts.Clear();
        var culture = Thread.CurrentThread.CurrentUICulture.IetfLanguageTag.Split(['-'], StringSplitOptions.RemoveEmptyEntries);
        var language = culture.Length > 0 ? culture[0] : null;
        var country = culture.Length > 1 ? culture[1] : null;
        MyTexts.LoadTexts(@$"{gameContentPath}\Data\Localization", language, country);
        IsDefinitionsLoadComplete = true;
    }

    private static void Preallocate()
    {
        ForceStaticCtor(
        [
            typeof(MyEntities),
            typeof(MyObjectBuilder_Base),
            typeof(MyMath)
        ]);
        static void ForceStaticCtor(IEnumerable<Type> types)
        {
            foreach (Type type in types)
            {
                RuntimeHelpers.RunClassConstructor(type.TypeHandle);
            }
        }
    }
    private static void InitMultithreading()
    {
        ParallelTasks.Parallel.Scheduler = new PrioritizedScheduler(Math.Max(Environment.ProcessorCount / 2, 1), amd: true, null);
    }

    private static void InitSandboxGame()
    {
        MySandboxGame.Static = (MySandboxGame)GetUninitializedObject(typeof(MySandboxGame));
        MySandboxGame @static = MySandboxGame.Static;
        object value = Activator.CreateInstance(typeof(MyConcurrentQueue<>).MakeGenericType(typeof(MySandboxGame).GetNestedType("MyInvokeData", BindingFlags.NonPublic)!), 32)!;
        object value2 = Activator.CreateInstance(typeof(MyConcurrentQueue<>).MakeGenericType(typeof(MySandboxGame).GetNestedType("MyInvokeData", BindingFlags.NonPublic)!), 32)!;
        typeof(MySandboxGame).GetField("m_invokeQueue", BindingFlags.Instance | BindingFlags.NonPublic)!.SetValue(@static, value);
        typeof(MySandboxGame).GetField("m_invokeQueueExecuting", BindingFlags.Instance | BindingFlags.NonPublic)!.SetValue(@static, value2);
        RegisterAssemblies();
        MyGlobalTypeMetadata.Static.Init();
        Preallocate();
    }

    private static void RegisterAssemblies()
    {
        MyPlugins.RegisterGameAssemblyFile(MyPerGameSettings.GameModAssembly);
        if (MyPerGameSettings.GameModBaseObjBuildersAssembly != null)
        {
            MyPlugins.RegisterBaseGameObjectBuildersAssemblyFile(MyPerGameSettings.GameModBaseObjBuildersAssembly);
        }

        MyPlugins.RegisterGameObjectBuildersAssemblyFile(MyPerGameSettings.GameModObjBuildersAssembly);
        MyPlugins.RegisterSandboxAssemblyFile(MyPerGameSettings.SandboxAssembly);
        MyPlugins.RegisterSandboxGameAssemblyFile(MyPerGameSettings.SandboxGameAssembly);
        MyPlugins.Load();
    }

    private static string GetBackingFieldName(string propertyName)
    {
        return $"<{propertyName}>k__BackingField";
    }
    private static FieldInfo GetFieldInfo(Type type, string fieldName)
    {
        FieldInfo field;
        do
        {
            field = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)!;
            if (field == null)
            {
                field = type.GetField(GetBackingFieldName(fieldName), BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)!;
            }
            type = type.BaseType!;
        }
        while (field == null && type != null);
        return field!;
    }
    public static void SetFieldValue(Type type, string fieldName, object val)
    {
        FieldInfo fieldInfo = GetFieldInfo(type, fieldName) ?? throw new ArgumentOutOfRangeException(nameof(fieldName), "Couldn't find field " + fieldName + " in type " + type.FullName);
        fieldInfo.SetValue(type, val);
    }
    public static object CreateInstance(Type type)
    {
        IEnumerable<object> source = from parameter in type.GetConstructors().First().GetParameters()
                                     select CreateInstance(parameter.ParameterType);
        return Activator.CreateInstance(type, source.ToArray<object>())!;
    }
    public static void ConstructField(object obj, string fieldName)
    {
        if (obj == null)
        {
            return;
        }
        FieldInfo field = obj.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)!;
        if (field == null)
        {
            return;
        }
        object value = CreateInstance(field.FieldType);
        field.SetValue(obj, value);
    }
}