Example #1
0
    public void Close()
    {
        loop.Destroy();
            loop = null;

            lua.Dispose();
            lua = null;
            loader = null;
    }
Example #2
0
    // Use this for initialization
    void Awake()
    {
        loader = new LuaLoader();
            lua = new LuaState();
            this.OpenLibs();
            lua.LuaSetTop(0);

            LuaBinder.Bind(lua);
            LuaCoroutine.Register(lua, this);
    }
Example #3
0
    // Use this for initialization;
    void Awake()
    {
        loader = new LuaLoader();
        lua    = new LuaState();
        this.OpenLibs();
        lua.LuaSetTop(0);

        LuaBinder.Bind(lua);
        DelegateFactory.Init();
        LuaCoroutine.Register(lua, this);
    }
Example #4
0
    public override void Awake()
    {
        base.Awake();
        loader = new LuaLoader();
        lua    = new LuaState();
        OpenLibs();
        lua.LuaSetTop(0);

        LuaBinder.Bind(lua);
        DelegateFactory.Init();
        LuaCoroutine.Register(lua, this);
    }
Example #5
0
    // Use this for initialization
    void Awake()
    {
        instance = this;

        loader = new LuaLoader();
        lua    = new LuaState();
        this.OpenLibs();
        lua.LuaSetTop(0);

        LuaBinder.Bind(lua);
        LuaCoroutine.Register(lua, this);
    }
Example #6
0
    public void Close()
    {
        if (loop != null)
        {
            loop.Destroy();
            loop = null;
        }

        lua.Dispose();
        lua    = null;
        loader = null;
    }
Example #7
0
 /// <summary>
 /// 初始化LUA环境
 /// </summary>
 void InitLua()
 {
     m_LuaState = new LuaState();
     OpenLibs();
     if (m_LuaLoader == null)
     {
         m_LuaLoader = new LuaLoader();
     }
     m_LuaState.LuaSetTop(0);
     LuaBinder.Bind(m_LuaState);
     DelegateFactory.Init();
     LuaCoroutine.Register(m_LuaState, this);
 }
Example #8
0
    public void Init()
    {
        _loader = new LuaLoader();
        _lua    = new LuaState();
        OpenLibs();
        lua.LuaSetTop(0);
        LuaBinder.Bind(_lua);
        DelegateFactory.Init();
        LuaCoroutine.Register(_lua, this);

        // Lua读取路径
        _loader.beZip = GameMain.Inst.ResourceMode != 0;

        // 如果是打包模式,读AB,否则读Lua目录
        if (_loader.beZip)
        {
            if (IsEncode)
            {
#if UNITY_ANDROID
                if (IntPtr.Size == 8) //64位
                {
                    cpuTypeStr = "64_";
                }
#elif UNITY_IOS
                cpuTypeStr = "64_";
#endif
            }
            _loader.AddBundle("lua_" + cpuTypeStr + "logic");
            _loader.AddBundle("lua_" + cpuTypeStr + "module");
            _loader.AddBundle("lua_" + cpuTypeStr + "tolua");
            _loader.AddBundle("lua_" + cpuTypeStr + "ui");
            _loader.AddBundle("lua_" + cpuTypeStr + "utils");
        }
        else
        {
            _lua.AddSearchPath(LuaConst.luaDir);
            _lua.AddSearchPath(LuaConst.luaDir + "/ToLua");
        }

        //启动LuaVM
        _lua.Start();

        // Lua计时
        gameObject.AddComponent <LuaLooper>().luaState = _lua;

        // 添加lua之间的引用关系
        DoFile("logic/Main");
    }
Example #9
0
    // Use this for initialization
    protected override void OnInit() 
    {
        try
        {
            loader = new LuaLoader();
            lua = new LuaState();
            this.OpenLibs();
            lua.LuaSetTop(0);
        }
        catch(System.Exception e)
        {
            Debug.Log(e.Message);
        }

        
    }
Example #10
0
        public override void Initialize()
        {
            managerObject = ManagementCenter.managerObject;

            luaSrcPath = Util.DataPath + "scripts";
            loader     = new LuaLoader(luaSrcPath);
            lua        = new LuaState();
            this.OpenLibs();
            lua.LuaSetTop(0);

            LuaBinder.Bind(lua);
            DelegateFactory.Init();
            LuaCoroutine.Register(lua, ManagementCenter.main);

            this.InitStart();   //初始化开始
        }
