KStarbound/src/main/kotlin/ru/dbotthepony/kstarbound/defs/tile/RenderTemplate.kt

205 lines
5.1 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<Entry>,
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<String>()
}
}
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<Piece> = ImmutableList.of(),
val matchAllPoints: ImmutableList<Matcher> = ImmutableList.of(),
val matchAnyPoints: ImmutableList<Matcher> = ImmutableList.of(),
val subMatches: ImmutableList<RenderMatch> = 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<RenderPiece>()
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<RenderRuleList>()
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<RenderMatch>
) {
fun resolve(template: RenderTemplate) {
for (value in list) {
value.resolve(template)
}
}
}
@JsonFactory
data class RenderTemplate(
val pieces: ImmutableMap<String, RenderPiece>,
val representativePiece: String,
val matches: ImmutableList<RenderMatchList>,
val rules: ImmutableMap<String, RenderRuleList>,
) {
init {
for (value in matches) {
value.resolve(this)
}
}
}