Even more ComputeAction/Constant codecs
This commit is contained in:
parent
47feee8425
commit
41b5b1a57b
112
src/main/kotlin/ru/dbotthepony/mc/otm/data/CodecList.kt
Normal file
112
src/main/kotlin/ru/dbotthepony/mc/otm/data/CodecList.kt
Normal file
@ -0,0 +1,112 @@
|
||||
package ru.dbotthepony.mc.otm.data
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.mojang.datafixers.util.Pair
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.DataResult
|
||||
import com.mojang.serialization.DynamicOps
|
||||
import ru.dbotthepony.mc.otm.core.stream
|
||||
import java.util.function.Predicate
|
||||
import java.util.stream.Stream
|
||||
|
||||
class CodecList<S : Any>(codecs: Stream<Codec<S>>) : Codec<S> {
|
||||
constructor(codecs: Collection<Codec<S>>) : this(codecs.stream())
|
||||
constructor(vararg codecs: Codec<S>) : this(codecs.stream() as Stream<Codec<S>>)
|
||||
|
||||
private val codecs = codecs.collect(ImmutableList.toImmutableList())
|
||||
|
||||
init {
|
||||
require(this.codecs.isNotEmpty()) { "No codecs provided" }
|
||||
}
|
||||
|
||||
override fun <T : Any> encode(input: S, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
val results = ArrayList<DataResult<T>>(codecs.size)
|
||||
|
||||
for (codec in codecs) {
|
||||
val result = codec.encode(input, ops, prefix)
|
||||
|
||||
if (result.result().isPresent) {
|
||||
return result
|
||||
} else {
|
||||
results.add(result)
|
||||
}
|
||||
}
|
||||
|
||||
return DataResult.error {
|
||||
"None of codecs encoded the input:\n " + results.joinToString(";\n ") { it.error().get().message() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<S, T>> {
|
||||
val results = ArrayList<DataResult<Pair<S, T>>>(codecs.size)
|
||||
|
||||
for (codec in codecs) {
|
||||
val result = codec.decode(ops, input)
|
||||
|
||||
if (result.result().isPresent) {
|
||||
return result
|
||||
} else {
|
||||
results.add(result)
|
||||
}
|
||||
}
|
||||
|
||||
return DataResult.error {
|
||||
"None of codecs decoded the input:\n " + results.joinToString(";\n ") { it.error().get().message() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PredicatedCodecList<S : Any>(codecs: Stream<kotlin.Pair<Codec<S>, Predicate<S>>>) : Codec<S> {
|
||||
constructor(codecs: Collection<kotlin.Pair<Codec<S>, Predicate<S>>>) : this(codecs.stream())
|
||||
constructor(vararg codecs: kotlin.Pair<Codec<S>, Predicate<S>>) : this(codecs.stream() as Stream<kotlin.Pair<Codec<S>, Predicate<S>>>)
|
||||
|
||||
private val codecs = codecs.collect(ImmutableList.toImmutableList())
|
||||
|
||||
init {
|
||||
require(this.codecs.isNotEmpty()) { "No codecs provided" }
|
||||
}
|
||||
|
||||
override fun <T : Any> encode(input: S, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
val results = ArrayList<DataResult<T>>(codecs.size)
|
||||
var i = -1
|
||||
|
||||
for ((codec, predicate) in codecs) {
|
||||
i++
|
||||
|
||||
if (predicate.test(input)) {
|
||||
val result = codec.encode(input, ops, prefix)
|
||||
|
||||
if (result.result().isPresent) {
|
||||
return result
|
||||
} else {
|
||||
results.add(result)
|
||||
}
|
||||
} else {
|
||||
val i2 = i
|
||||
results.add(DataResult.error { "Codec #$i2 predicate tested false" })
|
||||
}
|
||||
}
|
||||
|
||||
return DataResult.error {
|
||||
"None of codecs encoded the input:\n " + results.joinToString(";\n ") { it.error().get().message() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<S, T>> {
|
||||
val results = ArrayList<DataResult<Pair<S, T>>>(codecs.size)
|
||||
|
||||
for ((codec) in codecs) {
|
||||
val result = codec.decode(ops, input)
|
||||
|
||||
if (result.result().isPresent) {
|
||||
return result
|
||||
} else {
|
||||
results.add(result)
|
||||
}
|
||||
}
|
||||
|
||||
return DataResult.error {
|
||||
"None of codecs decoded the input:\n " + results.joinToString(";\n ") { it.error().get().message() }
|
||||
}
|
||||
}
|
||||
}
|
@ -12,12 +12,20 @@ object DecimalCodec : Codec<Decimal> {
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Decimal, T>> {
|
||||
return ops.getStringValue(input).flatMap {
|
||||
val result = ops.getStringValue(input).flatMap {
|
||||
try {
|
||||
DataResult.success(Pair(Decimal(it), ops.empty()))
|
||||
} catch (err: NumberFormatException) {
|
||||
DataResult.error { "Not a valid number for converting into Decimal: $it" }
|
||||
}
|
||||
}
|
||||
|
||||
if (result.result().isPresent) {
|
||||
return result
|
||||
}
|
||||
|
||||
return ops.getNumberValue(input).flatMap {
|
||||
DataResult.success(Pair(Decimal(it.toString()), ops.empty()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,9 @@ import net.minecraft.world.item.Item
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.data.DecimalCodec
|
||||
import ru.dbotthepony.mc.otm.data.PredicatedCodecList
|
||||
import java.util.Optional
|
||||
import java.util.function.Predicate
|
||||
|
||||
class ComputeAction(
|
||||
id: Either<ResourceLocation, TagKey<Item>>,
|
||||
@ -21,74 +23,158 @@ class ComputeAction(
|
||||
priority: Optional<Int> = Optional.empty(),
|
||||
) : AbstractRegistryAction(id, priority = priority) {
|
||||
companion object : Type<ComputeAction> {
|
||||
private val constantCodecConcise: Codec<Constant> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
it.group(
|
||||
DecimalCodec.fieldOf("matter").forGetter(Constant::matter),
|
||||
Codec.DOUBLE.fieldOf("complexity").forGetter(Constant::complexity),
|
||||
IMatterFunction.registry.codec.fieldOf("function").forGetter(Constant::matterFunction),
|
||||
).apply(it, ::Constant)
|
||||
}
|
||||
}
|
||||
|
||||
private val constantCodecVeryConcise: Codec<Constant> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
it.group(
|
||||
DecimalCodec.fieldOf("value").forGetter(Constant::matter),
|
||||
IMatterFunction.registry.codec.fieldOf("function").forGetter(Constant::matterFunction),
|
||||
).apply(it, ::Constant)
|
||||
}
|
||||
}
|
||||
|
||||
private val constantCodecVeryConcise2: Codec<Constant> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
it.group(
|
||||
Codec.DOUBLE.fieldOf("value").forGetter(Constant::complexity),
|
||||
IMatterFunction.registry.codec.fieldOf("function").forGetter(Constant::matterFunction),
|
||||
).apply(it, ::Constant)
|
||||
}
|
||||
}
|
||||
|
||||
private val constantCodecVerbose: Codec<Constant> by lazy {
|
||||
RecordCodecBuilder.create {
|
||||
private val constantCodecFull: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||
RecordCodecBuilder.create<Constant> {
|
||||
it.group(
|
||||
DecimalCodec.fieldOf("matter").forGetter(Constant::matter),
|
||||
Codec.DOUBLE.fieldOf("complexity").forGetter(Constant::complexity),
|
||||
IMatterFunction.registry.codec.fieldOf("matterFunction").forGetter(Constant::matterFunction),
|
||||
IMatterFunction.registry.codec.fieldOf("complexityFunction").forGetter(Constant::complexityFunction),
|
||||
).apply(it, ::Constant)
|
||||
} to Predicate { true }
|
||||
}
|
||||
|
||||
private val constantCodecValues: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||
RecordCodecBuilder.create<Constant> {
|
||||
it.group(
|
||||
DecimalCodec.fieldOf("matter").forGetter(Constant::matter),
|
||||
Codec.DOUBLE.fieldOf("complexity").forGetter(Constant::complexity),
|
||||
IMatterFunction.registry.codec.fieldOf("function").forGetter(Constant::matterFunction),
|
||||
).apply(it) { a, b, c -> Constant(a, b, c, c) }
|
||||
} to Predicate { it.matterFunction == it.complexityFunction }
|
||||
}
|
||||
|
||||
private val constantCodecFunctions: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||
RecordCodecBuilder.create<Constant> {
|
||||
it.group(
|
||||
DecimalCodec.fieldOf("value").forGetter(Constant::matter),
|
||||
IMatterFunction.registry.codec.fieldOf("matterFunction").forGetter(Constant::matterFunction),
|
||||
IMatterFunction.registry.codec.fieldOf("complexityFunction").forGetter(Constant::complexityFunction),
|
||||
).apply(it) { a, b, c -> Constant(a, a.toDouble(), b, c) }
|
||||
} to Predicate { it.matter == Decimal(it.complexity.toString()) }
|
||||
}
|
||||
|
||||
private val constantCodecConcise: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||
RecordCodecBuilder.create<Constant> {
|
||||
it.group(
|
||||
DecimalCodec.fieldOf("value").forGetter(Constant::matter),
|
||||
IMatterFunction.registry.codec.fieldOf("function").forGetter(Constant::matterFunction),
|
||||
).apply(it) { a, b -> Constant(a, a.toDouble(), b, b) }
|
||||
} to Predicate { it.matter == Decimal(it.complexity.toString()) && it.matterFunction == it.complexityFunction }
|
||||
}
|
||||
|
||||
private val constantCodecComplexity: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||
RecordCodecBuilder.create<Constant> {
|
||||
it.group(
|
||||
Codec.DOUBLE.fieldOf("complexity").forGetter(Constant::complexity),
|
||||
IMatterFunction.registry.codec.fieldOf("function").forGetter(Constant::complexityFunction),
|
||||
).apply(it) { a, b -> Constant(Decimal.ZERO, a.toDouble(), IMatterFunction.NOOP, b) }
|
||||
} to Predicate { it.matterFunction == IMatterFunction.NOOP }
|
||||
}
|
||||
|
||||
private val constantCodecComplexity2: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||
RecordCodecBuilder.create<Constant> {
|
||||
it.group(
|
||||
Codec.DOUBLE.fieldOf("complexity").forGetter(Constant::complexity),
|
||||
IMatterFunction.registry.codec.fieldOf("complexityFunction").forGetter(Constant::complexityFunction),
|
||||
).apply(it) { a, b -> Constant(Decimal.ZERO, a.toDouble(), IMatterFunction.NOOP, b) }
|
||||
} to Predicate { it.matterFunction == IMatterFunction.NOOP }
|
||||
}
|
||||
|
||||
private val constantCodecMatter: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||
RecordCodecBuilder.create<Constant> {
|
||||
it.group(
|
||||
DecimalCodec.fieldOf("matter").forGetter(Constant::matter),
|
||||
IMatterFunction.registry.codec.fieldOf("function").forGetter(Constant::matterFunction),
|
||||
).apply(it) { a, b -> Constant(a, 0.0, b, IMatterFunction.NOOP) }
|
||||
} to Predicate { it.complexityFunction == IMatterFunction.NOOP }
|
||||
}
|
||||
|
||||
private val constantCodecMatter2: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||
RecordCodecBuilder.create<Constant> {
|
||||
it.group(
|
||||
DecimalCodec.fieldOf("matter").forGetter(Constant::matter),
|
||||
IMatterFunction.registry.codec.fieldOf("matterFunction").forGetter(Constant::matterFunction),
|
||||
).apply(it) { a, b -> Constant(a, 0.0, b, IMatterFunction.NOOP) }
|
||||
} to Predicate { it.complexityFunction == IMatterFunction.NOOP }
|
||||
}
|
||||
|
||||
private data class StringConstantCodec(val fn: IMatterFunction, val symbol: Char) : Codec<Constant>, Predicate<Constant> {
|
||||
val pair = this to this
|
||||
|
||||
override fun <T : Any> encode(input: Constant, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
return DataResult.success(ops.createString(symbol + input.matter.toString()))
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Constant, T>> {
|
||||
return ops.getStringValue(input).flatMap {
|
||||
if (it[0] == symbol) {
|
||||
try {
|
||||
DataResult.success(Pair(Constant(Decimal(it.substring(1).trim()), it.substring(1).trim().toDouble(), fn, fn), ops.empty()))
|
||||
} catch (err: NumberFormatException) {
|
||||
DataResult.error { "Not a number: ${it.substring(1).trim()} (input string: $it)" }
|
||||
}
|
||||
} else {
|
||||
DataResult.error { "Input string does not match expected operand: expected $symbol, got ${it[0]} (for input $it)" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun test(t: Constant): Boolean {
|
||||
return t.matterFunction == fn && t.complexityFunction == fn && t.matter == Decimal(t.complexity.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private object PlainStringConstantCodec : Codec<Constant>, Predicate<Constant> {
|
||||
override fun <T : Any> encode(input: Constant, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
return DataResult.success(ops.createString(input.matter.toString()))
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Constant, T>> {
|
||||
val result = ops.getNumberValue(input).flatMap {
|
||||
try {
|
||||
DataResult.success(Pair(Constant(Decimal(it.toString()), it.toDouble(), IMatterFunction.PLUS, IMatterFunction.PLUS), ops.empty()))
|
||||
} catch (err: NumberFormatException) {
|
||||
DataResult.error { "Not a number: $it" }
|
||||
}
|
||||
}
|
||||
|
||||
if (result.result().isPresent)
|
||||
return result
|
||||
|
||||
return ops.getStringValue(input).flatMap {
|
||||
try {
|
||||
DataResult.success(Pair(Constant(Decimal(it), it.toDouble(), IMatterFunction.PLUS, IMatterFunction.PLUS), ops.empty()))
|
||||
} catch (err: NumberFormatException) {
|
||||
DataResult.error { "Not a number: $it" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun test(t: Constant): Boolean {
|
||||
return t.matterFunction == IMatterFunction.PLUS && t.complexityFunction == IMatterFunction.PLUS && t.matter == Decimal(t.complexity.toString())
|
||||
}
|
||||
}
|
||||
|
||||
private val constantCodec: Codec<Constant> by lazy {
|
||||
Codec.either(constantCodecConcise, constantCodecVerbose)
|
||||
.xmap({ it.map({ it }, { it }) }, { if (it.matterFunction == it.complexityFunction) Either.left(it) else Either.right(it) })
|
||||
}
|
||||
|
||||
private object ActualConstantCodec : Codec<Constant> {
|
||||
override fun <T : Any> encode(input: Constant, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
||||
if (input.complexity == input.matter.toDouble()) {
|
||||
return constantCodecVeryConcise.encode(input, ops, prefix)
|
||||
} else {
|
||||
return constantCodec.encode(input, ops, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Constant, T>> {
|
||||
var result = constantCodecVeryConcise.decode(ops, input)
|
||||
|
||||
if (result.result().isPresent) {
|
||||
return result
|
||||
}
|
||||
|
||||
result = constantCodecVeryConcise2.decode(ops, input)
|
||||
|
||||
if (result.result().isPresent) {
|
||||
return result
|
||||
}
|
||||
|
||||
return constantCodec.decode(ops, input)
|
||||
}
|
||||
PredicatedCodecList(
|
||||
PlainStringConstantCodec to PlainStringConstantCodec,
|
||||
StringConstantCodec(IMatterFunction.DIV, '/').pair,
|
||||
StringConstantCodec(IMatterFunction.MUL, '*').pair,
|
||||
StringConstantCodec(IMatterFunction.AT_LEAST, '>').pair,
|
||||
StringConstantCodec(IMatterFunction.AT_MOST, '<').pair,
|
||||
StringConstantCodec(IMatterFunction.MINUS, '-').pair,
|
||||
StringConstantCodec(IMatterFunction.MOD, '%').pair,
|
||||
StringConstantCodec(IMatterFunction.REPLACE, '^').pair,
|
||||
constantCodecMatter,
|
||||
constantCodecMatter2,
|
||||
constantCodecComplexity,
|
||||
constantCodecComplexity2,
|
||||
constantCodecConcise,
|
||||
constantCodecFunctions,
|
||||
constantCodecValues,
|
||||
constantCodecFull,
|
||||
)
|
||||
}
|
||||
|
||||
private val valueCodecConcise: Codec<Value> by lazy {
|
||||
@ -140,7 +226,7 @@ class ComputeAction(
|
||||
it.group(
|
||||
TargetCodec.fieldOf("id").forGetter(ComputeAction::id),
|
||||
Codec.list(Codec
|
||||
.either(ActualConstantCodec, ActualValueCodec)
|
||||
.either(constantCodec, ActualValueCodec)
|
||||
.xmap({ it.map({ it }, { it }) }, { if (it is Constant) Either.left(it) else Either.right(it as Value) }))
|
||||
.fieldOf("values")
|
||||
.forGetter(ComputeAction::values),
|
||||
@ -179,12 +265,6 @@ class ComputeAction(
|
||||
matterFunction: IMatterFunction,
|
||||
complexityFunction: IMatterFunction = matterFunction,
|
||||
) : Source(matterFunction, complexityFunction) {
|
||||
constructor(
|
||||
value: Decimal,
|
||||
matterFunction: IMatterFunction,
|
||||
complexityFunction: IMatterFunction = matterFunction
|
||||
) : this(value, value.toDouble(), matterFunction, complexityFunction)
|
||||
|
||||
constructor(
|
||||
value: Double,
|
||||
matterFunction: IMatterFunction,
|
||||
|
Loading…
Reference in New Issue
Block a user