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 // These should be permanent
if (ruinRewards.isEmpty()) if (!ruinRewardsFile.exists())
ruinRewards.putAll(fallbackRuleset.ruinRewards) ruinRewards.putAll(fallbackRuleset.ruinRewards)
if (globalUniques.uniques.isEmpty()) { if (!globalUniquesFile.exists()) {
globalUniques = fallbackRuleset.globalUniques globalUniques = fallbackRuleset.globalUniques
} }
// If we have no victories, add all the default victories // If we have no victories, add all the default victories
if (victories.isEmpty()) victories.putAll(fallbackRuleset.victories) if (victories.isEmpty()) victories.putAll(fallbackRuleset.victories)
if (speeds.isEmpty()) speeds.putAll(fallbackRuleset.speeds) if (speeds.isEmpty()) speeds.putAll(fallbackRuleset.speeds)
if (difficulties.isEmpty()) difficulties.putAll(fallbackRuleset.difficulties)
if (cityStateTypes.isEmpty()) if (cityStateTypes.isEmpty())
for (cityStateType in fallbackRuleset.cityStateTypes.values) for (cityStateType in fallbackRuleset.cityStateTypes.values)

View File

@ -31,6 +31,12 @@ internal class BaseRulesetValidator(
* value a Set of its prerequisites including indirect ones */ * value a Set of its prerequisites including indirect ones */
private val prereqsHashMap = HashMap<String, HashSet<String>>() 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 { init {
// The `UniqueValidator.checkUntypedUnique` filtering Unique test ("X not found in Unciv's unique types, and is not used as a filtering unique") // 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 // 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)) if (!ruleset.difficulties.containsKey(difficulty))
lines.add("${reward.name} references difficulty ${difficulty}, which does not exist!", sourceObject = reward) 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) { 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 */ /** Used to determine if certain uniques are used for filtering */
private val allUniqueParameters = HashSet<String>() 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) { private fun addToHashsets(uniqueHolder: IHasUniques) {
for (unique in uniqueHolder.uniqueObjects) { for (unique in uniqueHolder.uniqueObjects) {
if (unique.type == null) allNonTypedUniques.add(unique.text) if (unique.type == null) allNonTypedUniques.add(unique.text)
@ -94,6 +100,8 @@ class UniqueValidator(val ruleset: Ruleset) {
addConditionalErrors(conditional, rulesetErrors, prefix, unique, uniqueContainer, reportRulesetSpecificErrors) addConditionalErrors(conditional, rulesetErrors, prefix, unique, uniqueContainer, reportRulesetSpecificErrors)
} }
addUniqueTypeSpecificErrors(rulesetErrors, prefix, unique, uniqueContainer, reportRulesetSpecificErrors)
val conditionals = unique.modifiers.filter { it.type?.canAcceptUniqueTarget(UniqueTarget.Conditional) == true } val conditionals = unique.modifiers.filter { it.type?.canAcceptUniqueTarget(UniqueTarget.Conditional) == true }
if (conditionals.size > 1){ if (conditionals.size > 1){
val lastCheapConditional = conditionals.lastOrNull { it.type !in performanceHeavyConditionals } 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) 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( private fun addDeprecationAnnotationErrors(
unique: Unique, unique: Unique,
prefix: String, prefix: String,