Example #11
0
    /// <summary>
    /// Lua环境注销
    /// </summary>
    private void UnInitLua()
    {
        if (m_LuaLoop != null)
        {
            m_LuaLoop.Destroy();
            m_LuaLoop = null;
        }

        if (m_LuaState != null)
        {
            m_LuaState.Dispose();
            m_LuaState = null;
        }

        m_LuaLoader = null;
    }
Example #12
0
    public void Close() 
    {
        if (null != loop)
        {
            loop.enabled = false;
            loop.Destroy();
            loop = null;
        }

        if (null != lua) 
        {
            lua.Dispose();
            lua = null;
        }
        
        loader = null;
    }
Example #13
0
    public void Init()
    {
        _loader = new LuaLoader();
        _lua    = new LuaState();
        OpenLibs();

        LuaBinder.Bind(_lua);
        DelegateFactory.Register();
        LuaCoroutine.Register(_lua, this);

        // Lua读取路径
        LuaFileUtils.Instance.beZip = AppConst.resourceMode != 0;

        // 如果是打包模式,读AB,否则读Lua目录
        if (LuaFileUtils.Instance.beZip)
        {
            _loader.AddBundle("lua_ui");
            _loader.AddBundle("lua_logic");
            _loader.AddBundle("lua_protobuf");
            _loader.AddBundle("lua_protocols");
            _loader.AddBundle("lua_tolua");
            _loader.AddBundle("lua_fight");
            _loader.AddBundle("lua_character");
            _loader.AddBundle("lua_utils");
            _loader.AddBundle("lua_skill");
            _loader.AddBundle("lua_cache");
        }
        else
        {
            _lua.AddSearchPath(LuaConst.luaDir);
        }

        //启动LuaVM
        _lua.Start();

        // Lua计时
        gameObject.AddComponent <LuaLooper>().luaState = _lua;

        // 添加lua之间的引用关系
        DoFile("logic/Main");
    }
Example #14
0
    void Initialization()
    {
        //new LuaResLoader();
        instance = this;
        loader   = new LuaLoader();
        lua      = new LuaState();

        DelegateFactory.Init();
        this.OpenLibs();
        lua.LuaSetTop(0);

        LuaBinder.Bind(lua);

        InitLuaPath();
        InitLuaBundle();
        this.lua.Start();    //启动LUAVM

        GameObject luaGameObject = new GameObject("LuaManger");
        LuaLooper  loop          = luaGameObject.AddComponent <LuaLooper>();

        loop.luaState = lua;
        Object.DontDestroyOnLoad(luaGameObject);
    }
Example #15
0
        /// <summary>
        /// Register a new EverestModule (mod) dynamically. Invokes LoadSettings and Load.
        /// </summary>
        /// <param name="module">Mod to register.</param>
        public static void Register(this EverestModule module)
        {
            lock (_Modules) {
                _Modules.Add(module);
            }

            LuaLoader.Precache(module.GetType().Assembly);

            bool newStrawberriesRegistered = false;

            foreach (Type type in module.GetType().Assembly.GetTypesSafe())
            {
                // Search for all entities marked with the CustomEntityAttribute.
                foreach (CustomEntityAttribute attrib in type.GetCustomAttributes <CustomEntityAttribute>())
                {
                    foreach (string idFull in attrib.IDs)
                    {
                        string   id;
                        string   genName;
                        string[] split = idFull.Split('=');

                        if (split.Length == 1)
                        {
                            id      = split[0];
                            genName = "Load";
                        }
                        else if (split.Length == 2)
                        {
                            id      = split[0];
                            genName = split[1];
                        }
                        else
                        {
                            Logger.Log(LogLevel.Warn, "core", $"Invalid number of custom entity ID elements: {idFull} ({type.FullName})");
                            continue;
                        }

                        id      = id.Trim();
                        genName = genName.Trim();

                        patch_Level.EntityLoader loader = null;

                        ConstructorInfo ctor;
                        MethodInfo      gen;

                        gen = type.GetMethod(genName, new Type[] { typeof(Level), typeof(LevelData), typeof(Vector2), typeof(EntityData) });
                        if (gen != null && gen.IsStatic && gen.ReturnType.IsCompatible(typeof(Entity)))
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)gen.Invoke(null, new object[] { level, levelData, offset, entityData });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(EntityData), typeof(Vector2), typeof(EntityID) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { entityData, offset, new EntityID(levelData.Name, entityData.ID) });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(EntityData), typeof(Vector2) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { entityData, offset });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(Vector2) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { offset });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(_EmptyTypeArray);
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(_EmptyObjectArray);
                            goto RegisterEntityLoader;
                        }

