This commit is contained in:
2025-08-22 02:19:48 +01:00
commit a4c82452be
373 changed files with 52044 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
using MareSynchronos.API.Data;
using MareSynchronos.API.Data.Enum;
namespace MareSynchronos.PlayerData.Data;
public class CharacterData
{
public Dictionary<ObjectKind, string> CustomizePlusScale { get; set; } = [];
public Dictionary<ObjectKind, HashSet<FileReplacement>> FileReplacements { get; set; } = [];
public Dictionary<ObjectKind, string> GlamourerString { get; set; } = [];
public string HeelsData { get; set; } = string.Empty;
public string HonorificData { get; set; } = string.Empty;
public string ManipulationString { get; set; } = string.Empty;
public string PetNamesData { get; set; } = string.Empty;
public string MoodlesData { get; set; } = string.Empty;
public API.Data.CharacterData ToAPI()
{
Dictionary<ObjectKind, List<FileReplacementData>> fileReplacements =
FileReplacements.ToDictionary(k => k.Key, k => k.Value.Where(f => f.HasFileReplacement && !f.IsFileSwap)
.GroupBy(f => f.Hash, StringComparer.OrdinalIgnoreCase)
.Select(g =>
{
return new FileReplacementData()
{
GamePaths = g.SelectMany(f => f.GamePaths).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(),
Hash = g.First().Hash,
};
}).ToList());
foreach (var item in FileReplacements)
{
var fileSwapsToAdd = item.Value.Where(f => f.IsFileSwap).Select(f => f.ToFileReplacementDto());
fileReplacements[item.Key].AddRange(fileSwapsToAdd);
}
return new API.Data.CharacterData()
{
FileReplacements = fileReplacements,
GlamourerData = GlamourerString.ToDictionary(d => d.Key, d => d.Value),
ManipulationData = ManipulationString,
HeelsData = HeelsData,
CustomizePlusData = CustomizePlusScale.ToDictionary(d => d.Key, d => d.Value),
HonorificData = HonorificData,
PetNamesData = PetNamesData,
MoodlesData = MoodlesData
};
}
}

View File

@@ -0,0 +1,42 @@
using MareSynchronos.API.Data;
using System.Text.RegularExpressions;
namespace MareSynchronos.PlayerData.Data;
public partial class FileReplacement
{
public FileReplacement(string[] gamePaths, string filePath)
{
GamePaths = gamePaths.Select(g => g.Replace('\\', '/').ToLowerInvariant()).ToHashSet(StringComparer.Ordinal);
ResolvedPath = filePath.Replace('\\', '/');
}
public HashSet<string> GamePaths { get; init; }
public bool HasFileReplacement => GamePaths.Count >= 1 && GamePaths.Any(p => !string.Equals(p, ResolvedPath, StringComparison.Ordinal));
public string Hash { get; set; } = string.Empty;
public bool IsFileSwap => !LocalPathRegex().IsMatch(ResolvedPath) && GamePaths.All(p => !LocalPathRegex().IsMatch(p));
public string ResolvedPath { get; init; }
public FileReplacementData ToFileReplacementDto()
{
return new FileReplacementData
{
GamePaths = [.. GamePaths],
Hash = Hash,
FileSwapPath = IsFileSwap ? ResolvedPath : string.Empty,
};
}
public override string ToString()
{
return $"HasReplacement:{HasFileReplacement},IsFileSwap:{IsFileSwap} - {string.Join(",", GamePaths)} => {ResolvedPath}";
}
#pragma warning disable MA0009
[GeneratedRegex(@"^[a-zA-Z]:(/|\\)", RegexOptions.ECMAScript)]
private static partial Regex LocalPathRegex();
#pragma warning restore MA0009
}

View File

@@ -0,0 +1,47 @@
namespace MareSynchronos.PlayerData.Data;
public class FileReplacementComparer : IEqualityComparer<FileReplacement>
{
private static readonly FileReplacementComparer _instance = new();
private FileReplacementComparer()
{ }
public static FileReplacementComparer Instance => _instance;
public bool Equals(FileReplacement? x, FileReplacement? y)
{
if (x == null || y == null) return false;
return x.ResolvedPath.Equals(y.ResolvedPath) && CompareLists(x.GamePaths, y.GamePaths);
}
public int GetHashCode(FileReplacement obj)
{
return HashCode.Combine(obj.ResolvedPath.GetHashCode(StringComparison.OrdinalIgnoreCase), GetOrderIndependentHashCode(obj.GamePaths));
}
private static bool CompareLists(HashSet<string> list1, HashSet<string> list2)
{
if (list1.Count != list2.Count)
return false;
for (int i = 0; i < list1.Count; i++)
{
if (!string.Equals(list1.ElementAt(i), list2.ElementAt(i), StringComparison.OrdinalIgnoreCase))
return false;
}
return true;
}
private static int GetOrderIndependentHashCode<T>(IEnumerable<T> source) where T : notnull
{
int hash = 0;
foreach (T element in source)
{
hash = unchecked(hash +
EqualityComparer<T>.Default.GetHashCode(element));
}
return hash;
}
}

View File

@@ -0,0 +1,49 @@
using MareSynchronos.API.Data;
namespace MareSynchronos.PlayerData.Data;
public class FileReplacementDataComparer : IEqualityComparer<FileReplacementData>
{
private static readonly FileReplacementDataComparer _instance = new();
private FileReplacementDataComparer()
{ }
public static FileReplacementDataComparer Instance => _instance;
public bool Equals(FileReplacementData? x, FileReplacementData? y)
{
if (x == null || y == null) return false;
return x.Hash.Equals(y.Hash) && CompareHashSets(x.GamePaths.ToHashSet(StringComparer.Ordinal), y.GamePaths.ToHashSet(StringComparer.Ordinal)) && string.Equals(x.FileSwapPath, y.FileSwapPath, StringComparison.Ordinal);
}
public int GetHashCode(FileReplacementData obj)
{
return HashCode.Combine(obj.Hash.GetHashCode(StringComparison.OrdinalIgnoreCase), GetOrderIndependentHashCode(obj.GamePaths), StringComparer.Ordinal.GetHashCode(obj.FileSwapPath));
}
private static bool CompareHashSets(HashSet<string> list1, HashSet<string> list2)
{
if (list1.Count != list2.Count)
return false;
for (int i = 0; i < list1.Count; i++)
{
if (!string.Equals(list1.ElementAt(i), list2.ElementAt(i), StringComparison.OrdinalIgnoreCase))
return false;
}
return true;
}
private static int GetOrderIndependentHashCode<T>(IEnumerable<T> source) where T : notnull
{
int hash = 0;
foreach (T element in source)
{
hash = unchecked(hash +
EqualityComparer<T>.Default.GetHashCode(element));
}
return hash;
}
}

View File

@@ -0,0 +1,14 @@
namespace MareSynchronos.PlayerData.Pairs;
public enum PlayerChanges
{
ModFiles = 1,
ModManip = 2,
Glamourer = 3,
Customize = 4,
Heels = 5,
Honorific = 7,
ForcedRedraw = 8,
Moodles = 9,
PetNames = 10,
}