225 lines
11 KiB
C#
225 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
using DTLib;
|
|
using DTLib.Filesystem;
|
|
using DTLib.Logging;
|
|
using DTLib.Extensions;
|
|
|
|
static class ParadoxModMerger
|
|
{
|
|
|
|
// вывод лога в консоль и файл
|
|
static ConsoleLogger logger = new ConsoleLogger("merger-logs", "merger");
|
|
static void Log(params string[] msg) => logger.Log(msg);
|
|
|
|
static void Main(string[] args)
|
|
{
|
|
try
|
|
{
|
|
PublicLog.LogEvent += Log;
|
|
|
|
// хелп
|
|
if (args.Length == 0 || args[0] == "/?" || args[0] == "-h")
|
|
{
|
|
Log(
|
|
"b", "paradox mod merger help:\n",
|
|
"c", "-clear \"steamworkshop dir\" -out \"utput dir\" ",
|
|
"b", "clear mod files and put them into separate dirs in output dir\n",
|
|
"c", "-merge \"dir with mods\" -out \"output dir\" ",
|
|
"b", "merge mods and show conflicts\n",
|
|
"c", "-merge-single \"dir with mod\" -out \"output dir\" ",
|
|
"b", "copy single mod files and show conflicts\n",
|
|
"c", "-diff \"dir with mods\" \"another dir with mods\" -out \"output file\" ",
|
|
"b", "compare mod files hashes for finding different files");
|
|
Console.ResetColor();
|
|
return;
|
|
}
|
|
|
|
Log("c", "args: ");
|
|
string srcdir = "";
|
|
string srcdir2 = "";
|
|
string outdir = "";
|
|
int mode = -1;
|
|
// определение всех аргументов
|
|
for (sbyte i = 0; i < args.Length; i++)
|
|
{
|
|
Log("g", $" {args[i]}");
|
|
switch (args[i])
|
|
{
|
|
case "-clear":
|
|
srcdir = args[++i].Replace("\"", "");
|
|
Log("g", $" {args[i]}");
|
|
mode = 0;
|
|
break;
|
|
case "-merge":
|
|
srcdir = args[++i].Replace("\"", "");
|
|
Log("g", $" {args[i]}");
|
|
mode = 1;
|
|
break;
|
|
case "-diff":
|
|
srcdir = args[++i].Replace("\"", "");
|
|
Log("g", $" {args[i]}");
|
|
srcdir2 = args[++i].Replace("\"", "");
|
|
Log("g", $" {args[i]}");
|
|
mode = 2;
|
|
break;
|
|
case "-merge-single":
|
|
srcdir = args[++i].Replace("\"", "");
|
|
Log("g", $" {args[i]}");
|
|
mode = 3;
|
|
break;
|
|
case "-out":
|
|
outdir = args[++i].Replace("\"", "");
|
|
Log("g", $" {args[i]}");
|
|
break;
|
|
default:
|
|
throw new Exception($"invalid argument: <{args[i]}>");
|
|
}
|
|
}
|
|
Log("");
|
|
|
|
var conflicts = new List<string>();
|
|
string[] moddirs = Directory.GetDirectories(srcdir);
|
|
switch (mode)
|
|
{
|
|
case 0:
|
|
Log("b", $"found {moddirs.Length} mod dirs");
|
|
for (int i = 0; i < moddirs.Length; i++)
|
|
{
|
|
string modarch = "";
|
|
if (Directory.GetFiles(moddirs[i], "*.zip").Length != 0) modarch = Directory.GetFiles(moddirs[i], "*.zip")[0];
|
|
if (modarch.Length != 0)
|
|
{
|
|
Log("y", $"archive found: {modarch}");
|
|
var pr = new Process();
|
|
pr.StartInfo.CreateNoWindow = true;
|
|
pr.StartInfo.UseShellExecute = false;
|
|
pr.StartInfo.FileName = "7z\\7z.exe";
|
|
pr.StartInfo.Arguments = $"x -y -o_TEMP \"{modarch}\"";
|
|
pr.Start();
|
|
pr.WaitForExit();
|
|
moddirs[i] = "_TEMP";
|
|
Log("g", "\tfiles extracted");
|
|
}
|
|
string modname = File.ReadAllText($"{moddirs[i]}\\descriptor.mod");
|
|
modname = modname.Remove(0, modname.IndexOf("name=\"") + 6);
|
|
modname = modname.Remove(modname.IndexOf("\""))
|
|
.Replace("\\", "").Replace(":", "").Replace("?", "").Replace("\"", "").Replace("/", "")
|
|
.Replace("\'", "").Replace("|", "").Replace("<", "").Replace(">", "").Replace("*", "");
|
|
Log("b", $"[{i + 1}/{moddirs.Length}] copying mod ", "c", $"{modname}");
|
|
string[] subdirs = Directory.GetDirectories(moddirs[i]);
|
|
for (sbyte n = 0; n < subdirs.Length; n++)
|
|
{
|
|
subdirs[n] = subdirs[n].Remove(0, subdirs[n].LastIndexOf('\\') + 1);
|
|
switch (subdirs[n])
|
|
{
|
|
// stellaris
|
|
case "common":
|
|
case "events":
|
|
case "flags":
|
|
case "fonts":
|
|
case "gfx":
|
|
case "interface":
|
|
case "localisation":
|
|
case "localisation_synced":
|
|
case "map":
|
|
case "music":
|
|
case "prescripted_countries":
|
|
case "sound":
|
|
// hoi4
|
|
case "history":
|
|
case "portraits":
|
|
Directory.Copy($"{moddirs[i]}\\{subdirs[n]}", $"{outdir}\\{modname}\\{subdirs[n]}", out List<string> _conflicts, true);
|
|
conflicts.AddRange(_conflicts);
|
|
break;
|
|
}
|
|
}
|
|
if (Directory.Exists("_TEMP")) Directory.Delete("_TEMP");
|
|
}
|
|
break;
|
|
case 1:
|
|
Log("b", $"found {moddirs.Length} mod dirs");
|
|
for (short i = 0; i < moddirs.Length; i++)
|
|
{
|
|
Log("b", $"[{i + 1}/{moddirs.Length}] merging mod ", "c", $"{moddirs[i]}");
|
|
Directory.Copy(moddirs[i], outdir, out List<string> _conflicts, true);
|
|
conflicts.AddRange(_conflicts);
|
|
}
|
|
break;
|
|
case 2:
|
|
var hasher = new Hasher();
|
|
var diff = new Dictionary<string, byte[]>();
|
|
// добавление файлов из первой папки
|
|
List<string> files = Directory.GetAllFiles(srcdir);
|
|
var mods = new List<string>();
|
|
for (short i = 0; i < files.Count; i++)
|
|
{
|
|
byte[] hash = hasher.HashFile(files[i]);
|
|
files[i] = files[i].Replace(srcdir, "");
|
|
diff.Add(files[i], hash);
|
|
AddMod(files[i]);
|
|
}
|
|
// убирание совпадающих файлов
|
|
files = Directory.GetAllFiles(srcdir2);
|
|
for (short i = 0; i < files.Count; i++)
|
|
{
|
|
byte[] hash = hasher.HashFile(files[i]);
|
|
files[i] = files[i].Replace(srcdir2, "");
|
|
if (diff.ContainsKey(files[i]) && diff[files[i]].HashToString() == hash.HashToString()) diff.Remove(files[i]);
|
|
else
|
|
{
|
|
diff.Add(srcdir2 + files[i], hash);
|
|
AddMod(files[i]);
|
|
}
|
|
}
|
|
void AddMod(string mod)
|
|
{
|
|
mod = mod.Remove(0, 1);
|
|
mod = mod.Remove(mod.IndexOf('\\'));
|
|
if (!mods.Contains(mod)) mods.Add(mod);
|
|
}
|
|
// вывод результата
|
|
StringBuilder output = new StringBuilder();
|
|
output.Append($"[{DateTime.Now}]\n\n");
|
|
foreach (string mod in mods)
|
|
{
|
|
output.Append('\n').Append(mod).Append("\n{\n");
|
|
foreach (string file in diff.Keys)
|
|
{
|
|
if (file.Contains(mod))
|
|
{
|
|
output.Append('\t');
|
|
if (!file.Contains(srcdir2)) output.Append(srcdir).Append(file).Append('\n');
|
|
output.Append(file).Append('\n');
|
|
}
|
|
}
|
|
output.Append("}\n");
|
|
// не убирать, это полезное
|
|
if (output[output.Length - 4] == '{') output.Remove(output.Length - mod.Length - 5, mod.Length + 5);
|
|
}
|
|
// хоть называется outdir, в данном случае это путь к файлу
|
|
var _outStr = output.ToString();
|
|
File.WriteAllText(outdir, _outStr);
|
|
Log("g", $"output written to {outdir}");
|
|
break;
|
|
case 3:
|
|
Directory.Copy(srcdir, outdir, out List<string> __conflicts, true);
|
|
conflicts.AddRange(__conflicts);
|
|
break;
|
|
}
|
|
// вывод конфликтующих файлов при -merge и -clear если такие есть
|
|
if (conflicts.Count > 0)
|
|
{
|
|
Log("r", $"found {conflicts.Count} conflicts:\n",
|
|
"m", conflicts.MergeToString("\n"));
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log("r", $"{ex.Message}\n{ex.StackTrace}");
|
|
}
|
|
Console.ResetColor();
|
|
}
|
|
} |