RegisterEntityLoader:
                        if (loader == null)
                        {
                            Logger.Log(LogLevel.Warn, "core", $"Found custom entity without suitable constructor / {genName}(Level, LevelData, Vector2, EntityData): {id} ({type.FullName})");
                            continue;
                        }
                        patch_Level.EntityLoaders[id] = loader;
                    }
                }
                // Register with the StrawberryRegistry all entities marked with RegisterStrawberryAttribute.
                foreach (RegisterStrawberryAttribute attrib in type.GetCustomAttributes <RegisterStrawberryAttribute>())
                {
                    List <string> names = new List <string>();
                    foreach (CustomEntityAttribute nameAttrib in type.GetCustomAttributes <CustomEntityAttribute>())
                    {
                        foreach (string idFull in nameAttrib.IDs)
                        {
                            string[] split = idFull.Split('=');
                            if (split.Length == 0)
                            {
                                Logger.Log(LogLevel.Warn, "core", $"Invalid number of custom entity ID elements: {idFull} ({type.FullName})");
                                continue;
                            }
                            names.Add(split[0]);
                        }
                    }
                    if (names.Count == 0)
                    {
                        goto NoDefinedBerryNames; // no customnames? skip out on registering berry
                    }
                    foreach (string name in names)
                    {
                        StrawberryRegistry.Register(type, name, attrib.isTracked, attrib.blocksNormalCollection);
                        newStrawberriesRegistered = true;
                    }
                }
