public void Close() { loop.Destroy(); loop = null; lua.Dispose(); lua = null; loader = null; }
// Use this for initialization void Awake() { loader = new LuaLoader(); lua = new LuaState(); this.OpenLibs(); lua.LuaSetTop(0); LuaBinder.Bind(lua); LuaCoroutine.Register(lua, this); }
// 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); }
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); }
// 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); }
public void Close() { if (loop != null) { loop.Destroy(); loop = null; } lua.Dispose(); lua = null; loader = null; }
/// <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); }
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"); }
// 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); } }
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(); //初始化开始 }
/// <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; }
public void Close() { if (null != loop) { loop.enabled = false; loop.Destroy(); loop = null; } if (null != lua) { lua.Dispose(); lua = null; } loader = null; }
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"); }
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); }
/// <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(); }
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); }
public bool LuaAssetBundleIsLoaded(string luaAssetBundlePath) { return(LuaLoader.LuaFileIsLoaded(luaAssetBundlePath)); }
protected override LuaFileUtils InitLoader() { luaLoader = new LuaLoader(); return(luaLoader); }
/// <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); } }
/// <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); } } }
public void Close() { lua.Dispose(); lua = null; loader = null; }