Make Codec2RecipeSerializer thread safe

This commit is contained in:
DBotThePony 2023-08-18 13:59:57 +07:00
parent 933521df10
commit 182bb4c8ba
Signed by: DBot
GPG Key ID: DCC23B5715498507

View File

@ -18,16 +18,25 @@ import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.core.util.readBinaryJsonWithCodecIndirect
import ru.dbotthepony.mc.otm.core.util.writeBinaryJsonWithCodec
import kotlin.collections.ArrayDeque
import kotlin.concurrent.getOrSet
class Codec2RecipeSerializer<S : Recipe<*>> private constructor(
val empty: S?,
private val id: ArrayDeque<ResourceLocation>,
/**
* [ThreadLocal] because optimization mods can (and probably should) parallelize recipe deserialization,
* since RecipeSerializers are expected to be stateless. [Codec2RecipeSerializer], however, is stateful (threading PoV).
* To make it stateless, [ThreadLocal] is used.
*/
private val idStack: ThreadLocal<ArrayDeque<ResourceLocation>>,
codec: (Codec2RecipeSerializer<S>.Context) -> Codec<S>,
) : Codec<S>, RecipeSerializer<S> {
constructor(empty: S?, codec: (Codec2RecipeSerializer<S>.Context) -> Codec<S>) : this(empty, ArrayDeque(), codec)
constructor(empty: S?, codec: (Codec2RecipeSerializer<S>.Context) -> Codec<S>) : this(empty, ThreadLocal(), codec)
constructor(supplier: (Codec2RecipeSerializer<S>.Context) -> Codec<S>) : this(null, supplier)
private val codec = codec.invoke(Context())
private val id: ArrayDeque<ResourceLocation>
get() = idStack.getOrSet { ArrayDeque() }
inner class Context() {
val id: ResourceLocation
@ -65,7 +74,7 @@ class Codec2RecipeSerializer<S : Recipe<*>> private constructor(
}
fun <O : Recipe<*>> xmap(to: (S) -> O, from: (O) -> S): Codec2RecipeSerializer<O> {
return Codec2RecipeSerializer(empty?.let(to), id) { _ ->
return Codec2RecipeSerializer(empty?.let(to), idStack) { _ ->
codec.xmap(to, from)
}
}