NoDefinedBerryNames:
                ;

                // Search for all Entities marked with the CustomEventAttribute.
                foreach (CustomEventAttribute attrib in type.GetCustomAttributes <CustomEventAttribute>())
                {
                    foreach (string idFull in attrib.IDs)
                    {
                        string   id;
                        string   genName;
                        string[] split = idFull.Split('=');

                        if (split.Length == 1)
                        {
                            id      = split[0];
                            genName = "Load";
                        }
                        else if (split.Length == 2)
                        {
                            id      = split[0];
                            genName = split[1];
                        }
                        else
                        {
                            Logger.Log(LogLevel.Warn, "core", $"Invalid number of custom cutscene ID elements: {idFull} ({type.FullName})");
                            continue;
                        }

                        id      = id.Trim();
                        genName = genName.Trim();

                        patch_EventTrigger.CutsceneLoader loader = null;

                        ConstructorInfo ctor;
                        MethodInfo      gen;

                        gen = type.GetMethod(genName, new Type[] { typeof(EventTrigger), typeof(Player), typeof(string) });
                        if (gen != null && gen.IsStatic && gen.ReturnType.IsCompatible(typeof(Entity)))
                        {
                            loader = (trigger, player, eventID) => (Entity)gen.Invoke(null, new object[] { trigger, player, eventID });
                            goto RegisterCutsceneLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(EventTrigger), typeof(Player), typeof(string) });
                        if (ctor != null)
                        {
                            loader = (trigger, player, eventID) => (Entity)ctor.Invoke(new object[] { trigger, player, eventID });
                            goto RegisterCutsceneLoader;
                        }

                        ctor = type.GetConstructor(_EmptyTypeArray);
                        if (ctor != null)
                        {
                            loader = (trigger, player, eventID) => (Entity)ctor.Invoke(_EmptyObjectArray);
                            goto RegisterCutsceneLoader;
                        }

RegisterCutsceneLoader:
                        if (loader == null)
                        {
                            Logger.Log(LogLevel.Warn, "core", $"Found custom cutscene without suitable constructor / {genName}(EventTrigger, Player, string): {id} ({type.FullName})");
                            continue;
                        }
                        patch_EventTrigger.CutsceneLoaders[id] = loader;
                    }
                }
            }

            module.LoadSettings();
            module.Load();
            if (_ContentLoaded)
            {
                module.LoadContent(true);
            }
            if (_Initialized)
            {
                Tracker.Initialize();
                module.Initialize();
                Input.Initialize();

                if (SaveData.Instance != null)
                {
                    // we are in a save. we are expecting the save data to already be loaded at this point
                    Logger.Log("core", $"Loading save data slot {SaveData.Instance.FileSlot} for {module.Metadata}");
                    module.LoadSaveData(SaveData.Instance.FileSlot);

                    if (SaveData.Instance.CurrentSession?.InArea ?? false)
                    {
                        // we are in a level. we are expecting the session to already be loaded at this point
                        Logger.Log("core", $"Loading session slot {SaveData.Instance.FileSlot} for {module.Metadata}");
                        module.LoadSession(SaveData.Instance.FileSlot, false);
                    }
                }

                // Check if the module defines a PrepareMapDataProcessors method. If this is the case, we want to reload maps so that they are applied.
                // We should also run the map data processors again if new berry types are registered, so that CoreMapDataProcessor assigns them checkpoint IDs and orders.
                if (newStrawberriesRegistered || module.GetType().GetMethod("PrepareMapDataProcessors", new Type[] { typeof(MapDataFixup) })?.DeclaringType == module.GetType())
                {
                    Logger.Log("core", $"Module {module.Metadata} has custom strawberries or map data processors: reloading maps.");
                    AssetReloadHelper.ReloadAllMaps();
                }
            }

            if (Engine.Instance != null && Engine.Scene is Overworld overworld)
            {
                // we already are in the overworld. Register new Ouis real quick!
                Type[] types = FakeAssembly.GetFakeEntryAssembly().GetTypesSafe();
                foreach (Type type in types)
                {
                    if (typeof(Oui).IsAssignableFrom(type) && !type.IsAbstract && !overworld.UIs.Any(ui => ui.GetType() == type))
                    {
                        Logger.Log("core", $"Instanciating UI from {module.Metadata}: {type.FullName}");

                        Oui oui = (Oui)Activator.CreateInstance(type);
                        oui.Visible = false;
                        overworld.Add(oui);
                        overworld.UIs.Add(oui);
                    }
                }
            }

            InvalidateInstallationHash();

            EverestModuleMetadata meta = module.Metadata;

            meta.Hash = GetChecksum(meta);

            // Audio banks are cached, and as such use the module's hash. We can only ingest those now.
            if (patch_Audio.AudioInitialized)
            {
                patch_Audio.IngestNewBanks();
            }

            Logger.Log(LogLevel.Info, "core", $"Module {module.Metadata} registered.");

            CheckDependenciesOfDelayedMods();
        }
