public override List <AssetOp> GetInstallOps(ModContext context) { if (InstallAction == null) { throw new InvalidOperationException("Tried to install AssetsModComponent, but install action is null."); } if (InstallAction.Actions == null || InstallAction.Actions.Count < 1) { throw new InvalidOperationException("Install action has no asset actions defined!"); } using (new LogTiming("preloading asset files for assets mod")) { if (InstallAction.PreloadFiles != null) { InstallAction.PreloadFiles.ForEach(x => context.GetEngine().Manager.GetAssetsFile(x)); } } List <AssetOp> ops = new List <AssetOp>(); foreach (var action in InstallAction.Actions.OrderBy(x => x.StepNumber)) { using (new LogTiming($"getting operations for asset mod action step {action.StepNumber}")) { ops.AddRange(action.GetOps(context)); } } Log.LogMsg($"Returning {ops.Count} for assets mod component installation..."); return(ops); }
public override IEnumerable <AssetOp> GetOps(ModContext context) { //TODO: I don't like the root path constant here. Get rid of it. if (!context.Config.RootFileProvider.FileExists(context.ModPath.CombineFwdSlash(FromDataFile))) { throw new Exception($"ReplaceAssetsAction could not find the asset data file {FromDataFile}"); } if (Locator == null) { throw new Exception("Locator is null for ReplaceAssetsAction!"); } byte[] assetData; try { assetData = context.Config.RootFileProvider.Read(context.ModPath.CombineFwdSlash(FromDataFile)); } catch (Exception ex) { Log.LogMsg($"Exception reading {FromDataFile} for ReplaceAssetAction.", ex); throw new Exception($"ReplaceAssetAction could not read data file {FromDataFile}", ex); } yield return(new ReplaceAssetOp(Locator, assetData, AllowOverwriteName)); }
public void LoadMods(string modsPath) { if (Directory.Exists(modsPath)) { foreach (string localModPath in Directory.GetDirectories(modsPath)) { if (!ModContext.IsValidModPath(localModPath)) { // Debug.LogWarning($"Invalid mod path, skipping {localModPath}"); // there are also blueprints in this folder continue; } var mod = ModContext.FromFolderPath(localModPath); if (mods.ContainsKey(mod.Description.LocalId)) { Debug.LogWarning($"This mod is already loaded, skipping {localModPath}"); } else { mods.TryAdd(mod.Description.LocalId, mod); mod.LoadModShapes(); LoadLanguageFiles(Path.Combine(mod.ModFolderPath, "Gui", "Language")); } } } }
/// <summary> /// 获取当前数据上下文 /// </summary> /// <returns></returns> public static ModContext GetCurrentContext() { var nContext = CallContext.GetData("ModContext") as ModContext; if (nContext == null) { nContext = new ModContext(); CallContext.SetData("ModContext", nContext); } return nContext; }
public Part(PartData partData, ModContext mod = null) : base(mod) { this.partData = partData; this.partData.LoadRenderableData(mod?.ModFolderPath); // load json file //importer.SetConfig(new Assimp.Configs.MeshVertexLimitConfig(60000)); //importer.SetConfig(new Assimp.Configs.MeshTriangleLimitConfig(60000)); //importer.SetConfig(new Assimp.Configs.RemoveDegeneratePrimitivesConfig(true)); //importer.SetConfig(new Assimp.Configs.SortByPrimitiveTypeConfig(Assimp.PrimitiveType.Line | Assimp.PrimitiveType.Point)); //Assimp.PostProcessSteps postProcessSteps = Assimp.PostProcessPreset.TargetRealTimeMaximumQuality | Assimp.PostProcessSteps.MakeLeftHanded | Assimp.PostProcessSteps.FlipWindingOrder; }
public static void LoadShapes(PartListData partListData, ModContext mod = null) // modUuid can be "vanilla" { if (partListData.PartList != null) { Parallel.ForEach(partListData.PartList, partData => { var part = new Part(partData, mod); loadedShapes.TryAdd(partData.Uuid, part); }); } if (partListData.BlockList != null) { Parallel.ForEach(partListData.BlockList, blockData => { var block = new Block(blockData, mod); loadedShapes.TryAdd(blockData.Uuid, block); }); } }
public IEnumerable <ModContext> Activate() { List <ModContext> mods = new List <ModContext>(); var runtime = _modDirectory.EnumerateFiles().First( f => f.Extension == ".dll"); var modAss = Assembly.LoadFile(runtime.FullName); var primaryModule = modAss.Modules.First(); var modEntries = primaryModule.GetTypes().Where(t => typeof(ISoLModV1).IsAssignableFrom(t)); foreach (var modEntry in modEntries) { ISoLModV1 mod = (ISoLModV1)Activator.CreateInstance(modEntry); ModContext ctx = new ModContext(mod, _modDirectory); mod.Init(AnankeContext.Current, ctx); mods.Add(ctx); } return(mods); }
public void LoadMods() { var knownMods = this.Config.KnownMods; GlobalLog.Default.PrintLine("Total known mods: " + knownMods.Count); foreach (var modInfo in knownMods) { var modIdentifier = ModUtils.GetReadableIdentifier(modInfo); if (modInfo.Active == false) { GlobalLog.Debug.PrintLine("Skipping (not active): " + modIdentifier); continue; } using (GlobalLog.Default.OpenScope("Loading: " + modIdentifier, "Finished loading: " + modIdentifier)) { var modContext = new ModContext(modInfo); this.LoadedMods.Add(modContext); } } }
public Mod(ModContext context) { _modLoader = context.ModLoader; _hooks = context.Hooks; _logger = context.Logger; _owner = context.Owner; #if (IncludeConfig) _configuration = context.Configuration; #endif _modConfig = context.ModConfig; #if DEBUG // Attaches debugger in debug mode; ignored in release. Debugger.Launch(); #endif // For more information about this template, please see // https://reloaded-project.github.io/Reloaded-II/ModTemplate/ // If you want to implement e.g. unload support in your mod, // and some other neat features, override the methods in ModBase. // TODO: Implement some mod logic }
public PathHelper(ModContext context) { localDir = context.ModDirectory; }
public abstract IEnumerable <AssetOps.AssetOp> GetOps(ModContext context);
internal static IEnumerable <IModContext <IFallout4Mod, IMajorRecordCommon, IMajorRecordCommonGetter> > EnumerateMajorRecordContexts( this IReadOnlyList <IWorldspaceBlockGetter> worldspaceBlocks, IWorldspaceGetter worldspace, ILinkCache linkCache, Type type, ModKey modKey, IModContext?parent, bool throwIfUnknown, Func <IFallout4Mod, IWorldspaceGetter, IWorldspace> getOrAddAsOverride, Func <IFallout4Mod, IWorldspaceGetter, string?, IWorldspace> duplicateInto) { foreach (var readOnlyBlock in worldspaceBlocks) { var blockNumX = readOnlyBlock.BlockNumberX; var blockNumY = readOnlyBlock.BlockNumberY; var blockContext = new ModContext <IWorldspaceBlockGetter>( modKey: modKey, parent: parent, record: readOnlyBlock); foreach (var readOnlySubBlock in readOnlyBlock.Items) { var subBlockNumY = readOnlySubBlock.BlockNumberY; var subBlockNumX = readOnlySubBlock.BlockNumberX; var subBlockContext = new ModContext <IWorldspaceSubBlockGetter>( modKey: modKey, parent: blockContext, record: readOnlySubBlock); foreach (var readOnlyCell in readOnlySubBlock.Items) { Func <IFallout4Mod, ICellGetter, bool, string?, ICell> cellGetter = (mod, copyCell, dup, edid) => { var worldspaceCopy = getOrAddAsOverride(mod, worldspace); var formKey = copyCell.FormKey; var retrievedBlock = worldspaceCopy.SubCells.FirstOrDefault(x => x.BlockNumberX == blockNumX && x.BlockNumberY == blockNumY); if (retrievedBlock == null) { retrievedBlock = new WorldspaceBlock() { BlockNumberX = blockNumX, BlockNumberY = blockNumY, GroupType = GroupTypeEnum.ExteriorCellBlock, }; worldspaceCopy.SubCells.Add(retrievedBlock); } var subBlock = retrievedBlock.Items.FirstOrDefault(x => x.BlockNumberX == subBlockNumX && x.BlockNumberY == subBlockNumY); if (subBlock == null) { subBlock = new WorldspaceSubBlock() { BlockNumberX = subBlockNumX, BlockNumberY = subBlockNumY, GroupType = GroupTypeEnum.ExteriorCellSubBlock, }; retrievedBlock.Items.Add(subBlock); } var cell = subBlock.Items.FirstOrDefault(cell => cell.FormKey == formKey); if (cell == null) { if (dup) { cell = copyCell.Duplicate(mod.GetNextFormKey(edid), CellCopyMask); } else { cell = copyCell.DeepCopy(CellCopyMask); } subBlock.Items.Add(cell); } return(cell); }; if (LoquiRegistration.TryGetRegister(type, out var regis) && regis.ClassType == typeof(Cell)) { yield return(new ModContext <IFallout4Mod, IMajorRecordCommon, IMajorRecordCommonGetter>( modKey: modKey, record: readOnlyCell, getOrAddAsOverride: (m, r) => cellGetter(m, (ICellGetter)r, false, default(string?)), duplicateInto: (m, r, e) => cellGetter(m, (ICellGetter)r, true, e), parent: subBlockContext)); } else { foreach (var con in CellCommon.Instance.EnumerateMajorRecordContexts( readOnlyCell, linkCache, type, modKey, subBlockContext, throwIfUnknown, (m, c) => cellGetter(m, c, false, default(string?)), (m, c, e) => cellGetter(m, c, true, e))) { yield return(con); } } } } } }
public override IEnumerable <AssetOp> GetOps(ModContext context) { if (Locator == null) { throw new Exception("Locator is null for RestoreAssetsAction!"); } if (context.BackupEngine == null) { throw new Exception("BackupEngine is not set in the context!"); } byte[] assetData = null; try { var bqae = context.BackupEngine; var fromAsset = Locator.Locate(bqae.Manager); if (fromAsset == null) { throw new Exception($"Unable to locate asset in backup apk for mod uninstallation on step {StepNumber}!"); } using (var ms = new MemoryStream()) { using (var writer = new AssetsWriter(ms)) { fromAsset.Write(writer); } ms.Seek(0, SeekOrigin.Begin); assetData = ms.ToArray(); } } catch (Exception ex) { Log.LogErr("Exception while restoring asset!", ex); throw; } AssetLocator locatorOverride = null; try { var res = Locator.Locate(context.GetEngine().Manager, false); if (res == null) { throw new LocatorException("Unable to find asset."); } } catch (LocatorException ex) { Log.LogErr($"The locator for restore threw an exception, attempting to locate against backup and identify path.", ex); try { var res = Locator.Locate(context.BackupEngine.Manager, false); if (res == null) { throw new LocatorException("Unable to find asset, locator returned null"); } locatorOverride = new AssetLocator() { PathIs = new PathLocator() { AssetFilename = res.ObjectInfo.ParentFile.AssetsFilename, PathID = res.ObjectInfo.ObjectID } }; } catch (Exception ex2) { Log.LogErr($"Unable to find path in backup for the locator either", ex2); throw ex; } } yield return(new ReplaceAssetOp(locatorOverride ?? Locator, assetData, true)); }
public Block(BlockData blockData, ModContext mod = null) : base(mod) { this.blockData = blockData; }
internal static IEnumerable <IModContext <IOblivionMod, IOblivionModGetter, IMajorRecordCommon, IMajorRecordCommonGetter> > EnumerateMajorRecordContexts( this IListGroupGetter <ICellBlockGetter> cellBlocks, ILinkCache linkCache, Type type, ModKey modKey, IModContext?parent, bool throwIfUnknown) { foreach (var readOnlyBlock in cellBlocks.Records) { var blockNum = readOnlyBlock.BlockNumber; var blockModified = readOnlyBlock.LastModified; var blockContext = new ModContext <ICellBlockGetter>( modKey: modKey, parent: parent, record: readOnlyBlock); foreach (var readOnlySubBlock in readOnlyBlock.SubBlocks) { var subBlockNum = readOnlySubBlock.BlockNumber; var subBlockModified = readOnlySubBlock.LastModified; var subBlockContext = new ModContext <ICellSubBlockGetter>( modKey: modKey, parent: blockContext, record: readOnlySubBlock); foreach (var readOnlyCell in readOnlySubBlock.Cells) { Func <IOblivionMod, ICellGetter, bool, string?, ICell> cellGetter = (mod, copyCell, dup, edid) => { var formKey = copyCell.FormKey; var retrievedBlock = mod.Cells.Records.FirstOrDefault(x => x.BlockNumber == blockNum); if (retrievedBlock == null) { retrievedBlock = new CellBlock() { BlockNumber = blockNum, GroupType = GroupTypeEnum.InteriorCellBlock, LastModified = blockModified, }; mod.Cells.Records.Add(retrievedBlock); } var subBlock = retrievedBlock.SubBlocks.FirstOrDefault(x => x.BlockNumber == subBlockNum); if (subBlock == null) { subBlock = new CellSubBlock() { BlockNumber = subBlockNum, GroupType = GroupTypeEnum.InteriorCellSubBlock, LastModified = subBlockModified, }; retrievedBlock.SubBlocks.Add(subBlock); } var cell = subBlock.Cells.FirstOrDefault(cell => cell.FormKey == formKey); if (cell == null) { if (dup) { cell = copyCell.Duplicate(mod.GetNextFormKey(edid), CellCopyMask); } else { cell = copyCell.DeepCopy(CellCopyMask); } subBlock.Cells.Add(cell); } return(cell); }; if (LoquiRegistration.TryGetRegister(type, out var regis) && regis.ClassType == typeof(Cell)) { yield return(new ModContext <IOblivionMod, IOblivionModGetter, IMajorRecordCommon, IMajorRecordCommonGetter>( modKey: modKey, record: readOnlyCell, getOrAddAsOverride: (m, r) => cellGetter(m, (ICellGetter)r, false, default(string?)), duplicateInto: (m, r, e) => cellGetter(m, (ICellGetter)r, true, e), parent: subBlockContext)); } else { foreach (var con in CellCommon.Instance.EnumerateMajorRecordContexts( readOnlyCell, linkCache, type, modKey, subBlockContext, throwIfUnknown, (m, c) => cellGetter(m, c, false, default(string?)), (m, c, e) => cellGetter(m, c, true, e))) { yield return(con); } } } } } }
public override List <AssetOp> GetUninstallOps(ModContext context) { if (UninstallAction == null) { throw new InvalidOperationException("Tried to install AssetsModComponent, but uninstall action is null."); } if (UninstallAction.Actions == null || UninstallAction.Actions.Count < 1) { throw new InvalidOperationException("Uninstall action has no asset actions defined!"); } if (string.IsNullOrEmpty(context.Config.BackupApkFileAbsolutePath)) { throw new InvalidOperationException("Uninstall assets mod can't happen when the backup APK isn't set!"); } string backup = null; if (!File.Exists(context.Config.BackupApkFileAbsolutePath)) { Log.LogErr($"WARNING: primary APK backup doesn't exist at {context.Config.BackupApkFileAbsolutePath}, will attempt to fall back..."); if (!File.Exists(context.Config.ModdedFallbackBackupPath)) { throw new Exception($"Backup APK file does not exist at {context.Config.BackupApkFileAbsolutePath} and even the fallback doesn't exist at {context.Config.ModdedFallbackBackupPath}"); } else { backup = context.Config.ModdedFallbackBackupPath; } } else { backup = context.Config.BackupApkFileAbsolutePath; } using (new LogTiming("preloading asset files for uninstall assets mod")) { if (UninstallAction.PreloadFiles != null) { UninstallAction.PreloadFiles.ForEach(x => context.GetEngine().Manager.GetAssetsFile(x)); } } Log.LogMsg($"Opening backup APK..."); List <AssetOp> ops = new List <AssetOp>(); using (var apk = new ZipFileProvider(backup, FileCacheMode.Memory, true, FileUtils.GetTempDirectory())) { var backupCfg = new QaeConfig() { AssetsPath = BeatSaber.BSConst.KnownFiles.AssetsRootPath, SongsPath = "", ModsSourcePath = "", PlaylistArtPath = "", RootFileProvider = apk }; using (var backupQae = new QuestomAssetsEngine(backupCfg)) { using (new LogTiming("preloading asset files for uninstall assets mod on BACKUP apk/qae")) { if (UninstallAction.PreloadFiles != null) { UninstallAction.PreloadFiles.ForEach(x => backupQae.Manager.GetAssetsFile(x)); } } using (new LogTiming("preloading asset files that are loaded in the main engine")) { context.GetEngine().Manager.OpenFiles.ForEach(x => backupQae.Manager.GetAssetsFile(x.AssetsFilename)); } context.BackupEngine = backupQae; foreach (var action in UninstallAction.Actions.OrderBy(x => x.StepNumber)) { using (new LogTiming($"getting operations for asset mod uninstall action step {action.StepNumber}")) { ops.AddRange(action.GetOps(context)); } } } context.BackupEngine = null; } Log.LogMsg($"Returning {ops.Count} for assets mod component uninstall..."); return(ops); }
internal static IEnumerable <IModContext <IOblivionMod, IMajorRecordCommon, IMajorRecordCommonGetter> > EnumerateMajorRecordContexts( this IReadOnlyList <IWorldspaceBlockGetter> worldspaceBlocks, IWorldspaceGetter worldspace, ILinkCache linkCache, Type type, ModKey modKey, IModContext?parent, bool throwIfUnknown, Func <IOblivionMod, IWorldspaceGetter, IWorldspace> getter) { foreach (var readOnlyBlock in worldspaceBlocks) { var blockNumX = readOnlyBlock.BlockNumberX; var blockNumY = readOnlyBlock.BlockNumberY; var blockModified = readOnlyBlock.LastModified; var blockContext = new ModContext <IWorldspaceBlockGetter>( modKey: modKey, parent: parent, record: readOnlyBlock); foreach (var readOnlySubBlock in readOnlyBlock.Items) { var subBlockNumY = readOnlySubBlock.BlockNumberY; var subBlockNumX = readOnlySubBlock.BlockNumberX; var subBlockModified = readOnlySubBlock.LastModified; var subBlockContext = new ModContext <IWorldspaceSubBlockGetter>( modKey: modKey, parent: blockContext, record: readOnlySubBlock); foreach (var readOnlyCell in readOnlySubBlock.Items) { Func <IOblivionMod, ICellGetter, ICell> cellGetter = (mod, copyCell) => { var worldspaceCopy = getter(mod, worldspace); var formKey = copyCell.FormKey; var retrievedBlock = worldspaceCopy.SubCells.FirstOrDefault(x => x.BlockNumberX == blockNumX && x.BlockNumberY == blockNumY); if (retrievedBlock == null) { retrievedBlock = new WorldspaceBlock() { BlockNumberX = blockNumX, BlockNumberY = blockNumY, GroupType = GroupTypeEnum.ExteriorCellBlock, LastModified = blockModified, }; worldspaceCopy.SubCells.Add(retrievedBlock); } var subBlock = retrievedBlock.Items.FirstOrDefault(x => x.BlockNumberX == subBlockNumX && x.BlockNumberY == subBlockNumY); if (subBlock == null) { subBlock = new WorldspaceSubBlock() { BlockNumberX = subBlockNumX, BlockNumberY = subBlockNumY, GroupType = GroupTypeEnum.ExteriorCellSubBlock, LastModified = readOnlySubBlock.LastModified, }; retrievedBlock.Items.Add(subBlock); } var cell = subBlock.Items.FirstOrDefault(cell => cell.FormKey == formKey); if (cell == null) { cell = copyCell.DeepCopy(CellCopyMask); subBlock.Items.Add(cell); } return(cell); }; if (LoquiRegistration.TryGetRegister(type, out var regis) && regis.ClassType == typeof(Cell)) { yield return(new ModContext <IOblivionMod, IMajorRecordCommon, IMajorRecordCommonGetter>( modKey: modKey, record: readOnlyCell, getter: (m, r) => cellGetter(m, (ICellGetter)r), parent: subBlockContext)); } else { foreach (var con in CellCommon.Instance.EnumerateMajorRecordContexts(readOnlyCell, linkCache, type, modKey, subBlockContext, throwIfUnknown, cellGetter)) { yield return(con); } } } } } }
public Shape(ModContext mod) { this.mod = mod; }
internal static IEnumerable <IModContext <ISkyrimMod, IMajorRecordCommon, IMajorRecordCommonGetter> > EnumerateMajorRecordContexts( this IListGroupGetter <ICellBlockGetter> cellBlocks, ILinkCache linkCache, Type type, ModKey modKey, IModContext?parent, bool throwIfUnknown) { foreach (var readOnlyBlock in cellBlocks.Records) { var blockNum = readOnlyBlock.BlockNumber; var blockContext = new ModContext <ICellBlockGetter>( modKey: modKey, parent: parent, record: readOnlyBlock); foreach (var readOnlySubBlock in readOnlyBlock.SubBlocks) { var subBlockNum = readOnlySubBlock.BlockNumber; var subBlockContext = new ModContext <ICellSubBlockGetter>( modKey: modKey, parent: blockContext, record: readOnlySubBlock); foreach (var readOnlyCell in readOnlySubBlock.Cells) { Func <ISkyrimMod, ICellGetter, ICell> cellGetter = (mod, copyCell) => { var formKey = copyCell.FormKey; var retrievedBlock = mod.Cells.Records.FirstOrDefault(x => x.BlockNumber == blockNum); if (retrievedBlock == null) { retrievedBlock = new CellBlock() { BlockNumber = blockNum, GroupType = GroupTypeEnum.InteriorCellBlock, }; mod.Cells.Records.Add(retrievedBlock); } var subBlock = retrievedBlock.SubBlocks.FirstOrDefault(x => x.BlockNumber == subBlockNum); if (subBlock == null) { subBlock = new CellSubBlock() { BlockNumber = subBlockNum, GroupType = GroupTypeEnum.InteriorCellSubBlock, }; retrievedBlock.SubBlocks.Add(subBlock); } var cell = subBlock.Cells.FirstOrDefault(cell => cell.FormKey == formKey); if (cell == null) { cell = copyCell.DeepCopy(CellCopyMask); subBlock.Cells.Add(cell); } return(cell); }; if (LoquiRegistration.TryGetRegister(type, out var regis) && regis.ClassType == typeof(Cell)) { yield return(new ModContext <ISkyrimMod, IMajorRecordCommon, IMajorRecordCommonGetter>( modKey: modKey, record: readOnlyCell, getter: (m, r) => cellGetter(m, (ICellGetter)r), parent: subBlockContext)); } else { foreach (var con in CellCommon.Instance.EnumerateMajorRecordContexts(readOnlyCell, linkCache, type, modKey, subBlockContext, throwIfUnknown, cellGetter)) { yield return(con); } } } } } }