Backport MCriterionTrigger to 1.20.1

This commit is contained in:
DBotThePony 2023-12-31 20:29:57 +07:00
parent 5453c8c793
commit 520112df77
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -17,6 +17,7 @@ import net.minecraft.advancements.CriterionTriggerInstance
import net.minecraft.advancements.critereon.ContextAwarePredicate
import net.minecraft.advancements.critereon.DeserializationContext
import net.minecraft.advancements.critereon.EntityPredicate
import net.minecraft.advancements.critereon.SerializationContext
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.PlayerAdvancements
import net.minecraft.server.level.ServerPlayer
@ -30,6 +31,10 @@ import java.util.function.Predicate
// allows to support both 1.20.1 and 1.20.2 with ease
// and has slightly less memory footprint than vanilla SimpleCriterionTrigger
abstract class MCriterionTrigger<T : MCriterionTrigger<T>.AbstractInstance>(val id: ResourceLocation) : CriterionTrigger<T> {
override fun getId(): ResourceLocation {
return id
}
private val listeners = Reference2ObjectOpenHashMap<PlayerAdvancements, ObjectOpenHashSet<CriterionTrigger.Listener<T>>>()
override fun addPlayerListener(advancements: PlayerAdvancements, listener: CriterionTrigger.Listener<T>) {
@ -62,16 +67,25 @@ abstract class MCriterionTrigger<T : MCriterionTrigger<T>.AbstractInstance>(val
val context = EntityPredicate.createContext(player, player)
listeners.iterator()
.filter { predicate.test(it.trigger) && it.trigger.playerPredicate.map { it.matches(context) }.orElse(true) }
.filter { predicate.test(it.triggerInstance) && it.triggerInstance.playerPredicate.map { it.matches(context) }.orElse(true) }
.toImmutableList()
.forEach { it.run(advancements) }
}
abstract inner class AbstractInstance(val playerPredicate: Optional<ContextAwarePredicate>) : CriterionTriggerInstance {
fun criterion() = Criterion(this@MCriterionTrigger, this as T)
fun criterion() = this as T
final override fun serializeToJson(): JsonObject {
return codec.toJsonStrict(this as T) as JsonObject
override fun getCriterion(): ResourceLocation {
return id
}
final override fun serializeToJson(context: SerializationContext): JsonObject {
return try {
serializationContext.get().addLast(context)
codec.toJsonStrict(this as T) as JsonObject
} finally {
serializationContext.get().removeLast()
}
}
}
@ -82,17 +96,23 @@ abstract class MCriterionTrigger<T : MCriterionTrigger<T>.AbstractInstance>(val
}
}
protected val serializationContext = object : ThreadLocal<ArrayDeque<SerializationContext>>() {
override fun initialValue(): ArrayDeque<SerializationContext> {
return ArrayDeque()
}
}
@JvmStatic
protected val predicateCodec: Codec<ContextAwarePredicate> = object : Codec<ContextAwarePredicate> {
override fun <T : Any?> encode(input: ContextAwarePredicate, ops: DynamicOps<T>, prefix: T): DataResult<T> {
return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.toJson()))
return DataResult.success(JsonOps.INSTANCE.convertTo(ops, input.toJson(serializationContext.get().lastOrNull() ?: return DataResult.error { "Not serializing trigger instance" })))
}
override fun <T : Any?> decode(ops: DynamicOps<T>, input: T): DataResult<Pair<ContextAwarePredicate, T>> {
val context = deserializationContext.get().lastOrNull() ?: return DataResult.error { "Not current deserializing trigger instance" }
return try {
DataResult.success(Pair.of(EntityPredicate.fromJson(JsonObject().also { it["a"] = ops.convertTo(JsonOps.INSTANCE, input) }, "a", context).get(), ops.empty()))
DataResult.success(Pair.of(EntityPredicate.fromJson(JsonObject().also { it["a"] = ops.convertTo(JsonOps.INSTANCE, input) }, "a", context), ops.empty()))
} catch (err: Exception) {
DataResult.error { "Failed to deserialize ContextAwarePredicate: " + err.message }
}