Example #16
0
        internal static void Boot()
        {
            Logger.Log(LogLevel.Info, "core", "Booting Everest");
            Logger.Log(LogLevel.Info, "core", $"AppDomain: {AppDomain.CurrentDomain.FriendlyName ?? "???"}");
            Logger.Log(LogLevel.Info, "core", $"VersionCelesteString: {VersionCelesteString}");

            if (Type.GetType("Mono.Runtime") != null)
            {
                // Mono hates HTTPS.
                ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => {
                    return(true);
                };
            }

            // enable TLS 1.2 to fix connecting to everestapi.github.io
            ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

            PathGame = Path.GetDirectoryName(typeof(Celeste).Assembly.Location);

            // .NET hates it when strong-named dependencies get updated.
            AppDomain.CurrentDomain.AssemblyResolve += (asmSender, asmArgs) => {
                AssemblyName asmName = new AssemblyName(asmArgs.Name);
                if (!asmName.Name.StartsWith("Mono.Cecil") &&
                    !asmName.Name.StartsWith("YamlDotNet") &&
                    !asmName.Name.StartsWith("NLua"))
                {
                    return(null);
                }

                Assembly asm = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(other => other.GetName().Name == asmName.Name);
                if (asm != null)
                {
                    return(asm);
                }

                return(Assembly.LoadFrom(Path.Combine(PathGame, asmName.Name + ".dll")));
            };

            // .NET hates to acknowledge manually loaded assemblies.
            AppDomain.CurrentDomain.AssemblyResolve += (asmSender, asmArgs) => {
                AssemblyName asmName = new AssemblyName(asmArgs.Name);
                foreach (Assembly asm in _RelinkedAssemblies)
                {
                    if (asm.GetName().Name == asmName.Name)
                    {
                        return(asm);
                    }
                }

                return(null);
            };

            // Preload some basic dependencies.
            Assembly.Load("MonoMod.RuntimeDetour");
            Assembly.Load("MonoMod.Utils");
            Assembly.Load("Mono.Cecil");
            Assembly.Load("YamlDotNet");
            Assembly.Load("Newtonsoft.Json");
            Assembly.Load("Jdenticon");

            if (!File.Exists(Path.Combine(PathGame, "EverestXDGFlag")))
            {
                XDGPaths    = false;
                PathEverest = PathGame;
            }
            else
            {
                XDGPaths = true;
                string dataDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                Directory.CreateDirectory(PathEverest = Path.Combine(dataDir, "Everest"));
                Directory.CreateDirectory(Path.Combine(dataDir, "Everest", "Mods")); // Make sure it exists before content gets initialized
            }

            // Old versions of Everest have used a separate ModSettings folder.
            string modSettingsOld = Path.Combine(PathEverest, "ModSettings");
            string modSettingsRIP = Path.Combine(PathEverest, "ModSettings-OBSOLETE");

            if (Directory.Exists(modSettingsOld) || Directory.Exists(modSettingsRIP))
            {
                Logger.Log(LogLevel.Warn, "core", "THE ModSettings FOLDER IS OBSOLETE AND WILL NO LONGER BE USED!");
                if (Directory.Exists(modSettingsOld) && !Directory.Exists(modSettingsRIP))
                {
                    Directory.Move(modSettingsOld, modSettingsRIP);
                }
            }

            _DetourModManager           = new DetourModManager();
            _DetourModManager.OnILHook += (owner, from, to) => {
                _DetourOwners.Add(owner);
                object target = to.Target;
                _DetourLog.Add($"new ILHook by {owner.GetName().Name}: {from.GetID()} -> {to.Method?.GetID() ?? "???"}" + (target == null ? "" : $" (target: {target})"));
            };
            _DetourModManager.OnHook += (owner, from, to, target) => {
                _DetourOwners.Add(owner);
                _DetourLog.Add($"new Hook by {owner.GetName().Name}: {from.GetID()} -> {to.GetID()}" + (target == null ? "" : $" (target: {target})"));
            };
            _DetourModManager.OnDetour += (owner, from, to) => {
                _DetourOwners.Add(owner);
                _DetourLog.Add($"new Detour by {owner.GetName().Name}: {from.GetID()} -> {to.GetID()}");
            };
            _DetourModManager.OnNativeDetour += (owner, fromMethod, from, to) => {
                _DetourOwners.Add(owner);
                _DetourLog.Add($"new NativeDetour by {owner.GetName().Name}: {fromMethod?.ToString() ?? from.ToString("16X")} -> {to.ToString("16X")}");
            };
            HookEndpointManager.OnAdd += (from, to) => {
                Assembly owner = HookEndpointManager.GetOwner(to) as Assembly ?? typeof(Everest).Assembly;
                _DetourOwners.Add(owner);
                object target = to.Target;
                _DetourLog.Add($"new On.+= by {owner.GetName().Name}: {from.GetID()} -> {to.Method?.GetID() ?? "???"}" + (target == null ? "" : $" (target: {target})"));
                return(true);
            };
            HookEndpointManager.OnModify += (from, to) => {
                Assembly owner = HookEndpointManager.GetOwner(to) as Assembly ?? typeof(Everest).Assembly;
                _DetourOwners.Add(owner);
                object target = to.Target;
                _DetourLog.Add($"new IL.+= by {owner.GetName().Name}: {from.GetID()} -> {to.Method?.GetID() ?? "???"}" + (target == null ? "" : $" (target: {target})"));
                return(true);
            };

            // Before even initializing anything else, make sure to prepare any static flags.
            Flags.Initialize();

            // 0.1 parses into 1 in regions using ,
            // This also somehow sets the exception message language to English.
            CultureInfo.DefaultThreadCurrentCulture   = CultureInfo.InvariantCulture;
            CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;

            if (!Flags.IsHeadless)
            {
                // Initialize the content helper.
                Content.Initialize();

                // Initialize all main managers before loading any mods.
                TouchInputManager.Instance = new TouchInputManager(Celeste.Instance);
                // Don't add it yet, though - add it in Initialize.
            }

            MainThreadHelper.Instance = new MainThreadHelper(Celeste.Instance);

            // Register our core module and load any other modules.
            new CoreModule().Register();

            // Note: Everest fulfills some mod dependencies by itself.
            new NullModule(new EverestModuleMetadata()
            {
                Name          = "Celeste",
                VersionString = $"{Celeste.Instance.Version.ToString()}-{(typeof(Game).Assembly.FullName.Contains("FNA") ? "fna" : "xna")}"
            }).Register();
            new NullModule(new EverestModuleMetadata()
            {
                Name          = "DialogCutscene",
                VersionString = "1.0.0"
            }).Register();
            new NullModule(new EverestModuleMetadata()
            {
                Name          = "UpdateChecker",
                VersionString = "1.0.2"
            }).Register();

            LuaLoader.Initialize();

            Loader.LoadAuto();

            if (!Flags.IsHeadless)
            {
                // Load stray .bins afterwards.
                Content.Crawl(new MapBinsInModsModContent(Path.Combine(PathEverest, "Mods")));
            }

            // Also let all mods parse the arguments.
            Queue <string> args = new Queue <string>(Args);

            while (args.Count > 0)
            {
                string arg = args.Dequeue();
                foreach (EverestModule mod in _Modules)
                {
                    if (mod.ParseArg(arg, args))
                    {
                        break;
                    }
                }
            }

            // Start requesting the version list ASAP.
            Updater.RequestAll();

            // Request the mod update list as well.
            ModUpdaterHelper.RunAsyncCheckForModUpdates(excludeBlacklist: true);
        }
