Skip to content

Commit c861268

Browse files
committed
Add support for creating and importing backup modpacks
1 parent 7f38b5d commit c861268

File tree

3 files changed

+180
-2
lines changed

3 files changed

+180
-2
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace xivModdingFramework.Mods.DataContainers
5+
{
6+
public class BackupModPackData
7+
{
8+
/// <summary>
9+
/// The name of the mod pack
10+
/// </summary>
11+
public string Name { get; set; }
12+
13+
/// <summary>
14+
/// The mod pack author
15+
/// </summary>
16+
public string Author = "TexTools";
17+
18+
/// <summary>
19+
/// The mod pack version
20+
/// </summary>
21+
public Version Version = new Version("1.0.0");
22+
23+
/// <summary>
24+
/// The modpack Url
25+
/// </summary>
26+
public string Url = "";
27+
28+
/// <summary>
29+
/// The description for the mod pack
30+
/// </summary>
31+
public string Description = "";
32+
33+
/// <summary>
34+
/// The list of mods to back up
35+
/// </summary>
36+
public List<BackupModData> ModsToBackup { get; set; }
37+
}
38+
39+
public class BackupModData
40+
{
41+
/// <summary>
42+
/// Simple mod data
43+
/// </summary>
44+
public SimpleModData SimpleModData { get; set; }
45+
46+
/// <summary>
47+
/// Mod pack that the mod is a part of
48+
/// </summary>
49+
public ModPack ModPack { get; set; }
50+
}
51+
}

xivModdingFramework/Mods/DataContainers/ModList.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
using System.Diagnostics.Contracts;
2121
using System.Security.Cryptography;
2222
using System.Text;
23+
using xivModdingFramework.General.Enums;
2324
using xivModdingFramework.Helpers;
25+
using xivModdingFramework.Resources;
2426

2527
namespace xivModdingFramework.Mods.DataContainers
2628
{
@@ -114,6 +116,21 @@ public bool IsCustomFile()
114116
{
115117
return data.modOffset == data.originalOffset;
116118
}
119+
120+
public static Mod MakeModFromJson(ModsJson modsJson, string sourceApplication)
121+
{
122+
return new Mod
123+
{
124+
source = sourceApplication,
125+
name = modsJson.Name,
126+
category = modsJson.Category,
127+
fullPath = modsJson.FullPath,
128+
datFile = IOUtil.GetDataFileFromPath(modsJson.FullPath).GetDataFileName(),
129+
enabled = true,
130+
modPack = modsJson.ModPackEntry,
131+
data = new Data()
132+
};
133+
}
117134
}
118135

119136
public class Data

xivModdingFramework/Mods/FileTypes/TTMP.cs

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,114 @@ public async Task<int> CreateSimpleModPack(SimpleModPackData modPackData, Direct
336336
return processCount;
337337
}
338338

