diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/CobblemonImplementation.kt b/common/src/main/kotlin/com/cobblemon/mod/common/CobblemonImplementation.kt index 79c07adc50..36fa39b1aa 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/CobblemonImplementation.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/CobblemonImplementation.kt @@ -12,6 +12,7 @@ import com.cobblemon.mod.common.api.net.NetworkPacket import com.mojang.brigadier.arguments.ArgumentType import kotlin.reflect.KClass import net.minecraft.commands.synchronization.ArgumentTypeInfo +import net.minecraft.core.HolderLookup import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation import net.minecraft.server.MinecraftServer @@ -168,12 +169,16 @@ interface CobblemonImplementation { * TODO * * @param identifier - * @param reloader + * @param reloaderFactory * @param type * @param dependencies */ - fun registerResourceReloader(identifier: ResourceLocation, reloader: PreparableReloadListener, type: PackType, dependencies: Collection) - + fun registerResourceReloader( + identifier: ResourceLocation, + type: PackType, + dependencies: Collection, + reloaderFactory: (HolderLookup.Provider) -> PreparableReloadListener + ) /** * TODO * diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/data/ServerJsonDataRegistry.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/data/ServerJsonDataRegistry.kt new file mode 100644 index 0000000000..71d4bece09 --- /dev/null +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/data/ServerJsonDataRegistry.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2023 Cobblemon Contributors + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +package com.cobblemon.mod.common.api.data + +import com.cobblemon.mod.common.util.endsWith +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken +import net.minecraft.core.HolderLookup +import java.io.BufferedReader +import java.io.File +import java.util.concurrent.ExecutionException +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.packs.PackType +import net.minecraft.server.packs.resources.ResourceManager + +/** + * A [DataRegistry] that consumes JSON files. + * Every deserialized instance is attached to an [Identifier]. + * For example a file under data/mymod/[resourcePath]/entry.json would be backed by the identifier modid:entry. + * + * @param T The type of the data consumed by this registry. + * + * @author Licious + * @since August 5th, 2022 + */ +interface ServerJsonDataRegistry : DataRegistry { + + /** + * The [TypeToken] of type [T]. + */ + val typeToken: TypeToken + + /** + * The folder location for the data this registry will consume. + */ + val resourcePath: String + + override val type: PackType + get() = PackType.SERVER_DATA + + override fun reload(manager: ResourceManager) { + //NO-OP, handled by reload(manager, registry) + } + + fun reload(manager: ResourceManager, registry: HolderLookup.Provider) { + val gson = setupParser(registry) + val data = hashMapOf() + manager.listResources(resourcePath) { path -> path.endsWith(JSON_EXTENSION) }.forEach { (identifier, resource) -> + if (identifier.namespace == "pixelmon") { + return@forEach + } + + resource.open().use { stream -> + stream.bufferedReader().use { reader -> + val resolvedIdentifier = ResourceLocation.fromNamespaceAndPath(identifier.namespace, File(identifier.path).nameWithoutExtension) + data[resolvedIdentifier] = parse(reader, resolvedIdentifier, gson) + } + } + } + + reload(data, registry) + } + + fun parse(reader: BufferedReader, identifier: ResourceLocation, gson: Gson): T { + return try { + gson.fromJson(reader, typeToken.type) + } catch (exception: Exception) { + throw ExecutionException("Error loading JSON for data: $identifier", exception) + } + } + + /** + * Allows the creation of [Gson] instances which have adapters that are registry-aware, e.g. [com.cobblemon.mod.common.pokemon.evolution.adapters.LegacyItemConditionWrapperAdapter] + */ + fun setupParser(registry: HolderLookup.Provider): Gson + + /** + * Reloads this registry from the deserialized data. + * + * @param data A map of the data associating an instance to the respective identifier from the [ResourceManager]. + */ + fun reload(data: Map, registry: HolderLookup.Provider) + + companion object { + const val JSON_EXTENSION = ".json" + } +} diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/api/interaction/PokemonInteractions.kt b/common/src/main/kotlin/com/cobblemon/mod/common/api/interaction/PokemonInteractions.kt index 84312908b4..ef13ce8c36 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/api/interaction/PokemonInteractions.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/api/interaction/PokemonInteractions.kt @@ -10,7 +10,7 @@ package com.cobblemon.mod.common.api.interaction import com.cobblemon.mod.common.Cobblemon import com.cobblemon.mod.common.api.conditional.RegistryLikeCondition -import com.cobblemon.mod.common.api.data.JsonDataRegistry +import com.cobblemon.mod.common.api.data.ServerJsonDataRegistry import com.cobblemon.mod.common.api.molang.ExpressionLike import com.cobblemon.mod.common.api.pokemon.PokemonProperties import com.cobblemon.mod.common.api.pokemon.requirement.Requirement @@ -26,6 +26,7 @@ import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.reflect.TypeToken import net.minecraft.advancements.critereon.ItemPredicate +import net.minecraft.core.HolderLookup import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer import net.minecraft.server.packs.PackType @@ -36,28 +37,31 @@ import net.minecraft.world.level.block.Block import net.minecraft.world.level.levelgen.structure.Structure import net.minecraft.world.level.material.Fluid -object PokemonInteractions : JsonDataRegistry { +object PokemonInteractions : ServerJsonDataRegistry { override val id = cobblemonResource("pokemon_interactions") override val type = PackType.SERVER_DATA + override fun setupParser(registry: HolderLookup.Provider): Gson { + return GsonBuilder() + .registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter) + .registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter) + .registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter(registry)) + .registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter) + .registerTypeAdapter(InteractionEffect::class.java, InteractionEffectAdapter) + .registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter) + .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter) + .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter) + .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter) + .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Structure::class.java).type, StructureLikeConditionAdapter) + .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter) + .registerTypeAdapter(IntRange::class.java, IntRangeAdapter) + .registerTypeAdapterFactory(LowerCaseEnumTypeAdapterFactory()) + .setPrettyPrinting() + .create() + } + override val observable = SimpleObservable() override val typeToken: TypeToken = TypeToken.get(PokemonInteractionSet::class.java) override val resourcePath = "pokemon_interactions" - override val gson: Gson = GsonBuilder() - .registerTypeAdapter(ResourceLocation::class.java, IdentifierAdapter) - .registerTypeAdapter(PokemonProperties::class.java, pokemonPropertiesShortAdapter) - .registerTypeAdapter(ItemPredicate::class.java, LegacyItemConditionWrapperAdapter) - .registerTypeAdapter(Requirement::class.java, CobblemonRequirementAdapter) - .registerTypeAdapter(InteractionEffect::class.java, InteractionEffectAdapter) - .registerTypeAdapter(ExpressionLike::class.java, ExpressionLikeAdapter) - .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Biome::class.java).type, BiomeLikeConditionAdapter) - .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Block::class.java).type, BlockLikeConditionAdapter) - .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Item::class.java).type, ItemLikeConditionAdapter) - .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Structure::class.java).type, StructureLikeConditionAdapter) - .registerTypeAdapter(TypeToken.getParameterized(RegistryLikeCondition::class.java, Fluid::class.java).type, FluidLikeConditionAdapter) - .registerTypeAdapter(IntRange::class.java, IntRangeAdapter) - .registerTypeAdapterFactory(LowerCaseEnumTypeAdapterFactory()) - .setPrettyPrinting() - .create() val interactions = mutableListOf() @@ -65,7 +69,7 @@ object PokemonInteractions : JsonDataRegistry { PokemonInteractionsSyncPacket(interactions).sendToPlayer(player) } - override fun reload(data: Map) { + override fun reload(data: Map, registry: HolderLookup.Provider) { interactions.clear() val split = data.entries .partition { @@ -87,4 +91,4 @@ object PokemonInteractions : JsonDataRegistry { .flatMap { it.interactions } .firstOrNull(interactionCheck) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt b/common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt index d32c982aa7..258d67665a 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/data/CobblemonDataProvider.kt @@ -15,6 +15,7 @@ import com.cobblemon.mod.common.api.berry.Berries import com.cobblemon.mod.common.api.cooking.Seasonings import com.cobblemon.mod.common.api.data.DataProvider import com.cobblemon.mod.common.api.data.DataRegistry +import com.cobblemon.mod.common.api.data.ServerJsonDataRegistry import com.cobblemon.mod.common.api.dialogue.Dialogues import com.cobblemon.mod.common.api.events.CobblemonEvents import com.cobblemon.mod.common.api.fishing.PokeRods @@ -51,6 +52,7 @@ import com.cobblemon.mod.common.pokemon.properties.PropertiesCompletionProvider import com.cobblemon.mod.common.util.cobblemonResource import com.cobblemon.mod.common.util.ifClient import com.cobblemon.mod.common.util.server +import net.minecraft.core.HolderLookup import java.util.UUID import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer @@ -71,8 +73,8 @@ object CobblemonDataProvider : DataProvider { // client is public only so we can use it cross-module. maybe a more elegant solution exists, but this works @ApiStatus.Internal - val clientResourceReloader: PreparableReloadListener = SimpleResourceReloader(PackType.CLIENT_RESOURCES) - private val serverResourceReloader: PreparableReloadListener = SimpleResourceReloader(PackType.SERVER_DATA) + val clientResourceReloader: PreparableReloadListener = ClientResourceReloader() + private val serverResourceReloader: PreparableReloadListener = ServerResourceReloader() fun registerDefaults() { this.register(CobblemonScripts, reloadable = true) @@ -126,8 +128,10 @@ object CobblemonDataProvider : DataProvider { } ifClient { + Cobblemon.implementation.registerResourceReloader(cobblemonResource("client_resources"), PackType.CLIENT_RESOURCES, emptyList()) { ClientResourceReloader() } Cobblemon.implementation.registerResourceReloader(cobblemonResource("client_resources"), clientResourceReloader, PackType.CLIENT_RESOURCES, emptyList()) } + Cobblemon.implementation.registerResourceReloader(cobblemonResource("data_resources"), PackType.SERVER_DATA, emptyList()) { ServerResourceReloader(it) } Cobblemon.implementation.registerResourceReloader(cobblemonResource("data_resources"), serverResourceReloader, PackType.SERVER_DATA, emptyList()) } @@ -167,11 +171,22 @@ object CobblemonDataProvider : DataProvider { } } - private class SimpleResourceReloader(private val type: PackType) : ResourceManagerReloadListener { + private class ClientResourceReloader : ResourceManagerReloadListener { + override fun onResourceManagerReload(manager: ResourceManager) { + registries.filter { it.type == PackType.CLIENT_RESOURCES }.forEach { it.reload(manager) } + } + } + + private class ServerResourceReloader(private val registryAccess: HolderLookup.Provider) : ResourceManagerReloadListener { override fun onResourceManagerReload(manager: ResourceManager) { // Check for a server running, this is due to the create a world screen triggering datapack reloads, these are fine to happen as many times as needed as players may be in the process of adding their datapacks. val reloadAllowed = server()?.isReady != true - registries.filter { it.type == this.type && (reloadAllowed || it in reloadableRegistries) } + registries + .filter { it.type == PackType.SERVER_DATA && (reloadAllowed || it in reloadableRegistries) } + .filterIsInstance>() + .forEach { it.reload(manager, registryAccess) } + registries + .filter { it.type == PackType.SERVER_DATA && (reloadAllowed || it in reloadableRegistries) } .forEach { it.reload(manager) } } } diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/evolution/adapters/LegacyItemConditionWrapperAdapter.kt b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/evolution/adapters/LegacyItemConditionWrapperAdapter.kt index a55b17941c..a7da51e213 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/evolution/adapters/LegacyItemConditionWrapperAdapter.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/pokemon/evolution/adapters/LegacyItemConditionWrapperAdapter.kt @@ -9,6 +9,7 @@ package com.cobblemon.mod.common.pokemon.evolution.adapters import com.cobblemon.mod.common.util.adapters.CodecBackedAdapter +import com.cobblemon.mod.common.util.adapters.RegistryAccessResolver import com.google.gson.JsonDeserializationContext import com.google.gson.JsonDeserializer import com.google.gson.JsonElement @@ -19,6 +20,7 @@ import net.minecraft.advancements.critereon.ItemCustomDataPredicate import net.minecraft.advancements.critereon.ItemPredicate import net.minecraft.advancements.critereon.ItemSubPredicates import net.minecraft.advancements.critereon.NbtPredicate +import net.minecraft.core.HolderLookup import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.core.registries.Registries import net.minecraft.resources.ResourceLocation @@ -26,13 +28,16 @@ import net.minecraft.tags.TagKey import java.lang.reflect.Type // This is an ugly adapter because breaking changes are scary and people would ;( -object LegacyItemConditionWrapperAdapter : JsonDeserializer, JsonSerializer { +class LegacyItemConditionWrapperAdapter(val registryAccess: HolderLookup.Provider = RegistryAccessResolver.getAccess()) + : JsonDeserializer, JsonSerializer { - private const val TAG_PREFIX = "#" - private const val LEGACY_ITEM = "item" - private const val LEGACY_NBT = "nbt" + companion object { + private const val TAG_PREFIX = "#" + private const val LEGACY_ITEM = "item" + private const val LEGACY_NBT = "nbt" + } - private val codecAdapter = CodecBackedAdapter(ItemPredicate.CODEC) + private val codecAdapter = CodecBackedAdapter(ItemPredicate.CODEC, registryAccess) override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ItemPredicate { if (json.isJsonPrimitive) { @@ -64,7 +69,9 @@ object LegacyItemConditionWrapperAdapter : JsonDeserializer, Json { id -> if (isTag) { val tag = TagKey.create(Registries.ITEM, id) - builder.of(tag) + registryAccess.lookup(Registries.ITEM) + .map { builder.of(tag) } + .orElseGet { builder } } else { BuiltInRegistries.ITEM.getOptional(id) .map { builder.of(it) } @@ -75,4 +82,4 @@ object LegacyItemConditionWrapperAdapter : JsonDeserializer, Json ) } -} \ No newline at end of file +} diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/CodecBackedAdapter.kt b/common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/CodecBackedAdapter.kt index 7351a18b7c..0361c9aea9 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/CodecBackedAdapter.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/CodecBackedAdapter.kt @@ -10,16 +10,19 @@ package com.cobblemon.mod.common.util.adapters import com.google.gson.* import com.mojang.serialization.Codec +import com.mojang.serialization.JsonOps +import net.minecraft.core.HolderLookup +import net.minecraft.resources.RegistryOps import java.lang.reflect.Type -class CodecBackedAdapter(val codec: Codec) : JsonDeserializer, JsonSerializer { +class CodecBackedAdapter(val codec: Codec, val registryAccess: HolderLookup.Provider = RegistryAccessResolver.getAccess()) : JsonDeserializer, JsonSerializer { override fun deserialize( jElement: JsonElement, typeOfT: Type, context: JsonDeserializationContext ): T { - val ops = RegistryOpsProvider.getOpsWithDefaultFallback() + val ops = RegistryOps.create(JsonOps.INSTANCE, registryAccess) val result = ops.withDecoder(codec).apply(jElement) return result.result().orElseThrow { IllegalStateException("Failed to deserialize $jElement: ${result.error().orElse(null)}") @@ -31,7 +34,7 @@ class CodecBackedAdapter(val codec: Codec) : JsonDeserializer, JsonSeri typeOfSrc: Type?, context: JsonSerializationContext? ): JsonElement { - val ops = RegistryOpsProvider.getOpsWithDefaultFallback() + val ops = RegistryOps.create(JsonOps.INSTANCE, registryAccess) val result = ops.withEncoder(codec).apply(src) return result.result().orElseThrow { IllegalStateException("Failed to serialize $src: ${result.error().orElse(null)}") diff --git a/common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/RegistryOpsProvider.kt b/common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/RegistryOpsProvider.kt index 71d24b7214..003e95d5c6 100644 --- a/common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/RegistryOpsProvider.kt +++ b/common/src/main/kotlin/com/cobblemon/mod/common/util/adapters/RegistryOpsProvider.kt @@ -15,27 +15,33 @@ import com.google.gson.JsonElement import com.mojang.serialization.DynamicOps import com.mojang.serialization.JsonOps import net.minecraft.client.Minecraft +import net.minecraft.core.RegistryAccess import net.minecraft.resources.RegistryOps /** - * Utility for obtaining RegistryOps with the correct client/server registry access. - * Used when manually encoding/decoding registry-backed values (e.g., items, predicates). + * Utility for getting RegistryAccess with the correct client/server registry access. + * Used when as a fallback when manually encoding/decoding registry-backed values (e.g., items, predicates). */ -object RegistryOpsProvider { - fun getOpsWithDefaultFallback(): DynamicOps { +object RegistryAccessResolver { + fun getAccess(): RegistryAccess { + try { + Cobblemon.implementation + } catch (e: UninitializedPropertyAccessException) { + return RegistryAccess.EMPTY + } if (Cobblemon.implementation.environment() == Environment.CLIENT) { val minecraft = Minecraft.getInstance() if (minecraft != null && minecraft.level != null) - return RegistryOps.create(JsonOps.INSTANCE, minecraft.level!!.registryAccess()) + return minecraft.level!!.registryAccess() } if (Cobblemon.implementation.environment() == Environment.SERVER) { val server = server() if (server != null) - return RegistryOps.create(JsonOps.INSTANCE, server.registryAccess()) + return server.registryAccess() } - return JsonOps.INSTANCE + return RegistryAccess.EMPTY } } \ No newline at end of file diff --git a/fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt b/fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt index a8934dbe00..9fcc930de9 100644 --- a/fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt +++ b/fabric/src/main/kotlin/com/cobblemon/mod/fabric/CobblemonFabric.kt @@ -59,7 +59,9 @@ import net.fabricmc.fabric.impl.resource.loader.ResourceManagerHelperImpl import net.fabricmc.loader.api.FabricLoader import net.minecraft.client.Minecraft import net.minecraft.commands.synchronization.ArgumentTypeInfo +import net.minecraft.core.HolderLookup import net.minecraft.core.Registry +import net.minecraft.core.RegistryAccess import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.network.syncher.EntityDataSerializers import net.minecraft.resources.ResourceKey @@ -345,8 +347,52 @@ object CobblemonFabric : CobblemonImplementation { } } - override fun registerResourceReloader(identifier: ResourceLocation, reloader: PreparableReloadListener, type: PackType, dependencies: Collection) { - ResourceManagerHelper.get(type).registerReloadListener(CobblemonReloadListener(identifier, reloader, dependencies)) + override fun registerResourceReloader( + identifier: ResourceLocation, + type: PackType, + dependencies: Collection, + reloaderFactory: (HolderLookup.Provider) -> PreparableReloadListener + ) { + if (type == PackType.SERVER_DATA) { + val resourceLoader = ResourceManagerHelper.get(PackType.CLIENT_RESOURCES) + resourceLoader.registerReloadListener(identifier, { object : IdentifiableResourceReloadListener { + override fun reload( + synchronizer: PreparableReloadListener.PreparationBarrier, + manager: ResourceManager, + prepareProfiler: ProfilerFiller, + applyProfiler: ProfilerFiller, + prepareExecutor: Executor, + applyExecutor: Executor + ): CompletableFuture { + return reloaderFactory.invoke(it).reload(synchronizer, + manager, prepareProfiler, applyProfiler, + prepareExecutor, applyExecutor) + } + + override fun getFabricId() = identifier + + }}) + } + else { + val resourceLoader = ResourceManagerHelper.get(PackType.CLIENT_RESOURCES) + resourceLoader.registerReloadListener(object : IdentifiableResourceReloadListener { + override fun reload( + synchronizer: PreparableReloadListener.PreparationBarrier, + manager: ResourceManager, + prepareProfiler: ProfilerFiller, + applyProfiler: ProfilerFiller, + prepareExecutor: Executor, + applyExecutor: Executor + ): CompletableFuture { + return reloaderFactory.invoke(RegistryAccess.EMPTY).reload(synchronizer, + manager, prepareProfiler, applyProfiler, + prepareExecutor, applyExecutor) + } + + override fun getFabricId() = identifier + + }) + } } override fun server(): MinecraftServer? = if (this.environment() == Environment.CLIENT) Minecraft.getInstance().singleplayerServer else this.server diff --git a/neoforge/src/main/kotlin/com/cobblemon/mod/neoforge/CobblemonNeoForge.kt b/neoforge/src/main/kotlin/com/cobblemon/mod/neoforge/CobblemonNeoForge.kt index 0bcc5b414f..8a3951c38d 100644 --- a/neoforge/src/main/kotlin/com/cobblemon/mod/neoforge/CobblemonNeoForge.kt +++ b/neoforge/src/main/kotlin/com/cobblemon/mod/neoforge/CobblemonNeoForge.kt @@ -38,6 +38,8 @@ import com.cobblemon.mod.neoforge.worldgen.CobblemonBiomeModifiers import com.mojang.brigadier.arguments.ArgumentType import net.minecraft.commands.synchronization.ArgumentTypeInfo import net.minecraft.commands.synchronization.ArgumentTypeInfos +import net.minecraft.core.HolderLookup +import net.minecraft.core.RegistryAccess import net.minecraft.core.registries.Registries import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation @@ -92,11 +94,16 @@ import kotlin.reflect.KClass @Mod(Cobblemon.MODID) class CobblemonNeoForge : CobblemonImplementation { + private data class QueuedReloadListener( + val identifier: ResourceLocation, + val listener: (HolderLookup.Provider) -> PreparableReloadListener, + val dependencies: Collection + ) override val modAPI = ModAPI.NEOFORGE private val hasBeenSynced = hashSetOf() private val commandArgumentTypes = DeferredRegister.create(Registries.COMMAND_ARGUMENT_TYPE, Cobblemon.MODID) - private val reloadableResources = arrayListOf() + private val reloadableResources = arrayListOf() private val queuedWork = arrayListOf<() -> Unit>() override val networkManager = CobblemonNeoForgeNetworkManager @@ -438,13 +445,21 @@ class CobblemonNeoForge : CobblemonImplementation { } } - override fun registerResourceReloader(identifier: ResourceLocation, reloader: PreparableReloadListener, type: PackType, dependencies: Collection) { - if (type == PackType.SERVER_DATA) - this.reloadableResources += reloader + override fun registerResourceReloader( + identifier: ResourceLocation, + type: PackType, + dependencies: Collection, + reloaderFactory: (HolderLookup.Provider) -> PreparableReloadListener + ) { + if (type == PackType.SERVER_DATA) { + this.reloadableResources += QueuedReloadListener(identifier, reloaderFactory, dependencies) + } } private fun onReload(e: AddReloadListenerEvent) { - this.reloadableResources.forEach(e::addListener) + this.reloadableResources.forEach { queued -> + e.addListener(queued.listener.invoke(e.serverResources.registryLookup)) + } } override fun server(): MinecraftServer? = ServerLifecycleHooks.getCurrentServer()