Example #17
0
 public bool LuaAssetBundleIsLoaded(string luaAssetBundlePath)
 {
     return(LuaLoader.LuaFileIsLoaded(luaAssetBundlePath));
 }
Example #18
0
 protected override LuaFileUtils InitLoader()
 {
     luaLoader = new LuaLoader();
     return(luaLoader);
 }
Example #19
0
        /// <summary>
        /// Register a new EverestModule (mod) dynamically. Invokes LoadSettings and Load.
        /// </summary>
        /// <param name="module">Mod to register.</param>
        public static void Register(this EverestModule module)
        {
            lock (_Modules) {
                _Modules.Add(module);
                _ModuleTypes.Add(module.GetType());
            }

            LuaLoader.Precache(module.GetType().Assembly);

            foreach (Type type in module.GetType().Assembly.GetTypes())
            {
                // Search for all entities marked with the CustomEntityAttribute.
                foreach (CustomEntityAttribute attrib in type.GetCustomAttributes <CustomEntityAttribute>())
                {
                    foreach (string idFull in attrib.IDs)
                    {
                        string   id;
                        string   genName;
                        string[] split = idFull.Split('=');

                        if (split.Length == 1)
                        {
                            id      = split[0];
                            genName = "Load";
                        }
                        else if (split.Length == 2)
                        {
                            id      = split[0];
                            genName = split[1];
                        }
                        else
                        {
                            Logger.Log(LogLevel.Warn, "core", $"Invalid number of custom entity ID elements: {idFull} ({type.FullName})");
                            continue;
                        }

                        id      = id.Trim();
                        genName = genName.Trim();

                        patch_Level.EntityLoader loader = null;

                        ConstructorInfo ctor;
                        MethodInfo      gen;

                        gen = type.GetMethod(genName, new Type[] { typeof(Level), typeof(LevelData), typeof(Vector2), typeof(EntityData) });
                        if (gen != null && gen.IsStatic && gen.ReturnType.IsCompatible(typeof(Entity)))
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)gen.Invoke(null, new object[] { level, levelData, offset, entityData });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(EntityData), typeof(Vector2), typeof(EntityID) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { entityData, offset, new EntityID(levelData.Name, entityData.ID) });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(EntityData), typeof(Vector2) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { entityData, offset });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(Vector2) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { offset });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(_EmptyTypeArray);
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(_EmptyObjectArray);
                            goto RegisterEntityLoader;
                        }

