Skip to content

Commit

Permalink
feat: JASM will now check gamebanana urls for new mod files. It does …
Browse files Browse the repository at this point in the history
…this by checking if there are any new mods since the last check. (Jorixon#78)

feat: JASM will now auto detect image in mod folder, looks for images in this order 1. ".jasm_cover" 2. "preview" 3. "cover"

chore: Added easter egg because idk

chore: Reduced the number of loose files in JASM folder
  • Loading branch information
Jorixon authored Nov 10, 2023
1 parent cf7e099 commit f05043c
Show file tree
Hide file tree
Showing 57 changed files with 2,442 additions and 267 deletions.
3 changes: 3 additions & 0 deletions src/GIMI-ModManager.Core/Contracts/Entities/ISkinMod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,7 @@ public interface ISkinMod : IMod, IEqualityComparer<ISkinMod>

public bool ContainsOnlyJasmFiles();
public string? GetModIniPath();

// Get folder name without the disabled prefix
public string GetNameWithoutDisabledPrefix();
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public interface ISkinManagerService : IDisposable
public string UnloadedModsFolderPath { get; }
public string ActiveModsFolderPath { get; }
public IReadOnlyCollection<ICharacterModList> CharacterModLists { get; }
bool IsInitialized { get; }
public Task ScanForModsAsync();
public ICharacterModList GetCharacterModList(string internalName);
public ICharacterModList GetCharacterModList(IModdableObject character);
Expand Down
4 changes: 2 additions & 2 deletions src/GIMI-ModManager.Core/Entities/CharacterModList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public sealed class CharacterModList : ICharacterModList

private readonly object _modsLock = new();

internal CharacterModList(ICharacter character, string absPath, ILogger? logger = null)
internal CharacterModList(IModdableObject character, string absPath, ILogger? logger = null)
{
_logger = logger?.ForContext<CharacterModList>();
Character = character;
Expand Down Expand Up @@ -140,7 +140,7 @@ public void TrackMod(ISkinMod mod)
_mods.Add(ModFolderHelpers.FolderHasDisabledPrefix(mod.Name)
? new CharacterSkinEntry(mod, this, false)
: new CharacterSkinEntry(mod, this, true));
_logger?.Debug("Tracking {ModName} in {CharacterName} modList", mod.Name, Character.InternalName);
_logger?.Verbose("Tracking {ModName} in {CharacterName} modList", mod.Name, Character.InternalName);
Debug.Assert(_mods.DistinctBy(m => m.Id).Count() == _mods.Count);
}
}
Expand Down
10 changes: 2 additions & 8 deletions src/GIMI-ModManager.Core/Entities/CharacterSkinEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,7 @@ public bool Equals(CharacterSkinEntry? x, CharacterSkinEntry? y)
return x.Id.Equals(y.Id);
}

public int GetHashCode(CharacterSkinEntry obj)
{
return obj.Id.GetHashCode();
}
public int GetHashCode(CharacterSkinEntry obj) => obj.Id.GetHashCode();

