Allow mods with no global uniques, no ruins or no difficulties file (#13521)

* Allow mods with no GlobalUniques

* Allow mods omitting Difficulties to fall back to Vanilla

* Allow mods with no Ancient Ruins + Checks
This commit is contained in:
SomeTroglodyte 2025-06-26 22:45:34 +02:00 committed by GitHub
parent 86d7324298
commit 2d3b6047f3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 2 deletions

View File

@ -449,16 +449,17 @@ class Ruleset {
}
// These should be permanent
if (ruinRewards.isEmpty())
if (!ruinRewardsFile.exists())
ruinRewards.putAll(fallbackRuleset.ruinRewards)
if (globalUniques.uniques.isEmpty()) {
if (!globalUniquesFile.exists()) {
globalUniques = fallbackRuleset.globalUniques
}
// If we have no victories, add all the default victories
if (victories.isEmpty()) victories.putAll(fallbackRuleset.victories)
if (speeds.isEmpty()) speeds.putAll(fallbackRuleset.speeds)
if (difficulties.isEmpty()) difficulties.putAll(fallbackRuleset.difficulties)
if (cityStateTypes.isEmpty())
for (cityStateType in fallbackRuleset.cityStateTypes.values)

View File

@ -31,6 +31,12 @@ internal class BaseRulesetValidator(
* value a Set of its prerequisites including indirect ones */
private val prereqsHashMap = HashMap<String, HashSet<String>>()
private val anyAncientRuins: Boolean by lazy {
ruleset.tileImprovements.values.asSequence()
.flatMap { it.uniqueObjects }
.any { it.type == UniqueType.IsAncientRuinsEquivalent }
}
init {
// The `UniqueValidator.checkUntypedUnique` filtering Unique test ("X not found in Unciv's unique types, and is not used as a filtering unique")
// should not complain when running the RulesetInvariant version, because an Extension Mod may e.g. define additional "Aircraft" and the _use_ of the
@ -266,6 +272,15 @@ internal class BaseRulesetValidator(
if (!ruleset.difficulties.containsKey(difficulty))
lines.add("${reward.name} references difficulty ${difficulty}, which does not exist!", sourceObject = reward)
}
// brainstorm: What additional constraints apply for rulesets without any ruins?
// * Any UniqueType.RuinsUpgrade is not OK -> See UniqueValidator.addUniqueTypeSpecificErrors
// * Any RuinRewards is not OK
// * Conversely, No ruinRewards is only OK for such rulesets
if (anyAncientRuins && ruleset.ruinRewards.isEmpty())
lines.add("There are Ancient Ruins or equivalents, but not RuinRewards", sourceObject = null)
if (!anyAncientRuins && ruleset.ruinRewards.isNotEmpty())
lines.add("There are RuinRewards, but no Ancient Ruins or equivalents", RulesetErrorSeverity.Warning, sourceObject = null)
}
override fun addSpecialistErrors(lines: RulesetErrorList) {

View File

@ -23,6 +23,12 @@ class UniqueValidator(val ruleset: Ruleset) {
/** Used to determine if certain uniques are used for filtering */
private val allUniqueParameters = HashSet<String>()
private val anyAncientRuins: Boolean by lazy {
ruleset.tileImprovements.values.asSequence()
.flatMap { it.uniqueObjects }
.any { it.type == UniqueType.IsAncientRuinsEquivalent }
}
private fun addToHashsets(uniqueHolder: IHasUniques) {
for (unique in uniqueHolder.uniqueObjects) {
if (unique.type == null) allNonTypedUniques.add(unique.text)
@ -94,6 +100,8 @@ class UniqueValidator(val ruleset: Ruleset) {
addConditionalErrors(conditional, rulesetErrors, prefix, unique, uniqueContainer, reportRulesetSpecificErrors)
}
addUniqueTypeSpecificErrors(rulesetErrors, prefix, unique, uniqueContainer, reportRulesetSpecificErrors)
val conditionals = unique.modifiers.filter { it.type?.canAcceptUniqueTarget(UniqueTarget.Conditional) == true }
if (conditionals.size > 1){
val lastCheapConditional = conditionals.lastOrNull { it.type !in performanceHeavyConditionals }
@ -260,6 +268,18 @@ class UniqueValidator(val ruleset: Ruleset) {
addDeprecationAnnotationErrors(conditional, "$prefix contains modifier \"${conditional.text}\" which", rulesetErrors, uniqueContainer)
}
private fun addUniqueTypeSpecificErrors(
rulesetErrors: RulesetErrorList, prefix: String, unique: Unique, uniqueContainer: IHasUniques?, reportRulesetSpecificErrors: Boolean
) {
when(unique.type) {
UniqueType.RuinsUpgrade -> {
if (reportRulesetSpecificErrors && !anyAncientRuins)
rulesetErrors.add("$prefix is pointless - there are no ancient ruins", RulesetErrorSeverity.Warning, uniqueContainer, unique)
}
else -> return
}
}
private fun addDeprecationAnnotationErrors(
unique: Unique,
prefix: String,