RegisterEntityLoader:
                        if (loader == null)
                        {
                            Logger.Log(LogLevel.Warn, "core", $"Found custom entity without suitable constructor / {genName}(Level, LevelData, Vector2, EntityData): {id} ({type.FullName})");
                            continue;
                        }
                        patch_Level.EntityLoaders[id] = loader;
                    }
                }
            }

            module.LoadSettings();
            module.Load();
            if (_Initialized)
            {
                module.Initialize();
            }

            InvalidateInstallationHash();

            EverestModuleMetadata meta = module.Metadata;

            meta.Hash = GetChecksum(meta);

            Logger.Log(LogLevel.Info, "core", $"Module {module.Metadata} registered.");

            // Attempt to load mods after their dependencies have been loaded.
            // Only load and lock the delayed list if we're not already loading delayed mods.
            if (Interlocked.CompareExchange(ref Loader.DelayedLock, 1, 0) == 0)
            {
                lock (Loader.Delayed) {
                    for (int i = Loader.Delayed.Count - 1; i > -1; i--)
                    {
                        Tuple <EverestModuleMetadata, Action> entry = Loader.Delayed[i];
                        if (!Loader.DependenciesLoaded(entry.Item1))
                        {
                            continue;
                        }

                        Loader.LoadMod(entry.Item1);
                        Loader.Delayed.RemoveAt(i);

                        entry.Item2?.Invoke();
                    }
                }
                Interlocked.Decrement(ref Loader.DelayedLock);
            }
        }
Example #20
0
        /// <summary>
        /// Register a new EverestModule (mod) dynamically. Invokes LoadSettings and Load.
        /// </summary>
        /// <param name="module">Mod to register.</param>
        public static void Register(this EverestModule module)
        {
            lock (_Modules) {
                _Modules.Add(module);
            }

            LuaLoader.Precache(module.GetType().Assembly);

            foreach (Type type in module.GetType().Assembly.GetTypes())
            {
                // Search for all entities marked with the CustomEntityAttribute.
                foreach (CustomEntityAttribute attrib in type.GetCustomAttributes <CustomEntityAttribute>())
                {
                    foreach (string idFull in attrib.IDs)
                    {
                        string   id;
                        string   genName;
                        string[] split = idFull.Split('=');

                        if (split.Length == 1)
                        {
                            id      = split[0];
                            genName = "Load";
                        }
                        else if (split.Length == 2)
                        {
                            id      = split[0];
                            genName = split[1];
                        }
                        else
                        {
                            Logger.Log(LogLevel.Warn, "core", $"Invalid number of custom entity ID elements: {idFull} ({type.FullName})");
                            continue;
                        }

                        id      = id.Trim();
                        genName = genName.Trim();

                        patch_Level.EntityLoader loader = null;

                        ConstructorInfo ctor;
                        MethodInfo      gen;

                        gen = type.GetMethod(genName, new Type[] { typeof(Level), typeof(LevelData), typeof(Vector2), typeof(EntityData) });
                        if (gen != null && gen.IsStatic && gen.ReturnType.IsCompatible(typeof(Entity)))
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)gen.Invoke(null, new object[] { level, levelData, offset, entityData });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(EntityData), typeof(Vector2), typeof(EntityID) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { entityData, offset, new EntityID(levelData.Name, entityData.ID) });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(EntityData), typeof(Vector2) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { entityData, offset });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(new Type[] { typeof(Vector2) });
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(new object[] { offset });
                            goto RegisterEntityLoader;
                        }

                        ctor = type.GetConstructor(_EmptyTypeArray);
                        if (ctor != null)
                        {
                            loader = (level, levelData, offset, entityData) => (Entity)ctor.Invoke(_EmptyObjectArray);
                            goto RegisterEntityLoader;
                        }