public override string ToString()
{
return "CharacterSkinEntry: " + Mod.Name + " (" + Id + ")";
}
public override string ToString() => "CharacterSkinEntry: " + Mod.Name + " (" + Id + ")";
}
23 changes: 18 additions & 5 deletions src/GIMI-ModManager.Core/Entities/Mods/Contract/ModSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ namespace GIMI_ModManager.Core.Entities.Mods.Contract;
public record ModSettings
{
public ModSettings(Guid id, string? customName = null, string? author = null, string? version = null,
Uri? modUrl = null, Uri? imagePath = null, string? characterSkinOverride = null)
Uri? modUrl = null, Uri? imagePath = null, string? characterSkinOverride = null, DateTime? dateAdded = null,
DateTime? lastChecked = null)
{
Id = id;
CustomName = customName;
Expand All @@ -16,9 +17,11 @@ public ModSettings(Guid id, string? customName = null, string? author = null, st
ModUrl = modUrl;
ImagePath = imagePath;
CharacterSkinOverride = characterSkinOverride;
DateAdded = dateAdded;
LastChecked = lastChecked;
}

public ModSettings DeepCopyWithProperties(string? characterSkinOverride = null)
public ModSettings DeepCopyWithProperties(string? newCharacterSkinOverride = null, DateTime? newLastChecked = null)
{
return new ModSettings(
Id,
Expand All @@ -27,7 +30,9 @@ public ModSettings DeepCopyWithProperties(string? characterSkinOverride = null)
Version,
ModUrl,
ImagePath,
characterSkinOverride ?? CharacterSkinOverride
newCharacterSkinOverride ?? CharacterSkinOverride,
DateAdded,
newLastChecked ?? LastChecked
);
}

Expand All @@ -49,6 +54,10 @@ internal ModSettings()

public string? CharacterSkinOverride { get; internal set; }

public DateTime? DateAdded { get; internal set; }

public DateTime? LastChecked { get; internal set; }


internal static ModSettings FromJsonSkinSettings(ISkinMod skinMod, JsonModSettings settings)
{
Expand All @@ -60,7 +69,9 @@ internal static ModSettings FromJsonSkinSettings(ISkinMod skinMod, JsonModSettin
Version = settings.Version,
ModUrl = ModsHelpers.StringUrlToUri(settings.ModUrl),
ImagePath = ModsHelpers.RelativeModPathToAbsPath(skinMod.FullPath, settings.ImagePath),
CharacterSkinOverride = settings.CharacterSkinOverride
CharacterSkinOverride = settings.CharacterSkinOverride,
DateAdded = DateTime.TryParse(settings.DateAdded, out var dateAdded) ? dateAdded : null,
LastChecked = DateTime.TryParse(settings.LastChecked, out var lastChecked) ? lastChecked : null
};
}

Expand All @@ -74,7 +85,9 @@ internal JsonModSettings ToJsonSkinSettings(ISkinMod skinMod)
Version = Version,
ModUrl = ModUrl?.ToString(),
ImagePath = ModsHelpers.UriPathToModRelativePath(skinMod, ImagePath?.LocalPath),
CharacterSkinOverride = CharacterSkinOverride
CharacterSkinOverride = CharacterSkinOverride,
DateAdded = DateAdded?.ToString(),
LastChecked = LastChecked?.ToString()
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace GIMI_ModManager.Core.Entities.Mods.Exceptions;

public class ModSettingsNotFoundException : Exception
{
public ModSettingsNotFoundException(string message) : base(message)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,10 @@ internal class JsonModSettings

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? CharacterSkinOverride { get; set; }

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? DateAdded { get; set; }

[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string? LastChecked { get; set; }
}
4 changes: 4 additions & 0 deletions src/GIMI-ModManager.Core/Entities/Mods/SkinMod/SkinMod.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GIMI_ModManager.Core.Contracts.Entities;
using GIMI_ModManager.Core.Helpers;

namespace GIMI_ModManager.Core.Entities.Mods.SkinMod;

Expand Down Expand Up @@ -105,6 +106,9 @@ public bool ContainsOnlyJasmFiles()

public string? GetModIniPath() => HasMergedInIFile(_modDirectory);

public string GetNameWithoutDisabledPrefix() =>
ModFolderHelpers.GetFolderNameWithoutDisabledPrefix(_modDirectory.Name);

public static bool operator ==(SkinMod? left, SkinMod? right)
{
if (ReferenceEquals(left, right)) return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using System.Text.Json;
using System.Globalization;
using System.Text.Json;
using GIMI_ModManager.Core.Contracts.Entities;
using GIMI_ModManager.Core.Entities.Mods.Contract;
using GIMI_ModManager.Core.Entities.Mods.Exceptions;
using GIMI_ModManager.Core.Entities.Mods.FileModels;
using GIMI_ModManager.Core.Entities.Mods.Helpers;
using GIMI_ModManager.Core.Helpers;
using Newtonsoft.Json;
using OneOf;
using JsonSerializer = System.Text.Json.JsonSerializer;
Expand All @@ -12,6 +15,7 @@ namespace GIMI_ModManager.Core.Entities.Mods.SkinMod;
public class SkinModSettingsManager
{
private readonly ISkinMod _skinMod;
private readonly IReadOnlyCollection<string> _supportedImageExtensions = Constants.SupportedImageExtensions;
private const string configFileName = ".JASM_ModConfig.json";
private const string ImageName = ".JASM_Cover";

Expand Down Expand Up @@ -40,20 +44,52 @@ internal async Task<Guid> InitializeAsync()
if (File.Exists(_settingsFilePath))
{
var modSettings = await ReadSettingsAsync().ConfigureAwait(false);
var updateSettings = false;

if (modSettings.Id == Guid.Empty)
{
modSettings.Id = Guid.NewGuid();
await SaveSettingsAsync(modSettings).ConfigureAwait(false);
_settings = modSettings;
updateSettings = true;
}

if (modSettings.DateAdded is null)
{
modSettings.DateAdded = DateTime.Now;
updateSettings = true;
}

if (modSettings.ImagePath is not null && !File.Exists(modSettings.ImagePath.LocalPath))
{
modSettings.ImagePath = null;
updateSettings = true;
}

if (modSettings.ImagePath is null)
{
var images = DetectImages();
if (images.Any())
{
modSettings.ImagePath = images.FirstOrDefault();
updateSettings = true;
}
}


if (updateSettings)
await SaveSettingsAsync(modSettings).ConfigureAwait(false);

return modSettings.Id;
}

var newId = Guid.NewGuid();
var settings = new JsonModSettings() { Id = newId.ToString() };

var image = DetectImages().FirstOrDefault();

var settings = new JsonModSettings()
{
Id = newId.ToString(), ImagePath = image?.LocalPath,
DateAdded = DateTime.Now.ToString(CultureInfo.CurrentCulture)
};
var json = JsonSerializer.Serialize(settings, _serializerOptions);

await File.WriteAllTextAsync(_settingsFilePath, json).ConfigureAwait(false);
Expand Down Expand Up @@ -114,19 +150,6 @@ public OneOf<ModSettings, SettingsNotLoaded> GetSettings()
return _settings;
}

private Task CopyAndSetModImage(ModSettings modSettings, string imagePath)
{
var uri = Uri.TryCreate(imagePath, UriKind.Absolute, out var result) &&
result.Scheme == Uri.UriSchemeFile
? result
: null;

if (uri is null)
throw new ArgumentException("Invalid image path.", nameof(imagePath));

return CopyAndSetModImage(modSettings, uri);
}

private async Task CopyAndSetModImage(ModSettings modSettings, Uri imagePath)
{
var oldModSettings = _settings ?? await ReadSettingsAsync();
Expand Down Expand Up @@ -159,12 +182,41 @@ private static void DeleteOldImage(Uri? oldImageUri)

File.Delete(oldImageUri.LocalPath);
}
}

public class ModSettingsNotFoundException : Exception
{
public ModSettingsNotFoundException(string message) : base(message)
private readonly string[] _imageNamePriority = new[] { ".jasm_cover", "preview", "cover" };

public Uri[] DetectImages()
{
var modDir = new DirectoryInfo(_skinMod.FullPath);
if (!modDir.Exists)
return Array.Empty<Uri>();

var images = new List<FileInfo>();
foreach (var file in modDir.EnumerateFiles())
{
if (!_imageNamePriority.Any(i => file.Name.ToLower().StartsWith(i)))
continue;


var extension = file.Extension.ToLower();
if (!_supportedImageExtensions.Contains(extension))
continue;

images.Add(file);
}

// Sort images by priority
foreach (var imageName in _imageNamePriority.Reverse())
{
var image = images.FirstOrDefault(x => x.Name.ToLower().StartsWith(imageName));
if (image is null)
continue;

images.Remove(image);
images.Insert(0, image);
}

return images.Select(x => new Uri(x.FullName)).ToArray();
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/GIMI-ModManager.Core/GIMI-ModManager.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@
<PackageReference Include="ErrorOr" Version="1.2.1" />
<PackageReference Include="FuzzySharp" Version="2.0.2" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="OneOf" Version="3.0.263" />
<PackageReference Include="Polly" Version="8.1.0" />
<PackageReference Include="Polly.RateLimiting" Version="8.1.0" />
<PackageReference Include="Serilog" Version="3.0.1" />
<PackageReference Include="SharpCompress" Version="0.33.0" />
</ItemGroup>
Expand Down
19 changes: 4 additions & 15 deletions src/GIMI-ModManager.Core/GamesService/GameService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,24 +224,13 @@ public Dictionary<ICharacter, int> QueryCharacters(string searchQuery,

public List<IRegion> GetRegions() => Regions.AllRegions.ToList();

public List<ICharacter> GetCharacters()
{
var characters = _characters.ToList();
return characters;
}
public List<ICharacter> GetCharacters() => _characters.ToList();

public List<ICharacter> GetDisabledCharacters()
{
var characters = _disabledCharacters.ToList();
return characters;
}
public List<ICharacter> GetDisabledCharacters() => _disabledCharacters.ToList();


public bool IsMultiMod(IModdableObject moddableObject)
{
var isMultiMod = IsMultiMod(moddableObject.InternalName);
return isMultiMod || moddableObject.IsMultiMod;
}
public bool IsMultiMod(IModdableObject moddableObject) =>
IsMultiMod(moddableObject.InternalName) || moddableObject.IsMultiMod;

public bool IsMultiMod(string modInternalName)
{
Expand Down
4 changes: 2 additions & 2 deletions src/GIMI-ModManager.Core/GamesService/Models/Character.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,13 @@ public CharacterBuilder SetRegion(IReadOnlyCollection<IRegion> regions)
connectedRegions.Add(region);
}
else
Log.Warning("Region {Region} not found in regions list", internalRegionName);
Log.Debug("Region {Region} not found in regions list", internalRegionName);
}

_character.Regions = connectedRegions;

if (connectedRegions.Count == 0)
Log.Warning("No regions found for character {Character}", _character.DisplayName);
Log.Debug("No regions found for character {Character}", _character.DisplayName);

_regionSet = true;
return this;
Expand Down
7 changes: 7 additions & 0 deletions src/GIMI-ModManager.Core/Helpers/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace GIMI_ModManager.Core.Helpers;

public static class Constants
{
public static readonly IReadOnlyCollection<string> SupportedImageExtensions = new[]
{ ".png", ".jpg", ".jpeg", ".bmp", ".gif", ".tif", ".tiff", ".ico", ".svg", ".webp", ".bitmap" };
}
Loading

0 comments on commit f05043c

Please sign in to comment.