diff --git a/src/Bannerlord.ModuleManager.Models/ApplicationVersion.cs b/src/Bannerlord.ModuleManager.Models/ApplicationVersion.cs
index 2eb85b3..91a1385 100644
--- a/src/Bannerlord.ModuleManager.Models/ApplicationVersion.cs
+++ b/src/Bannerlord.ModuleManager.Models/ApplicationVersion.cs
@@ -62,7 +62,14 @@ public bool IsSame(ApplicationVersion? other) =>
public bool IsSameWithChangeSet(ApplicationVersion? other) =>
Major == other?.Major && Minor == other.Minor && Revision == other.Revision && ChangeSet == other.ChangeSet;
- public override string ToString() => $"{GetPrefix(ApplicationVersionType)}{Major}.{Minor}.{Revision}.{ChangeSet}";
+ public override string ToString()
+ {
+ // Most user mods skip this, so to be user-friendly we can omit it if it was not originally specified.
+ return ChangeSet == 0
+ ? $"{GetPrefix(ApplicationVersionType)}{Major}.{Minor}.{Revision}"
+ : $"{GetPrefix(ApplicationVersionType)}{Major}.{Minor}.{Revision}.{ChangeSet}";
+ }
+ public string ToStringWithoutChangeset() => $"{GetPrefix(ApplicationVersionType)}{Major}.{Minor}.{Revision}";
public int CompareTo(ApplicationVersion? other) => ApplicationVersionComparer.CompareStandard(this, other);
diff --git a/src/Bannerlord.ModuleManager.Models/ApplicationVersionRange.cs b/src/Bannerlord.ModuleManager.Models/ApplicationVersionRange.cs
index 04185b2..ba82ae3 100644
--- a/src/Bannerlord.ModuleManager.Models/ApplicationVersionRange.cs
+++ b/src/Bannerlord.ModuleManager.Models/ApplicationVersionRange.cs
@@ -54,7 +54,16 @@ public bool IsSame(ApplicationVersionRange? other) =>
public bool IsSameWithChangeSet(ApplicationVersionRange? other) =>
Min.IsSameWithChangeSet(other?.Min) && Max.IsSameWithChangeSet(other?.Max);
- public override string ToString() => $"{Min} - {Max}";
+ public override string ToString()
+ {
+ // If the min and max changeset are at their default (0 and i32::MAX), we can
+ // simplify how we print the version. End user mods rarely use the changeset,
+ // it's only really used in official packages.
+ if (Min.ChangeSet == 0 && Max.ChangeSet == int.MaxValue)
+ return $"{Min.ToStringWithoutChangeset()} - {Max.ToStringWithoutChangeset()}";
+
+ return $"{Min} - {Max}";
+ }
public static bool TryParse(string versionRangeAsString, out ApplicationVersionRange versionRange)
{
diff --git a/src/Bannerlord.ModuleManager.Models/Issues/ModuleIssueV2.cs b/src/Bannerlord.ModuleManager.Models/Issues/ModuleIssueV2.cs
index d2f08bb..87904c1 100644
--- a/src/Bannerlord.ModuleManager.Models/Issues/ModuleIssueV2.cs
+++ b/src/Bannerlord.ModuleManager.Models/Issues/ModuleIssueV2.cs
@@ -326,11 +326,11 @@ ApplicationVersionRange VersionRange
) : ModuleVersionMismatchIssue(Module, Dependency);
///
-/// Represents an issue where a dependency's version is higher than the maximum allowed specific version.
-/// This occurs when a dependency module's version exceeds an exact version requirement.
+/// Represents an issue where a dependency's version is lower than the minimum allowed specific version.
+/// This occurs when a dependency module's version is below an version requirement.
///
/// The module with the version constraint
-/// The dependency module that exceeds the version requirement
+/// The dependency module that is under the version requirement
/// The specific version that should not be exceeded
///
/// This issue occurs when a module specifies incompatible versions.
@@ -338,32 +338,32 @@ ApplicationVersionRange VersionRange
/// Example scenario:
/// ```xml
///
-///
-///
+///
+///
+///
///
-///
-///
-///
+///
+///
+///
///
///
/// ```
///
-/// If a higher version of Harmony (e.g., `v2.3.0`) is installed than allowed, this issue will be raised.
+/// If a higher or equal version of Harmony (e.g., `v2.3.0`) is installed than allowed, this issue will be solved.
///
#if !BANNERLORDBUTRMODULEMANAGER_PUBLIC
internal
#else
public
# endif
- sealed record ModuleVersionMismatchLessThanOrEqualSpecificIssue(
+ sealed record ModuleVersionTooLowIssue(
ModuleInfoExtended Module,
ModuleInfoExtended Dependency,
ApplicationVersion Version
) : ModuleVersionMismatchSpecificIssue(Module, Dependency, Version)
{
public override string ToString() =>
- $"The module '{Module.Id}' requires version {Version} or lower of '{Dependency.Id}', but version {Dependency.Version} is installed";
+ $"The module '{Module.Id}' requires version {Version} or higher of '{Dependency.Id}', but version {Dependency.Version} is installed";
public override LegacyModuleIssue ToLegacy() => new(Module, Dependency.Id, ModuleIssueType.VersionMismatchLessThanOrEqual, ToString(), new ApplicationVersionRange(Version, Version));
}
@@ -456,7 +456,7 @@ public override string ToString() =>
/// This occurs when one module explicitly declares it cannot work with another module.
///
/// The module that has declared an incompatibility
-/// The ID of the module that is incompatible with the target
+/// The module that is incompatible with the target
///
/// This issue occurs when a module explicitly marks another module as incompatible.
///
@@ -480,11 +480,11 @@ public override string ToString() =>
# endif
sealed record ModuleIncompatibleIssue(
ModuleInfoExtended Module,
- string IncompatibleModuleId
+ ModuleInfoExtended IncompatibleModule
) : ModuleIssueV2(Module)
{
- public override string ToString() => $"'{IncompatibleModuleId}' is incompatible with this module";
- public override LegacyModuleIssue ToLegacy() => new(Module, IncompatibleModuleId, ModuleIssueType.Incompatible, ToString(), ApplicationVersionRange.Empty);
+ public override string ToString() => $"'{IncompatibleModule.Id}' is incompatible with this module";
+ public override LegacyModuleIssue ToLegacy() => new(Module, IncompatibleModule.Id, ModuleIssueType.Incompatible, ToString(), ApplicationVersionRange.Empty);
}
///
@@ -610,7 +610,7 @@ DependentModuleMetadata ConflictingModule
# endif
sealed record ModuleDependencyConflictCircularIssue(
ModuleInfoExtended Module,
- DependentModuleMetadata CircularDependency
+ ModuleInfoExtended CircularDependency
) : ModuleIssueV2(Module)
{
public override string ToString() => $"Module '{Module.Id}' and '{CircularDependency.Id}' have circular dependencies";
@@ -648,11 +648,11 @@ DependentModuleMetadata CircularDependency
# endif
sealed record ModuleDependencyNotLoadedBeforeIssue(
ModuleInfoExtended Module,
- string DependencyId
+ DependentModuleMetadata Dependency
) : ModuleIssueV2(Module)
{
- public override string ToString() => $"'{DependencyId}' should be loaded before '{Module.Id}'";
- public override LegacyModuleIssue ToLegacy() => new(Module, DependencyId, ModuleIssueType.DependencyNotLoadedBeforeThis, ToString(), ApplicationVersionRange.Empty);
+ public override string ToString() => $"'{Dependency.Id}' should be loaded before '{Module.Id}'";
+ public override LegacyModuleIssue ToLegacy() => new(Module, Dependency.Id, ModuleIssueType.DependencyNotLoadedBeforeThis, ToString(), ApplicationVersionRange.Empty);
}
///
@@ -686,11 +686,11 @@ string DependencyId
# endif
sealed record ModuleDependencyNotLoadedAfterIssue(
ModuleInfoExtended Module,
- string DependencyId
+ DependentModuleMetadata Dependency
) : ModuleIssueV2(Module)
{
- public override string ToString() => $"'{DependencyId}' should be loaded after '{Module.Id}'";
- public override LegacyModuleIssue ToLegacy() => new(Module, DependencyId, ModuleIssueType.DependencyNotLoadedAfterThis, ToString(), ApplicationVersionRange.Empty);
+ public override string ToString() => $"'{Dependency.Id}' should be loaded after '{Module.Id}'";
+ public override LegacyModuleIssue ToLegacy() => new(Module, Dependency.Id, ModuleIssueType.DependencyNotLoadedAfterThis, ToString(), ApplicationVersionRange.Empty);
}
///
@@ -773,8 +773,8 @@ ModuleInfoExtended Module
///
///
///
-///
-///
+///
+///
///
diff --git a/src/Bannerlord.ModuleManager/ModuleUtilities.cs b/src/Bannerlord.ModuleManager/ModuleUtilities.cs
index d756de6..515b83a 100644
--- a/src/Bannerlord.ModuleManager/ModuleUtilities.cs
+++ b/src/Bannerlord.ModuleManager/ModuleUtilities.cs
@@ -263,12 +263,14 @@ public static IEnumerable ValidateModuleEx(
/// The module to validate
/// Function that determines if a module is enabled
/// Function that determines if a module is valid
+ /// Set this to true to also report errors in the target module's dependencies. e.g. Missing dependencies of dependencies.
/// Any errors that were detected during inspection
public static IEnumerable ValidateModuleEx(
IReadOnlyList modules,
ModuleInfoExtended targetModule,
Func isSelected,
- Func isValid)
+ Func isValid,
+ bool validateDependencies = true)
{
var visited = new HashSet();
foreach (var issue in ValidateModuleEx(modules, targetModule, visited, isSelected, isValid))
@@ -287,7 +289,7 @@ public static IEnumerable ValidateModuleEx(
/// Function that determines if a module is valid
/// Set this to true to also report errors in the target module's dependencies. e.g. Missing dependencies of dependencies.
/// Any errors that were detected during inspection
- private static IEnumerable ValidateModuleEx(
+ public static IEnumerable ValidateModuleEx(
IReadOnlyList modules,
ModuleInfoExtended targetModule,
HashSet visitedModules,
@@ -386,8 +388,12 @@ public static IEnumerable ValidateModuleDependenciesDeclarationsE
.Where(x => x.LoadType != LoadType.None)
.FirstOrDefault(x => string.Equals(x.Id, targetModule.Id, StringComparison.Ordinal)) is { } metadata)
{
- if (metadata.LoadType == module.LoadType)
- yield return new ModuleDependencyConflictCircularIssue(targetModule, metadata);
+ if (metadata.LoadType != module.LoadType)
+ continue;
+
+ // Find the full module with given ID.
+ var fullModule = modules.First(x => moduleInfo.Id == x.Id);
+ yield return new ModuleDependencyConflictCircularIssue(targetModule, fullModule);
}
}
}
@@ -477,7 +483,7 @@ private static IEnumerable ValidateModuleDependenciesEx(
// dependedModuleMetadata.Version > dependedModule.Version
if (!metadata.IsOptional && (ApplicationVersionComparer.CompareStandard(metadata.Version, metadataModule.Version) > 0))
{
- yield return new ModuleVersionMismatchLessThanOrEqualSpecificIssue(
+ yield return new ModuleVersionTooLowIssue(
targetModule,
metadataModule,
metadata.Version);
@@ -517,7 +523,7 @@ private static IEnumerable ValidateModuleDependenciesEx(
// If the incompatible mod is selected, this mod should be disabled
if (isSelected(metadataModule))
- yield return new ModuleIncompatibleIssue(targetModule, metadataModule.Id);
+ yield return new ModuleIncompatibleIssue(targetModule, metadataModule);
}
// If another mod declared incompatibility and is selected, disable this
@@ -535,7 +541,7 @@ private static IEnumerable ValidateModuleDependenciesEx(
// If the incompatible mod is selected, this mod is disabled
if (isSelected(module))
- yield return new ModuleIncompatibleIssue(targetModule, module.Id);
+ yield return new ModuleIncompatibleIssue(targetModule, module);
}
}
}
@@ -603,14 +609,15 @@ public static IEnumerable ValidateLoadOrderEx(
continue;
}
+ // TODO(sewer): Return full module here later. Right now I don't have a good way to test some assertions.
if (metadata.LoadType == LoadType.LoadBeforeThis && metadataIdx > targetModuleIdx)
{
- yield return new ModuleDependencyNotLoadedBeforeIssue(targetModule, metadata.Id);
+ yield return new ModuleDependencyNotLoadedBeforeIssue(targetModule, metadata);
}
if (metadata.LoadType == LoadType.LoadAfterThis && metadataIdx < targetModuleIdx)
{
- yield return new ModuleDependencyNotLoadedAfterIssue(targetModule, metadata.Id);
+ yield return new ModuleDependencyNotLoadedAfterIssue(targetModule, metadata);
}
}
}