RegisterEntityLoader:
                        if (loader == null)
                        {
                            Logger.Log(LogLevel.Warn, "core", $"Found custom entity without suitable constructor / {genName}(Level, LevelData, Vector2, EntityData): {id} ({type.FullName})");
                            continue;
                        }
                        patch_Level.EntityLoaders[id] = loader;
                    }
                }
                // Register with the StrawberryRegistry all entities marked with RegisterStrawberryAttribute.
                foreach (RegisterStrawberryAttribute attrib in type.GetCustomAttributes <RegisterStrawberryAttribute>())
                {
                    List <string> names = new List <string>();
                    foreach (CustomEntityAttribute nameAttrib in type.GetCustomAttributes <CustomEntityAttribute>())
                    {
                        foreach (string idFull in nameAttrib.IDs)
                        {
                            string[] split = idFull.Split('=');
                            if (split.Length == 0)
                            {
                                Logger.Log(LogLevel.Warn, "core", $"Invalid number of custom entity ID elements: {idFull} ({type.FullName})");
                                continue;
                            }
                            names.Add(split[0]);
                        }
                    }
                    if (names.Count == 0)
                    {
                        goto NoDefinedBerryNames; // no customnames? skip out on registering berry
                    }
                    foreach (string name in names)
                    {
                        StrawberryRegistry.Register(type, name, attrib.isTracked, attrib.blocksNormalCollection);
                    }
                }
NoDefinedBerryNames:
                ;
            }

            module.LoadSettings();
            module.Load();
            if (_ContentLoaded)
            {
                module.LoadContent(true);
            }
            if (_Initialized)
            {
                Tracker.Initialize();
                module.Initialize();

                // check if the module defines a PrepareMapDataProcessors method. If this is the case, we want to reload maps so that they are applied.
                if (module.GetType().GetMethod("PrepareMapDataProcessors", new Type[] { typeof(MapDataFixup) })?.DeclaringType == module.GetType())
                {
                    Logger.Log("core", $"Module {module.Metadata} has map data processors: reloading maps.");
                    OuiHelper_ChapterSelect_Reload.Reload(false);
                }
            }

            if (Engine.Instance != null && Engine.Scene is Overworld overworld)
            {
                // we already are in the overworld. Register new Ouis real quick!
                Type[] types = FakeAssembly.GetFakeEntryAssembly().GetTypes();
                foreach (Type type in types)
                {
                    if (typeof(Oui).IsAssignableFrom(type) && !type.IsAbstract && !overworld.UIs.Any(ui => ui.GetType() == type))
                    {
                        Logger.Log("core", $"Instanciating UI from {module.Metadata}: {type.FullName}");

                        Oui oui = (Oui)Activator.CreateInstance(type);
                        oui.Visible = false;
                        overworld.Add(oui);
                        overworld.UIs.Add(oui);
                    }
                }
            }

            InvalidateInstallationHash();

            EverestModuleMetadata meta = module.Metadata;

            meta.Hash = GetChecksum(meta);

            // Audio banks are cached, and as such use the module's hash. We can only ingest those now.
            if (patch_Audio.AudioInitialized)
            {
                patch_Audio.IngestNewBanks();
            }

            Logger.Log(LogLevel.Info, "core", $"Module {module.Metadata} registered.");

            // Attempt to load mods after their dependencies have been loaded.
            // Only load and lock the delayed list if we're not already loading delayed mods.
            if (Interlocked.CompareExchange(ref Loader.DelayedLock, 1, 0) == 0)
            {
                try {
                    lock (Loader.Delayed) {
                        for (int i = 0; i < Loader.Delayed.Count; i++)
                        {
                            Tuple <EverestModuleMetadata, Action> entry = Loader.Delayed[i];
                            if (!Loader.DependenciesLoaded(entry.Item1))
                            {
                                continue; // dependencies are still missing!
                            }
                            Logger.Log(LogLevel.Info, "core", $"Dependencies of mod {entry.Item1} are now satisfied: loading");
                            entry.Item2?.Invoke();
                            Loader.LoadMod(entry.Item1);
                            Loader.Delayed.RemoveAt(i);

                            // we now loaded an extra mod, consider all delayed mods again to deal with transitive dependencies.
                            i = -1;
                        }
                    }
                } finally {
                    Interlocked.Decrement(ref Loader.DelayedLock);
                }
            }
        }
Example #21
0
 public void Close()
 {
     lua.Dispose();
     lua    = null;
     loader = null;
 }