339+
public async Task<int> CreateBackupModpack(BackupModPackData backupModpackData, DirectoryInfo gameDirectory, IProgress<(int current, int total, string message)> progress, bool overwriteModpack)
340+
{
341+
var processCount = await Task.Run<int>(() =>
342+
{
343+
var dat = new Dat(gameDirectory);
344+
345+
var guid = Guid.NewGuid();
346+
347+
var dir = Path.Combine(Path.GetTempPath(), guid.ToString());
348+
Directory.CreateDirectory(dir);
349+
350+
351+
_tempMPD = Path.Combine(dir, "TTMPD.mpd");
352+
_tempMPL = Path.Combine(dir, "TTMPL.mpl");
353+
354+
var modCount = 0;
355+
356+
var modPackJson = new ModPackJson
357+
{
358+
TTMPVersion = _currentBackupTTMPVersion,
359+
Name = backupModpackData.Name,
360+
Author = backupModpackData.Author,
361+
Version = backupModpackData.Version.ToString(),
362+
MinimumFrameworkVersion = _minimumAssembly,
363+
Url = backupModpackData.Url,
364+
Description = backupModpackData.Description,
365+
SimpleModsList = new List<ModsJson>()
366+
};
367+
368+
try
369+
{
370+
using (var binaryWriter = new BinaryWriter(File.Open(_tempMPD, FileMode.Create)))
371+
{
372+
foreach (var backupModData in backupModpackData.ModsToBackup)
373+
{
374+
if (ForbiddenModTypes.Contains(Path.GetExtension(backupModData.SimpleModData.FullPath))) continue;
375+
376+
var modsJson = new ModsJson
377+
{
378+
Name = backupModData.SimpleModData.Name,
379+
Category = backupModData.SimpleModData.Category.GetEnDisplayName(),
380+
FullPath = backupModData.SimpleModData.FullPath,
381+
ModSize = backupModData.SimpleModData.ModSize,
382+
DatFile = backupModData.SimpleModData.DatFile,
383+
IsDefault = backupModData.SimpleModData.IsDefault,
384+
ModOffset = binaryWriter.BaseStream.Position,
385+
ModPackEntry = backupModData.ModPack,
386+
};
387+
388+
var rawData = dat.GetRawData(backupModData.SimpleModData.ModOffset,
389+
XivDataFiles.GetXivDataFile(backupModData.SimpleModData.DatFile),
390+
backupModData.SimpleModData.ModSize);
391+
392+
if (rawData == null)
393+
{
394+
throw new Exception("Unable to obtain data for the following mod\n\n" +
395+
$"Name: {backupModData.SimpleModData.Name}\nFull Path: {backupModData.SimpleModData.FullPath}\n" +
396+
$"Mod Offset: {backupModData.SimpleModData.ModOffset}\nData File: {backupModData.SimpleModData.DatFile}\n\n" +
397+
$"Unselect the above mod and try again.");
398+
}
399+
400+
binaryWriter.Write(rawData);
401+
402+
modPackJson.SimpleModsList.Add(modsJson);
403+
404+
progress?.Report((++modCount, backupModpackData.ModsToBackup.Count, string.Empty));
405+
}
406+
}
407+
408+
progress?.Report((0, backupModpackData.ModsToBackup.Count, GeneralStrings.TTMP_Creating));
409+
410+
File.WriteAllText(_tempMPL, JsonConvert.SerializeObject(modPackJson));
411+
412+
var modPackPath = Path.Combine(_modPackDirectory.FullName, $"{backupModpackData.Name}.ttmp2");
413+
414+
if (File.Exists(modPackPath) && !overwriteModpack)
415+
{
416+
var fileNum = 1;
417+
modPackPath = Path.Combine(_modPackDirectory.FullName, $"{backupModpackData.Name}({fileNum}).ttmp2");
418+
while (File.Exists(modPackPath))
419+
{
420+
fileNum++;
421+
modPackPath = Path.Combine(_modPackDirectory.FullName, $"{backupModpackData.Name}({fileNum}).ttmp2");
422+
}
423+
}
424+
else if (File.Exists(modPackPath) && overwriteModpack)
425+
{
426+
File.Delete(modPackPath);
427+
}
428+
429+
var zf = new ZipFile();
430+
zf.UseZip64WhenSaving = Zip64Option.AsNecessary;
431+
zf.CompressionLevel = Ionic.Zlib.CompressionLevel.None;
432+
zf.AddFile(_tempMPL, "");
433+
zf.AddFile(_tempMPD, "");
434+
zf.Save(modPackPath);
435+
}
436+
finally
437+
{
438+
Directory.Delete(dir, true);
439+
}
440+
441+
return modCount;
442+
});
443+
444+
return processCount;
445+
}
446+
339447
/// <summary>
340448
/// Gets the data from a mod pack including images if present
341449
/// </summary>
@@ -673,6 +781,8 @@ await Task.Run(async () =>
673781
// Add entries for new modpacks to the mod list
674782
foreach (var modsJson in filteredModsJson)
675783
{
784+
if (modsJson.ModPackEntry == null) continue;
785+
676786
var modPackExists = modList.ModPacks.Any(modpack => modpack.name == modsJson.ModPackEntry.name);
677787

678788
if (!modPackExists)
@@ -685,8 +795,8 @@ await Task.Run(async () =>
685795
if (GetRootConversionsFunction != null)
686796
{
687797
// Get the modpack to list the conversions under, this is the just the modpack entry of the first modsJson since they're all the same unless it's a backup
688-
// However, this code isn't used for importing backup modpacks since they already had the choice to change the destination item after the initial import
689-
var modPack = modList.ModPacks.First(x => x.name == filteredModsJson[0].ModPackEntry.name);
798+
// However, this code shouldn't be used when importing backup modpacks since they already had the choice to change the destination item after the initial import
799+
var modPack = modList.ModPacks.First(x => x.name == filteredModsJson[0].ModPackEntry?.name);
690800

691801
Dictionary<XivDependencyRoot, (XivDependencyRoot Root, int Variant)> rootConversions = null;
692802
try

0 commit comments

Comments
 (0)