205 lines
5.1 KiB
Kotlin
205 lines
5.1 KiB
Kotlin
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)
|
||
}
|
||
}
|
||
}
|