private void BtnOpenMod_Click(object sender, EventArgs e) { openModFolder.Description = Resources.Caption_Select_mod_folder; openModFolder.ShowNewFolderButton = false; if (openModFolder.ShowDialog() == DialogResult.OK) { ClearAll(); tbModFolder.Text = openModFolder.SelectedPath; Log.LogInfo("Open Mod", $"Path: {tbModFolder.Text}"); _manifest = ModManifest.Load(tbModFolder.Text); tbModInfoName.Text = _manifest.Info.Name; tbModInfoDesc.Text = _manifest.Info.Description; tbModInfoAuthor.Text = _manifest.Info.Author; tbModInfoVersion.Text = _manifest.Info.Version; tbModInfoCreated.Text = _manifest.Info.CreatedOn; lbModInfoDependencies.DataSource = _manifest.Info.Dependencies; lbModInfoGameVersions.DataSource = _manifest.Supports; Log.LogInfo("Open mod", $"Name: {_manifest.Info.Name}"); Log.LogInfo("Open mod", "Start loading structure"); LoadModStructure(openModFolder.SelectedPath, _dataNode, false); LoadModStructure(openModFolder.SelectedPath, _localizationNode, true); Log.LogInfo("Open mod", "Finished loading structure"); UpdateControls(); } }
public static void Invoke(string pulseId, IPulsableObject data, ModManifest dispatchingMod) { if (Listeners.GetInvocationList().Length > 0) { Listeners(null, new PulseEventArgs(pulseId, dispatchingMod, data)); } }
/// <summary> /// Reattaches disabled delegates for previously disabled mods /// </summary> /// <param name="mod">The manifest of the mod to reactivate</param> public static void ReactivateMod(ModManifest mod) { if (mod.ModAssembly != null) { ModEventManager.ReattachDelegates(mod.ModAssembly); } }
public ModPrototype(ModDefinition definition, ReadOnlyFileSystem fileSystem, ModManifest manifest) { Definition = definition; FileSystem = fileSystem; Manifest = manifest; }
private void OnShown(object sender, EventArgs e) { DialogResult = DialogResult.OK; int modCount = mods.Count; int modIndex = 0; SetTaskCount(modCount); CancellationToken token = tokenSource.Token; var generator = new ModManifestGenerator(); void hashStart(object o, FileHashEventArgs args) { args.Cancel = token.IsCancellationRequested; SetStep($"Checking file {args.FileIndex}/{args.FileCount}: {args.FileName}"); SetProgress(args.FileIndex / (double)args.FileCount); } void hashEnd(object o, FileHashEventArgs args) { args.Cancel = token.IsCancellationRequested; } generator.FileHashStart += hashStart; generator.FileHashEnd += hashEnd; using (var task = new Task(() => { foreach (Tuple <string, ModInfo> i in mods) { string path = Path.Combine("mods", i.Item1); ModInfo info = i.Item2; SetTaskAndStep($"Verifying mod {++modIndex}/{modCount}: {info.Name}", "Loading local manifest..."); List <ModManifest> local = ModManifest.FromFile(Path.Combine(path, "mod.manifest")); List <ModManifestDiff> diff = generator.Verify(path, local); if (diff?.Any(x => x.State != ModManifestState.Unchanged) == true) { Failed.Add(new Tuple <string, ModInfo, List <ModManifestDiff> >(i.Item1, info, diff)); } NextTask(); } })) { task.Start(); while (!task.IsCompleted && !task.IsCanceled) { Application.DoEvents(); } task.Wait(token); } }
public static void ClearDirtyFlag(string itemId, ModManifest mod = null, bool ignoreModPrefixes = false) { var items = GetItem(itemId, mod, ignoreModPrefixes); foreach (var item in items) { item.IsDirty = false; } }
private void generateManifestToolStripMenuItem_Click(object sender, EventArgs e) { if (!displayedManifestWarning) { DialogResult result = MessageBox.Show(this, Resources.GenerateManifestWarning, "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result != DialogResult.Yes) { return; } displayedManifestWarning = true; } foreach (ListViewItem item in modListView.SelectedItems) { var modPath = Path.Combine("mods", (string)item.Tag); var manifestPath = Path.Combine(modPath, "mod.manifest"); List <ModManifest> manifest; List <ModManifestDiff> diff; using (var progress = new ManifestDialog(modPath, $"Generating manifest: {(string)item.Tag}", true)) { progress.SetTask("Generating file index..."); if (progress.ShowDialog(this) == DialogResult.Cancel) { continue; } diff = progress.Diff; } if (diff == null) { continue; } if (diff.Count(x => x.State != ModManifestState.Unchanged) <= 0) { continue; } using (var dialog = new ManifestDiffDialog(diff)) { if (dialog.ShowDialog(this) == DialogResult.Cancel) { continue; } manifest = dialog.MakeNewManifest(); } ModManifest.ToFile(manifest, manifestPath); } }
public ModPacker(ModManifest manifest, string baseDir, string targetPath) { this.manifest = manifest; this.baseDir = baseDir; this.targetPath = targetPath; InitializeComponent(); Shown += StartWork; }
/// <summary> /// Forcibly deactivates a mod by detaching it's event listeners. /// </summary> /// <param name="mod">The manifest of the mod to deactive</param> /// <param name="state">The new state of this mod. Defaults to ModState.Deactivated</param> /// <param name="error">The exception encountered causing the mod to be unloaded. Defaults to null</param> public static void DeactivateMod(ModManifest mod, ModState state = ModState.Deactivated, Exception error = null) { try { DetachAssemblyDelegates(mod.ModAssembly); mod.ModState = state; mod.LastException = error; Log.Success($"Successfully unloaded mod {mod.Name} by {mod.Author}"); } catch (Exception) { // Ignored } }
public static void LoadModData(ref ModData mod, string manifestFileName) { using (var modStream = new FileStream(PATH(manifestFileName), FileMode.Open, FileAccess.Read, FileShare.Read)) { ModManifest modManifest = (ModManifest)bFormatter.Deserialize(modStream); if (modManifest.RMMCode == ModFormatInfo.RMMCode) { if (modManifest.Version == ModFormatInfo.VERSION) { mod = modManifest.Data; mod.LocalData = new LocalData(); string docsPath = WorkingDirectory + "Documents/"; string[] docs = Directory.GetFiles(PATH(docsPath)); #if UNITY_STANDALONE_WIN for (int i = 0; i < docs.Length; ++i) { docs[i] = ConvertToUnixPath(docs[i]); } #endif mod.LocalData.Documents = docs; string savesPath = WorkingDirectory + "Saves/"; string[] saves = Directory.GetFiles(PATH(savesPath)); #if UNITY_STANDALONE_WIN for (int i = 0; i < saves.Length; ++i) { saves[i] = ConvertToUnixPath(saves[i]); } #endif mod.LocalData.Saves = saves; } else { Debug.LogError("Error: Unsupported manifest file version!"); } } else { Debug.LogError("Error: The file is not a RoleplayOverlod manifest file!"); } } }
/// <summary> /// Register ModXnb with key /// </summary> /// <param name="itemId">Id of ModXnb to return</param> /// <param name="item">ModXnb to register</param> /// <param name="mod">Mod this ModXnb belongs to</param> public static void RegisterItem(string itemId, ModXnb item, ModManifest mod = null) { var xnb = RegistryInstance.GetItem(mod == null ? itemId : GetModSpecificId(mod, itemId)); if (xnb != null) { xnb.Add(item); } else { RegistryInstance.RegisterItem(mod == null ? itemId : GetModSpecificId(mod, itemId), new List <ModXnb> { item }); } }
private void ResolveLoadingIssue(DisableableOptionCheckbox checkbox, ModManifest mod) { checkbox.IsDisabled = true; if (mod.ModState == ModState.MissingDependency) { var missingDependencies = mod.Dependencies.Where(n => n.DependencyState == DependencyState.Missing); var missingParents = mod.Dependencies.Where(n => n.DependencyState == DependencyState.ParentMissing); var tooLow = mod.Dependencies.Where(n => n.DependencyState == DependencyState.TooLowVersion); var tooHigh = mod.Dependencies.Where(n => n.DependencyState == DependencyState.TooHighVersion); var modDependencies = missingDependencies as ModDependency[] ?? missingDependencies.ToArray(); if (modDependencies.Any()) { checkbox.DisableReason = $"Missing Dependencies: : {string.Join(", ", modDependencies.Select(n => n.UniqueId))}"; } else if (modDependencies.Any()) { checkbox.DisableReason = $"Dependent Mods Missing Dependencies: : {string.Join(", ", missingParents.Select(n => n.UniqueId))}"; } else { var tooLowDependencies = tooLow as ModDependency[] ?? tooLow.ToArray(); if (tooLowDependencies.Any()) { checkbox.DisableReason = $"Dependency Version Too Low: : {string.Join(", ", tooLowDependencies.Select(n => n.UniqueId + $"(Minimum: {n.MinimumVersion.ToString()})"))}"; } else { var tooHighDependencies = tooHigh as ModDependency[] ?? tooHigh.ToArray(); if (tooHighDependencies.Any()) { checkbox.DisableReason = $"Dependency Version Too High: : {string.Join(",", tooHighDependencies.Select(n => n.UniqueId + $"(Maximum: {n.MaximumVersion.ToString()})"))}"; } } } } else if (mod.ModState == ModState.Errored) { var lastException = mod.LastException?.Message ?? ""; checkbox.DisableReason = $"Error: {lastException}"; } }
public static void Initialize() { string[] modStrings = Directory.GetFiles(FileIO.DataDirectory, "modmanifest", SearchOption.AllDirectories); foreach (string s in modStrings) { ModManifest manifest = FileIO.ReadFileString(s).Deserialize <ModManifest>(); mods.Add(new Mod(manifest)); } // TODO: Works, but needs more testing... mods = mods.OrderBy(x => x.LoadOrder).ToList(); foreach (Mod mod in mods) { mod.PostConstructor(); ModLoadIteration(mod); } }
public static bool Verify(this ModManifest manifest, out string[] errors) { var errs = new List <string>(); void Missing(string field) { errs.Add($"Missing required property `{field}`."); } if (manifest.ManifestRevision == null) { Missing(nameof(manifest.ManifestRevision)); } if (manifest.ManifestRevision != ModManifest.MANIFEST_REVISION) { errs.Add($"Invalid manifest revision. Supported values are: `{ModManifest.MANIFEST_REVISION}`."); } if (manifest.Guid == null) { Missing(nameof(manifest.Guid)); } if (manifest.Name == null) { Missing(nameof(manifest.Name)); } if (manifest.Version == null) { errs.Add("Missing or invalid `version`. Version must be of form `X.X.X`."); } foreach (var assetMapping in manifest.AssetMappings) { if (assetMapping.Path == null) { Missing(nameof(assetMapping.Path)); } if (assetMapping.Target == null) { Missing(nameof(assetMapping.Path)); } } errors = errs.ToArray(); return(errors.Length == 0); }
public override object LoadMod(Assembly modAssembly, Type[] assemblyTypes, ModManifest manifest) { StardewModdingAPI.Mod instance = null; try { var type = assemblyTypes.First(x => x.BaseType == typeof(StardewModdingAPI.Mod)); instance = (StardewModdingAPI.Mod)modAssembly.CreateInstance(type.ToString()); if (instance != null) { instance.PathOnDisk = manifest.ModDirectory; instance.Entry(); } } catch (Exception ex) { Farmhand.Logging.Log.Exception("Error in Entry on SMAPI mod", ex); } return(instance); }
private static void BubbleDependencyLoadError(ModManifest erroredMod) { Log.Error($"Marking {erroredMod.Name} dependency hierarchy as failed"); var problemMods = new Stack <IModManifest>(); // We use this one to avoid circular resolution issues var resolvedMods = new List <IModManifest>(); problemMods.Push(erroredMod); do { var mod = problemMods.Pop(); resolvedMods.Add(mod); var dependants = ModRegistry.GetRegisteredItems() .Where(n => n.IsFarmhandMod) .Cast <ModManifest>() .Where( n => n.Dependencies != null && n.Dependencies.Any(d => d.IsRequired && mod.UniqueId.Equals(d.UniqueId))); foreach (var dependant in dependants) { dependant.ModState = ModState.DependencyLoadError; if (!resolvedMods.Contains(dependant)) { Log.Verbose( $"\tDisabling {dependant.Name} due to {mod.Name} failure." + (mod == erroredMod ? string.Empty : $" (Cascaded failure loading {erroredMod.Name}")); problemMods.Push(dependant); } } }while (problemMods.Count > 0); Log.Verbose($"{erroredMod.Name} all marked failed"); }
public static string GetModSpecificId(ModManifest mod, string itemId) { var modPrefix = GetModSpecificPrefix(mod); return($"{modPrefix}{itemId}"); }
private static string GetModSpecificPrefix(ModManifest mod) { return($"\\{mod.UniqueId.ThisId}\\"); }
/// <summary> /// Remove ModXnb /// </summary> /// <param name="itemId">Id of ModXnb to remove</param> /// <param name="mod">Mod this ModXnb belongs to</param> public static void UnregisterItem(string itemId, ModManifest mod = null) { RegistryInstance.UnregisterItem(mod == null ? itemId : GetModSpecificId(mod, itemId)); }
public IkenFelineMod(ModManifest manifest) { Manifest = manifest; Logger = new ModLogger(this); Version = new Version(Manifest.Version); }
public abstract object LoadMod(Assembly modAssembly, Type[] assemblyTypes, ModManifest manifest);
/// <summary> /// Registers item with it /// </summary> /// <param name="itemId">Id of item to register</param> /// <param name="item">Texture to register</param> /// <param name="mod">Owning mod, defaults to null</param> public static void RegisterItem(string itemId, DiskTexture item, ModManifest mod = null) { RegistryInstance.RegisterItem(mod == null ? itemId : GetModSpecificId(mod, itemId), item); }
internal static void InvokeModLoadError(ModManifest mod) { EventCommon.SafeInvoke(OnModLoadError, null, new EventArgsOnModLoadEvent(mod)); }
static void CreateDefaultMod() { var processInfo = new System.Diagnostics.ProcessStartInfo("copyTestResources.bat"); var process = System.Diagnostics.Process.Start(processInfo); process.WaitForExit(); string[] defaultResourceDirs = { "Textures/Walls/", "Textures/Floor/", "Textures/Ceiling/", "Textures/Skybox/", "Audio/", "Models/Classes/", "Models/Figures/", }; System.Diagnostics.Debug.Assert(defaultResourceDirs.Length == (int)ResourceTypeID.Count); ModManifest defaultMod = new ModManifest { Name = "Default", RMMCode = ModFormatInfo.RMMCode, Version = ModFormatInfo.VERSION }; ModData defaultModData = new ModData(); int resourceTypeCount = (int)ResourceTypeID.Count; ResourceType[] resourceTypeEntries = new ResourceType[resourceTypeCount]; for (int i = 0; i < resourceTypeCount; ++i) { resourceTypeEntries[i] = new ResourceType(); } defaultModData.ResourceTypeEntries = resourceTypeEntries; string workingDirectory = PATH("build/Mods/Default/"); int runningResourceCount = 0; List <Resource> resourcesToBuild = new List <Resource>(); for (int i = 0; i < resourceTypeCount; ++i) { string resDir = PATH(workingDirectory + defaultResourceDirs[i]); string[] resourceFiles = Directory.GetFiles(resDir); Resource[] resources = new Resource[resourceFiles.Length]; for (int j = 0; j < resourceFiles.Length; ++j) { string file = defaultResourceDirs[i] + Path.GetFileName(resourceFiles[j]); resources[j] = new Resource { File = file }; } defaultModData.ResourceTypeEntries[i].FirstResourceIndex = runningResourceCount; for (int j = 0; j < resources.Length; ++j) { resourcesToBuild.Add(resources[j]); ++runningResourceCount; } defaultModData.ResourceTypeEntries[i].OnePastLastResourceIndex = runningResourceCount; } defaultModData.Resources = resourcesToBuild.ToArray(); defaultMod.Data = defaultModData; string defaultModManifestPath = PATH("build/Mods/Default/Default.rmm"); using (var fs = new FileStream(defaultModManifestPath, FileMode.Create, FileAccess.Write, FileShare.None)) { var formatter = new BinaryFormatter(); formatter.Serialize(fs, defaultMod); } }
public static bool IsDirty(string itemId, ModManifest mod = null, bool ignoreModPrefixes = false) { return(GetItem(itemId, mod, ignoreModPrefixes).Any(n => n.IsDirty)); }
public EventArgsOnModLoadEvent(ModManifest mod) { Mod = mod; }
/// <summary> /// Returns item with matching id /// </summary> /// <param name="itemId">ID of the item to return</param> /// <param name="mod">Owning mod, defaults to null</param> /// <returns> /// The <see cref="ModMap" /> for this ID /// </returns> public static ModMap GetItem(string itemId, ModManifest mod = null) { return(RegistryInstance.GetItem(mod == null ? itemId : GetModSpecificId(mod, itemId))); }
private void uninstallToolStripMenuItem_Click(object sender, EventArgs e) { DialogResult result = MessageBox.Show(this, "This will uninstall all selected mods." + "\n\nAre you sure you wish to continue?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result != DialogResult.Yes) { return; } result = MessageBox.Show(this, "Would you like to keep mod user data where possible? (Save files, config files, etc)", "User Data", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); if (result == DialogResult.Cancel) { return; } foreach (ListViewItem item in modListView.SelectedItems) { var dir = (string)item.Tag; var modDir = Path.Combine("mods", dir); var manpath = Path.Combine(modDir, "mod.manifest"); try { if (result == DialogResult.Yes && File.Exists(manpath)) { List <ModManifest> manifest = ModManifest.FromFile(manpath); foreach (var entry in manifest) { var path = Path.Combine(modDir, entry.FilePath); if (File.Exists(path)) { File.Delete(path); } } File.Delete(manpath); var version = Path.Combine(modDir, "mod.version"); if (File.Exists(version)) { File.Delete(version); } } else { if (result == DialogResult.Yes) { var retain = MessageBox.Show(this, $"The mod \"{ mods[dir].Name }\" (\"mods\\{ dir }\") does not have a manifest, so mod user data cannot be retained." + " Do you want to uninstall it anyway?", "Cannot Retain User Data", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (retain == DialogResult.No) { continue; } } Directory.Delete(modDir, true); } } catch (Exception ex) { MessageBox.Show(this, $"Failed to uninstall mod \"{ mods[dir].Name }\" from \"{ dir }\": { ex.Message }", "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error); } } LoadModList(); }
private void OnShown(object sender, EventArgs e) { CancellationToken token = tokenSource.Token; var generator = new ModManifestGenerator(); generator.FilesIndexed += (o, args) => { SetTask("Manifest generation complete!"); SetTaskCount(args.FileCount); }; generator.FileHashStart += (o, args) => { args.Cancel = token.IsCancellationRequested; SetTaskAndStep($"Hashing file: {args.FileIndex}/{args.FileCount}", args.FileName); SetProgress(args.FileIndex / (double)args.FileCount); }; generator.FileHashEnd += (o, args) => { args.Cancel = token.IsCancellationRequested; NextTask(); }; using (var task = new Task(() => { manifest = generator.Generate(modPath); if (!token.IsCancellationRequested) { Diff = ModManifestGenerator.Diff(manifest, File.Exists(manifestPath) ? ModManifest.FromFile(manifestPath) : null); } })) { task.Start(); while (!task.IsCompleted && !task.IsCanceled) { Application.DoEvents(); } task.Wait(token); } DialogResult = DialogResult.OK; }
private void OnShown(object sender, EventArgs eventArgs) { DialogResult = DialogResult.OK; SetTaskCount(1); SetProgress(1); CancellationToken token = tokenSource.Token; DialogResult result; do { result = DialogResult.Cancel; try { // poor man's await Task.Run (not available in .net 4.0) using (var task = new Task(() => { string newManPath = Path.Combine(updatePath, "loader.manifest"); string oldManPath = "loader.manifest"; SetTaskAndStep("Parsing manifest..."); if (token.IsCancellationRequested) { return; } List <ModManifestEntry> newManifest = ModManifest.FromFile(newManPath); SetTaskAndStep("Applying manifest..."); if (token.IsCancellationRequested) { return; } if (File.Exists(oldManPath)) { List <ModManifestEntry> oldManifest = ModManifest.FromFile(oldManPath); List <string> oldFiles = oldManifest.Except(newManifest) .Select(x => x.FilePath) .ToList(); foreach (string file in oldFiles) { if (File.Exists(file)) { File.Delete(file); } } RemoveEmptyDirectories(oldManifest, newManifest); } foreach (ModManifestEntry file in newManifest) { string dir = Path.GetDirectoryName(file.FilePath); if (!string.IsNullOrEmpty(dir)) { string newDir = dir; if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); } } string dest = file.FilePath; if (File.Exists(dest)) { File.Delete(dest); } File.Copy(Path.Combine(updatePath, file.FilePath), dest); } File.Copy(newManPath, oldManPath, true); Process.Start(Path.GetFileName(Application.ExecutablePath), $"cleanupdate \"{updatePath}\""); }, token)) { task.Start(); while (!task.IsCompleted && !task.IsCanceled) { Application.DoEvents(); } task.Wait(token); } } catch (AggregateException ae) { ae.Handle(ex => { result = MessageBox.Show(this, $"Failed to update:\r\n{ex.Message}", "Update Failed", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error); return(true); }); } } while (result == DialogResult.Retry); Close(); }
/// <summary> /// Get ModXnb with key /// </summary> /// <param name="itemId">Id of ModXnb to return</param> /// <param name="mod">Mod this ModXnb belongs to</param> /// <param name="ignoreModPrefixes">Whether this search should ignore mod-filtering prefixes</param> /// <returns>Matching ModXnb</returns> public static IEnumerable <ModXnb> GetItem(string itemId, ModManifest mod = null, bool ignoreModPrefixes = false) { return(ignoreModPrefixes ? GetRegisteredItems().Where(n => n.Original == itemId) : RegistryInstance.GetItem(mod == null ? itemId : GetModSpecificId(mod, itemId))); }