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>> {
|
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 {
|
try {
|
||||||
DataResult.success(Pair(Decimal(it), ops.empty()))
|
DataResult.success(Pair(Decimal(it), ops.empty()))
|
||||||
} catch (err: NumberFormatException) {
|
} catch (err: NumberFormatException) {
|
||||||
DataResult.error { "Not a valid number for converting into Decimal: $it" }
|
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 net.minecraftforge.registries.ForgeRegistries
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.data.DecimalCodec
|
import ru.dbotthepony.mc.otm.data.DecimalCodec
|
||||||
|
import ru.dbotthepony.mc.otm.data.PredicatedCodecList
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
import java.util.function.Predicate
|
||||||
|
|
||||||
class ComputeAction(
|
class ComputeAction(
|
||||||
id: Either<ResourceLocation, TagKey<Item>>,
|
id: Either<ResourceLocation, TagKey<Item>>,
|
||||||
@ -21,74 +23,158 @@ class ComputeAction(
|
|||||||
priority: Optional<Int> = Optional.empty(),
|
priority: Optional<Int> = Optional.empty(),
|
||||||
) : AbstractRegistryAction(id, priority = priority) {
|
) : AbstractRegistryAction(id, priority = priority) {
|
||||||
companion object : Type<ComputeAction> {
|
companion object : Type<ComputeAction> {
|
||||||
private val constantCodecConcise: Codec<Constant> by lazy {
|
private val constantCodecFull: kotlin.Pair<Codec<Constant>, Predicate<Constant>> by lazy {
|
||||||
RecordCodecBuilder.create {
|
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, ::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 {
|
|
||||||
it.group(
|
it.group(
|
||||||
DecimalCodec.fieldOf("matter").forGetter(Constant::matter),
|
DecimalCodec.fieldOf("matter").forGetter(Constant::matter),
|
||||||
Codec.DOUBLE.fieldOf("complexity").forGetter(Constant::complexity),
|
Codec.DOUBLE.fieldOf("complexity").forGetter(Constant::complexity),
|
||||||
IMatterFunction.registry.codec.fieldOf("matterFunction").forGetter(Constant::matterFunction),
|
IMatterFunction.registry.codec.fieldOf("matterFunction").forGetter(Constant::matterFunction),
|
||||||
IMatterFunction.registry.codec.fieldOf("complexityFunction").forGetter(Constant::complexityFunction),
|
IMatterFunction.registry.codec.fieldOf("complexityFunction").forGetter(Constant::complexityFunction),
|
||||||
).apply(it, ::Constant)
|
).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 {
|
private val constantCodec: Codec<Constant> by lazy {
|
||||||
Codec.either(constantCodecConcise, constantCodecVerbose)
|
PredicatedCodecList(
|
||||||
.xmap({ it.map({ it }, { it }) }, { if (it.matterFunction == it.complexityFunction) Either.left(it) else Either.right(it) })
|
PlainStringConstantCodec to PlainStringConstantCodec,
|
||||||
}
|
StringConstantCodec(IMatterFunction.DIV, '/').pair,
|
||||||
|
StringConstantCodec(IMatterFunction.MUL, '*').pair,
|
||||||
private object ActualConstantCodec : Codec<Constant> {
|
StringConstantCodec(IMatterFunction.AT_LEAST, '>').pair,
|
||||||
override fun <T : Any> encode(input: Constant, ops: DynamicOps<T>, prefix: T): DataResult<T> {
|
StringConstantCodec(IMatterFunction.AT_MOST, '<').pair,
|
||||||
if (input.complexity == input.matter.toDouble()) {
|
StringConstantCodec(IMatterFunction.MINUS, '-').pair,
|
||||||
return constantCodecVeryConcise.encode(input, ops, prefix)
|
StringConstantCodec(IMatterFunction.MOD, '%').pair,
|
||||||
} else {
|
StringConstantCodec(IMatterFunction.REPLACE, '^').pair,
|
||||||
return constantCodec.encode(input, ops, prefix)
|
constantCodecMatter,
|
||||||
}
|
constantCodecMatter2,
|
||||||
}
|
constantCodecComplexity,
|
||||||
|
constantCodecComplexity2,
|
||||||
override fun <T : Any> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<Constant, T>> {
|
constantCodecConcise,
|
||||||
var result = constantCodecVeryConcise.decode(ops, input)
|
constantCodecFunctions,
|
||||||
|
constantCodecValues,
|
||||||
if (result.result().isPresent) {
|
constantCodecFull,
|
||||||
return result
|
)
|
||||||
}
|
|
||||||
|
|
||||||
result = constantCodecVeryConcise2.decode(ops, input)
|
|
||||||
|
|
||||||
if (result.result().isPresent) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
return constantCodec.decode(ops, input)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val valueCodecConcise: Codec<Value> by lazy {
|
private val valueCodecConcise: Codec<Value> by lazy {
|
||||||
@ -140,7 +226,7 @@ class ComputeAction(
|
|||||||
it.group(
|
it.group(
|
||||||
TargetCodec.fieldOf("id").forGetter(ComputeAction::id),
|
TargetCodec.fieldOf("id").forGetter(ComputeAction::id),
|
||||||
Codec.list(Codec
|
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) }))
|
.xmap({ it.map({ it }, { it }) }, { if (it is Constant) Either.left(it) else Either.right(it as Value) }))
|
||||||
.fieldOf("values")
|
.fieldOf("values")
|
||||||
.forGetter(ComputeAction::values),
|
.forGetter(ComputeAction::values),
|
||||||
@ -179,12 +265,6 @@ class ComputeAction(
|
|||||||
matterFunction: IMatterFunction,
|
matterFunction: IMatterFunction,
|
||||||
complexityFunction: IMatterFunction = matterFunction,
|
complexityFunction: IMatterFunction = matterFunction,
|
||||||
) : Source(matterFunction, complexityFunction) {
|
) : Source(matterFunction, complexityFunction) {
|
||||||
constructor(
|
|
||||||
value: Decimal,
|
|
||||||
matterFunction: IMatterFunction,
|
|
||||||
complexityFunction: IMatterFunction = matterFunction
|
|
||||||
) : this(value, value.toDouble(), matterFunction, complexityFunction)
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
value: Double,
|
value: Double,
|
||||||
matterFunction: IMatterFunction,
|
matterFunction: IMatterFunction,
|
||||||
|
Loading…
Reference in New Issue
Block a user