package ru.dbotthepony.kstarbound.defs.tile import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableMap import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import org.apache.logging.log4j.LogManager import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory import ru.dbotthepony.kstarbound.util.WriteOnce import ru.dbotthepony.kstarbound.world.ITileGetter import ru.dbotthepony.kstarbound.world.TileState import ru.dbotthepony.kvector.vector.Vector2i @JsonFactory data class RenderPiece( val texture: String? = null, val textureSize: Vector2i, val texturePosition: Vector2i, val colorStride: Vector2i? = null, val variantStride: Vector2i? = null, ) fun interface EqualityRuleTester { fun test(thisTile: TileState, otherTile: TileState): Boolean } @JsonFactory data class RenderRuleList( val entries: ImmutableList, val join: Combination = Combination.ALL ) { enum class Combination { ALL, ANY; } @JsonFactory data class Entry( val type: String, val matchHue: Boolean = false, val inverse: Boolean = false, ) { private fun doTest(getter: ITileGetter, equalityTester: EqualityRuleTester, thisPos: Vector2i, offsetPos: Vector2i): Boolean { return when (type) { "EqualsSelf" -> equalityTester.test(getter.getTile(thisPos), getter.getTile(thisPos + offsetPos)) "Connects" -> getter.getTile(thisPos + offsetPos).material != null else -> { if (LOGGED.add(type)) { LOGGER.error("Unknown render rule test $type!") } false } } } fun test(getter: ITileGetter, equalityTester: EqualityRuleTester, thisPos: Vector2i, offsetPos: Vector2i): Boolean { if (inverse) { return !doTest(getter, equalityTester, thisPos, offsetPos) } return doTest(getter, equalityTester, thisPos, offsetPos) } companion object { private val LOGGER = LogManager.getLogger() private val LOGGED = ObjectOpenHashSet() } } fun test(getter: ITileGetter, equalityTester: EqualityRuleTester, thisPos: Vector2i, offset: Vector2i): Boolean { when (join) { Combination.ALL -> { for (entry in entries) { if (!entry.test(getter, equalityTester, thisPos, offset)) { return false } } return true } Combination.ANY -> { for (entry in entries) { if (entry.test(getter, equalityTester, thisPos, offset)) { return true } } return false } } } } @JsonFactory data class RenderMatch( val pieces: ImmutableList = ImmutableList.of(), val matchAllPoints: ImmutableList = ImmutableList.of(), val matchAnyPoints: ImmutableList = ImmutableList.of(), val subMatches: ImmutableList = ImmutableList.of(), val haltOnMatch: Boolean = false, val haltOnSubMatch: Boolean = false, ) { @JsonFactory(asList = true) data class Piece( val name: String, val offset: Vector2i ) { var piece by WriteOnce() fun resolve(template: RenderTemplate) { piece = template.pieces[name] ?: throw IllegalStateException("Unable to find render piece $name") } } @JsonFactory(asList = true) data class Matcher( val offset: Vector2i, val ruleName: String ) { var rule by WriteOnce() fun test(getter: ITileGetter, equalityTester: EqualityRuleTester, thisPos: Vector2i): Boolean { return rule.test(getter, equalityTester, thisPos, offset) } fun resolve(template: RenderTemplate) { rule = template.rules[ruleName] ?: throw IllegalStateException("Unable to find render rule $ruleName") } } fun resolve(template: RenderTemplate) { for (value in matchAllPoints) { value.resolve(template) } for (value in pieces) { value.resolve(template) } for (value in matchAnyPoints) { value.resolve(template) } for (value in subMatches) { value.resolve(template) } } /** * Возвращает, сработали ли ВСЕ [matchAllPoints] или ЛЮБОЙ ИЗ [matchAnyPoints] * * Если хотя бы один из них вернул false, весь тест возвращает false * * [subMatches] стоит итерировать только если это вернуло true * * [equalityTester] требуется для проверки раенства между "этим" тайлом и другим */ fun test(tileAccess: ITileGetter, equalityTester: EqualityRuleTester, thisPos: Vector2i): Boolean { for (matcher in matchAllPoints) { if (!matcher.test(tileAccess, equalityTester, thisPos)) { return false } } if (matchAnyPoints.isEmpty()) { return true } for (matcher in matchAnyPoints) { if (matcher.test(tileAccess, equalityTester, thisPos)) { return true } } return false } } @JsonFactory(asList = true) data class RenderMatchList( val name: String, val list: ImmutableList ) { fun resolve(template: RenderTemplate) { for (value in list) { value.resolve(template) } } } @JsonFactory data class RenderTemplate( val pieces: ImmutableMap, val representativePiece: String, val matches: ImmutableList, val rules: ImmutableMap, ) { init { for (value in matches) { value.resolve(this) } } }