From 1aab51feb8fc35d09e12020e5acbf9540747a27a Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 16 Nov 2024 18:12:46 +0900 Subject: [PATCH 01/27] Updated target compatability from 8 to 21 --- build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index a73a804..f904cc3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -43,14 +43,14 @@ loom { kotlin { jvmToolchain(21) compilerOptions { - jvmTarget.set(JvmTarget.JVM_1_8) + jvmTarget.set(JvmTarget.JVM_21) } } java { withSourcesJar() sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_21 } ktlint { From 0ba33ec8036e83dd78afe53123c5822a04751f96 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 16 Nov 2024 18:13:21 +0900 Subject: [PATCH 02/27] Added tag module --- .../core/mixin/TagManagerLoaderMixin.java | 69 +++++++++++ .../kotlin/dev/robustum/core/RobustumCore.kt | 15 ++- .../core/extensions/IdentifierExtensions.kt | 13 ++ .../robustum/core/extensions/TagExtensions.kt | 9 ++ .../kotlin/dev/robustum/core/tag/LazyTag.kt | 36 ++++++ .../robustum/core/tag/RobustumTagCodecs.kt | 22 ++++ .../dev/robustum/core/tag/RobustumTagEntry.kt | 71 +++++++++++ .../dev/robustum/core/tag/RobustumTagFile.kt | 20 ++++ .../core/tag/RobustumTagGroupLoader.kt | 112 ++++++++++++++++++ .../robustum/core/tag/RuntimeTagCallback.kt | 36 ++++++ src/main/resources/fabric.mod.json | 4 +- src/main/resources/robustum.mixins.json | 11 ++ 12 files changed, 412 insertions(+), 6 deletions(-) create mode 100644 src/main/java/dev/robustum/core/mixin/TagManagerLoaderMixin.java create mode 100644 src/main/kotlin/dev/robustum/core/extensions/IdentifierExtensions.kt create mode 100644 src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/LazyTag.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagFile.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/RuntimeTagCallback.kt create mode 100644 src/main/resources/robustum.mixins.json diff --git a/src/main/java/dev/robustum/core/mixin/TagManagerLoaderMixin.java b/src/main/java/dev/robustum/core/mixin/TagManagerLoaderMixin.java new file mode 100644 index 0000000..6b80e54 --- /dev/null +++ b/src/main/java/dev/robustum/core/mixin/TagManagerLoaderMixin.java @@ -0,0 +1,69 @@ +package dev.robustum.core.mixin; + +import dev.robustum.core.tag.RobustumTagGroupLoader; +import net.minecraft.block.Block; +import net.minecraft.entity.EntityType; +import net.minecraft.fluid.Fluid; +import net.minecraft.item.Item; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourceReloader; +import net.minecraft.tag.ServerTagManagerHolder; +import net.minecraft.tag.TagGroup; +import net.minecraft.tag.TagManager; +import net.minecraft.tag.TagManagerLoader; +import net.minecraft.util.profiler.Profiler; +import net.minecraft.util.registry.Registry; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +@Mixin(TagManagerLoader.class) +public abstract class TagManagerLoaderMixin { + + @Unique + private final RobustumTagGroupLoader blockLoader = new RobustumTagGroupLoader<>(Registry.BLOCK, "tags/blocks"); + + @Unique + private final RobustumTagGroupLoader itemLoader = new RobustumTagGroupLoader<>(Registry.ITEM, "tags/items"); + + @Unique + private final RobustumTagGroupLoader fluidLoader = new RobustumTagGroupLoader<>(Registry.FLUID, "tags/fluids"); + + @Unique + private final RobustumTagGroupLoader> entityLoader = new RobustumTagGroupLoader<>(Registry.ENTITY_TYPE, "tags/entity_types"); + + @Shadow + private TagManager tagManager; + + @SuppressWarnings("unchecked") + @Inject(method = "reload", at = @At("HEAD"), cancellable = true) + private void robustumCore$reload(ResourceReloader.Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor, CallbackInfoReturnable> cir) { + List>> rawMaps = List.of( + CompletableFuture.supplyAsync(() -> blockLoader.load(manager), prepareExecutor), + CompletableFuture.supplyAsync(() -> itemLoader.load(manager), prepareExecutor), + CompletableFuture.supplyAsync(() -> fluidLoader.load(manager), prepareExecutor), + CompletableFuture.supplyAsync(() -> entityLoader.load(manager), prepareExecutor) + ); + cir.setReturnValue( + CompletableFuture.allOf(rawMaps.toArray(CompletableFuture[]::new)) + .thenCompose(synchronizer::whenPrepared) + .thenAcceptAsync(void1 -> { + TagGroup blockGroup = (TagGroup) rawMaps.getFirst().join(); + TagGroup itemGroup = (TagGroup) rawMaps.get(1).join(); + TagGroup fluidGroup = (TagGroup) rawMaps.get(2).join(); + TagGroup> entityGroup = (TagGroup>) rawMaps.get(3).join(); + TagManager tagManager = TagManager.create(blockGroup, itemGroup, fluidGroup, entityGroup); + ServerTagManagerHolder.setTagManager(tagManager); + this.tagManager = tagManager; + }, applyExecutor) + ); + } + +} diff --git a/src/main/kotlin/dev/robustum/core/RobustumCore.kt b/src/main/kotlin/dev/robustum/core/RobustumCore.kt index 7ef0212..6821a64 100644 --- a/src/main/kotlin/dev/robustum/core/RobustumCore.kt +++ b/src/main/kotlin/dev/robustum/core/RobustumCore.kt @@ -1,13 +1,18 @@ package dev.robustum.core import net.fabricmc.api.ModInitializer +import net.minecraft.util.Identifier import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger -class RobustumCore : ModInitializer { - companion object { - const val MOD_ID = "robustum_core" - private val logger = LogManager.getLogger(RobustumCore::class.java) - } +object RobustumCore : ModInitializer { + const val MOD_ID = "robustum_core" + const val MOD_NAME = "Robustum Core" + + @JvmStatic + fun id(path: String): Identifier = Identifier(MOD_ID, path) + + private val logger: Logger = LogManager.getLogger(RobustumCore::class.java) override fun onInitialize() { logger.info("Robustum Core is loaded!") diff --git a/src/main/kotlin/dev/robustum/core/extensions/IdentifierExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/IdentifierExtensions.kt new file mode 100644 index 0000000..c7d4262 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/extensions/IdentifierExtensions.kt @@ -0,0 +1,13 @@ +package dev.robustum.core.extensions + +import net.minecraft.util.Identifier + +fun Identifier.prefix(prefix: String): Identifier = Identifier(this.namespace, prefix + this.path) + +fun Identifier.suffix(suffix: String): Identifier = Identifier(this.namespace, this.path + suffix) + +inline fun Identifier.modify(transform: (String) -> String): Identifier = Identifier(this.namespace, transform(this.path)) + +fun Identifier.removePrefix(prefix: String): Identifier = Identifier(this.namespace, this.path.removePrefix(prefix)) + +fun Identifier.removeSuffix(suffix: String): Identifier = Identifier(this.namespace, this.path.removeSuffix(suffix)) diff --git a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt new file mode 100644 index 0000000..824d40d --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt @@ -0,0 +1,9 @@ +package dev.robustum.core.extensions + +import net.minecraft.tag.Tag +import net.minecraft.util.Identifier + +// Tag // + +val Tag.idOrNull: Identifier? + get() = (this as? Tag.Identified)?.id diff --git a/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt b/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt new file mode 100644 index 0000000..ced3199 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt @@ -0,0 +1,36 @@ +package dev.robustum.core.tag + +import net.fabricmc.fabric.api.tag.TagRegistry +import net.minecraft.block.Block +import net.minecraft.entity.EntityType +import net.minecraft.fluid.Fluid +import net.minecraft.item.Item +import net.minecraft.tag.Tag +import net.minecraft.util.Identifier + +class LazyTag private constructor(private val id: Identifier, private val tagGetter: (Identifier) -> Tag) : Tag.Identified { + companion object { + @JvmStatic + fun block(id: Identifier): LazyTag = LazyTag(id, TagRegistry::block) + + @JvmStatic + fun entityType(id: Identifier): LazyTag> = LazyTag(id, TagRegistry::entityType) + + @JvmStatic + fun fluid(id: Identifier): LazyTag = LazyTag(id, TagRegistry::fluid) + + @JvmStatic + fun item(id: Identifier): LazyTag = LazyTag(id, TagRegistry::item) + } + + private val delegatedTag: Tag + get() = tagGetter(id) + + // Tag // + + override fun contains(entry: T): Boolean = delegatedTag.contains(entry) + + override fun values(): List = delegatedTag.values() + + override fun getId(): Identifier = id +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt new file mode 100644 index 0000000..257ab39 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt @@ -0,0 +1,22 @@ +package dev.robustum.core.tag + +import com.mojang.serialization.Codec +import net.minecraft.util.Identifier +import net.minecraft.util.StringIdentifiable + +object RobustumTagCodecs { + @JvmField + val TAG_ID: Codec = Codec.STRING.xmap({ + when (it.startsWith("#")) { + true -> TagEntryId(Identifier(it.removePrefix("#")), true) + false -> TagEntryId(Identifier(it), false) + } + }, TagEntryId::asString) + + data class TagEntryId(val id: Identifier, val isTag: Boolean) : StringIdentifiable { + override fun asString(): String = when (isTag) { + true -> id.toString() + false -> "#$id" + } + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt new file mode 100644 index 0000000..0839fa9 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt @@ -0,0 +1,71 @@ +package dev.robustum.core.tag + +import com.mojang.datafixers.util.Either +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.tag.Tag +import net.minecraft.util.Identifier + +class RobustumTagEntry private constructor(val id: Identifier, val isTag: Boolean, val required: Boolean) { + companion object { + @JvmStatic + private val ENTRY_CODEC: Codec = RecordCodecBuilder.create { instance -> + instance + .group( + RobustumTagCodecs.TAG_ID.fieldOf("id").forGetter(RobustumTagEntry::tagEntryId), + Codec.BOOL.optionalFieldOf("required", true).forGetter(RobustumTagEntry::required), + ).apply(instance, ::RobustumTagEntry) + } + + @JvmField + val CODEC: Codec = Codec.either(RobustumTagCodecs.TAG_ID, ENTRY_CODEC).xmap( + { either: Either -> + either.map({ + RobustumTagEntry( + it, + true, + ) + }, { it }) + }, + { + when (it.required) { + true -> Either.left(it.tagEntryId) + false -> Either.right(it) + } + }, + ) + + @JvmStatic + fun create(id: Identifier, required: Boolean = true): RobustumTagEntry = RobustumTagEntry(id, false, required) + + @JvmStatic + fun create(obj: T, transform: (T) -> Identifier, required: Boolean = true): RobustumTagEntry = + RobustumTagEntry(transform(obj), false, required) + + @JvmStatic + fun createTag(id: Identifier, required: Boolean = true): RobustumTagEntry = RobustumTagEntry(id, true, required) + } + + constructor(tagId: RobustumTagCodecs.TagEntryId, required: Boolean) : this(tagId.id, tagId.isTag, required) + + private val tagEntryId = RobustumTagCodecs.TagEntryId(id, isTag) + + fun resolve(valueGetter: ValueGetter, consumer: (T) -> Unit): Boolean { + if (isTag) { + valueGetter.tag(id)?.values()?.forEach(consumer) ?: return !required + } else { + valueGetter.direct(id)?.let(consumer) ?: return !required + } + return true + } + + override fun toString(): String = "RobustumTagEntry[id=$id, isTag=$isTag, required=$required]" + + // ValueGetter // + + interface ValueGetter { + fun direct(id: Identifier): T? + + fun tag(id: Identifier): Tag? + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagFile.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagFile.kt new file mode 100644 index 0000000..b5e0178 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagFile.kt @@ -0,0 +1,20 @@ +package dev.robustum.core.tag + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder + +data class RobustumTagFile(val entries: List, val replace: Boolean) { + companion object { + @JvmField + val CODEC: Codec = RecordCodecBuilder.create { instance -> + instance + .group( + RobustumTagEntry.CODEC + .listOf() + .fieldOf("values") + .forGetter(RobustumTagFile::entries), + Codec.BOOL.optionalFieldOf("replace", false).forGetter(RobustumTagFile::replace), + ).apply(instance, ::RobustumTagFile) + } + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt new file mode 100644 index 0000000..41a3c04 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt @@ -0,0 +1,112 @@ +package dev.robustum.core.tag + +import com.google.common.collect.ImmutableSet +import com.google.gson.JsonElement +import com.google.gson.JsonParser +import com.mojang.serialization.Dynamic +import com.mojang.serialization.JsonOps +import dev.robustum.core.RobustumCore +import dev.robustum.core.extensions.removePrefix +import dev.robustum.core.extensions.removeSuffix +import net.minecraft.resource.Resource +import net.minecraft.resource.ResourceManager +import net.minecraft.tag.Tag +import net.minecraft.tag.TagGroup +import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry +import net.minecraft.util.registry.RegistryKey +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger + +class RobustumTagGroupLoader(private val registry: Registry, private val dataType: String) { + private val logger: Logger = LogManager.getLogger() + private val parser = JsonParser() + + private val registryKey: RegistryKey> = registry.key + + private fun loadTags(resourceManager: ResourceManager): Map> = + buildMap> { + resourceManager.findResources(dataType) { it.endsWith(".json") }.forEach { resourceId: Identifier -> + val fixedId: Identifier = resourceId.removePrefix("$dataType/").removeSuffix(".json") + resourceManager.getAllResources(resourceId).forEach { resource: Resource -> + runCatching { + val json: JsonElement = resource.use { resourceIn: Resource -> + parser.parse(resourceIn.inputStream.bufferedReader()) + } + val builder: MutableList = this.computeIfAbsent(fixedId) { mutableListOf() } + val tagFile: RobustumTagFile = + RobustumTagFile.CODEC.parse(Dynamic(JsonOps.INSTANCE, json)).getOrThrow(false, logger::error) + if (tagFile.replace) { + builder.clear() + } + tagFile.entries.forEach { entry: RobustumTagEntry -> + builder.add( + TrackedEntry( + entry, + resource.resourcePackName, + ), + ) + } + }.onFailure(logger::error) + } + RuntimeTagCallback.EVENT.invoker().onRegister( + RuntimeTagCallback.Helper(registry) { tagId: Identifier, entry: RobustumTagEntry -> + this.computeIfAbsent(tagId) { mutableListOf() }.add(TrackedEntry(entry, RobustumCore.MOD_NAME)) + }, + ) + } + } + + private fun buildGroup(rawMap: Map>): TagGroup = TagGroup.create( + buildMap { + val valueGetter = object : RobustumTagEntry.ValueGetter { + override fun direct(id: Identifier): T? = registry.get(id) + + override fun tag(id: Identifier): Tag? = this@buildMap[id] + } + val copiedMap: MutableMap> = rawMap.toMutableMap() + while (copiedMap.isNotEmpty()) { + var result = false + copiedMap.toList().forEach { (id: Identifier, entries: List) -> + resolveEntries(valueGetter, entries)?.let { tag: Tag -> + this[id] = tag + copiedMap.remove(id) + result = true + } + } + if (!result) { + break + } + } + copiedMap.forEach { (id: Identifier, entries: List) -> + logger.error( + "Couldn't load ${registryKey.value.path} tag: $id as it is missing following references: [${ + getUnresolvedEntries( + valueGetter, + entries, + ).joinToString(separator = ", ", transform = TrackedEntry::toString) + }]", + ) + } + }, + ) + + private fun resolveEntries(valueGetter: RobustumTagEntry.ValueGetter, entries: List): Tag? { + val setBuilder: ImmutableSet.Builder = ImmutableSet.builder() + entries.forEach { entry: TrackedEntry -> + if (!entry.entry.resolve(valueGetter, setBuilder::add)) { + return null + } + } + return Tag.of(setBuilder.build()) + } + + private fun getUnresolvedEntries(valueGetter: RobustumTagEntry.ValueGetter, entries: List): List = + entries.filter { !it.entry.resolve(valueGetter) {} } + + fun load(resourceManager: ResourceManager): TagGroup = buildGroup(loadTags(resourceManager)) + + // TrackedEntry // + + data class TrackedEntry(val entry: RobustumTagEntry, val source: String) +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RuntimeTagCallback.kt b/src/main/kotlin/dev/robustum/core/tag/RuntimeTagCallback.kt new file mode 100644 index 0000000..ee39cd0 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/RuntimeTagCallback.kt @@ -0,0 +1,36 @@ +package dev.robustum.core.tag + +import dev.robustum.core.extensions.idOrNull +import net.fabricmc.fabric.api.event.Event +import net.fabricmc.fabric.api.event.EventFactory +import net.minecraft.tag.Tag +import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry +import net.minecraft.util.registry.RegistryKey + +fun interface RuntimeTagCallback { + companion object { + @JvmField + val EVENT: Event = EventFactory.createArrayBacked(RuntimeTagCallback::class.java) { callbacks -> + RuntimeTagCallback { helper: Helper -> callbacks.forEach { it.onRegister(helper) } } + } + } + + fun onRegister(helper: Helper) + + // Helper // + + class Helper(private val registry: Registry<*>, private val consumer: (Identifier, RobustumTagEntry) -> Unit) { + @Suppress("UNCHECKED_CAST") + fun add(registryKey: RegistryKey>, tag: Tag, vararg values: T) { + val tagId: Identifier = tag.idOrNull ?: return + if (registryKey == registry.key) { + val fixedRegistry: Registry = (registry as? Registry) ?: return + values + .mapNotNull(fixedRegistry::getId) + .map(RobustumTagEntry.Companion::create) + .forEach { consumer(tagId, it) } + } + } + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index ed03006..371ae30 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -18,7 +18,9 @@ } ] }, - "mixins": [], + "mixins": [ + "robustum.mixins.json" + ], "depends": { "fabricloader": ">=0.15.0", "fabric": "*", diff --git a/src/main/resources/robustum.mixins.json b/src/main/resources/robustum.mixins.json new file mode 100644 index 0000000..a196419 --- /dev/null +++ b/src/main/resources/robustum.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "dev.robustum.core.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "TagManagerLoaderMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} From eb8709696fd7084e12bd44ee3e53401ef83c5ff8 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 16 Nov 2024 20:00:52 +0900 Subject: [PATCH 03/27] Renamed RobustumTagCodecs to RobustumCodecs Experimental: Added new format ingredient --- build.gradle.kts | 2 + .../RobustumCodecs.kt} | 19 +++++-- .../robustum/core/recipe/RegistryEntryList.kt | 49 +++++++++++++++++++ .../core/recipe/WeightedIngredient.kt | 47 ++++++++++++++++++ .../dev/robustum/core/tag/RobustumTagEntry.kt | 13 ++--- .../core/tag/RobustumTagFormatRegistry.kt | 34 +++++++++++++ .../core/tag/RobustumTagGroupLoader.kt | 7 ++- .../dev/robustum/core/tag/TagFormatter.kt | 16 ++++++ src/main/resources/fabric.mod.json | 3 +- .../resources/robustum_core.accesswidener | 1 + ....mixins.json => robustum_core.mixins.json} | 0 11 files changed, 178 insertions(+), 13 deletions(-) rename src/main/kotlin/dev/robustum/core/{tag/RobustumTagCodecs.kt => extensions/RobustumCodecs.kt} (52%) create mode 100644 src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt create mode 100644 src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagFormatRegistry.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/TagFormatter.kt create mode 100644 src/main/resources/robustum_core.accesswidener rename src/main/resources/{robustum.mixins.json => robustum_core.mixins.json} (100%) diff --git a/build.gradle.kts b/build.gradle.kts index f904cc3..13b7ad7 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -33,6 +33,8 @@ dependencies { } loom { + accessWidenerPath = file("src/main/resources/robustum_core.accesswidener") + mods { create("robustum_core") { sourceSet(sourceSets.main.get()) diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt similarity index 52% rename from src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt rename to src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt index 257ab39..adb34c0 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt @@ -1,10 +1,13 @@ -package dev.robustum.core.tag +package dev.robustum.core.extensions import com.mojang.serialization.Codec +import net.minecraft.tag.Tag import net.minecraft.util.Identifier import net.minecraft.util.StringIdentifiable -object RobustumTagCodecs { +object RobustumCodecs { + // Tag // + @JvmField val TAG_ID: Codec = Codec.STRING.xmap({ when (it.startsWith("#")) { @@ -14,9 +17,17 @@ object RobustumTagCodecs { }, TagEntryId::asString) data class TagEntryId(val id: Identifier, val isTag: Boolean) : StringIdentifiable { + companion object { + @JvmStatic + fun of(entry: T, transform: (T) -> Identifier): TagEntryId = TagEntryId(transform(entry), false) + + @JvmStatic + fun tag(tag: Tag, transform: (Tag) -> Identifier): TagEntryId = TagEntryId(transform(tag), true) + } + override fun asString(): String = when (isTag) { - true -> id.toString() - false -> "#$id" + true -> "#$id" + false -> id.toString() } } } diff --git a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt new file mode 100644 index 0000000..df58744 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt @@ -0,0 +1,49 @@ +package dev.robustum.core.recipe + +import com.mojang.datafixers.util.Either +import com.mojang.serialization.Codec +import dev.robustum.core.extensions.RobustumCodecs +import net.minecraft.tag.Tag +import net.minecraft.tag.TagGroup +import net.minecraft.util.registry.DefaultedRegistry + +sealed interface RegistryEntryList : Iterable { + companion object { + @JvmStatic + fun codec(registry: DefaultedRegistry, groupGetter: () -> TagGroup): Codec> = + RobustumCodecs.TAG_ID.xmap( + { + when (it.isTag) { + true -> Tagged(groupGetter().getTagOrEmpty(it.id)) + false -> Direct(checkNotNull(registry.get(it.id))) + } + }, + { + it.storage.map( + { tag: Tag -> RobustumCodecs.TagEntryId.tag(tag, groupGetter()::getTagId) }, + { entry: T -> RobustumCodecs.TagEntryId.of(entry, registry::getId) }, + ) + }, + ) + + @JvmStatic + fun of(entry: T): RegistryEntryList = Direct(entry) + + @JvmStatic + fun tag(tag: Tag): RegistryEntryList = Tagged(tag) + } + + val storage: Either, T> + + private class Direct(private val entry: T) : RegistryEntryList { + override val storage: Either, T> = Either.right(entry) + + override fun iterator(): Iterator = listOf(entry).iterator() + } + + private class Tagged(val tag: Tag) : RegistryEntryList { + override val storage: Either, T> = Either.left(tag) + + override fun iterator(): Iterator = tag.values().iterator() + } +} diff --git a/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt new file mode 100644 index 0000000..ea5c0e1 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt @@ -0,0 +1,47 @@ +package dev.robustum.core.recipe + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.recipe.Ingredient +import net.minecraft.tag.ServerTagManagerHolder +import net.minecraft.tag.Tag +import net.minecraft.util.registry.Registry +import java.util.function.Predicate + +class WeightedIngredient private constructor(val entries: RegistryEntryList, val count: Int) : Predicate { + companion object { + @JvmField + val CODEC: Codec = RecordCodecBuilder.create { instance -> + instance + .group( + RegistryEntryList + .codec(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) + .fieldOf("items") + .forGetter(WeightedIngredient::entries), + Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(WeightedIngredient::count), + ).apply(instance, ::WeightedIngredient) + } + } + + constructor(tag: Tag, count: Int = 1) : this(RegistryEntryList.tag(tag), count) + + constructor(item: Item, count: Int = 1) : this(RegistryEntryList.of(item), count) + + val isEmpty: Boolean + get() = entries.storage.map({ it.values().isEmpty() }, { it == Items.AIR }) || count <= 0 + + val vanillaIngredient: Ingredient + get() = entries.storage.map(Ingredient::fromTag, Ingredient::ofItems) + + override fun test(stack: ItemStack): Boolean = when (stack.isEmpty) { + true -> this.isEmpty + false -> entries.storage.map( + { stack.item in it }, + { stack.item == it }, + ) && + stack.count >= count + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt index 0839fa9..65e2c41 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt @@ -3,23 +3,24 @@ package dev.robustum.core.tag import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.extensions.RobustumCodecs import net.minecraft.tag.Tag import net.minecraft.util.Identifier -class RobustumTagEntry private constructor(val id: Identifier, val isTag: Boolean, val required: Boolean) { +class RobustumTagEntry private constructor(private val id: Identifier, private val isTag: Boolean, private val required: Boolean) { companion object { @JvmStatic private val ENTRY_CODEC: Codec = RecordCodecBuilder.create { instance -> instance .group( - RobustumTagCodecs.TAG_ID.fieldOf("id").forGetter(RobustumTagEntry::tagEntryId), + RobustumCodecs.TAG_ID.fieldOf("id").forGetter(RobustumTagEntry::tagEntryId), Codec.BOOL.optionalFieldOf("required", true).forGetter(RobustumTagEntry::required), ).apply(instance, ::RobustumTagEntry) } @JvmField - val CODEC: Codec = Codec.either(RobustumTagCodecs.TAG_ID, ENTRY_CODEC).xmap( - { either: Either -> + val CODEC: Codec = Codec.either(RobustumCodecs.TAG_ID, ENTRY_CODEC).xmap( + { either: Either -> either.map({ RobustumTagEntry( it, @@ -46,9 +47,9 @@ class RobustumTagEntry private constructor(val id: Identifier, val isTag: Boolea fun createTag(id: Identifier, required: Boolean = true): RobustumTagEntry = RobustumTagEntry(id, true, required) } - constructor(tagId: RobustumTagCodecs.TagEntryId, required: Boolean) : this(tagId.id, tagId.isTag, required) + constructor(tagId: RobustumCodecs.TagEntryId, required: Boolean) : this(tagId.id, tagId.isTag, required) - private val tagEntryId = RobustumTagCodecs.TagEntryId(id, isTag) + private val tagEntryId = RobustumCodecs.TagEntryId(id, isTag) fun resolve(valueGetter: ValueGetter, consumer: (T) -> Unit): Boolean { if (isTag) { diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagFormatRegistry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagFormatRegistry.kt new file mode 100644 index 0000000..3780e70 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagFormatRegistry.kt @@ -0,0 +1,34 @@ +package dev.robustum.core.tag + +import dev.robustum.core.extensions.modify +import net.minecraft.util.Identifier + +object RobustumTagFormatRegistry { + @JvmStatic + private val registry: MutableList = mutableListOf() + + @JvmStatic + fun register(formatter: TagFormatter) { + registry.add(formatter) + } + + @JvmStatic + fun format(id: Identifier): Identifier { + if (id.namespace == "minecraft") return id + registry.forEach { formatter: TagFormatter -> + if (formatter.canFormat(id.path)) { + return id.modify(formatter::format) + } + } + return id + } + + init { + register(TagFormatter.conventional("blocks")) + register(TagFormatter.conventional("bricks")) + register(TagFormatter.conventional("ingots")) + register(TagFormatter.conventional("logs")) + register(TagFormatter.conventional("nuggets")) + register(TagFormatter.conventional("ores")) + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt index 41a3c04..ce7bfa8 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt @@ -27,7 +27,10 @@ class RobustumTagGroupLoader(private val registry: Registry, private private fun loadTags(resourceManager: ResourceManager): Map> = buildMap> { resourceManager.findResources(dataType) { it.endsWith(".json") }.forEach { resourceId: Identifier -> - val fixedId: Identifier = resourceId.removePrefix("$dataType/").removeSuffix(".json") + val fixedId: Identifier = resourceId + .removePrefix("$dataType/") + .removeSuffix(".json") + // .let(RobustumTagFormatRegistry::format) resourceManager.getAllResources(resourceId).forEach { resource: Resource -> runCatching { val json: JsonElement = resource.use { resourceIn: Resource -> @@ -55,7 +58,7 @@ class RobustumTagGroupLoader(private val registry: Registry, private }, ) } - } + }.onEach { logger.info("Tag - ${it.key}") } private fun buildGroup(rawMap: Map>): TagGroup = TagGroup.create( buildMap { diff --git a/src/main/kotlin/dev/robustum/core/tag/TagFormatter.kt b/src/main/kotlin/dev/robustum/core/tag/TagFormatter.kt new file mode 100644 index 0000000..22e719a --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/TagFormatter.kt @@ -0,0 +1,16 @@ +package dev.robustum.core.tag + +interface TagFormatter { + fun canFormat(path: String): Boolean + + fun format(path: String): String + + companion object { + @JvmStatic + fun conventional(name: String): TagFormatter = object : TagFormatter { + override fun canFormat(path: String): Boolean = path.endsWith("_$name") + + override fun format(path: String): String = "$name/" + path.removeSuffix("_$name") + } + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 371ae30..90c0c77 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -18,8 +18,9 @@ } ] }, + "accessWidener" : "robustum_core.accesswidener", "mixins": [ - "robustum.mixins.json" + "robustum_core.mixins.json" ], "depends": { "fabricloader": ">=0.15.0", diff --git a/src/main/resources/robustum_core.accesswidener b/src/main/resources/robustum_core.accesswidener new file mode 100644 index 0000000..9ab2173 --- /dev/null +++ b/src/main/resources/robustum_core.accesswidener @@ -0,0 +1 @@ +accessWidener v2 named diff --git a/src/main/resources/robustum.mixins.json b/src/main/resources/robustum_core.mixins.json similarity index 100% rename from src/main/resources/robustum.mixins.json rename to src/main/resources/robustum_core.mixins.json From c568d0d2b7589e2d744cce06591a18e345944bd4 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Mon, 18 Nov 2024 20:40:43 +0900 Subject: [PATCH 04/27] Added DelegatedRecipeSerializer --- .../kotlin/dev/robustum/core/RobustumCore.kt | 3 + .../core/extensions/CodecExtensions.kt | 65 +++++++++ .../core/extensions/CollectionExtensions.kt | 8 ++ .../robustum/core/extensions/ItemExtension.kt | 15 ++ .../robustum/core/extensions/TagExtensions.kt | 2 + .../core/recipe/DelegatedRecipeSerializer.kt | 28 ++++ .../robustum/core/recipe/FluidIngredient.kt | 45 ++++++ ...eightedIngredient.kt => ItemIngredient.kt} | 37 +++-- .../dev/robustum/core/recipe/RecipeCodec.kt | 9 ++ .../robustum/core/recipe/RegistryEntryList.kt | 85 ++++++++--- .../core/recipe/RobustumRecipeSerializers.kt | 136 ++++++++++++++++++ .../kotlin/dev/robustum/core/tag/LazyTag.kt | 36 ----- .../dev/robustum/core/tag/RobustumTagEntry.kt | 3 +- 13 files changed, 404 insertions(+), 68 deletions(-) create mode 100644 src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt create mode 100644 src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt create mode 100644 src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt create mode 100644 src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt create mode 100644 src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt rename src/main/kotlin/dev/robustum/core/recipe/{WeightedIngredient.kt => ItemIngredient.kt} (50%) create mode 100644 src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt create mode 100644 src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt delete mode 100644 src/main/kotlin/dev/robustum/core/tag/LazyTag.kt diff --git a/src/main/kotlin/dev/robustum/core/RobustumCore.kt b/src/main/kotlin/dev/robustum/core/RobustumCore.kt index 6821a64..5b04300 100644 --- a/src/main/kotlin/dev/robustum/core/RobustumCore.kt +++ b/src/main/kotlin/dev/robustum/core/RobustumCore.kt @@ -1,5 +1,6 @@ package dev.robustum.core +import dev.robustum.core.recipe.RobustumRecipeSerializers import net.fabricmc.api.ModInitializer import net.minecraft.util.Identifier import org.apache.logging.log4j.LogManager @@ -15,6 +16,8 @@ object RobustumCore : ModInitializer { private val logger: Logger = LogManager.getLogger(RobustumCore::class.java) override fun onInitialize() { + RobustumRecipeSerializers + logger.info("Robustum Core is loaded!") } } diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt new file mode 100644 index 0000000..a38498a --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -0,0 +1,65 @@ +package dev.robustum.core.extensions + +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import com.mojang.serialization.MapLike +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.nbt.NbtCompound +import net.minecraft.util.registry.Registry +import java.util.* + +// Codec // + +private val ITEM_CODEC: Codec = lazeCodec { Registry.ITEM }.validate { item: Item -> + when (item) { + Items.AIR -> DataResult.error("Item must not be minecraft:air") + else -> DataResult.success(item) + } +} + +private val RAW_STACK_CODEC: Codec = RecordCodecBuilder.create { instance -> + instance + .group( + ITEM_CODEC.fieldOf("id").forGetter(ItemStack::getItem), + Codec.intRange(0, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemStack::getCount), + NbtCompound.CODEC.optionalFieldOf("tag").forGetter { stack: ItemStack -> Optional.ofNullable(stack.tag) }, + ).apply(instance) { item: Item, count: Int, nbt: Optional -> + ItemStack(item, count).apply { nbt.ifPresent(this::setTag) } + } +} + +val ITEM_STACK_CODEC: Codec = optionalCodec(RAW_STACK_CODEC).xmap( + { it.orElse(ItemStack.EMPTY) }, + { if (it.isEmpty) Optional.empty() else Optional.of(it) }, +) + +fun Codec.validate(validator: (A) -> DataResult): Codec = flatXmap(validator, validator) + +fun lazeCodec(getter: () -> Codec): Codec = object : Codec { + override fun encode(input: A, ops: DynamicOps, prefix: T): DataResult = getter().encode(input, ops, prefix) + + override fun decode(ops: DynamicOps, input: T): DataResult> = getter().decode(ops, input) +} + +fun optionalCodec(codec: Codec): Codec> = object : Codec> { + override fun encode(input: Optional, ops: DynamicOps, prefix: T): DataResult = when (input.isEmpty) { + true -> DataResult.success(ops.emptyMap()) + false -> codec.encode(input.get(), ops, prefix) + } + + private fun isEmpty(ops: DynamicOps, input: T): Boolean = ops + .getMap(input) + .result() + .map { mapLike: MapLike -> mapLike.entries().findAny().isEmpty } + .orElse(false) + + override fun decode(ops: DynamicOps, input: T): DataResult, T>> = when { + isEmpty(ops, input) -> DataResult.success(Pair.of(Optional.empty(), input)) + else -> codec.decode(ops, input).map { pair: Pair -> pair.mapFirst(Optional::of) } + } +} diff --git a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt new file mode 100644 index 0000000..8c98d4c --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt @@ -0,0 +1,8 @@ +package dev.robustum.core.extensions + +import net.minecraft.util.collection.DefaultedList + +// DefaultedList // + +inline fun Iterable.toDefaultedList(defaultValue: T): DefaultedList = + DefaultedList.copyOf(defaultValue, *this.toList().toTypedArray()) diff --git a/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt b/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt new file mode 100644 index 0000000..599fec8 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt @@ -0,0 +1,15 @@ +package dev.robustum.core.extensions + +import dev.robustum.core.recipe.RegistryEntryList +import net.minecraft.item.Item +import net.minecraft.item.ItemConvertible +import net.minecraft.item.ItemStack +import net.minecraft.tag.Tag + +// ItemStack // + +fun ItemStack.isOf(item: ItemConvertible): Boolean = this.item == item.asItem() + +fun ItemStack.isIn(tag: Tag): Boolean = this.item in tag + +fun ItemStack.isIn(entryList: RegistryEntryList): Boolean = this.item in entryList diff --git a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt index 824d40d..1543714 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt @@ -7,3 +7,5 @@ import net.minecraft.util.Identifier val Tag.idOrNull: Identifier? get() = (this as? Tag.Identified)?.id + +fun Tag.getSafeValue(): List = runCatching { values() }.getOrDefault(listOf()) diff --git a/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt b/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt new file mode 100644 index 0000000..a8d87b0 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt @@ -0,0 +1,28 @@ +package dev.robustum.core.recipe + +import com.google.gson.JsonObject +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import com.mojang.serialization.JsonOps +import net.minecraft.network.PacketByteBuf +import net.minecraft.recipe.Recipe +import net.minecraft.recipe.RecipeSerializer +import net.minecraft.util.Identifier + +class DelegatedRecipeSerializer>(private val delegated: RecipeSerializer, private val recipeCodec: RecipeCodec) : + RecipeSerializer { + override fun read(id: Identifier, json: JsonObject): T = recipeCodec + .createCodec(id) + .parse(JsonOps.INSTANCE, json) + .result() + .orElseThrow() + + fun write(dynamicOps: DynamicOps, recipe: T): DataResult = + recipeCodec.createCodec(recipe.id).encodeStart(dynamicOps, recipe) + + override fun read(id: Identifier, buf: PacketByteBuf): T = delegated.read(id, buf) + + override fun write(buf: PacketByteBuf, recipe: T) { + delegated.write(buf, recipe) + } +} diff --git a/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt new file mode 100644 index 0000000..166f65c --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt @@ -0,0 +1,45 @@ +package dev.robustum.core.recipe + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants +import net.minecraft.fluid.Fluid +import net.minecraft.fluid.Fluids +import net.minecraft.tag.ServerTagManagerHolder +import net.minecraft.tag.Tag +import net.minecraft.util.registry.Registry +import java.util.function.BiPredicate + +@Suppress("UnstableApiUsage") +class FluidIngredient private constructor(val entryList: RegistryEntryList, val amount: Long) : BiPredicate { + companion object { + @JvmField + val EMPTY = FluidIngredient(RegistryEntryList.empty(), 0) + + @JvmField + val CODEC: Codec = RecordCodecBuilder.create { instance -> + instance + .group( + RegistryEntryList + .codec(Registry.FLUID, ServerTagManagerHolder.getTagManager()::getFluids) + .fieldOf("fluids") + .forGetter(FluidIngredient::entryList), + Codec.LONG.optionalFieldOf("amount", FluidConstants.BUCKET).forGetter(FluidIngredient::amount), + ).apply(instance, ::FluidIngredient) + } + } + + constructor(tag: Tag, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.tag(tag), amount) + + constructor(fluid: Fluid, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.of(fluid), amount) + + constructor(fluids: List, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.of(fluids), amount) + + val isEmpty: Boolean + get() = entryList.isEmpty || amount <= 0 + + override fun test(fluid: Fluid, amount: Long): Boolean = when { + fluid == Fluids.EMPTY || amount <= 0 -> this.isEmpty + else -> fluid in entryList && amount >= this.amount + } +} diff --git a/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt similarity index 50% rename from src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt rename to src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt index ea5c0e1..040fdd3 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt @@ -2,46 +2,57 @@ package dev.robustum.core.recipe import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.extensions.isIn import net.minecraft.item.Item import net.minecraft.item.ItemStack -import net.minecraft.item.Items import net.minecraft.recipe.Ingredient import net.minecraft.tag.ServerTagManagerHolder import net.minecraft.tag.Tag import net.minecraft.util.registry.Registry import java.util.function.Predicate -class WeightedIngredient private constructor(val entries: RegistryEntryList, val count: Int) : Predicate { +class ItemIngredient private constructor(val entryList: RegistryEntryList, val count: Int) : Predicate { companion object { @JvmField - val CODEC: Codec = RecordCodecBuilder.create { instance -> + val EMPTY = ItemIngredient(RegistryEntryList.empty(), 0) + + @JvmField + val CODEC: Codec = RecordCodecBuilder.create { instance -> instance .group( RegistryEntryList .codec(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) .fieldOf("items") - .forGetter(WeightedIngredient::entries), - Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(WeightedIngredient::count), - ).apply(instance, ::WeightedIngredient) + .forGetter(ItemIngredient::entryList), + Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemIngredient::count), + ).apply(instance, ::ItemIngredient) } + + @JvmField + val VANILLA_CODEC: Codec = CODEC.xmap( + { it.vanillaIngredient }, + { ItemIngredient(it.matchingItemIds.map(Registry.ITEM::get)) }, + ) } constructor(tag: Tag, count: Int = 1) : this(RegistryEntryList.tag(tag), count) constructor(item: Item, count: Int = 1) : this(RegistryEntryList.of(item), count) + constructor(items: List, count: Int = 1) : this(RegistryEntryList.of(items), count) + val isEmpty: Boolean - get() = entries.storage.map({ it.values().isEmpty() }, { it == Items.AIR }) || count <= 0 + get() = entryList.isEmpty || count <= 0 val vanillaIngredient: Ingredient - get() = entries.storage.map(Ingredient::fromTag, Ingredient::ofItems) + get() = entryList.storage.map(Ingredient::fromTag) { + Ingredient.ofStacks( + it.stream().map(Item::getDefaultStack), + ) + } override fun test(stack: ItemStack): Boolean = when (stack.isEmpty) { true -> this.isEmpty - false -> entries.storage.map( - { stack.item in it }, - { stack.item == it }, - ) && - stack.count >= count + false -> stack.isIn(entryList) && stack.count >= count } } diff --git a/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt b/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt new file mode 100644 index 0000000..a3980e5 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt @@ -0,0 +1,9 @@ +package dev.robustum.core.recipe + +import com.mojang.serialization.Codec +import net.minecraft.recipe.Recipe +import net.minecraft.util.Identifier + +fun interface RecipeCodec> { + fun createCodec(id: Identifier): Codec +} diff --git a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt index df58744..415bd8a 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt @@ -3,47 +3,96 @@ package dev.robustum.core.recipe import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import dev.robustum.core.extensions.RobustumCodecs +import dev.robustum.core.extensions.getSafeValue import net.minecraft.tag.Tag import net.minecraft.tag.TagGroup import net.minecraft.util.registry.DefaultedRegistry +import java.util.function.Function +import kotlin.random.Random sealed interface RegistryEntryList : Iterable { companion object { @JvmStatic - fun codec(registry: DefaultedRegistry, groupGetter: () -> TagGroup): Codec> = - RobustumCodecs.TAG_ID.xmap( - { - when (it.isTag) { - true -> Tagged(groupGetter().getTagOrEmpty(it.id)) - false -> Direct(checkNotNull(registry.get(it.id))) - } + fun codec(registry: DefaultedRegistry, groupGetter: () -> TagGroup): Codec> = Codec + .either(RobustumCodecs.TAG_ID, RobustumCodecs.TAG_ID.listOf()) + .xmap( + { either: Either> -> + either.map( + { entry: RobustumCodecs.TagEntryId -> + when (entry.isTag) { + true -> tag(groupGetter().getTagOrEmpty(entry.id)) + false -> of(checkNotNull(registry.get(entry.id))) + } + }, + { entries: List -> + when { + entries.isEmpty() -> empty() + !entries.all(RobustumCodecs.TagEntryId::isTag) -> of( + entries.map(RobustumCodecs.TagEntryId::id).map(registry::get), + ) + + else -> throw IllegalStateException("Could not serialize TagEntryId list containing tag entry!!") + } + }, + ) }, - { - it.storage.map( - { tag: Tag -> RobustumCodecs.TagEntryId.tag(tag, groupGetter()::getTagId) }, - { entry: T -> RobustumCodecs.TagEntryId.of(entry, registry::getId) }, + { entryList: RegistryEntryList -> + entryList.storage.map( + { Either.left(RobustumCodecs.TagEntryId.tag(it, groupGetter()::getTagId)) }, + { entries: List -> + when (entries.size) { + 0 -> throw IllegalStateException("Could not serialize empty list to TagEntryId!") + 1 -> Either.left(RobustumCodecs.TagEntryId.of(entries[0], registry::getId)) + else -> Either.right( + entries.map { entry: T -> + RobustumCodecs.TagEntryId.of(entry, registry::getId) + }, + ) + } + }, ) }, ) @JvmStatic - fun of(entry: T): RegistryEntryList = Direct(entry) + fun empty(): RegistryEntryList = Direct(listOf()) + + @JvmStatic + fun of(vararg entries: T): RegistryEntryList = Direct(entries.toList()) + + @JvmStatic + fun of(entries: List): RegistryEntryList = Direct(entries.toList()) @JvmStatic fun tag(tag: Tag): RegistryEntryList = Tagged(tag) } - val storage: Either, T> + val storage: Either, List> + + val isEmpty: Boolean + get() = entries.isEmpty() + + val entries: List + get() = storage.map(Tag::getSafeValue, Function.identity()) + + val size: Int + get() = entries.size + + fun getRandom(random: Random): T? = entries.randomOrNull(random) + + operator fun get(index: Int): T = entries[index] + + operator fun contains(entry: T): Boolean = storage.map({ it.contains(entry) }, { it.any { entryIn: T -> entryIn == entry } }) - private class Direct(private val entry: T) : RegistryEntryList { - override val storage: Either, T> = Either.right(entry) + private class Direct(private val list: List) : RegistryEntryList { + override val storage: Either, List> = Either.right(list) - override fun iterator(): Iterator = listOf(entry).iterator() + override fun iterator(): Iterator = list.iterator() } private class Tagged(val tag: Tag) : RegistryEntryList { - override val storage: Either, T> = Either.left(tag) + override val storage: Either, List> = Either.left(tag) - override fun iterator(): Iterator = tag.values().iterator() + override fun iterator(): Iterator = tag.getSafeValue().iterator() } } diff --git a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt new file mode 100644 index 0000000..f897c92 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt @@ -0,0 +1,136 @@ +package dev.robustum.core.recipe + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.RobustumCore +import dev.robustum.core.extensions.ITEM_STACK_CODEC +import dev.robustum.core.extensions.toDefaultedList +import net.minecraft.item.ItemStack +import net.minecraft.recipe.* +import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry + +object RobustumRecipeSerializers { + @JvmField + val SHAPELESS: DelegatedRecipeSerializer = + registerDelegated( + "shapeless", + RecipeSerializer.SHAPELESS, + ) { id: Identifier -> + RecordCodecBuilder.create { instance -> + instance + .group( + Codec.STRING + .optionalFieldOf("group", "") + .forGetter(ShapelessRecipe::getGroup), + ItemIngredient.VANILLA_CODEC + .listOf() + .fieldOf("ingredients") + .forGetter(ShapelessRecipe::getIngredients), + ITEM_STACK_CODEC + .fieldOf("result") + .forGetter(ShapelessRecipe::getOutput), + ).apply(instance) { group: String, ingredients: List, result: ItemStack -> + ShapelessRecipe(id, group, result, ingredients.toDefaultedList(Ingredient.EMPTY)) + } + } + } + + @JvmField + val SMELTING: DelegatedRecipeSerializer = + registerDelegated( + "smelting", + RecipeSerializer.SMELTING, + createCookingRecipe(::SmeltingRecipe), + ) + + @JvmField + val BLASTING: DelegatedRecipeSerializer = + registerDelegated( + "blasting", + RecipeSerializer.BLASTING, + createCookingRecipe(::BlastingRecipe), + ) + + @JvmField + val SMOKING: DelegatedRecipeSerializer = + registerDelegated( + "smoking", + RecipeSerializer.SMOKING, + createCookingRecipe(::SmokingRecipe), + ) + + @JvmField + val CAMPFIRE_COOKING: DelegatedRecipeSerializer = + registerDelegated( + "campfire_cooking", + RecipeSerializer.CAMPFIRE_COOKING, + createCookingRecipe(::CampfireCookingRecipe), + ) + + @JvmField + val STONECUTTING: DelegatedRecipeSerializer = registerDelegated( + "stonecutting", + RecipeSerializer.STONECUTTING, + ) { id: Identifier -> + RecordCodecBuilder.create { instance -> + instance + .group( + Codec.STRING + .optionalFieldOf("group", "") + .forGetter(StonecuttingRecipe::getGroup), + ItemIngredient.VANILLA_CODEC + .fieldOf("ingredient") + .forGetter { it.ingredients[0] }, + ITEM_STACK_CODEC + .fieldOf("result") + .forGetter(StonecuttingRecipe::getOutput), + ).apply(instance) { group: String, ingredient: Ingredient, result: ItemStack -> + StonecuttingRecipe(id, group, ingredient, result) + } + } + } + + @JvmStatic + private fun createCookingRecipe( + factory: (Identifier, String, Ingredient, ItemStack, Float, Int) -> T, + ): RecipeCodec = RecipeCodec { id: Identifier -> + RecordCodecBuilder.create { instance -> + instance + .group( + Codec.STRING + .optionalFieldOf("group", "") + .forGetter { it.group }, + ItemIngredient.VANILLA_CODEC + .fieldOf("ingredient") + .forGetter { it.ingredients[0] }, + ITEM_STACK_CODEC + .fieldOf("result") + .forGetter { it.output }, + Codec.FLOAT + .optionalFieldOf("exp", 0.0f) + .forGetter { it.experience }, + Codec + .intRange(0, Short.MAX_VALUE.toInt()) + .optionalFieldOf("time", 200) + .forGetter { it.cookTime }, + ).apply(instance) { group: String, ingredient: Ingredient, result: ItemStack, exp: Float, time: Int -> + factory(id, group, ingredient, result, exp, time) + } + } + } + + @JvmStatic + private fun > registerDelegated( + path: String, + serializer: RecipeSerializer, + recipeCodec: RecipeCodec, + ): DelegatedRecipeSerializer = register(path, DelegatedRecipeSerializer(serializer, recipeCodec)) + + @JvmStatic + private fun , R : RecipeSerializer> register(path: String, serializer: R): R = Registry.register( + Registry.RECIPE_SERIALIZER, + RobustumCore.id(path), + serializer, + ) +} diff --git a/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt b/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt deleted file mode 100644 index ced3199..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt +++ /dev/null @@ -1,36 +0,0 @@ -package dev.robustum.core.tag - -import net.fabricmc.fabric.api.tag.TagRegistry -import net.minecraft.block.Block -import net.minecraft.entity.EntityType -import net.minecraft.fluid.Fluid -import net.minecraft.item.Item -import net.minecraft.tag.Tag -import net.minecraft.util.Identifier - -class LazyTag private constructor(private val id: Identifier, private val tagGetter: (Identifier) -> Tag) : Tag.Identified { - companion object { - @JvmStatic - fun block(id: Identifier): LazyTag = LazyTag(id, TagRegistry::block) - - @JvmStatic - fun entityType(id: Identifier): LazyTag> = LazyTag(id, TagRegistry::entityType) - - @JvmStatic - fun fluid(id: Identifier): LazyTag = LazyTag(id, TagRegistry::fluid) - - @JvmStatic - fun item(id: Identifier): LazyTag = LazyTag(id, TagRegistry::item) - } - - private val delegatedTag: Tag - get() = tagGetter(id) - - // Tag // - - override fun contains(entry: T): Boolean = delegatedTag.contains(entry) - - override fun values(): List = delegatedTag.values() - - override fun getId(): Identifier = id -} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt index 65e2c41..c4b57b5 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt @@ -4,6 +4,7 @@ import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder import dev.robustum.core.extensions.RobustumCodecs +import dev.robustum.core.extensions.getSafeValue import net.minecraft.tag.Tag import net.minecraft.util.Identifier @@ -53,7 +54,7 @@ class RobustumTagEntry private constructor(private val id: Identifier, private v fun resolve(valueGetter: ValueGetter, consumer: (T) -> Unit): Boolean { if (isTag) { - valueGetter.tag(id)?.values()?.forEach(consumer) ?: return !required + valueGetter.tag(id)?.getSafeValue()?.forEach(consumer) ?: return !required } else { valueGetter.direct(id)?.let(consumer) ?: return !required } From bd4a2e37d4ab18c1dcf49cea549dd8c8f0864ee9 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 16 Nov 2024 18:13:21 +0900 Subject: [PATCH 05/27] Rebased tag_update with sinoalice --- .../robustum/core/extensions/TagExtensions.kt | 2 -- .../kotlin/dev/robustum/core/tag/LazyTag.kt | 36 +++++++++++++++++++ .../robustum/core/tag/RobustumTagCodecs.kt | 22 ++++++++++++ .../dev/robustum/core/tag/RobustumTagEntry.kt | 16 ++++----- .../core/tag/RobustumTagGroupLoader.kt | 7 ++-- src/main/resources/fabric.mod.json | 3 +- src/main/resources/robustum.mixins.json | 11 ++++++ 7 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 src/main/kotlin/dev/robustum/core/tag/LazyTag.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt create mode 100644 src/main/resources/robustum.mixins.json diff --git a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt index 1543714..824d40d 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt @@ -7,5 +7,3 @@ import net.minecraft.util.Identifier val Tag.idOrNull: Identifier? get() = (this as? Tag.Identified)?.id - -fun Tag.getSafeValue(): List = runCatching { values() }.getOrDefault(listOf()) diff --git a/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt b/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt new file mode 100644 index 0000000..ced3199 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt @@ -0,0 +1,36 @@ +package dev.robustum.core.tag + +import net.fabricmc.fabric.api.tag.TagRegistry +import net.minecraft.block.Block +import net.minecraft.entity.EntityType +import net.minecraft.fluid.Fluid +import net.minecraft.item.Item +import net.minecraft.tag.Tag +import net.minecraft.util.Identifier + +class LazyTag private constructor(private val id: Identifier, private val tagGetter: (Identifier) -> Tag) : Tag.Identified { + companion object { + @JvmStatic + fun block(id: Identifier): LazyTag = LazyTag(id, TagRegistry::block) + + @JvmStatic + fun entityType(id: Identifier): LazyTag> = LazyTag(id, TagRegistry::entityType) + + @JvmStatic + fun fluid(id: Identifier): LazyTag = LazyTag(id, TagRegistry::fluid) + + @JvmStatic + fun item(id: Identifier): LazyTag = LazyTag(id, TagRegistry::item) + } + + private val delegatedTag: Tag + get() = tagGetter(id) + + // Tag // + + override fun contains(entry: T): Boolean = delegatedTag.contains(entry) + + override fun values(): List = delegatedTag.values() + + override fun getId(): Identifier = id +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt new file mode 100644 index 0000000..257ab39 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt @@ -0,0 +1,22 @@ +package dev.robustum.core.tag + +import com.mojang.serialization.Codec +import net.minecraft.util.Identifier +import net.minecraft.util.StringIdentifiable + +object RobustumTagCodecs { + @JvmField + val TAG_ID: Codec = Codec.STRING.xmap({ + when (it.startsWith("#")) { + true -> TagEntryId(Identifier(it.removePrefix("#")), true) + false -> TagEntryId(Identifier(it), false) + } + }, TagEntryId::asString) + + data class TagEntryId(val id: Identifier, val isTag: Boolean) : StringIdentifiable { + override fun asString(): String = when (isTag) { + true -> id.toString() + false -> "#$id" + } + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt index c4b57b5..0839fa9 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt @@ -3,25 +3,23 @@ package dev.robustum.core.tag import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder -import dev.robustum.core.extensions.RobustumCodecs -import dev.robustum.core.extensions.getSafeValue import net.minecraft.tag.Tag import net.minecraft.util.Identifier -class RobustumTagEntry private constructor(private val id: Identifier, private val isTag: Boolean, private val required: Boolean) { +class RobustumTagEntry private constructor(val id: Identifier, val isTag: Boolean, val required: Boolean) { companion object { @JvmStatic private val ENTRY_CODEC: Codec = RecordCodecBuilder.create { instance -> instance .group( - RobustumCodecs.TAG_ID.fieldOf("id").forGetter(RobustumTagEntry::tagEntryId), + RobustumTagCodecs.TAG_ID.fieldOf("id").forGetter(RobustumTagEntry::tagEntryId), Codec.BOOL.optionalFieldOf("required", true).forGetter(RobustumTagEntry::required), ).apply(instance, ::RobustumTagEntry) } @JvmField - val CODEC: Codec = Codec.either(RobustumCodecs.TAG_ID, ENTRY_CODEC).xmap( - { either: Either -> + val CODEC: Codec = Codec.either(RobustumTagCodecs.TAG_ID, ENTRY_CODEC).xmap( + { either: Either -> either.map({ RobustumTagEntry( it, @@ -48,13 +46,13 @@ class RobustumTagEntry private constructor(private val id: Identifier, private v fun createTag(id: Identifier, required: Boolean = true): RobustumTagEntry = RobustumTagEntry(id, true, required) } - constructor(tagId: RobustumCodecs.TagEntryId, required: Boolean) : this(tagId.id, tagId.isTag, required) + constructor(tagId: RobustumTagCodecs.TagEntryId, required: Boolean) : this(tagId.id, tagId.isTag, required) - private val tagEntryId = RobustumCodecs.TagEntryId(id, isTag) + private val tagEntryId = RobustumTagCodecs.TagEntryId(id, isTag) fun resolve(valueGetter: ValueGetter, consumer: (T) -> Unit): Boolean { if (isTag) { - valueGetter.tag(id)?.getSafeValue()?.forEach(consumer) ?: return !required + valueGetter.tag(id)?.values()?.forEach(consumer) ?: return !required } else { valueGetter.direct(id)?.let(consumer) ?: return !required } diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt index ce7bfa8..41a3c04 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt @@ -27,10 +27,7 @@ class RobustumTagGroupLoader(private val registry: Registry, private private fun loadTags(resourceManager: ResourceManager): Map> = buildMap> { resourceManager.findResources(dataType) { it.endsWith(".json") }.forEach { resourceId: Identifier -> - val fixedId: Identifier = resourceId - .removePrefix("$dataType/") - .removeSuffix(".json") - // .let(RobustumTagFormatRegistry::format) + val fixedId: Identifier = resourceId.removePrefix("$dataType/").removeSuffix(".json") resourceManager.getAllResources(resourceId).forEach { resource: Resource -> runCatching { val json: JsonElement = resource.use { resourceIn: Resource -> @@ -58,7 +55,7 @@ class RobustumTagGroupLoader(private val registry: Registry, private }, ) } - }.onEach { logger.info("Tag - ${it.key}") } + } private fun buildGroup(rawMap: Map>): TagGroup = TagGroup.create( buildMap { diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 90c0c77..371ae30 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -18,9 +18,8 @@ } ] }, - "accessWidener" : "robustum_core.accesswidener", "mixins": [ - "robustum_core.mixins.json" + "robustum.mixins.json" ], "depends": { "fabricloader": ">=0.15.0", diff --git a/src/main/resources/robustum.mixins.json b/src/main/resources/robustum.mixins.json new file mode 100644 index 0000000..a196419 --- /dev/null +++ b/src/main/resources/robustum.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "dev.robustum.core.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "TagManagerLoaderMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} From 79df2a68cfc35f3c5a59f7858704696a325dfb90 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 16 Nov 2024 20:00:52 +0900 Subject: [PATCH 06/27] Rebase --- .../robustum/core/recipe/RegistryEntryList.kt | 85 ++++--------------- .../core/recipe/WeightedIngredient.kt | 47 ++++++++++ .../robustum/core/tag/RobustumTagCodecs.kt | 22 ----- .../dev/robustum/core/tag/RobustumTagEntry.kt | 13 +-- .../core/tag/RobustumTagGroupLoader.kt | 7 +- src/main/resources/fabric.mod.json | 3 +- src/main/resources/robustum.mixins.json | 11 --- 7 files changed, 79 insertions(+), 109 deletions(-) create mode 100644 src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt delete mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt delete mode 100644 src/main/resources/robustum.mixins.json diff --git a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt index 415bd8a..df58744 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt @@ -3,96 +3,47 @@ package dev.robustum.core.recipe import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import dev.robustum.core.extensions.RobustumCodecs -import dev.robustum.core.extensions.getSafeValue import net.minecraft.tag.Tag import net.minecraft.tag.TagGroup import net.minecraft.util.registry.DefaultedRegistry -import java.util.function.Function -import kotlin.random.Random sealed interface RegistryEntryList : Iterable { companion object { @JvmStatic - fun codec(registry: DefaultedRegistry, groupGetter: () -> TagGroup): Codec> = Codec - .either(RobustumCodecs.TAG_ID, RobustumCodecs.TAG_ID.listOf()) - .xmap( - { either: Either> -> - either.map( - { entry: RobustumCodecs.TagEntryId -> - when (entry.isTag) { - true -> tag(groupGetter().getTagOrEmpty(entry.id)) - false -> of(checkNotNull(registry.get(entry.id))) - } - }, - { entries: List -> - when { - entries.isEmpty() -> empty() - !entries.all(RobustumCodecs.TagEntryId::isTag) -> of( - entries.map(RobustumCodecs.TagEntryId::id).map(registry::get), - ) - - else -> throw IllegalStateException("Could not serialize TagEntryId list containing tag entry!!") - } - }, - ) + fun codec(registry: DefaultedRegistry, groupGetter: () -> TagGroup): Codec> = + RobustumCodecs.TAG_ID.xmap( + { + when (it.isTag) { + true -> Tagged(groupGetter().getTagOrEmpty(it.id)) + false -> Direct(checkNotNull(registry.get(it.id))) + } }, - { entryList: RegistryEntryList -> - entryList.storage.map( - { Either.left(RobustumCodecs.TagEntryId.tag(it, groupGetter()::getTagId)) }, - { entries: List -> - when (entries.size) { - 0 -> throw IllegalStateException("Could not serialize empty list to TagEntryId!") - 1 -> Either.left(RobustumCodecs.TagEntryId.of(entries[0], registry::getId)) - else -> Either.right( - entries.map { entry: T -> - RobustumCodecs.TagEntryId.of(entry, registry::getId) - }, - ) - } - }, + { + it.storage.map( + { tag: Tag -> RobustumCodecs.TagEntryId.tag(tag, groupGetter()::getTagId) }, + { entry: T -> RobustumCodecs.TagEntryId.of(entry, registry::getId) }, ) }, ) @JvmStatic - fun empty(): RegistryEntryList = Direct(listOf()) - - @JvmStatic - fun of(vararg entries: T): RegistryEntryList = Direct(entries.toList()) - - @JvmStatic - fun of(entries: List): RegistryEntryList = Direct(entries.toList()) + fun of(entry: T): RegistryEntryList = Direct(entry) @JvmStatic fun tag(tag: Tag): RegistryEntryList = Tagged(tag) } - val storage: Either, List> - - val isEmpty: Boolean - get() = entries.isEmpty() - - val entries: List - get() = storage.map(Tag::getSafeValue, Function.identity()) - - val size: Int - get() = entries.size - - fun getRandom(random: Random): T? = entries.randomOrNull(random) - - operator fun get(index: Int): T = entries[index] - - operator fun contains(entry: T): Boolean = storage.map({ it.contains(entry) }, { it.any { entryIn: T -> entryIn == entry } }) + val storage: Either, T> - private class Direct(private val list: List) : RegistryEntryList { - override val storage: Either, List> = Either.right(list) + private class Direct(private val entry: T) : RegistryEntryList { + override val storage: Either, T> = Either.right(entry) - override fun iterator(): Iterator = list.iterator() + override fun iterator(): Iterator = listOf(entry).iterator() } private class Tagged(val tag: Tag) : RegistryEntryList { - override val storage: Either, List> = Either.left(tag) + override val storage: Either, T> = Either.left(tag) - override fun iterator(): Iterator = tag.getSafeValue().iterator() + override fun iterator(): Iterator = tag.values().iterator() } } diff --git a/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt new file mode 100644 index 0000000..ea5c0e1 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt @@ -0,0 +1,47 @@ +package dev.robustum.core.recipe + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.recipe.Ingredient +import net.minecraft.tag.ServerTagManagerHolder +import net.minecraft.tag.Tag +import net.minecraft.util.registry.Registry +import java.util.function.Predicate + +class WeightedIngredient private constructor(val entries: RegistryEntryList, val count: Int) : Predicate { + companion object { + @JvmField + val CODEC: Codec = RecordCodecBuilder.create { instance -> + instance + .group( + RegistryEntryList + .codec(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) + .fieldOf("items") + .forGetter(WeightedIngredient::entries), + Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(WeightedIngredient::count), + ).apply(instance, ::WeightedIngredient) + } + } + + constructor(tag: Tag, count: Int = 1) : this(RegistryEntryList.tag(tag), count) + + constructor(item: Item, count: Int = 1) : this(RegistryEntryList.of(item), count) + + val isEmpty: Boolean + get() = entries.storage.map({ it.values().isEmpty() }, { it == Items.AIR }) || count <= 0 + + val vanillaIngredient: Ingredient + get() = entries.storage.map(Ingredient::fromTag, Ingredient::ofItems) + + override fun test(stack: ItemStack): Boolean = when (stack.isEmpty) { + true -> this.isEmpty + false -> entries.storage.map( + { stack.item in it }, + { stack.item == it }, + ) && + stack.count >= count + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt deleted file mode 100644 index 257ab39..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagCodecs.kt +++ /dev/null @@ -1,22 +0,0 @@ -package dev.robustum.core.tag - -import com.mojang.serialization.Codec -import net.minecraft.util.Identifier -import net.minecraft.util.StringIdentifiable - -object RobustumTagCodecs { - @JvmField - val TAG_ID: Codec = Codec.STRING.xmap({ - when (it.startsWith("#")) { - true -> TagEntryId(Identifier(it.removePrefix("#")), true) - false -> TagEntryId(Identifier(it), false) - } - }, TagEntryId::asString) - - data class TagEntryId(val id: Identifier, val isTag: Boolean) : StringIdentifiable { - override fun asString(): String = when (isTag) { - true -> id.toString() - false -> "#$id" - } - } -} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt index 0839fa9..65e2c41 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt @@ -3,23 +3,24 @@ package dev.robustum.core.tag import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.extensions.RobustumCodecs import net.minecraft.tag.Tag import net.minecraft.util.Identifier -class RobustumTagEntry private constructor(val id: Identifier, val isTag: Boolean, val required: Boolean) { +class RobustumTagEntry private constructor(private val id: Identifier, private val isTag: Boolean, private val required: Boolean) { companion object { @JvmStatic private val ENTRY_CODEC: Codec = RecordCodecBuilder.create { instance -> instance .group( - RobustumTagCodecs.TAG_ID.fieldOf("id").forGetter(RobustumTagEntry::tagEntryId), + RobustumCodecs.TAG_ID.fieldOf("id").forGetter(RobustumTagEntry::tagEntryId), Codec.BOOL.optionalFieldOf("required", true).forGetter(RobustumTagEntry::required), ).apply(instance, ::RobustumTagEntry) } @JvmField - val CODEC: Codec = Codec.either(RobustumTagCodecs.TAG_ID, ENTRY_CODEC).xmap( - { either: Either -> + val CODEC: Codec = Codec.either(RobustumCodecs.TAG_ID, ENTRY_CODEC).xmap( + { either: Either -> either.map({ RobustumTagEntry( it, @@ -46,9 +47,9 @@ class RobustumTagEntry private constructor(val id: Identifier, val isTag: Boolea fun createTag(id: Identifier, required: Boolean = true): RobustumTagEntry = RobustumTagEntry(id, true, required) } - constructor(tagId: RobustumTagCodecs.TagEntryId, required: Boolean) : this(tagId.id, tagId.isTag, required) + constructor(tagId: RobustumCodecs.TagEntryId, required: Boolean) : this(tagId.id, tagId.isTag, required) - private val tagEntryId = RobustumTagCodecs.TagEntryId(id, isTag) + private val tagEntryId = RobustumCodecs.TagEntryId(id, isTag) fun resolve(valueGetter: ValueGetter, consumer: (T) -> Unit): Boolean { if (isTag) { diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt index 41a3c04..ce7bfa8 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt @@ -27,7 +27,10 @@ class RobustumTagGroupLoader(private val registry: Registry, private private fun loadTags(resourceManager: ResourceManager): Map> = buildMap> { resourceManager.findResources(dataType) { it.endsWith(".json") }.forEach { resourceId: Identifier -> - val fixedId: Identifier = resourceId.removePrefix("$dataType/").removeSuffix(".json") + val fixedId: Identifier = resourceId + .removePrefix("$dataType/") + .removeSuffix(".json") + // .let(RobustumTagFormatRegistry::format) resourceManager.getAllResources(resourceId).forEach { resource: Resource -> runCatching { val json: JsonElement = resource.use { resourceIn: Resource -> @@ -55,7 +58,7 @@ class RobustumTagGroupLoader(private val registry: Registry, private }, ) } - } + }.onEach { logger.info("Tag - ${it.key}") } private fun buildGroup(rawMap: Map>): TagGroup = TagGroup.create( buildMap { diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 371ae30..90c0c77 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -18,8 +18,9 @@ } ] }, + "accessWidener" : "robustum_core.accesswidener", "mixins": [ - "robustum.mixins.json" + "robustum_core.mixins.json" ], "depends": { "fabricloader": ">=0.15.0", diff --git a/src/main/resources/robustum.mixins.json b/src/main/resources/robustum.mixins.json deleted file mode 100644 index a196419..0000000 --- a/src/main/resources/robustum.mixins.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "required": true, - "package": "dev.robustum.core.mixin", - "compatibilityLevel": "JAVA_21", - "mixins": [ - "TagManagerLoaderMixin" - ], - "injectors": { - "defaultRequire": 1 - } -} From ecae895b24f191b8588cc84e4bf81c8a9ad782f1 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Mon, 18 Nov 2024 20:40:43 +0900 Subject: [PATCH 07/27] Added DelegatedRecipeSerializer --- .../robustum/core/extensions/TagExtensions.kt | 2 + .../robustum/core/recipe/RegistryEntryList.kt | 85 +++++++++++++++---- .../core/recipe/WeightedIngredient.kt | 47 ---------- .../kotlin/dev/robustum/core/tag/LazyTag.kt | 36 -------- .../dev/robustum/core/tag/RobustumTagEntry.kt | 3 +- 5 files changed, 71 insertions(+), 102 deletions(-) delete mode 100644 src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt delete mode 100644 src/main/kotlin/dev/robustum/core/tag/LazyTag.kt diff --git a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt index 824d40d..1543714 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt @@ -7,3 +7,5 @@ import net.minecraft.util.Identifier val Tag.idOrNull: Identifier? get() = (this as? Tag.Identified)?.id + +fun Tag.getSafeValue(): List = runCatching { values() }.getOrDefault(listOf()) diff --git a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt index df58744..415bd8a 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt @@ -3,47 +3,96 @@ package dev.robustum.core.recipe import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import dev.robustum.core.extensions.RobustumCodecs +import dev.robustum.core.extensions.getSafeValue import net.minecraft.tag.Tag import net.minecraft.tag.TagGroup import net.minecraft.util.registry.DefaultedRegistry +import java.util.function.Function +import kotlin.random.Random sealed interface RegistryEntryList : Iterable { companion object { @JvmStatic - fun codec(registry: DefaultedRegistry, groupGetter: () -> TagGroup): Codec> = - RobustumCodecs.TAG_ID.xmap( - { - when (it.isTag) { - true -> Tagged(groupGetter().getTagOrEmpty(it.id)) - false -> Direct(checkNotNull(registry.get(it.id))) - } + fun codec(registry: DefaultedRegistry, groupGetter: () -> TagGroup): Codec> = Codec + .either(RobustumCodecs.TAG_ID, RobustumCodecs.TAG_ID.listOf()) + .xmap( + { either: Either> -> + either.map( + { entry: RobustumCodecs.TagEntryId -> + when (entry.isTag) { + true -> tag(groupGetter().getTagOrEmpty(entry.id)) + false -> of(checkNotNull(registry.get(entry.id))) + } + }, + { entries: List -> + when { + entries.isEmpty() -> empty() + !entries.all(RobustumCodecs.TagEntryId::isTag) -> of( + entries.map(RobustumCodecs.TagEntryId::id).map(registry::get), + ) + + else -> throw IllegalStateException("Could not serialize TagEntryId list containing tag entry!!") + } + }, + ) }, - { - it.storage.map( - { tag: Tag -> RobustumCodecs.TagEntryId.tag(tag, groupGetter()::getTagId) }, - { entry: T -> RobustumCodecs.TagEntryId.of(entry, registry::getId) }, + { entryList: RegistryEntryList -> + entryList.storage.map( + { Either.left(RobustumCodecs.TagEntryId.tag(it, groupGetter()::getTagId)) }, + { entries: List -> + when (entries.size) { + 0 -> throw IllegalStateException("Could not serialize empty list to TagEntryId!") + 1 -> Either.left(RobustumCodecs.TagEntryId.of(entries[0], registry::getId)) + else -> Either.right( + entries.map { entry: T -> + RobustumCodecs.TagEntryId.of(entry, registry::getId) + }, + ) + } + }, ) }, ) @JvmStatic - fun of(entry: T): RegistryEntryList = Direct(entry) + fun empty(): RegistryEntryList = Direct(listOf()) + + @JvmStatic + fun of(vararg entries: T): RegistryEntryList = Direct(entries.toList()) + + @JvmStatic + fun of(entries: List): RegistryEntryList = Direct(entries.toList()) @JvmStatic fun tag(tag: Tag): RegistryEntryList = Tagged(tag) } - val storage: Either, T> + val storage: Either, List> + + val isEmpty: Boolean + get() = entries.isEmpty() + + val entries: List + get() = storage.map(Tag::getSafeValue, Function.identity()) + + val size: Int + get() = entries.size + + fun getRandom(random: Random): T? = entries.randomOrNull(random) + + operator fun get(index: Int): T = entries[index] + + operator fun contains(entry: T): Boolean = storage.map({ it.contains(entry) }, { it.any { entryIn: T -> entryIn == entry } }) - private class Direct(private val entry: T) : RegistryEntryList { - override val storage: Either, T> = Either.right(entry) + private class Direct(private val list: List) : RegistryEntryList { + override val storage: Either, List> = Either.right(list) - override fun iterator(): Iterator = listOf(entry).iterator() + override fun iterator(): Iterator = list.iterator() } private class Tagged(val tag: Tag) : RegistryEntryList { - override val storage: Either, T> = Either.left(tag) + override val storage: Either, List> = Either.left(tag) - override fun iterator(): Iterator = tag.values().iterator() + override fun iterator(): Iterator = tag.getSafeValue().iterator() } } diff --git a/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt deleted file mode 100644 index ea5c0e1..0000000 --- a/src/main/kotlin/dev/robustum/core/recipe/WeightedIngredient.kt +++ /dev/null @@ -1,47 +0,0 @@ -package dev.robustum.core.recipe - -import com.mojang.serialization.Codec -import com.mojang.serialization.codecs.RecordCodecBuilder -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import net.minecraft.recipe.Ingredient -import net.minecraft.tag.ServerTagManagerHolder -import net.minecraft.tag.Tag -import net.minecraft.util.registry.Registry -import java.util.function.Predicate - -class WeightedIngredient private constructor(val entries: RegistryEntryList, val count: Int) : Predicate { - companion object { - @JvmField - val CODEC: Codec = RecordCodecBuilder.create { instance -> - instance - .group( - RegistryEntryList - .codec(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) - .fieldOf("items") - .forGetter(WeightedIngredient::entries), - Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(WeightedIngredient::count), - ).apply(instance, ::WeightedIngredient) - } - } - - constructor(tag: Tag, count: Int = 1) : this(RegistryEntryList.tag(tag), count) - - constructor(item: Item, count: Int = 1) : this(RegistryEntryList.of(item), count) - - val isEmpty: Boolean - get() = entries.storage.map({ it.values().isEmpty() }, { it == Items.AIR }) || count <= 0 - - val vanillaIngredient: Ingredient - get() = entries.storage.map(Ingredient::fromTag, Ingredient::ofItems) - - override fun test(stack: ItemStack): Boolean = when (stack.isEmpty) { - true -> this.isEmpty - false -> entries.storage.map( - { stack.item in it }, - { stack.item == it }, - ) && - stack.count >= count - } -} diff --git a/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt b/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt deleted file mode 100644 index ced3199..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/LazyTag.kt +++ /dev/null @@ -1,36 +0,0 @@ -package dev.robustum.core.tag - -import net.fabricmc.fabric.api.tag.TagRegistry -import net.minecraft.block.Block -import net.minecraft.entity.EntityType -import net.minecraft.fluid.Fluid -import net.minecraft.item.Item -import net.minecraft.tag.Tag -import net.minecraft.util.Identifier - -class LazyTag private constructor(private val id: Identifier, private val tagGetter: (Identifier) -> Tag) : Tag.Identified { - companion object { - @JvmStatic - fun block(id: Identifier): LazyTag = LazyTag(id, TagRegistry::block) - - @JvmStatic - fun entityType(id: Identifier): LazyTag> = LazyTag(id, TagRegistry::entityType) - - @JvmStatic - fun fluid(id: Identifier): LazyTag = LazyTag(id, TagRegistry::fluid) - - @JvmStatic - fun item(id: Identifier): LazyTag = LazyTag(id, TagRegistry::item) - } - - private val delegatedTag: Tag - get() = tagGetter(id) - - // Tag // - - override fun contains(entry: T): Boolean = delegatedTag.contains(entry) - - override fun values(): List = delegatedTag.values() - - override fun getId(): Identifier = id -} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt index 65e2c41..c4b57b5 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt @@ -4,6 +4,7 @@ import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder import dev.robustum.core.extensions.RobustumCodecs +import dev.robustum.core.extensions.getSafeValue import net.minecraft.tag.Tag import net.minecraft.util.Identifier @@ -53,7 +54,7 @@ class RobustumTagEntry private constructor(private val id: Identifier, private v fun resolve(valueGetter: ValueGetter, consumer: (T) -> Unit): Boolean { if (isTag) { - valueGetter.tag(id)?.values()?.forEach(consumer) ?: return !required + valueGetter.tag(id)?.getSafeValue()?.forEach(consumer) ?: return !required } else { valueGetter.direct(id)?.let(consumer) ?: return !required } From 66c6ad1fbff37ea58f9d351f7de6424895d5484c Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Fri, 29 Nov 2024 21:43:24 +0900 Subject: [PATCH 08/27] Refined around codecs Formatted scripts --- .../core/extensions/CodecExtensions.kt | 131 +++++++++++++----- .../core/extensions/RobustumCodecs.kt | 33 +++++ .../core/recipe/RobustumRecipeSerializers.kt | 8 +- 3 files changed, 132 insertions(+), 40 deletions(-) diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index a38498a..3a091ed 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -1,43 +1,13 @@ package dev.robustum.core.extensions import com.mojang.datafixers.util.Pair -import com.mojang.serialization.Codec -import com.mojang.serialization.DataResult -import com.mojang.serialization.DynamicOps -import com.mojang.serialization.MapLike -import com.mojang.serialization.codecs.RecordCodecBuilder -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import net.minecraft.nbt.NbtCompound -import net.minecraft.util.registry.Registry +import com.mojang.serialization.* import java.util.* +import java.util.function.Function +import java.util.stream.Stream // Codec // -private val ITEM_CODEC: Codec = lazeCodec { Registry.ITEM }.validate { item: Item -> - when (item) { - Items.AIR -> DataResult.error("Item must not be minecraft:air") - else -> DataResult.success(item) - } -} - -private val RAW_STACK_CODEC: Codec = RecordCodecBuilder.create { instance -> - instance - .group( - ITEM_CODEC.fieldOf("id").forGetter(ItemStack::getItem), - Codec.intRange(0, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemStack::getCount), - NbtCompound.CODEC.optionalFieldOf("tag").forGetter { stack: ItemStack -> Optional.ofNullable(stack.tag) }, - ).apply(instance) { item: Item, count: Int, nbt: Optional -> - ItemStack(item, count).apply { nbt.ifPresent(this::setTag) } - } -} - -val ITEM_STACK_CODEC: Codec = optionalCodec(RAW_STACK_CODEC).xmap( - { it.orElse(ItemStack.EMPTY) }, - { if (it.isEmpty) Optional.empty() else Optional.of(it) }, -) - fun Codec.validate(validator: (A) -> DataResult): Codec = flatXmap(validator, validator) fun lazeCodec(getter: () -> Codec): Codec = object : Codec { @@ -46,10 +16,87 @@ fun lazeCodec(getter: () -> Codec): Codec = object : Codec { override fun decode(ops: DynamicOps, input: T): DataResult> = getter().decode(ops, input) } -fun optionalCodec(codec: Codec): Codec> = object : Codec> { +fun Codec.dispatch(type: Function, codec: Function>): Codec = dispatch("type", type, codec) + +fun Codec.dispatch(typeKey: String, type: Function, codec: Function>): Codec = + dispatchPartial(typeKey, type.andThen(DataResult::success), codec.andThen(DataResult::success)) + +fun Codec.dispatchPartial( + typeKey: String, + type: Function>, + codec: Function>>, +): Codec = KeyDispatchCodec(typeKey, this, type::apply, codec::apply).codec() + +private class KeyDispatchCodec( + val typeKey: String, + val keyCodec: Codec, + val type: (V) -> DataResult, + val decoder: (K) -> DataResult>, + val encoder: (V) -> DataResult>, +) : MapCodec() { + companion object { + @JvmStatic + private fun getCodec( + type: (V) -> DataResult, + codec: (K) -> DataResult>, + input: V, + ): DataResult> = type(input) + .flatMap { key: K -> codec(key).map(Function.identity()) } + } + + constructor( + typeKey: String, + keyCodec: Codec, + type: (V) -> DataResult, + codec: (K) -> DataResult>, + ) : this(typeKey, keyCodec, type, codec, { input: V -> getCodec(type, codec, input) }) + + private val valueKey = "value" + + override fun keys(ops: DynamicOps): Stream = Stream.of(typeKey, valueKey).map(ops::createString) + + override fun decode(ops: DynamicOps, input: MapLike): DataResult { + val elementName: T = + input.get(typeKey) ?: return DataResult.error("Input does not contain a key [$typeKey]: $input") + return keyCodec.decode(ops, elementName).flatMap { type1: Pair -> + decoder(type1.first).flatMap { elementDecoder: MapDecoder -> + if (ops.compressMaps()) { + input + .get(ops.createString(valueKey)) + ?.let { value: T -> elementDecoder.decoder().parse(ops, value).map(Function.identity()) } + ?: return@flatMap DataResult.error("Input does not have a \"value\" entry: $input") + } else { + elementDecoder.decode(ops, input).map(Function.identity()) + } + } + } + } + + override fun encode(input: V, ops: DynamicOps, prefix: RecordBuilder): RecordBuilder { + val encodeResult: DataResult> = encoder(input) + val builder: RecordBuilder = prefix.withErrorsFrom(encodeResult) + if (encodeResult.errored) { + return builder + } + val elementEncoder: MapEncoder = encodeResult.result().get() + return when { + ops.compressMaps() -> + prefix + .add(typeKey, type(input).flatMap { type1: K -> keyCodec.encodeStart(ops, type1) }) + .add(valueKey, elementEncoder.encoder().encodeStart(ops, input)) + + else -> + elementEncoder + .encode(input, ops, prefix) + .add(typeKey, type(input).flatMap { type1: K -> keyCodec.encodeStart(ops, type1) }) + } + } +} + +fun Codec.optionalOf(): Codec> = object : Codec> { override fun encode(input: Optional, ops: DynamicOps, prefix: T): DataResult = when (input.isEmpty) { true -> DataResult.success(ops.emptyMap()) - false -> codec.encode(input.get(), ops, prefix) + false -> this@optionalOf.encode(input.get(), ops, prefix) } private fun isEmpty(ops: DynamicOps, input: T): Boolean = ops @@ -60,6 +107,18 @@ fun optionalCodec(codec: Codec): Codec> = object : Code override fun decode(ops: DynamicOps, input: T): DataResult, T>> = when { isEmpty(ops, input) -> DataResult.success(Pair.of(Optional.empty(), input)) - else -> codec.decode(ops, input).map { pair: Pair -> pair.mapFirst(Optional::of) } + else -> this@optionalOf.decode(ops, input).map { pair: Pair -> pair.mapFirst(Optional::of) } } } + +// DataResult // + +val DataResult.succeeded: Boolean + get() = result().isPresent + +val DataResult.errored: Boolean + get() = error().isPresent + +fun DataResult.isSucceeded(action: (R) -> Unit): DataResult = apply { result().ifPresent(action) } + +fun DataResult.isErrored(action: (DataResult.PartialResult) -> Unit): DataResult = apply { error().ifPresent(action) } diff --git a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt index adb34c0..d71ec06 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt @@ -1,11 +1,44 @@ package dev.robustum.core.extensions import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.nbt.NbtCompound import net.minecraft.tag.Tag import net.minecraft.util.Identifier import net.minecraft.util.StringIdentifiable +import net.minecraft.util.registry.Registry +import java.util.Optional object RobustumCodecs { + // ItemStack // + + private val NON_AIR_ITEM: Codec = lazeCodec { Registry.ITEM }.validate { item: Item -> + when (item) { + Items.AIR -> DataResult.error("Item must not be minecraft:air") + else -> DataResult.success(item) + } + } + + private val RAW_STACK: Codec = RecordCodecBuilder.create { instance -> + instance + .group( + NON_AIR_ITEM.fieldOf("id").forGetter(ItemStack::getItem), + Codec.intRange(0, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemStack::getCount), + NbtCompound.CODEC.optionalFieldOf("tag").forGetter { stack: ItemStack -> Optional.ofNullable(stack.tag) }, + ).apply(instance) { item: Item, count: Int, nbt: Optional -> + ItemStack(item, count).apply { nbt.ifPresent(this::setTag) } + } + } + + val ITEM_STACK: Codec = RAW_STACK.optionalOf().xmap( + { it.orElse(ItemStack.EMPTY) }, + { if (it.isEmpty) Optional.empty() else Optional.of(it) }, + ) + // Tag // @JvmField diff --git a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt index f897c92..cb665cd 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt @@ -3,7 +3,7 @@ package dev.robustum.core.recipe import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder import dev.robustum.core.RobustumCore -import dev.robustum.core.extensions.ITEM_STACK_CODEC +import dev.robustum.core.extensions.RobustumCodecs import dev.robustum.core.extensions.toDefaultedList import net.minecraft.item.ItemStack import net.minecraft.recipe.* @@ -27,7 +27,7 @@ object RobustumRecipeSerializers { .listOf() .fieldOf("ingredients") .forGetter(ShapelessRecipe::getIngredients), - ITEM_STACK_CODEC + RobustumCodecs.ITEM_STACK .fieldOf("result") .forGetter(ShapelessRecipe::getOutput), ).apply(instance) { group: String, ingredients: List, result: ItemStack -> @@ -82,7 +82,7 @@ object RobustumRecipeSerializers { ItemIngredient.VANILLA_CODEC .fieldOf("ingredient") .forGetter { it.ingredients[0] }, - ITEM_STACK_CODEC + RobustumCodecs.ITEM_STACK .fieldOf("result") .forGetter(StonecuttingRecipe::getOutput), ).apply(instance) { group: String, ingredient: Ingredient, result: ItemStack -> @@ -104,7 +104,7 @@ object RobustumRecipeSerializers { ItemIngredient.VANILLA_CODEC .fieldOf("ingredient") .forGetter { it.ingredients[0] }, - ITEM_STACK_CODEC + RobustumCodecs.ITEM_STACK .fieldOf("result") .forGetter { it.output }, Codec.FLOAT From 6a9e28d5c894f1da854f1809f1bdbd0f55372d79 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:02:40 +0900 Subject: [PATCH 09/27] Added new classes for Registry extensions --- .../core/extensions/CodecExtensions.kt | 10 +- .../core/extensions/CollectionExtensions.kt | 5 + .../robustum/core/extensions/ItemExtension.kt | 13 ++- .../core/extensions/RegistryExtensions.kt | 15 +++ .../core/extensions/RobustumCodecs.kt | 20 +++- .../robustum/core/extensions/TagExtensions.kt | 23 +++++ .../robustum/core/recipe/FluidIngredient.kt | 14 +-- .../robustum/core/recipe/ItemIngredient.kt | 20 ++-- .../robustum/core/recipe/RegistryEntryList.kt | 98 ------------------- .../robustum/core/registry/RegistryEntry.kt | 5 + .../core/registry/RegistryEntryList.kt | 54 ++++++++++ .../core/registry/RegistryEntryListCodec.kt | 42 ++++++++ .../robustum/core/registry/RegistryLookup.kt | 68 +++++++++++++ .../core/tag/RobustumTagFormatRegistry.kt | 34 ------- .../dev/robustum/core/tag/TagFormatter.kt | 16 --- 15 files changed, 262 insertions(+), 175 deletions(-) create mode 100644 src/main/kotlin/dev/robustum/core/extensions/RegistryExtensions.kt delete mode 100644 src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt create mode 100644 src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt create mode 100644 src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt create mode 100644 src/main/kotlin/dev/robustum/core/registry/RegistryEntryListCodec.kt create mode 100644 src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt delete mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagFormatRegistry.kt delete mode 100644 src/main/kotlin/dev/robustum/core/tag/TagFormatter.kt diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index 3a091ed..d4bc842 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -2,6 +2,7 @@ package dev.robustum.core.extensions import com.mojang.datafixers.util.Pair import com.mojang.serialization.* +import net.minecraft.util.collection.DefaultedList import java.util.* import java.util.function.Function import java.util.stream.Stream @@ -10,7 +11,7 @@ import java.util.stream.Stream fun Codec.validate(validator: (A) -> DataResult): Codec = flatXmap(validator, validator) -fun lazeCodec(getter: () -> Codec): Codec = object : Codec { +fun lazyCodec(getter: () -> Codec): Codec = object : Codec { override fun encode(input: A, ops: DynamicOps, prefix: T): DataResult = getter().encode(input, ops, prefix) override fun decode(ops: DynamicOps, input: T): DataResult> = getter().decode(ops, input) @@ -111,6 +112,9 @@ fun Codec.optionalOf(): Codec> = object : Codec Codec>.defaultedListOf(defaultValue: A): Codec> = + xmap({ DefaultedList.copyOf(defaultValue, *it.toTypedArray()) }, Function.identity()) + // DataResult // val DataResult.succeeded: Boolean @@ -119,6 +123,6 @@ val DataResult.succeeded: Boolean val DataResult.errored: Boolean get() = error().isPresent -fun DataResult.isSucceeded(action: (R) -> Unit): DataResult = apply { result().ifPresent(action) } +fun DataResult.ifSucceeded(action: (R) -> Unit): DataResult = apply { result().ifPresent(action) } -fun DataResult.isErrored(action: (DataResult.PartialResult) -> Unit): DataResult = apply { error().ifPresent(action) } +fun DataResult.ifErrored(action: (DataResult.PartialResult) -> Unit): DataResult = apply { error().ifPresent(action) } diff --git a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt index 8c98d4c..8abd3c0 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt @@ -6,3 +6,8 @@ import net.minecraft.util.collection.DefaultedList inline fun Iterable.toDefaultedList(defaultValue: T): DefaultedList = DefaultedList.copyOf(defaultValue, *this.toList().toTypedArray()) + +inline fun Map.toDefaultedList( + defaultValue: T, + transform: (Map.Entry) -> T, +): DefaultedList = DefaultedList.copyOf(defaultValue, *this.map(transform).toTypedArray()) diff --git a/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt b/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt index 599fec8..6954087 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt @@ -1,15 +1,18 @@ package dev.robustum.core.extensions -import dev.robustum.core.recipe.RegistryEntryList -import net.minecraft.item.Item +import net.minecraft.block.BlockState +import net.minecraft.block.entity.BlockEntity import net.minecraft.item.ItemConvertible import net.minecraft.item.ItemStack -import net.minecraft.tag.Tag +import net.minecraft.item.ItemUsageContext // ItemStack // fun ItemStack.isOf(item: ItemConvertible): Boolean = this.item == item.asItem() -fun ItemStack.isIn(tag: Tag): Boolean = this.item in tag +// ItemUsageContext // -fun ItemStack.isIn(entryList: RegistryEntryList): Boolean = this.item in entryList +val ItemUsageContext.blockState: BlockState + get() = world.getBlockState(blockPos) + +inline fun ItemUsageContext.getBlockEntity(): T? = world.getBlockEntity(blockPos) as? T diff --git a/src/main/kotlin/dev/robustum/core/extensions/RegistryExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/RegistryExtensions.kt new file mode 100644 index 0000000..162392d --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/extensions/RegistryExtensions.kt @@ -0,0 +1,15 @@ +package dev.robustum.core.extensions + +import dev.robustum.core.registry.RegistryEntry +import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry + +// Registry // + +fun Registry.getEntry(id: Identifier): RegistryEntry? = get(id)?.let { RegistryEntry(id, it) } + +fun Registry.getEntryOrThrow(id: Identifier): RegistryEntry = checkNotNull(getEntry(id)) + +fun Registry.getEntry(value: T): RegistryEntry? = getId(value)?.let { RegistryEntry(it, value) } + +fun Registry.getEntryOrThrow(value: T): RegistryEntry = checkNotNull(getEntry(value)) diff --git a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt index d71ec06..e1d02ab 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt @@ -3,6 +3,8 @@ package dev.robustum.core.extensions import com.mojang.serialization.Codec import com.mojang.serialization.DataResult import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.block.Block +import net.minecraft.block.Blocks import net.minecraft.item.Item import net.minecraft.item.ItemStack import net.minecraft.item.Items @@ -14,19 +16,30 @@ import net.minecraft.util.registry.Registry import java.util.Optional object RobustumCodecs { - // ItemStack // + // Block // + + @JvmField + val BLOCK: Codec = lazyCodec { Registry.BLOCK }.validate { block: Block -> + when (block) { + Blocks.AIR -> DataResult.error("Block must not be minecraft:air") + else -> DataResult.success(block) + } + } - private val NON_AIR_ITEM: Codec = lazeCodec { Registry.ITEM }.validate { item: Item -> + // ItemStack // + @JvmField + val ITEM: Codec = lazyCodec { Registry.ITEM }.validate { item: Item -> when (item) { Items.AIR -> DataResult.error("Item must not be minecraft:air") else -> DataResult.success(item) } } + @JvmStatic private val RAW_STACK: Codec = RecordCodecBuilder.create { instance -> instance .group( - NON_AIR_ITEM.fieldOf("id").forGetter(ItemStack::getItem), + ITEM.fieldOf("id").forGetter(ItemStack::getItem), Codec.intRange(0, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemStack::getCount), NbtCompound.CODEC.optionalFieldOf("tag").forGetter { stack: ItemStack -> Optional.ofNullable(stack.tag) }, ).apply(instance) { item: Item, count: Int, nbt: Optional -> @@ -34,6 +47,7 @@ object RobustumCodecs { } } + @JvmField val ITEM_STACK: Codec = RAW_STACK.optionalOf().xmap( { it.orElse(ItemStack.EMPTY) }, { if (it.isEmpty) Optional.empty() else Optional.of(it) }, diff --git a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt index 1543714..b98ca97 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt @@ -1,5 +1,14 @@ package dev.robustum.core.extensions +import dev.robustum.core.registry.RegistryEntryList +import net.minecraft.block.Block +import net.minecraft.block.BlockState +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityType +import net.minecraft.fluid.Fluid +import net.minecraft.fluid.FluidState +import net.minecraft.item.Item +import net.minecraft.item.ItemStack import net.minecraft.tag.Tag import net.minecraft.util.Identifier @@ -9,3 +18,17 @@ val Tag.idOrNull: Identifier? get() = (this as? Tag.Identified)?.id fun Tag.getSafeValue(): List = runCatching { values() }.getOrDefault(listOf()) + +fun Entity.isIn(tag: Tag>): Boolean = this.type.isIn(tag) + +fun ItemStack.isIn(tag: Tag): Boolean = this.item.isIn(tag) + +// RegistryEntryList // + +fun BlockState.isIn(entryList: RegistryEntryList): Boolean = this.block in entryList + +fun FluidState.isIn(entryList: RegistryEntryList): Boolean = this.fluid in entryList + +fun Entity.isIn(entryList: RegistryEntryList>): Boolean = this.type in entryList + +fun ItemStack.isIn(entryList: RegistryEntryList): Boolean = this.item in entryList diff --git a/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt index 166f65c..fc83af1 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt @@ -2,10 +2,12 @@ package dev.robustum.core.recipe import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.extensions.getEntryOrThrow +import dev.robustum.core.registry.RegistryEntryList +import dev.robustum.core.registry.RegistryEntryListCodec import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants import net.minecraft.fluid.Fluid import net.minecraft.fluid.Fluids -import net.minecraft.tag.ServerTagManagerHolder import net.minecraft.tag.Tag import net.minecraft.util.registry.Registry import java.util.function.BiPredicate @@ -20,8 +22,7 @@ class FluidIngredient private constructor(val entryList: RegistryEntryList = RecordCodecBuilder.create { instance -> instance .group( - RegistryEntryList - .codec(Registry.FLUID, ServerTagManagerHolder.getTagManager()::getFluids) + RegistryEntryListCodec.FLUID .fieldOf("fluids") .forGetter(FluidIngredient::entryList), Codec.LONG.optionalFieldOf("amount", FluidConstants.BUCKET).forGetter(FluidIngredient::amount), @@ -31,9 +32,10 @@ class FluidIngredient private constructor(val entryList: RegistryEntryList, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.tag(tag), amount) - constructor(fluid: Fluid, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.of(fluid), amount) - - constructor(fluids: List, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.of(fluids), amount) + constructor(fluid: Fluid, amount: Long = FluidConstants.BUCKET) : this( + RegistryEntryList.of(fluid, Registry.FLUID::getEntryOrThrow), + amount, + ) val isEmpty: Boolean get() = entryList.isEmpty || amount <= 0 diff --git a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt index 040fdd3..861070f 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt @@ -2,11 +2,13 @@ package dev.robustum.core.recipe import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.extensions.getEntryOrThrow import dev.robustum.core.extensions.isIn +import dev.robustum.core.registry.RegistryEntryList +import dev.robustum.core.registry.RegistryEntryListCodec import net.minecraft.item.Item import net.minecraft.item.ItemStack import net.minecraft.recipe.Ingredient -import net.minecraft.tag.ServerTagManagerHolder import net.minecraft.tag.Tag import net.minecraft.util.registry.Registry import java.util.function.Predicate @@ -20,8 +22,7 @@ class ItemIngredient private constructor(val entryList: RegistryEntryList, val CODEC: Codec = RecordCodecBuilder.create { instance -> instance .group( - RegistryEntryList - .codec(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) + RegistryEntryListCodec.ITEM .fieldOf("items") .forGetter(ItemIngredient::entryList), Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemIngredient::count), @@ -37,19 +38,18 @@ class ItemIngredient private constructor(val entryList: RegistryEntryList, constructor(tag: Tag, count: Int = 1) : this(RegistryEntryList.tag(tag), count) - constructor(item: Item, count: Int = 1) : this(RegistryEntryList.of(item), count) + constructor(item: Item, count: Int = 1) : this( + RegistryEntryList.of(item, Registry.ITEM::getEntryOrThrow), + count, + ) - constructor(items: List, count: Int = 1) : this(RegistryEntryList.of(items), count) + private constructor(items: List, count: Int = 1) : this(Tag.of(items.toSet()), count) val isEmpty: Boolean get() = entryList.isEmpty || count <= 0 val vanillaIngredient: Ingredient - get() = entryList.storage.map(Ingredient::fromTag) { - Ingredient.ofStacks( - it.stream().map(Item::getDefaultStack), - ) - } + get() = entryList.storage.map(Ingredient::fromTag, Ingredient::ofItems) override fun test(stack: ItemStack): Boolean = when (stack.isEmpty) { true -> this.isEmpty diff --git a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt b/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt deleted file mode 100644 index 415bd8a..0000000 --- a/src/main/kotlin/dev/robustum/core/recipe/RegistryEntryList.kt +++ /dev/null @@ -1,98 +0,0 @@ -package dev.robustum.core.recipe - -import com.mojang.datafixers.util.Either -import com.mojang.serialization.Codec -import dev.robustum.core.extensions.RobustumCodecs -import dev.robustum.core.extensions.getSafeValue -import net.minecraft.tag.Tag -import net.minecraft.tag.TagGroup -import net.minecraft.util.registry.DefaultedRegistry -import java.util.function.Function -import kotlin.random.Random - -sealed interface RegistryEntryList : Iterable { - companion object { - @JvmStatic - fun codec(registry: DefaultedRegistry, groupGetter: () -> TagGroup): Codec> = Codec - .either(RobustumCodecs.TAG_ID, RobustumCodecs.TAG_ID.listOf()) - .xmap( - { either: Either> -> - either.map( - { entry: RobustumCodecs.TagEntryId -> - when (entry.isTag) { - true -> tag(groupGetter().getTagOrEmpty(entry.id)) - false -> of(checkNotNull(registry.get(entry.id))) - } - }, - { entries: List -> - when { - entries.isEmpty() -> empty() - !entries.all(RobustumCodecs.TagEntryId::isTag) -> of( - entries.map(RobustumCodecs.TagEntryId::id).map(registry::get), - ) - - else -> throw IllegalStateException("Could not serialize TagEntryId list containing tag entry!!") - } - }, - ) - }, - { entryList: RegistryEntryList -> - entryList.storage.map( - { Either.left(RobustumCodecs.TagEntryId.tag(it, groupGetter()::getTagId)) }, - { entries: List -> - when (entries.size) { - 0 -> throw IllegalStateException("Could not serialize empty list to TagEntryId!") - 1 -> Either.left(RobustumCodecs.TagEntryId.of(entries[0], registry::getId)) - else -> Either.right( - entries.map { entry: T -> - RobustumCodecs.TagEntryId.of(entry, registry::getId) - }, - ) - } - }, - ) - }, - ) - - @JvmStatic - fun empty(): RegistryEntryList = Direct(listOf()) - - @JvmStatic - fun of(vararg entries: T): RegistryEntryList = Direct(entries.toList()) - - @JvmStatic - fun of(entries: List): RegistryEntryList = Direct(entries.toList()) - - @JvmStatic - fun tag(tag: Tag): RegistryEntryList = Tagged(tag) - } - - val storage: Either, List> - - val isEmpty: Boolean - get() = entries.isEmpty() - - val entries: List - get() = storage.map(Tag::getSafeValue, Function.identity()) - - val size: Int - get() = entries.size - - fun getRandom(random: Random): T? = entries.randomOrNull(random) - - operator fun get(index: Int): T = entries[index] - - operator fun contains(entry: T): Boolean = storage.map({ it.contains(entry) }, { it.any { entryIn: T -> entryIn == entry } }) - - private class Direct(private val list: List) : RegistryEntryList { - override val storage: Either, List> = Either.right(list) - - override fun iterator(): Iterator = list.iterator() - } - - private class Tagged(val tag: Tag) : RegistryEntryList { - override val storage: Either, List> = Either.left(tag) - - override fun iterator(): Iterator = tag.getSafeValue().iterator() - } -} diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt new file mode 100644 index 0000000..8443c8f --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt @@ -0,0 +1,5 @@ +package dev.robustum.core.registry + +import net.minecraft.util.Identifier + +data class RegistryEntry(val key: Identifier, val value: T) diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt new file mode 100644 index 0000000..761eb06 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt @@ -0,0 +1,54 @@ +package dev.robustum.core.registry + +import com.mojang.datafixers.util.Either +import dev.robustum.core.extensions.getSafeValue +import net.minecraft.tag.SetTag +import net.minecraft.tag.Tag +import kotlin.random.Random + +sealed interface RegistryEntryList : Iterable { + companion object { + @JvmStatic + fun empty(): RegistryEntryList = Empty() + + @JvmStatic + fun of(entry: RegistryEntry): RegistryEntryList = Direct(entry) + + @JvmStatic + fun of(value: T, transform: (T) -> RegistryEntry): RegistryEntryList = of(transform(value)) + + @JvmStatic + fun tag(tag: Tag): RegistryEntryList = Tagged(tag) + } + + val storage: Either, T> + + val isEmpty: Boolean + get() = entries.isEmpty() + + val entries: List + get() = storage.map(Tag::getSafeValue, ::listOf) + + val size: Int + get() = entries.size + + fun getRandom(random: Random): T? = entries.randomOrNull(random) + + operator fun get(index: Int): T = entries[index] + + operator fun contains(entry: T): Boolean = storage.map({ it.contains(entry) }, { it == entry }) + + override fun iterator(): Iterator = entries.iterator() + + private class Empty : RegistryEntryList { + override val storage: Either, T> = Either.left(SetTag.empty()) + } + + private class Direct(entry: RegistryEntry) : RegistryEntryList { + override val storage: Either, T> = Either.right(entry.value) + } + + private class Tagged(tag: Tag) : RegistryEntryList { + override val storage: Either, T> = Either.left(tag) + } +} diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntryListCodec.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryListCodec.kt new file mode 100644 index 0000000..6732e36 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryListCodec.kt @@ -0,0 +1,42 @@ +package dev.robustum.core.registry + +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import dev.robustum.core.extensions.RobustumCodecs +import net.minecraft.block.Block +import net.minecraft.entity.EntityType +import net.minecraft.fluid.Fluid +import net.minecraft.item.Item + +class RegistryEntryListCodec(private val lookup: RegistryLookup) : Codec> { + companion object { + @JvmField + val BLOCK: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.BLOCK) + + @JvmField + val FLUID: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.FLUID) + + @JvmField + val ENTITY_TYPE: RegistryEntryListCodec> = RegistryEntryListCodec(RegistryLookup.ENTITY_TYPE) + + @JvmField + val ITEM: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.ITEM) + } + + override fun encode(input: RegistryEntryList, ops: DynamicOps, prefix: T): DataResult = input.storage + .map(lookup::getId, lookup::getId) + .map(RobustumCodecs.TagEntryId::asString) + .map(ops::createString) + + override fun decode(ops: DynamicOps, input: T): DataResult, T>> = RobustumCodecs.TAG_ID + .decode(ops, input) + .flatMap { pair: Pair -> + val tagEntry: RobustumCodecs.TagEntryId = pair.first + when (tagEntry.isTag) { + true -> lookup.getTag(tagEntry.id) + false -> lookup.getEntry(tagEntry.id).map(RegistryEntryList.Companion::of) + }.map { entryList: RegistryEntryList -> Pair.of(entryList, pair.second) } + } +} diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt new file mode 100644 index 0000000..93ef1cc --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt @@ -0,0 +1,68 @@ +package dev.robustum.core.registry + +import com.mojang.serialization.DataResult +import dev.robustum.core.extensions.RobustumCodecs +import net.minecraft.block.Block +import net.minecraft.entity.EntityType +import net.minecraft.fluid.Fluid +import net.minecraft.item.Item +import net.minecraft.tag.ServerTagManagerHolder +import net.minecraft.tag.Tag +import net.minecraft.tag.TagGroup +import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry + +interface RegistryLookup { + fun getEntry(id: Identifier): DataResult> + + fun getId(value: T): DataResult + + fun getTag(id: Identifier): DataResult> + + fun getId(tag: Tag): DataResult + + companion object { + @JvmStatic + fun of(registry: Registry, groupGetter: () -> TagGroup): RegistryLookup = object : RegistryLookup { + override fun getEntry(id: Identifier): DataResult> = registry + .get(id) + ?.let { RegistryEntry(id, it) } + ?.let(DataResult::success) + ?: DataResult.error("Unknown registry id: $id") + + override fun getId(value: T): DataResult = registry + .getId(value) + ?.let { RobustumCodecs.TagEntryId(it, false) } + ?.let(DataResult::success) + ?: DataResult.error("Unknown registry value: $value") + + override fun getTag(id: Identifier): DataResult> = groupGetter() + .getTag(id) + ?.let(RegistryEntryList.Companion::tag) + ?.let(DataResult>::success) + ?: DataResult.error("Unknown tag id: $id") + + override fun getId(tag: Tag): DataResult = groupGetter() + .getUncheckedTagId(tag) + ?.let { RobustumCodecs.TagEntryId(it, true) } + ?.let(DataResult::success) + ?: DataResult.error("Unknown tag: $tag") + } + + @JvmField + val BLOCK: RegistryLookup = + of(Registry.BLOCK, ServerTagManagerHolder.getTagManager()::getBlocks) + + @JvmField + val FLUID: RegistryLookup = + of(Registry.FLUID, ServerTagManagerHolder.getTagManager()::getFluids) + + @JvmField + val ENTITY_TYPE: RegistryLookup> = + of(Registry.ENTITY_TYPE, ServerTagManagerHolder.getTagManager()::getEntityTypes) + + @JvmField + val ITEM: RegistryLookup = + of(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagFormatRegistry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagFormatRegistry.kt deleted file mode 100644 index 3780e70..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagFormatRegistry.kt +++ /dev/null @@ -1,34 +0,0 @@ -package dev.robustum.core.tag - -import dev.robustum.core.extensions.modify -import net.minecraft.util.Identifier - -object RobustumTagFormatRegistry { - @JvmStatic - private val registry: MutableList = mutableListOf() - - @JvmStatic - fun register(formatter: TagFormatter) { - registry.add(formatter) - } - - @JvmStatic - fun format(id: Identifier): Identifier { - if (id.namespace == "minecraft") return id - registry.forEach { formatter: TagFormatter -> - if (formatter.canFormat(id.path)) { - return id.modify(formatter::format) - } - } - return id - } - - init { - register(TagFormatter.conventional("blocks")) - register(TagFormatter.conventional("bricks")) - register(TagFormatter.conventional("ingots")) - register(TagFormatter.conventional("logs")) - register(TagFormatter.conventional("nuggets")) - register(TagFormatter.conventional("ores")) - } -} diff --git a/src/main/kotlin/dev/robustum/core/tag/TagFormatter.kt b/src/main/kotlin/dev/robustum/core/tag/TagFormatter.kt deleted file mode 100644 index 22e719a..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/TagFormatter.kt +++ /dev/null @@ -1,16 +0,0 @@ -package dev.robustum.core.tag - -interface TagFormatter { - fun canFormat(path: String): Boolean - - fun format(path: String): String - - companion object { - @JvmStatic - fun conventional(name: String): TagFormatter = object : TagFormatter { - override fun canFormat(path: String): Boolean = path.endsWith("_$name") - - override fun format(path: String): String = "$name/" + path.removeSuffix("_$name") - } - } -} From 11ffa3388e26121c6d566119b1f86dc0de3c4ec9 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 7 Dec 2024 15:02:47 +0900 Subject: [PATCH 10/27] Added new events invoked after tag reloading Reverted tag loading system --- .../mixin/ClientPlayNetworkHandlerMixin.java | 25 ++++ .../mixin/ServerTagManagerHolderMixin.java | 25 ++++ .../core/mixin/TagGroupLoaderMixin.java | 46 +++++++ .../core/mixin/TagManagerLoaderMixin.java | 69 ----------- .../robustum/core/registry/RegistryLookup.kt | 32 ++--- .../dev/robustum/core/tag/RobustumTagEntry.kt | 73 ----------- .../robustum/core/tag/RobustumTagEvents.kt | 53 ++++++++ .../dev/robustum/core/tag/RobustumTagFile.kt | 20 --- .../core/tag/RobustumTagGroupLoader.kt | 115 ------------------ .../robustum/core/tag/RuntimeTagCallback.kt | 36 ------ src/main/resources/robustum_core.mixins.json | 8 +- 11 files changed, 171 insertions(+), 331 deletions(-) create mode 100644 src/main/java/dev/robustum/core/mixin/ClientPlayNetworkHandlerMixin.java create mode 100644 src/main/java/dev/robustum/core/mixin/ServerTagManagerHolderMixin.java create mode 100644 src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java delete mode 100644 src/main/java/dev/robustum/core/mixin/TagManagerLoaderMixin.java delete mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt create mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt delete mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagFile.kt delete mode 100644 src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt delete mode 100644 src/main/kotlin/dev/robustum/core/tag/RuntimeTagCallback.kt diff --git a/src/main/java/dev/robustum/core/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/dev/robustum/core/mixin/ClientPlayNetworkHandlerMixin.java new file mode 100644 index 0000000..695a567 --- /dev/null +++ b/src/main/java/dev/robustum/core/mixin/ClientPlayNetworkHandlerMixin.java @@ -0,0 +1,25 @@ +package dev.robustum.core.mixin; + +import dev.robustum.core.tag.RobustumTagEvents; +import net.fabricmc.api.EnvType; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.packet.s2c.play.SynchronizeTagsS2CPacket; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ClientPlayNetworkHandler.class) +public abstract class ClientPlayNetworkHandlerMixin { + @Unique + private static final Logger LOGGER = LogManager.getLogger(ClientPlayNetworkHandlerMixin.class); + + @Inject(method = "onSynchronizeTags", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;getSearchableContainer(Lnet/minecraft/client/search/SearchManager$Key;)Lnet/minecraft/client/search/SearchableContainer;")) + private void robustum$onSynchronizeTags(SynchronizeTagsS2CPacket packet, CallbackInfo ci) { + RobustumTagEvents.RELOAD.invoker().onReload(packet.getTagManager(), EnvType.CLIENT); + LOGGER.info("Client TagManager reloaded!"); + } +} diff --git a/src/main/java/dev/robustum/core/mixin/ServerTagManagerHolderMixin.java b/src/main/java/dev/robustum/core/mixin/ServerTagManagerHolderMixin.java new file mode 100644 index 0000000..823c96f --- /dev/null +++ b/src/main/java/dev/robustum/core/mixin/ServerTagManagerHolderMixin.java @@ -0,0 +1,25 @@ +package dev.robustum.core.mixin; + +import dev.robustum.core.tag.RobustumTagEvents; +import net.fabricmc.api.EnvType; +import net.minecraft.tag.ServerTagManagerHolder; +import net.minecraft.tag.TagManager; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerTagManagerHolder.class) +public abstract class ServerTagManagerHolderMixin { + @Unique + private static final Logger LOGGER = LogManager.getLogger(ServerTagManagerHolderMixin.class); + + @Inject(method = "setTagManager", at = @At("TAIL")) + private static void robustum$setTagManager(TagManager tagManager, CallbackInfo ci) { + RobustumTagEvents.RELOAD.invoker().onReload(tagManager, EnvType.SERVER); + LOGGER.info("Server TagManager reloaded!"); + } +} diff --git a/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java b/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java new file mode 100644 index 0000000..7ef2c6c --- /dev/null +++ b/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java @@ -0,0 +1,46 @@ +package dev.robustum.core.mixin; + +import dev.robustum.core.RobustumCore; +import dev.robustum.core.tag.RobustumTagEvents; +import net.minecraft.resource.ResourceManager; +import net.minecraft.tag.Tag; +import net.minecraft.tag.TagGroupLoader; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.Map; + +@Mixin(TagGroupLoader.class) +public abstract class TagGroupLoaderMixin { + @Final + @Shadow + private String entryType; + + @Nullable + @Unique + private Registry findRegistry() { + return switch (entryType) { + case "block" -> Registry.BLOCK; + case "item" -> Registry.ITEM; + case "fluid" -> Registry.FLUID; + case "entity_type" -> Registry.ENTITY_TYPE; + default -> null; + }; + } + + @Inject(method = "method_18243", at = @At("RETURN")) + private void robustum_Core$method_18243(ResourceManager resourceManager, CallbackInfoReturnable> cir) { + Registry registry = findRegistry(); + if (registry == null) return; + RobustumTagEvents.REGISTER.invoker().onRegister(new RobustumTagEvents.Helper(registry, (@NotNull Identifier tagId, Tag.@NotNull Entry entry) -> cir.getReturnValue().computeIfAbsent(tagId, k -> Tag.Builder.create()).add(entry, RobustumCore.MOD_NAME))); + } +} diff --git a/src/main/java/dev/robustum/core/mixin/TagManagerLoaderMixin.java b/src/main/java/dev/robustum/core/mixin/TagManagerLoaderMixin.java deleted file mode 100644 index 6b80e54..0000000 --- a/src/main/java/dev/robustum/core/mixin/TagManagerLoaderMixin.java +++ /dev/null @@ -1,69 +0,0 @@ -package dev.robustum.core.mixin; - -import dev.robustum.core.tag.RobustumTagGroupLoader; -import net.minecraft.block.Block; -import net.minecraft.entity.EntityType; -import net.minecraft.fluid.Fluid; -import net.minecraft.item.Item; -import net.minecraft.resource.ResourceManager; -import net.minecraft.resource.ResourceReloader; -import net.minecraft.tag.ServerTagManagerHolder; -import net.minecraft.tag.TagGroup; -import net.minecraft.tag.TagManager; -import net.minecraft.tag.TagManagerLoader; -import net.minecraft.util.profiler.Profiler; -import net.minecraft.util.registry.Registry; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; - -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -@Mixin(TagManagerLoader.class) -public abstract class TagManagerLoaderMixin { - - @Unique - private final RobustumTagGroupLoader blockLoader = new RobustumTagGroupLoader<>(Registry.BLOCK, "tags/blocks"); - - @Unique - private final RobustumTagGroupLoader itemLoader = new RobustumTagGroupLoader<>(Registry.ITEM, "tags/items"); - - @Unique - private final RobustumTagGroupLoader fluidLoader = new RobustumTagGroupLoader<>(Registry.FLUID, "tags/fluids"); - - @Unique - private final RobustumTagGroupLoader> entityLoader = new RobustumTagGroupLoader<>(Registry.ENTITY_TYPE, "tags/entity_types"); - - @Shadow - private TagManager tagManager; - - @SuppressWarnings("unchecked") - @Inject(method = "reload", at = @At("HEAD"), cancellable = true) - private void robustumCore$reload(ResourceReloader.Synchronizer synchronizer, ResourceManager manager, Profiler prepareProfiler, Profiler applyProfiler, Executor prepareExecutor, Executor applyExecutor, CallbackInfoReturnable> cir) { - List>> rawMaps = List.of( - CompletableFuture.supplyAsync(() -> blockLoader.load(manager), prepareExecutor), - CompletableFuture.supplyAsync(() -> itemLoader.load(manager), prepareExecutor), - CompletableFuture.supplyAsync(() -> fluidLoader.load(manager), prepareExecutor), - CompletableFuture.supplyAsync(() -> entityLoader.load(manager), prepareExecutor) - ); - cir.setReturnValue( - CompletableFuture.allOf(rawMaps.toArray(CompletableFuture[]::new)) - .thenCompose(synchronizer::whenPrepared) - .thenAcceptAsync(void1 -> { - TagGroup blockGroup = (TagGroup) rawMaps.getFirst().join(); - TagGroup itemGroup = (TagGroup) rawMaps.get(1).join(); - TagGroup fluidGroup = (TagGroup) rawMaps.get(2).join(); - TagGroup> entityGroup = (TagGroup>) rawMaps.get(3).join(); - TagManager tagManager = TagManager.create(blockGroup, itemGroup, fluidGroup, entityGroup); - ServerTagManagerHolder.setTagManager(tagManager); - this.tagManager = tagManager; - }, applyExecutor) - ); - } - -} diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt index 93ef1cc..3857bdd 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt @@ -22,6 +22,22 @@ interface RegistryLookup { fun getId(tag: Tag): DataResult companion object { + @JvmField + val BLOCK: RegistryLookup = + of(Registry.BLOCK, ServerTagManagerHolder.getTagManager()::getBlocks) + + @JvmField + val FLUID: RegistryLookup = + of(Registry.FLUID, ServerTagManagerHolder.getTagManager()::getFluids) + + @JvmField + val ENTITY_TYPE: RegistryLookup> = + of(Registry.ENTITY_TYPE, ServerTagManagerHolder.getTagManager()::getEntityTypes) + + @JvmField + val ITEM: RegistryLookup = + of(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) + @JvmStatic fun of(registry: Registry, groupGetter: () -> TagGroup): RegistryLookup = object : RegistryLookup { override fun getEntry(id: Identifier): DataResult> = registry @@ -48,21 +64,5 @@ interface RegistryLookup { ?.let(DataResult::success) ?: DataResult.error("Unknown tag: $tag") } - - @JvmField - val BLOCK: RegistryLookup = - of(Registry.BLOCK, ServerTagManagerHolder.getTagManager()::getBlocks) - - @JvmField - val FLUID: RegistryLookup = - of(Registry.FLUID, ServerTagManagerHolder.getTagManager()::getFluids) - - @JvmField - val ENTITY_TYPE: RegistryLookup> = - of(Registry.ENTITY_TYPE, ServerTagManagerHolder.getTagManager()::getEntityTypes) - - @JvmField - val ITEM: RegistryLookup = - of(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) } } diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt deleted file mode 100644 index c4b57b5..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEntry.kt +++ /dev/null @@ -1,73 +0,0 @@ -package dev.robustum.core.tag - -import com.mojang.datafixers.util.Either -import com.mojang.serialization.Codec -import com.mojang.serialization.codecs.RecordCodecBuilder -import dev.robustum.core.extensions.RobustumCodecs -import dev.robustum.core.extensions.getSafeValue -import net.minecraft.tag.Tag -import net.minecraft.util.Identifier - -class RobustumTagEntry private constructor(private val id: Identifier, private val isTag: Boolean, private val required: Boolean) { - companion object { - @JvmStatic - private val ENTRY_CODEC: Codec = RecordCodecBuilder.create { instance -> - instance - .group( - RobustumCodecs.TAG_ID.fieldOf("id").forGetter(RobustumTagEntry::tagEntryId), - Codec.BOOL.optionalFieldOf("required", true).forGetter(RobustumTagEntry::required), - ).apply(instance, ::RobustumTagEntry) - } - - @JvmField - val CODEC: Codec = Codec.either(RobustumCodecs.TAG_ID, ENTRY_CODEC).xmap( - { either: Either -> - either.map({ - RobustumTagEntry( - it, - true, - ) - }, { it }) - }, - { - when (it.required) { - true -> Either.left(it.tagEntryId) - false -> Either.right(it) - } - }, - ) - - @JvmStatic - fun create(id: Identifier, required: Boolean = true): RobustumTagEntry = RobustumTagEntry(id, false, required) - - @JvmStatic - fun create(obj: T, transform: (T) -> Identifier, required: Boolean = true): RobustumTagEntry = - RobustumTagEntry(transform(obj), false, required) - - @JvmStatic - fun createTag(id: Identifier, required: Boolean = true): RobustumTagEntry = RobustumTagEntry(id, true, required) - } - - constructor(tagId: RobustumCodecs.TagEntryId, required: Boolean) : this(tagId.id, tagId.isTag, required) - - private val tagEntryId = RobustumCodecs.TagEntryId(id, isTag) - - fun resolve(valueGetter: ValueGetter, consumer: (T) -> Unit): Boolean { - if (isTag) { - valueGetter.tag(id)?.getSafeValue()?.forEach(consumer) ?: return !required - } else { - valueGetter.direct(id)?.let(consumer) ?: return !required - } - return true - } - - override fun toString(): String = "RobustumTagEntry[id=$id, isTag=$isTag, required=$required]" - - // ValueGetter // - - interface ValueGetter { - fun direct(id: Identifier): T? - - fun tag(id: Identifier): Tag? - } -} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt new file mode 100644 index 0000000..577357b --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt @@ -0,0 +1,53 @@ +package dev.robustum.core.tag + +import dev.robustum.core.extensions.idOrNull +import net.fabricmc.api.EnvType +import net.fabricmc.fabric.api.event.Event +import net.fabricmc.fabric.api.event.EventFactory +import net.minecraft.tag.Tag +import net.minecraft.tag.TagManager +import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry +import net.minecraft.util.registry.RegistryKey +import java.util.function.BiConsumer + +object RobustumTagEvents { + @JvmField + val REGISTER: Event = + EventFactory.createArrayBacked(Register::class.java) { callbacks: Array -> + Register { helper: Helper -> callbacks.forEach { it.onRegister(helper) } } + } + + @JvmField + val RELOAD: Event = EventFactory.createArrayBacked(Reload::class.java) { callbacks: Array -> + Reload { manager: TagManager, environment: EnvType -> callbacks.forEach { it.onReload(manager, environment) } } + } + + // Register // + + fun interface Register { + fun onRegister(helper: Helper) + } + + // Helper // + + class Helper(private val registry: Registry<*>, private val consumer: BiConsumer) { + @Suppress("UNCHECKED_CAST") + fun add(registryKey: RegistryKey>, tag: Tag, vararg values: T) { + val tagId: Identifier = tag.idOrNull ?: return + if (registryKey == registry.key) { + val fixedRegistry: Registry = (registry as? Registry) ?: return + values + .mapNotNull(fixedRegistry::getId) + .map { Tag.ObjectEntry(it) } + .forEach { consumer.accept(tagId, it) } + } + } + } + + // Reload // + + fun interface Reload { + fun onReload(manager: TagManager, environment: EnvType) + } +} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagFile.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagFile.kt deleted file mode 100644 index b5e0178..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagFile.kt +++ /dev/null @@ -1,20 +0,0 @@ -package dev.robustum.core.tag - -import com.mojang.serialization.Codec -import com.mojang.serialization.codecs.RecordCodecBuilder - -data class RobustumTagFile(val entries: List, val replace: Boolean) { - companion object { - @JvmField - val CODEC: Codec = RecordCodecBuilder.create { instance -> - instance - .group( - RobustumTagEntry.CODEC - .listOf() - .fieldOf("values") - .forGetter(RobustumTagFile::entries), - Codec.BOOL.optionalFieldOf("replace", false).forGetter(RobustumTagFile::replace), - ).apply(instance, ::RobustumTagFile) - } - } -} diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt deleted file mode 100644 index ce7bfa8..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagGroupLoader.kt +++ /dev/null @@ -1,115 +0,0 @@ -package dev.robustum.core.tag - -import com.google.common.collect.ImmutableSet -import com.google.gson.JsonElement -import com.google.gson.JsonParser -import com.mojang.serialization.Dynamic -import com.mojang.serialization.JsonOps -import dev.robustum.core.RobustumCore -import dev.robustum.core.extensions.removePrefix -import dev.robustum.core.extensions.removeSuffix -import net.minecraft.resource.Resource -import net.minecraft.resource.ResourceManager -import net.minecraft.tag.Tag -import net.minecraft.tag.TagGroup -import net.minecraft.util.Identifier -import net.minecraft.util.registry.Registry -import net.minecraft.util.registry.RegistryKey -import org.apache.logging.log4j.LogManager -import org.apache.logging.log4j.Logger - -class RobustumTagGroupLoader(private val registry: Registry, private val dataType: String) { - private val logger: Logger = LogManager.getLogger() - private val parser = JsonParser() - - private val registryKey: RegistryKey> = registry.key - - private fun loadTags(resourceManager: ResourceManager): Map> = - buildMap> { - resourceManager.findResources(dataType) { it.endsWith(".json") }.forEach { resourceId: Identifier -> - val fixedId: Identifier = resourceId - .removePrefix("$dataType/") - .removeSuffix(".json") - // .let(RobustumTagFormatRegistry::format) - resourceManager.getAllResources(resourceId).forEach { resource: Resource -> - runCatching { - val json: JsonElement = resource.use { resourceIn: Resource -> - parser.parse(resourceIn.inputStream.bufferedReader()) - } - val builder: MutableList = this.computeIfAbsent(fixedId) { mutableListOf() } - val tagFile: RobustumTagFile = - RobustumTagFile.CODEC.parse(Dynamic(JsonOps.INSTANCE, json)).getOrThrow(false, logger::error) - if (tagFile.replace) { - builder.clear() - } - tagFile.entries.forEach { entry: RobustumTagEntry -> - builder.add( - TrackedEntry( - entry, - resource.resourcePackName, - ), - ) - } - }.onFailure(logger::error) - } - RuntimeTagCallback.EVENT.invoker().onRegister( - RuntimeTagCallback.Helper(registry) { tagId: Identifier, entry: RobustumTagEntry -> - this.computeIfAbsent(tagId) { mutableListOf() }.add(TrackedEntry(entry, RobustumCore.MOD_NAME)) - }, - ) - } - }.onEach { logger.info("Tag - ${it.key}") } - - private fun buildGroup(rawMap: Map>): TagGroup = TagGroup.create( - buildMap { - val valueGetter = object : RobustumTagEntry.ValueGetter { - override fun direct(id: Identifier): T? = registry.get(id) - - override fun tag(id: Identifier): Tag? = this@buildMap[id] - } - val copiedMap: MutableMap> = rawMap.toMutableMap() - while (copiedMap.isNotEmpty()) { - var result = false - copiedMap.toList().forEach { (id: Identifier, entries: List) -> - resolveEntries(valueGetter, entries)?.let { tag: Tag -> - this[id] = tag - copiedMap.remove(id) - result = true - } - } - if (!result) { - break - } - } - copiedMap.forEach { (id: Identifier, entries: List) -> - logger.error( - "Couldn't load ${registryKey.value.path} tag: $id as it is missing following references: [${ - getUnresolvedEntries( - valueGetter, - entries, - ).joinToString(separator = ", ", transform = TrackedEntry::toString) - }]", - ) - } - }, - ) - - private fun resolveEntries(valueGetter: RobustumTagEntry.ValueGetter, entries: List): Tag? { - val setBuilder: ImmutableSet.Builder = ImmutableSet.builder() - entries.forEach { entry: TrackedEntry -> - if (!entry.entry.resolve(valueGetter, setBuilder::add)) { - return null - } - } - return Tag.of(setBuilder.build()) - } - - private fun getUnresolvedEntries(valueGetter: RobustumTagEntry.ValueGetter, entries: List): List = - entries.filter { !it.entry.resolve(valueGetter) {} } - - fun load(resourceManager: ResourceManager): TagGroup = buildGroup(loadTags(resourceManager)) - - // TrackedEntry // - - data class TrackedEntry(val entry: RobustumTagEntry, val source: String) -} diff --git a/src/main/kotlin/dev/robustum/core/tag/RuntimeTagCallback.kt b/src/main/kotlin/dev/robustum/core/tag/RuntimeTagCallback.kt deleted file mode 100644 index ee39cd0..0000000 --- a/src/main/kotlin/dev/robustum/core/tag/RuntimeTagCallback.kt +++ /dev/null @@ -1,36 +0,0 @@ -package dev.robustum.core.tag - -import dev.robustum.core.extensions.idOrNull -import net.fabricmc.fabric.api.event.Event -import net.fabricmc.fabric.api.event.EventFactory -import net.minecraft.tag.Tag -import net.minecraft.util.Identifier -import net.minecraft.util.registry.Registry -import net.minecraft.util.registry.RegistryKey - -fun interface RuntimeTagCallback { - companion object { - @JvmField - val EVENT: Event = EventFactory.createArrayBacked(RuntimeTagCallback::class.java) { callbacks -> - RuntimeTagCallback { helper: Helper -> callbacks.forEach { it.onRegister(helper) } } - } - } - - fun onRegister(helper: Helper) - - // Helper // - - class Helper(private val registry: Registry<*>, private val consumer: (Identifier, RobustumTagEntry) -> Unit) { - @Suppress("UNCHECKED_CAST") - fun add(registryKey: RegistryKey>, tag: Tag, vararg values: T) { - val tagId: Identifier = tag.idOrNull ?: return - if (registryKey == registry.key) { - val fixedRegistry: Registry = (registry as? Registry) ?: return - values - .mapNotNull(fixedRegistry::getId) - .map(RobustumTagEntry.Companion::create) - .forEach { consumer(tagId, it) } - } - } - } -} diff --git a/src/main/resources/robustum_core.mixins.json b/src/main/resources/robustum_core.mixins.json index a196419..3f0485d 100644 --- a/src/main/resources/robustum_core.mixins.json +++ b/src/main/resources/robustum_core.mixins.json @@ -3,9 +3,13 @@ "package": "dev.robustum.core.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ - "TagManagerLoaderMixin" + "ServerTagManagerHolderMixin", + "TagGroupLoaderMixin" ], "injectors": { "defaultRequire": 1 - } + }, + "client": [ + "ClientPlayNetworkHandlerMixin" + ] } From ed8cfbe714e2814bfb238d98dfcd62760bee33e0 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 14 Dec 2024 14:00:22 +0900 Subject: [PATCH 11/27] Fixed method name --- src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java b/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java index 7ef2c6c..fb0d11b 100644 --- a/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java +++ b/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java @@ -38,7 +38,7 @@ private Registry findRegistry() { } @Inject(method = "method_18243", at = @At("RETURN")) - private void robustum_Core$method_18243(ResourceManager resourceManager, CallbackInfoReturnable> cir) { + private void robustum$method_18243(ResourceManager resourceManager, CallbackInfoReturnable> cir) { Registry registry = findRegistry(); if (registry == null) return; RobustumTagEvents.REGISTER.invoker().onRegister(new RobustumTagEvents.Helper(registry, (@NotNull Identifier tagId, Tag.@NotNull Entry entry) -> cir.getReturnValue().computeIfAbsent(tagId, k -> Tag.Builder.create()).add(entry, RobustumCore.MOD_NAME))); From 5460460e0ca4a390da29b0e302179227eb2d88bd Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 14 Dec 2024 14:40:06 +0900 Subject: [PATCH 12/27] Adding kdoc --- .../core/extensions/CodecExtensions.kt | 27 +++++++++++++-- .../core/extensions/CollectionExtensions.kt | 6 ++++ .../robustum/core/tag/RobustumTagEvents.kt | 34 ++++++++++++++++++- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index d4bc842..1d45650 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -9,8 +9,14 @@ import java.util.stream.Stream // Codec // +/** + * [validator]で[Codec]を検証する + */ fun Codec.validate(validator: (A) -> DataResult): Codec = flatXmap(validator, validator) +/** + * [getter]で[Codec]を遅延評価する + */ fun lazyCodec(getter: () -> Codec): Codec = object : Codec { override fun encode(input: A, ops: DynamicOps, prefix: T): DataResult = getter().encode(input, ops, prefix) @@ -76,7 +82,7 @@ private class KeyDispatchCodec( override fun encode(input: V, ops: DynamicOps, prefix: RecordBuilder): RecordBuilder { val encodeResult: DataResult> = encoder(input) val builder: RecordBuilder = prefix.withErrorsFrom(encodeResult) - if (encodeResult.errored) { + if (encodeResult.isErrored) { return builder } val elementEncoder: MapEncoder = encodeResult.result().get() @@ -112,17 +118,32 @@ fun Codec.optionalOf(): Codec> = object : Codec Codec>.defaultedListOf(defaultValue: A): Codec> = xmap({ DefaultedList.copyOf(defaultValue, *it.toTypedArray()) }, Function.identity()) // DataResult // -val DataResult.succeeded: Boolean +/** + * [DataResult]が成功しているかどうかを返す + */ +val DataResult.isSucceeded: Boolean get() = result().isPresent -val DataResult.errored: Boolean +/** + * [DataResult]が失敗しているかどうかを返す + */ +val DataResult.isErrored: Boolean get() = error().isPresent +/** + * [DataResult]が成功しているときのみ[action]を実行する + */ fun DataResult.ifSucceeded(action: (R) -> Unit): DataResult = apply { result().ifPresent(action) } +/** + * [DataResult]が失敗しているときのみ[action]を実行する + */ fun DataResult.ifErrored(action: (DataResult.PartialResult) -> Unit): DataResult = apply { error().ifPresent(action) } diff --git a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt index 8abd3c0..0584d78 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt @@ -4,9 +4,15 @@ import net.minecraft.util.collection.DefaultedList // DefaultedList // +/** + * [Iterable]を,[defaultValue]を初期値とした[DefaultedList]に変換する + */ inline fun Iterable.toDefaultedList(defaultValue: T): DefaultedList = DefaultedList.copyOf(defaultValue, *this.toList().toTypedArray()) +/** + * [Map]を,[defaultValue]を初期値とした[DefaultedList]に[transform]で変換する + */ inline fun Map.toDefaultedList( defaultValue: T, transform: (Map.Entry) -> T, diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt index 577357b..9c34f66 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt @@ -12,12 +12,18 @@ import net.minecraft.util.registry.RegistryKey import java.util.function.BiConsumer object RobustumTagEvents { + /** + * [net.minecraft.tag.TagGroupLoader.prepareReload]の最後で呼び出される + */ @JvmField val REGISTER: Event = EventFactory.createArrayBacked(Register::class.java) { callbacks: Array -> Register { helper: Helper -> callbacks.forEach { it.onRegister(helper) } } } + /** + * [net.minecraft.tag.ServerTagManagerHolder.setTagManager],[net.minecraft.client.network.ClientPlayNetworkHandler.onSynchronizeTags]の最後でそれぞれ呼び出される + */ @JvmField val RELOAD: Event = EventFactory.createArrayBacked(Reload::class.java) { callbacks: Array -> Reload { manager: TagManager, environment: EnvType -> callbacks.forEach { it.onReload(manager, environment) } } @@ -31,10 +37,28 @@ object RobustumTagEvents { // Helper // + /** + * @param registry 現在のレジストリ + * @param consumer 渡されたタグの[Identifier]とそのエントリ[Tag.Entry]を受け取る + */ class Helper(private val registry: Registry<*>, private val consumer: BiConsumer) { - @Suppress("UNCHECKED_CAST") + /** + * @param registryKey 登録しようとしているレジストリのキー + * @param tag 登録しようとしているタグ,[Tag.Identified]を実装している必要がある + * @param values 指定したタグに紐づけようとしている値 + */ fun add(registryKey: RegistryKey>, tag: Tag, vararg values: T) { val tagId: Identifier = tag.idOrNull ?: return + add(registryKey, tagId, *values) + } + + /** + * @param registryKey 登録しようとしているレジストリのキー + * @param tagId 登録しようとしているタグの[Identifier] + * @param values 指定したタグに紐づけようとしている値 + */ + @Suppress("UNCHECKED_CAST") + fun add(registryKey: RegistryKey>, tagId: Identifier, vararg values: T) { if (registryKey == registry.key) { val fixedRegistry: Registry = (registry as? Registry) ?: return values @@ -47,7 +71,15 @@ object RobustumTagEvents { // Reload // + /** + * @see [net.minecraft.tag.ServerTagManagerHolder.setTagManager] + * @see [net.minecraft.client.network.ClientPlayNetworkHandler.onSynchronizeTags] + */ fun interface Reload { + /** + * @param manager 各サイドにおける[TagManager] + * @param environment 各サイドにおける[EnvType] + */ fun onReload(manager: TagManager, environment: EnvType) } } From 7200b2b6e8002f155402e77e3ec502ef17ec26e1 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 14 Dec 2024 15:35:33 +0900 Subject: [PATCH 13/27] Adding kdoc Moved mixin classes into tag package --- .../ClientPlayNetworkHandlerMixin.java | 2 +- .../ServerTagManagerHolderMixin.java | 2 +- .../mixin/{ => tag}/TagGroupLoaderMixin.java | 2 +- .../core/extensions/CodecExtensions.kt | 30 +++++++++++----- .../core/extensions/CollectionExtensions.kt | 11 ++++-- .../core/extensions/IdentifierExtensions.kt | 25 +++++++++++++ .../robustum/core/extensions/ItemExtension.kt | 13 +++++++ .../core/extensions/RobustumCodecs.kt | 36 ++++++++++++++++--- .../robustum/core/extensions/TagExtensions.kt | 35 +++++++++++++++++- .../robustum/core/registry/RegistryEntry.kt | 6 ++++ src/main/resources/robustum_core.mixins.json | 6 ++-- 11 files changed, 146 insertions(+), 22 deletions(-) rename src/main/java/dev/robustum/core/mixin/{ => tag}/ClientPlayNetworkHandlerMixin.java (97%) rename src/main/java/dev/robustum/core/mixin/{ => tag}/ServerTagManagerHolderMixin.java (96%) rename src/main/java/dev/robustum/core/mixin/{ => tag}/TagGroupLoaderMixin.java (97%) diff --git a/src/main/java/dev/robustum/core/mixin/ClientPlayNetworkHandlerMixin.java b/src/main/java/dev/robustum/core/mixin/tag/ClientPlayNetworkHandlerMixin.java similarity index 97% rename from src/main/java/dev/robustum/core/mixin/ClientPlayNetworkHandlerMixin.java rename to src/main/java/dev/robustum/core/mixin/tag/ClientPlayNetworkHandlerMixin.java index 695a567..d7e9aa0 100644 --- a/src/main/java/dev/robustum/core/mixin/ClientPlayNetworkHandlerMixin.java +++ b/src/main/java/dev/robustum/core/mixin/tag/ClientPlayNetworkHandlerMixin.java @@ -1,4 +1,4 @@ -package dev.robustum.core.mixin; +package dev.robustum.core.mixin.tag; import dev.robustum.core.tag.RobustumTagEvents; import net.fabricmc.api.EnvType; diff --git a/src/main/java/dev/robustum/core/mixin/ServerTagManagerHolderMixin.java b/src/main/java/dev/robustum/core/mixin/tag/ServerTagManagerHolderMixin.java similarity index 96% rename from src/main/java/dev/robustum/core/mixin/ServerTagManagerHolderMixin.java rename to src/main/java/dev/robustum/core/mixin/tag/ServerTagManagerHolderMixin.java index 823c96f..7f5faba 100644 --- a/src/main/java/dev/robustum/core/mixin/ServerTagManagerHolderMixin.java +++ b/src/main/java/dev/robustum/core/mixin/tag/ServerTagManagerHolderMixin.java @@ -1,4 +1,4 @@ -package dev.robustum.core.mixin; +package dev.robustum.core.mixin.tag; import dev.robustum.core.tag.RobustumTagEvents; import net.fabricmc.api.EnvType; diff --git a/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java b/src/main/java/dev/robustum/core/mixin/tag/TagGroupLoaderMixin.java similarity index 97% rename from src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java rename to src/main/java/dev/robustum/core/mixin/tag/TagGroupLoaderMixin.java index fb0d11b..df05da8 100644 --- a/src/main/java/dev/robustum/core/mixin/TagGroupLoaderMixin.java +++ b/src/main/java/dev/robustum/core/mixin/tag/TagGroupLoaderMixin.java @@ -1,4 +1,4 @@ -package dev.robustum.core.mixin; +package dev.robustum.core.mixin.tag; import dev.robustum.core.RobustumCore; import dev.robustum.core.tag.RobustumTagEvents; diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index 1d45650..5ef9c26 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -10,12 +10,18 @@ import java.util.stream.Stream // Codec // /** - * [validator]で[Codec]を検証する + * 指定された[validator]で検証した[Codec]を返します。 + * @param A 値のクラス + * @param validator 値を[DataResult]で評価する。 + * @return [validator]で評価された[Codec] */ fun Codec.validate(validator: (A) -> DataResult): Codec = flatXmap(validator, validator) /** - * [getter]で[Codec]を遅延評価する + * 指定された[getter]で遅延評価された[Codec]を返します。 + * @param A 値のクラス + * @param getter 遅延評価された元の[Codec] + * @return [getter]で遅延評価された[Codec] */ fun lazyCodec(getter: () -> Codec): Codec = object : Codec { override fun encode(input: A, ops: DynamicOps, prefix: T): DataResult = getter().encode(input, ops, prefix) @@ -83,6 +89,7 @@ private class KeyDispatchCodec( val encodeResult: DataResult> = encoder(input) val builder: RecordBuilder = prefix.withErrorsFrom(encodeResult) if (encodeResult.isErrored) { + Result return builder } val elementEncoder: MapEncoder = encodeResult.result().get() @@ -119,7 +126,10 @@ fun Codec.optionalOf(): Codec> = object : Codec Codec>.defaultedListOf(defaultValue: A): Codec> = xmap({ DefaultedList.copyOf(defaultValue, *it.toTypedArray()) }, Function.identity()) @@ -127,23 +137,25 @@ inline fun Codec>.defaultedListOf(defaultValue: A): Co // DataResult // /** - * [DataResult]が成功しているかどうかを返す + * 存在する値がある場合はtrueを返し、それ以外の場合はfalseを返します。 */ val DataResult.isSucceeded: Boolean get() = result().isPresent /** - * [DataResult]が失敗しているかどうかを返す + * 存在する値がない場合はtrueを返し、それ以外の場合はfalseを返します。 */ val DataResult.isErrored: Boolean get() = error().isPresent /** - * [DataResult]が成功しているときのみ[action]を実行する + * [DataResult]が値を保持している場合は指定された[action]をその値で呼び出し、それ以外の場合は何も行いません。 + * @param action 値が存在する場合に実行されるブロック */ -fun DataResult.ifSucceeded(action: (R) -> Unit): DataResult = apply { result().ifPresent(action) } +fun DataResult.onSucceeded(action: (R) -> Unit): DataResult = apply { result().ifPresent(action) } /** - * [DataResult]が失敗しているときのみ[action]を実行する + * [DataResult]が値を保持していない場合は指定された[action]をその値で呼び出し、それ以外の場合は何も行いません。 + * @param action 値が存在しない場合に実行されるブロック */ -fun DataResult.ifErrored(action: (DataResult.PartialResult) -> Unit): DataResult = apply { error().ifPresent(action) } +fun DataResult.onErrored(action: (DataResult.PartialResult) -> Unit): DataResult = apply { error().ifPresent(action) } diff --git a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt index 0584d78..fa0ecd8 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt @@ -5,13 +5,20 @@ import net.minecraft.util.collection.DefaultedList // DefaultedList // /** - * [Iterable]を,[defaultValue]を初期値とした[DefaultedList]に変換する + * [Iterable]を[DefaultedList]に変換します。 + * @param T 値のクラス + * @param defaultValue [DefaultedList]の初期値 + * @return [defaultValue]を初期値に持つ[DefaultedList] */ inline fun Iterable.toDefaultedList(defaultValue: T): DefaultedList = DefaultedList.copyOf(defaultValue, *this.toList().toTypedArray()) /** - * [Map]を,[defaultValue]を初期値とした[DefaultedList]に[transform]で変換する + * [Map]を[DefaultedList]で変換する + * @param T 値のクラス + * @param defaultValue [DefaultedList]の初期値 + * @param transform [Map.Entry]を[T]に変換するブロック + * @return [defaultValue]を初期値に持つ[DefaultedList] */ inline fun Map.toDefaultedList( defaultValue: T, diff --git a/src/main/kotlin/dev/robustum/core/extensions/IdentifierExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/IdentifierExtensions.kt index c7d4262..47d70ce 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/IdentifierExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/IdentifierExtensions.kt @@ -2,12 +2,37 @@ package dev.robustum.core.extensions import net.minecraft.util.Identifier +/** + * 指定された[prefix]でパスを前置した[Identifier]を返します。 + * @param prefix パスの前置詞 + * @return [prefix]でパスを前置した新しい[Identifier] + */ fun Identifier.prefix(prefix: String): Identifier = Identifier(this.namespace, prefix + this.path) +/** + * 指定された[suffix]でパスを後置した[Identifier]を返します。 + * @param suffix パスの後置詞 + * @return [suffix]でパスを高知した新しい[Identifier] + */ fun Identifier.suffix(suffix: String): Identifier = Identifier(this.namespace, this.path + suffix) +/** + * 指定された[transform]でパスを変換した[Identifier]を返します。 + * @param transform [Identifier]のパスを変換するブロック + * @return [transform]でパスを置換した新しい[Identifier] + */ inline fun Identifier.modify(transform: (String) -> String): Identifier = Identifier(this.namespace, transform(this.path)) +/** + * 指定された[prefix]でパスの前置詞を削除した[Identifier]を返します。 + * @param prefix 削除するパスの前置詞 + * @return [prefix]でパスの前置詞を削除した新しい[Identifier] + */ fun Identifier.removePrefix(prefix: String): Identifier = Identifier(this.namespace, this.path.removePrefix(prefix)) +/** + * 指定された[suffix]でパスの後置詞を削除した[Identifier]を返します。 + * @param suffix 削除するパスの後置詞 + * @return [suffix]でパスの後置詞を削除した新しい[Identifier] + */ fun Identifier.removeSuffix(suffix: String): Identifier = Identifier(this.namespace, this.path.removeSuffix(suffix)) diff --git a/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt b/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt index 6954087..0d4a410 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt @@ -8,11 +8,24 @@ import net.minecraft.item.ItemUsageContext // ItemStack // +/** + * 指定された[item]を持っている場合はtrueを,それ以外の場合はfalseを返します。 + * @param item この[ItemStack]が持っているかどうか判定される要素 + * @return この[ItemStack]が持っている場合はtrue,それ以外はfalse + */ fun ItemStack.isOf(item: ItemConvertible): Boolean = this.item == item.asItem() // ItemUsageContext // +/** + * この[ItemUsageContext]が持っている[net.minecraft.world.World]と[net.minecraft.util.math.BlockPos]から[BlockState]を取得します。 + */ val ItemUsageContext.blockState: BlockState get() = world.getBlockState(blockPos) +/** + * この[ItemUsageContext]が持っている[net.minecraft.world.World]と[net.minecraft.util.math.BlockPos]から[T]を取得します。 + * @param T [BlockEntity]を継承したクラス + * @return [net.minecraft.world.World.getBlockEntity]で取得した[BlockEntity]が[T]を継承していない場合はnull + */ inline fun ItemUsageContext.getBlockEntity(): T? = world.getBlockEntity(blockPos) as? T diff --git a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt index e1d02ab..a6e19aa 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt @@ -13,11 +13,13 @@ import net.minecraft.tag.Tag import net.minecraft.util.Identifier import net.minecraft.util.StringIdentifiable import net.minecraft.util.registry.Registry -import java.util.Optional +import java.util.* object RobustumCodecs { // Block // - + /** + * [Blocks.AIR]を受け付けない[Block]の[Codec]です。 + */ @JvmField val BLOCK: Codec = lazyCodec { Registry.BLOCK }.validate { block: Block -> when (block) { @@ -27,6 +29,9 @@ object RobustumCodecs { } // ItemStack // + /** + * [Items.AIR]を受け付けない[Item]の[Codec]です。 + */ @JvmField val ITEM: Codec = lazyCodec { Registry.ITEM }.validate { item: Item -> when (item) { @@ -47,6 +52,9 @@ object RobustumCodecs { } } + /** + * [ItemStack.isEmpty]を返す[ItemStack]も受け付ける[ItemStack]の[Codec]です。 + */ @JvmField val ITEM_STACK: Codec = RAW_STACK.optionalOf().xmap( { it.orElse(ItemStack.EMPTY) }, @@ -54,7 +62,9 @@ object RobustumCodecs { ) // Tag // - + /** + * タグのIDを#で前置する[TagEntryId]の[Codec]です。 + */ @JvmField val TAG_ID: Codec = Codec.STRING.xmap({ when (it.startsWith("#")) { @@ -63,15 +73,33 @@ object RobustumCodecs { } }, TagEntryId::asString) + /** + * レジストリとタグのIDを共通化して扱うためのデータクラスです + */ data class TagEntryId(val id: Identifier, val isTag: Boolean) : StringIdentifiable { companion object { + /** + * [entry]から[RobustumCodecs.TagEntryId]を返します。 + * @param T 値のクラス + * @param transform [entry]を[Identifier]に変換するブロック + * @return [RobustumCodecs.TagEntryId.isTag]がfalseとなる[RobustumCodecs.TagEntryId] + */ @JvmStatic fun of(entry: T, transform: (T) -> Identifier): TagEntryId = TagEntryId(transform(entry), false) + /** + * [tag]から[RobustumCodecs.TagEntryId]を返します。 + * @param T 値のクラス + * @param transform [tag]を[Identifier]に変換するブロック + * @return [RobustumCodecs.TagEntryId.isTag]がtrueとなる[RobustumCodecs.TagEntryId] + */ @JvmStatic - fun tag(tag: Tag, transform: (Tag) -> Identifier): TagEntryId = TagEntryId(transform(tag), true) + fun ofTag(tag: Tag, transform: (Tag) -> Identifier): TagEntryId = TagEntryId(transform(tag), true) } + /** + * [RobustumCodecs.TagEntryId.isTag]がtrueの場合は#で[RobustumCodecs.TagEntryId.id]を前置し,それ以外の場合はそのまま返します。 + */ override fun asString(): String = when (isTag) { true -> "#$id" false -> id.toString() diff --git a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt index b98ca97..907b185 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt @@ -14,21 +14,54 @@ import net.minecraft.util.Identifier // Tag // +/** + * 指定された[Tag]から[Identifier]を取得します。 + * + * [Tag]が[Tag.Identified]を実装していない場合はnullを返します。 + */ val Tag.idOrNull: Identifier? get() = (this as? Tag.Identified)?.id -fun Tag.getSafeValue(): List = runCatching { values() }.getOrDefault(listOf()) +/** + * 指定された[Tag]の要素を取得します。 + * @return 取得に失敗した場合は[emptyList]を返します。 + */ +fun Tag.getSafeValue(): List = runCatching { values() }.getOrDefault(emptyList()) +/** + * 指定された[Entity]が[tag]に含まれているか判定します。 + * @return [tag]に含まれている場合はtrue + */ fun Entity.isIn(tag: Tag>): Boolean = this.type.isIn(tag) +/** + * 指定された[ItemStack]が[tag]に含まれているか判定します。 + * @return [tag]に含まれている場合はtrue + */ fun ItemStack.isIn(tag: Tag): Boolean = this.item.isIn(tag) // RegistryEntryList // +/** + * 指定された[BlockState]が[entryList]に含まれているか判定します。 + * @return [entryList]に含まれている場合はtrue + */ fun BlockState.isIn(entryList: RegistryEntryList): Boolean = this.block in entryList +/** + * 指定された[FluidState]が[entryList]に含まれているか判定します。 + * @return [entryList]に含まれている場合はtrue + */ fun FluidState.isIn(entryList: RegistryEntryList): Boolean = this.fluid in entryList +/** + * 指定された[Entity]が[entryList]に含まれているか判定します。 + * @return [entryList]に含まれている場合はtrue + */ fun Entity.isIn(entryList: RegistryEntryList>): Boolean = this.type in entryList +/** + * 指定された[ItemStack]が[entryList]に含まれているか判定します。 + * @return [entryList]に含まれている場合はtrue + */ fun ItemStack.isIn(entryList: RegistryEntryList): Boolean = this.item in entryList diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt index 8443c8f..9b32174 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt @@ -2,4 +2,10 @@ package dev.robustum.core.registry import net.minecraft.util.Identifier +/** + * レジストリIDとその値を持つデータクラスです。 + * @param T 値のクラス + * @param key レジストリID + * @param value [key]に対応する値 + */ data class RegistryEntry(val key: Identifier, val value: T) diff --git a/src/main/resources/robustum_core.mixins.json b/src/main/resources/robustum_core.mixins.json index 3f0485d..6bfe735 100644 --- a/src/main/resources/robustum_core.mixins.json +++ b/src/main/resources/robustum_core.mixins.json @@ -3,13 +3,13 @@ "package": "dev.robustum.core.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ - "ServerTagManagerHolderMixin", - "TagGroupLoaderMixin" + "tag.ServerTagManagerHolderMixin", + "tag.TagGroupLoaderMixin" ], "injectors": { "defaultRequire": 1 }, "client": [ - "ClientPlayNetworkHandlerMixin" + "tag.ClientPlayNetworkHandlerMixin" ] } From cd0bbbf0f942ee1a43476a9a7929c65c4f1bb88a Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sat, 14 Dec 2024 22:02:38 +0900 Subject: [PATCH 14/27] Added refined codec for vanilla Ingredient Renamed some fields for RobustumRecipeSerializers.kt --- .../core/mixin/recipe/IngredientAccessor.java | 11 +++ .../core/extensions/RobustumCodecs.kt | 68 +++++++++++++++++++ .../robustum/core/extensions/TagExtensions.kt | 7 ++ .../robustum/core/recipe/ItemIngredient.kt | 8 --- .../core/recipe/RobustumRecipeSerializers.kt | 18 ++--- .../core/registry/RegistryEntryList.kt | 38 +++++++++++ .../robustum/core/registry/RegistryLookup.kt | 34 ++++++++++ .../resources/robustum_core.accesswidener | 2 + src/main/resources/robustum_core.mixins.json | 1 + 9 files changed, 170 insertions(+), 17 deletions(-) create mode 100644 src/main/java/dev/robustum/core/mixin/recipe/IngredientAccessor.java diff --git a/src/main/java/dev/robustum/core/mixin/recipe/IngredientAccessor.java b/src/main/java/dev/robustum/core/mixin/recipe/IngredientAccessor.java new file mode 100644 index 0000000..7bbfefc --- /dev/null +++ b/src/main/java/dev/robustum/core/mixin/recipe/IngredientAccessor.java @@ -0,0 +1,11 @@ +package dev.robustum.core.mixin.recipe; + +import net.minecraft.recipe.Ingredient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Ingredient.class) +public interface IngredientAccessor { + @Accessor + Ingredient.Entry[] getEntries(); +} diff --git a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt index a6e19aa..7ca50f7 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt @@ -1,19 +1,25 @@ package dev.robustum.core.extensions +import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec import com.mojang.serialization.DataResult import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.mixin.recipe.IngredientAccessor +import dev.robustum.core.registry.RegistryEntryList +import dev.robustum.core.registry.RegistryEntryListCodec import net.minecraft.block.Block import net.minecraft.block.Blocks import net.minecraft.item.Item import net.minecraft.item.ItemStack import net.minecraft.item.Items import net.minecraft.nbt.NbtCompound +import net.minecraft.recipe.Ingredient import net.minecraft.tag.Tag import net.minecraft.util.Identifier import net.minecraft.util.StringIdentifiable import net.minecraft.util.registry.Registry import java.util.* +import kotlin.jvm.optionals.getOrNull object RobustumCodecs { // Block // @@ -73,6 +79,68 @@ object RobustumCodecs { } }, TagEntryId::asString) + // Ingredient // + /** + * よりシンプルな記法で書ける[Ingredient]の[Codec]です。 + * ``` + * "minecraft:dirt" -> Ingredient.ofItems(Items.DIRT) + * ["minecraft:dirt", "minecraft:stone"] -> Ingredient.ofItems(Items.DIRT, Items.STONE) + * "#minecraft:wool" -> Ingredient.fromTag(ItemTags.WOOL) + * ``` + */ + @Suppress("CAST_NEVER_SUCCEEDS") + @JvmField + val INGREDIENT: Codec = + Codec.either(RegistryEntryListCodec.ITEM, RegistryEntryListCodec.ITEM.listOf()).comapFlatMap( + { either: Either, List>> -> + either.map( + { entryList: RegistryEntryList -> + DataResult.success(entryList.storage.map(Ingredient::fromTag, Ingredient::ofItems)) + }, + { entryLists: List> -> + when { + entryLists.isEmpty() -> DataResult.success(Ingredient.EMPTY) + entryLists.all { it.storage.right().isPresent } -> + entryLists + .map(RegistryEntryList::storage) + .map { it.right() } + .mapNotNull(Optional::getOrNull) + .map(::ItemStack) + .stream() + .let(Ingredient::ofStacks) + .let(DataResult::success) + + else -> DataResult.error("Any entries do not contain tag id!") + } + }, + ) + }, + { ingredient: Ingredient -> + val empty: Either, List>> = Either.right(listOf()) + if (ingredient.isEmpty) { + empty + } else { + val entries: Array = (ingredient as IngredientAccessor).entries + entries + .runCatching { + val items: List = entries + .flatMap(Ingredient.Entry::getStacks) + .map(ItemStack::getItem) + .distinct() + when (items.size) { + 0 -> empty + + 1 -> Either.left(RegistryEntryList.of(items[0], Registry.ITEM::getEntryOrThrow)) + + else -> Either.right( + items.mapNotNull(Registry.ITEM::getEntry).map(RegistryEntryList.Companion::of), + ) + } + }.getOrDefault(empty) + } + }, + ) + /** * レジストリとタグのIDを共通化して扱うためのデータクラスです */ diff --git a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt index 907b185..950fe62 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/TagExtensions.kt @@ -10,6 +10,7 @@ import net.minecraft.fluid.FluidState import net.minecraft.item.Item import net.minecraft.item.ItemStack import net.minecraft.tag.Tag +import net.minecraft.tag.TagGroup import net.minecraft.util.Identifier // Tag // @@ -22,6 +23,12 @@ import net.minecraft.util.Identifier val Tag.idOrNull: Identifier? get() = (this as? Tag.Identified)?.id +/** + * 指定された[Tag]と[tagGroup]から[Identifier]を取得します。 + * @return [idOrNull]がnullの場合,[TagGroup.getUncheckedTagId]より取得します。 + */ +fun Tag.getIdOrNull(tagGroup: TagGroup): Identifier? = idOrNull ?: tagGroup.getUncheckedTagId(this) + /** * 指定された[Tag]の要素を取得します。 * @return 取得に失敗した場合は[emptyList]を返します。 diff --git a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt index 861070f..d980ffc 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt @@ -28,12 +28,6 @@ class ItemIngredient private constructor(val entryList: RegistryEntryList, Codec.intRange(1, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemIngredient::count), ).apply(instance, ::ItemIngredient) } - - @JvmField - val VANILLA_CODEC: Codec = CODEC.xmap( - { it.vanillaIngredient }, - { ItemIngredient(it.matchingItemIds.map(Registry.ITEM::get)) }, - ) } constructor(tag: Tag, count: Int = 1) : this(RegistryEntryList.tag(tag), count) @@ -43,8 +37,6 @@ class ItemIngredient private constructor(val entryList: RegistryEntryList, count, ) - private constructor(items: List, count: Int = 1) : this(Tag.of(items.toSet()), count) - val isEmpty: Boolean get() = entryList.isEmpty || count <= 0 diff --git a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt index cb665cd..5c177e1 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt @@ -23,12 +23,12 @@ object RobustumRecipeSerializers { Codec.STRING .optionalFieldOf("group", "") .forGetter(ShapelessRecipe::getGroup), - ItemIngredient.VANILLA_CODEC + RobustumCodecs.INGREDIENT .listOf() - .fieldOf("ingredients") + .fieldOf("inputs") .forGetter(ShapelessRecipe::getIngredients), RobustumCodecs.ITEM_STACK - .fieldOf("result") + .fieldOf("output") .forGetter(ShapelessRecipe::getOutput), ).apply(instance) { group: String, ingredients: List, result: ItemStack -> ShapelessRecipe(id, group, result, ingredients.toDefaultedList(Ingredient.EMPTY)) @@ -79,11 +79,11 @@ object RobustumRecipeSerializers { Codec.STRING .optionalFieldOf("group", "") .forGetter(StonecuttingRecipe::getGroup), - ItemIngredient.VANILLA_CODEC - .fieldOf("ingredient") + RobustumCodecs.INGREDIENT + .fieldOf("input") .forGetter { it.ingredients[0] }, RobustumCodecs.ITEM_STACK - .fieldOf("result") + .fieldOf("output") .forGetter(StonecuttingRecipe::getOutput), ).apply(instance) { group: String, ingredient: Ingredient, result: ItemStack -> StonecuttingRecipe(id, group, ingredient, result) @@ -101,11 +101,11 @@ object RobustumRecipeSerializers { Codec.STRING .optionalFieldOf("group", "") .forGetter { it.group }, - ItemIngredient.VANILLA_CODEC - .fieldOf("ingredient") + RobustumCodecs.INGREDIENT + .fieldOf("input") .forGetter { it.ingredients[0] }, RobustumCodecs.ITEM_STACK - .fieldOf("result") + .fieldOf("output") .forGetter { it.output }, Codec.FLOAT .optionalFieldOf("exp", 0.0f) diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt index 761eb06..4ccbf53 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt @@ -2,40 +2,78 @@ package dev.robustum.core.registry import com.mojang.datafixers.util.Either import dev.robustum.core.extensions.getSafeValue +import dev.robustum.core.registry.RegistryEntryList.Companion.tag import net.minecraft.tag.SetTag import net.minecraft.tag.Tag import kotlin.random.Random +/** + * [RegistryEntry]または[Tag]を持つオブジェクトです。 + */ sealed interface RegistryEntryList : Iterable { companion object { + /** + * 空の[RegistryEntryList]を返します。 + */ @JvmStatic fun empty(): RegistryEntryList = Empty() + /** + * [entry]を持つ[RegistryEntryList]を返します。 + */ @JvmStatic fun of(entry: RegistryEntry): RegistryEntryList = Direct(entry) + /** + * [value]から[RegistryEntryList]を返します。 + * @param transform [T]を[RegistryEntry]に変換するブロック + */ @JvmStatic fun of(value: T, transform: (T) -> RegistryEntry): RegistryEntryList = of(transform(value)) + /** + * [tag]を持つ[RegistryEntryList]を返します。 + */ @JvmStatic fun tag(tag: Tag): RegistryEntryList = Tagged(tag) } + /** + * [Tag]または[T]を持つ[Either]を返します。 + */ val storage: Either, T> + /** + * この[RegistryEntryList]の要素が空か判定します。 + */ val isEmpty: Boolean get() = entries.isEmpty() + /** + * この[RegistryEntryList]の要素のリストを返します。 + */ val entries: List get() = storage.map(Tag::getSafeValue, ::listOf) + /** + * この[RegistryEntryList]の要素の個数を返します。 + */ val size: Int get() = entries.size + /** + * この[RegistryEntryList]からランダムな要素を返します。 + */ fun getRandom(random: Random): T? = entries.randomOrNull(random) + /** + * 指定された[index]に対応する要素を返します。 + */ operator fun get(index: Int): T = entries[index] + /** + * 指定された要素[entry]が含まれるか判定します。 + */ operator fun contains(entry: T): Boolean = storage.map({ it.contains(entry) }, { it == entry }) override fun iterator(): Iterator = entries.iterator() diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt index 3857bdd..11eb08a 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt @@ -12,32 +12,66 @@ import net.minecraft.tag.TagGroup import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry +/** + * [Registry]と[TagGroup]を共通化させたインターフェースです。 + */ interface RegistryLookup { + /** + * 指定された[id]から[RegistryEntry]を返します。 + * @return 結果は[DataResult]でラップされます。 + */ fun getEntry(id: Identifier): DataResult> + /** + * 指定された[value]から[RobustumCodecs.TagEntryId]を返します。 + * @return 結果は[DataResult]でラップされます。 + */ fun getId(value: T): DataResult + /** + * 指定された[id]から[RegistryEntryList]を返します。 + * @return 結果は[DataResult]でラップされます。 + */ fun getTag(id: Identifier): DataResult> + /** + * 指定された[tag]から[RobustumCodecs.TagEntryId]を返します。 + * @return 結果は[DataResult]でラップされます。 + */ fun getId(tag: Tag): DataResult companion object { + /** + * [Block]に対する[RegistryLookup]です。 + */ @JvmField val BLOCK: RegistryLookup = of(Registry.BLOCK, ServerTagManagerHolder.getTagManager()::getBlocks) + /** + * [Fluid]に対する[RegistryLookup]です。 + */ @JvmField val FLUID: RegistryLookup = of(Registry.FLUID, ServerTagManagerHolder.getTagManager()::getFluids) + /** + * [EntityType]に対する[RegistryLookup]です。 + */ @JvmField val ENTITY_TYPE: RegistryLookup> = of(Registry.ENTITY_TYPE, ServerTagManagerHolder.getTagManager()::getEntityTypes) + /** + * [Item]に対する[RegistryLookup]です。 + */ @JvmField val ITEM: RegistryLookup = of(Registry.ITEM, ServerTagManagerHolder.getTagManager()::getItems) + /** + * [registry]と[groupGetter]から[RegistryLookup]のインスタンスを生成します。 + */ @JvmStatic fun of(registry: Registry, groupGetter: () -> TagGroup): RegistryLookup = object : RegistryLookup { override fun getEntry(id: Identifier): DataResult> = registry diff --git a/src/main/resources/robustum_core.accesswidener b/src/main/resources/robustum_core.accesswidener index 9ab2173..4d09665 100644 --- a/src/main/resources/robustum_core.accesswidener +++ b/src/main/resources/robustum_core.accesswidener @@ -1 +1,3 @@ accessWidener v2 named + +accessible class net/minecraft/recipe/Ingredient$Entry diff --git a/src/main/resources/robustum_core.mixins.json b/src/main/resources/robustum_core.mixins.json index 6bfe735..6fb5cf2 100644 --- a/src/main/resources/robustum_core.mixins.json +++ b/src/main/resources/robustum_core.mixins.json @@ -3,6 +3,7 @@ "package": "dev.robustum.core.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ + "recipe.IngredientAccessor", "tag.ServerTagManagerHolderMixin", "tag.TagGroupLoaderMixin" ], From 1c16b56a6de103df494fc75148e2c1b13d239dc6 Mon Sep 17 00:00:00 2001 From: turtton Date: Sat, 14 Dec 2024 16:23:53 +0900 Subject: [PATCH 15/27] Prepare registry depended junit test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.16バージョンでは`fabric-loader-junit`がそのままだと正常に動作しない(fabirc-loader#817)ため、先駆者のパッチを適用してfabric-loader自体にASMで書き換えを行った上で動かす必要がある --- build.gradle.kts | 17 +++++++ gradle/libs.versions.toml | 7 +++ settings.gradle.kts | 2 + test-agent/.gitignore | 1 + test-agent/build.gradle.kts | 92 +++++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+) create mode 100644 test-agent/.gitignore create mode 100644 test-agent/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts index 13b7ad7..3944196 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -24,12 +24,18 @@ repositories { } } +val testAgent = configurations.create("testAgent") { + isCanBeConsumed = false +} + dependencies { minecraft(libs.minecraft) mappings("net.fabricmc:yarn:${libs.versions.fabric.yarn.get()}:v2") modImplementation(libs.bundles.mods.fabric) modLocalRuntime(libs.bundles.mods.debug) testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation(libs.fabric.loader.junit) + testAgent(project(path = ":test-agent", configuration = "agentJar")) } loom { @@ -70,6 +76,17 @@ ktlint { tasks { test { useJUnitPlatform() + val runDir = file("build/test_run") + workingDir = runDir + + // Workaround https://github.com/FabricMC/fabric-loader/issues/817 + // Original: https://github.com/embeddedt/ModernFix/commit/03b23957827c42d5df5a11f3d07f807c5343e87e + jvmArgs("-javaagent:${testAgent.singleFile.absolutePath}") + dependsOn(testAgent) + + doFirst { + runDir.mkdir() + } } processResources { inputs.property("version", project.version) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 734ec1d..f05e1f8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,18 +7,25 @@ fabric-loader = "0.16.9" fabric-api = "0.42.0+1.16" fabric-yarn = "1.16.5+build.10" fabric-kotlin = "1.12.3+kotlin.2.0.21" +asm = "9.1" [libraries] minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" } fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" } fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" } fabric-kotlin = { group = "net.fabricmc", name = "fabric-language-kotlin", version.ref = "fabric-kotlin"} +asm-tree = { group = "org.ow2.asm", name = "asm-tree", version.ref = "asm" } +asm-commons = { group = "org.ow2.asm", name = "asm-commons", version.ref = "asm" } +asm-util = { group = "org.ow2.asm", name = "asm-util", version.ref = "asm" } +# test libraries +fabric-loader-junit = { group = "net.fabricmc", name = "fabric-loader-junit", version.ref = "fabric-loader" } mod-modmenu = { group = "maven.modrinth", name = "modmenu", version = "1.16.23" } [bundles] mods-fabric = ["fabric-loader", "fabric-api", "fabric-kotlin"] mods-debug = ["mod-modmenu"] +asm = [ "asm-tree", "asm-commons", "asm-util" ] [plugins] fabric-loom = { id = "fabric-loom", version.ref = "fabric-loom" } diff --git a/settings.gradle.kts b/settings.gradle.kts index eb8af7d..68a7a35 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,3 +15,5 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } rootProject.name = "robustum-core" + +include("test-agent") diff --git a/test-agent/.gitignore b/test-agent/.gitignore new file mode 100644 index 0000000..e831038 --- /dev/null +++ b/test-agent/.gitignore @@ -0,0 +1 @@ +src \ No newline at end of file diff --git a/test-agent/build.gradle.kts b/test-agent/build.gradle.kts new file mode 100644 index 0000000..bc315d2 --- /dev/null +++ b/test-agent/build.gradle.kts @@ -0,0 +1,92 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + +plugins { + kotlin("jvm") version libs.versions.kotlin +} + +group = "dev.robustum" +version = "1.0" +base { + archivesName = "test-agent" +} + +val agentJar = configurations.create("agentJar") { + isCanBeConsumed = true + isCanBeResolved = false +} + +repositories { + mavenCentral() + maven(url = "https://maven.fabricmc.net/") { + name = "Fabric" + } +} + +dependencies { + compileOnly(libs.fabric.loader) + implementation(libs.bundles.asm) +} + +kotlin { + jvmToolchain(21) + compilerOptions { + jvmTarget.set(JvmTarget.JVM_21) + } +} + +java { + withSourcesJar() + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 +} + +tasks { + withType { + options.encoding = "UTF-8" + } + + jar { + manifest { + attributes( + "Premain-Class" to "org.embeddedt.modernfix.testing.Agent", + "Can-Redefine-Classes" to "true", + "Can-Set-Native-Method-Prefix" to "true", + ) + } + } + + // fabric-loomに対するパッチのオリジナルはLGPL-3.0ライセンスなのでリスクを回避するために必要に応じてダウンロードする + // https://github.com/embeddedt/ModernFix?tab=License-1-ov-file#readme + // https://github.com/embeddedt/ModernFix/commit/03b23957827c42d5df5a11f3d07f807c5343e87e#diff-bb0eb72bce858352a965127feb642536626f7b5bc911482becf330cb173672f4 + val downloadCodes = create("downloadCodes") { + doFirst { + val projectDir = file("src/main/java/org/embeddedt/modernfix/testing") + projectDir.mkdirs() + val agent = projectDir.resolve("Agent.java") + if (!agent.exists()) { + uri( + "https://raw.githubusercontent.com/embeddedt/ModernFix/03b23957827c42d5df5a11f3d07f807c5343e87e/test_agent/src/main/java/org/embeddedt/modernfix/testing/Agent.java", + ).toURL().openStream().use { + agent.writeBytes(it.readBytes()) + } + } + val agentHooks = projectDir.resolve("AgentHooks.java") + if (!agentHooks.exists()) { + uri( + "https://raw.githubusercontent.com/embeddedt/ModernFix/03b23957827c42d5df5a11f3d07f807c5343e87e/test_agent/src/main/java/org/embeddedt/modernfix/testing/AgentHooks.java", + ).toURL() + .openStream() + .use { + agentHooks.writeBytes(it.readBytes()) + } + } + } + } + checkKotlinGradlePluginConfigurationErrors { + dependsOn(downloadCodes) + } +} + +artifacts { + add(agentJar.name, tasks.jar) +} From 8667d2b35666029def6279a4d044a7a2906ac8df Mon Sep 17 00:00:00 2001 From: turtton Date: Sat, 14 Dec 2024 16:27:40 +0900 Subject: [PATCH 16/27] Add TestRobustumRecipeSerializers --- src/test/kotlin/helper/JsonWrapper.kt | 29 +++++++++++ .../recipe/TestRobustumRecipeSerializers.kt | 50 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/test/kotlin/helper/JsonWrapper.kt create mode 100644 src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt diff --git a/src/test/kotlin/helper/JsonWrapper.kt b/src/test/kotlin/helper/JsonWrapper.kt new file mode 100644 index 0000000..f293f6b --- /dev/null +++ b/src/test/kotlin/helper/JsonWrapper.kt @@ -0,0 +1,29 @@ +package helper + +import com.google.gson.JsonElement +import com.google.gson.JsonObject + +infix fun JsonElement.shouldBe(builder: GsonObjectWrapper.() -> Unit) { + val expected = GsonObjectWrapper().apply(builder).jsonObject + assert(this == expected) { "Expected: $expected, but was: $this" } +} + +class GsonObjectWrapper(val jsonObject: JsonObject = JsonObject()) { + operator fun String.invoke(value: String) { + jsonObject.addProperty(this, value) + } + + operator fun String.invoke(value: Number) { + jsonObject.addProperty(this, value) + } + + operator fun String.invoke(value: Boolean) { + jsonObject.addProperty(this, value) + } + + operator fun String.invoke(builder: GsonObjectWrapper.() -> Unit) { + val innerObject = GsonObjectWrapper() + innerObject.builder() + jsonObject.add(this, innerObject.jsonObject) + } +} diff --git a/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt b/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt new file mode 100644 index 0000000..cc829c5 --- /dev/null +++ b/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt @@ -0,0 +1,50 @@ +package test.recipe + +import com.mojang.serialization.JsonOps +import dev.robustum.core.RobustumCore.id +import dev.robustum.core.extensions.onErrored +import dev.robustum.core.extensions.onSucceeded +import dev.robustum.core.recipe.RobustumRecipeSerializers +import helper.shouldBe +import net.minecraft.Bootstrap +import net.minecraft.SharedConstants +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.recipe.Ingredient +import net.minecraft.recipe.SmeltingRecipe +import org.junit.jupiter.api.Test +import kotlin.test.BeforeTest + +class TestRobustumRecipeSerializers { + @BeforeTest + fun setup() { + SharedConstants.getGameVersion() + Bootstrap.initialize() + } + + @Test + fun testSmelting() { + RobustumRecipeSerializers.SMELTING + .write( + JsonOps.INSTANCE, + SmeltingRecipe( + id("test_smelting"), + "", + Ingredient.ofItems(Items.DIRT), + ItemStack(Items.DIAMOND), + 32767f, + 200, + ), + ).onSucceeded { + it shouldBe { + "output" { + "id"("minecraft:diamond") + } + "exp"(32767.0) + "input"("minecraft:dirt") + } + }.onErrored { + error(it.message()) + } + } +} From 4cea2b87bdb8c61284c8dd56f3549e7802a23a70 Mon Sep 17 00:00:00 2001 From: turtton Date: Sat, 14 Dec 2024 16:27:56 +0900 Subject: [PATCH 17/27] Make gradlew executable --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From dfb42bb9981774e35b4243de98130538a064de66 Mon Sep 17 00:00:00 2001 From: turtton Date: Sun, 15 Dec 2024 12:26:52 +0900 Subject: [PATCH 18/27] Add kotest --- build.gradle.kts | 1 + gradle/libs.versions.toml | 4 ++++ src/test/kotlin/helper/JsonWrapper.kt | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 3944196..d5f7efa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -35,6 +35,7 @@ dependencies { modLocalRuntime(libs.bundles.mods.debug) testImplementation("org.jetbrains.kotlin:kotlin-test") testImplementation(libs.fabric.loader.junit) + testImplementation(libs.bundles.kotest) testAgent(project(path = ":test-agent", configuration = "agentJar")) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f05e1f8..20bcdc3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ fabric-api = "0.42.0+1.16" fabric-yarn = "1.16.5+build.10" fabric-kotlin = "1.12.3+kotlin.2.0.21" asm = "9.1" +kotest = "5.9.1" [libraries] minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" } @@ -19,6 +20,8 @@ asm-commons = { group = "org.ow2.asm", name = "asm-commons", version.ref = "asm" asm-util = { group = "org.ow2.asm", name = "asm-util", version.ref = "asm" } # test libraries fabric-loader-junit = { group = "net.fabricmc", name = "fabric-loader-junit", version.ref = "fabric-loader" } +kotest-runner-junit5 = { group = "io.kotest", name = "kotest-runner-junit5", version.ref = "kotest" } +kotest-assersions-core = { group = "io.kotest", name = "kotest-assertions-core", version.ref = "kotest" } mod-modmenu = { group = "maven.modrinth", name = "modmenu", version = "1.16.23" } @@ -26,6 +29,7 @@ mod-modmenu = { group = "maven.modrinth", name = "modmenu", version = "1.16.23" mods-fabric = ["fabric-loader", "fabric-api", "fabric-kotlin"] mods-debug = ["mod-modmenu"] asm = [ "asm-tree", "asm-commons", "asm-util" ] +kotest = [ "kotest-runner-junit5", "kotest-assersions-core" ] [plugins] fabric-loom = { id = "fabric-loom", version.ref = "fabric-loom" } diff --git a/src/test/kotlin/helper/JsonWrapper.kt b/src/test/kotlin/helper/JsonWrapper.kt index f293f6b..2e3ed62 100644 --- a/src/test/kotlin/helper/JsonWrapper.kt +++ b/src/test/kotlin/helper/JsonWrapper.kt @@ -2,10 +2,11 @@ package helper import com.google.gson.JsonElement import com.google.gson.JsonObject +import io.kotest.matchers.shouldBe infix fun JsonElement.shouldBe(builder: GsonObjectWrapper.() -> Unit) { val expected = GsonObjectWrapper().apply(builder).jsonObject - assert(this == expected) { "Expected: $expected, but was: $this" } + this shouldBe expected } class GsonObjectWrapper(val jsonObject: JsonObject = JsonObject()) { From 9ae4b757abe193281752dc09875d46575b40cd8c Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:17:03 +0900 Subject: [PATCH 19/27] Added new package "codec" Reworked RegistryEntryList.kt More refined Ingredient codec --- .../{recipe => codec}/IngredientAccessor.java | 2 +- .../robustum/core/codec/KeyDispatchCodec.kt | 81 ++++++++ .../dev/robustum/core/codec/OptionalCodec.kt | 26 +++ .../core/codec/RegistryEntryListCodec.kt | 93 +++++++++ .../dev/robustum/core/codec/RobustumCodecs.kt | 105 +++++++++++ .../core/extensions/CodecExtensions.kt | 94 +--------- .../core/extensions/RobustumCodecs.kt | 176 ------------------ .../robustum/core/recipe/FluidIngredient.kt | 13 +- .../robustum/core/recipe/ItemIngredient.kt | 17 +- .../core/recipe/RobustumRecipeSerializers.kt | 2 +- .../core/registry/RegistryEntryList.kt | 51 ++--- .../core/registry/RegistryEntryListCodec.kt | 42 ----- .../robustum/core/registry/RegistryLookup.kt | 25 ++- .../dev/robustum/core/registry/TagEntryId.kt | 49 +++++ src/main/resources/robustum_core.mixins.json | 2 +- 15 files changed, 420 insertions(+), 358 deletions(-) rename src/main/java/dev/robustum/core/mixin/{recipe => codec}/IngredientAccessor.java (86%) create mode 100644 src/main/kotlin/dev/robustum/core/codec/KeyDispatchCodec.kt create mode 100644 src/main/kotlin/dev/robustum/core/codec/OptionalCodec.kt create mode 100644 src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt create mode 100644 src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt delete mode 100644 src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt delete mode 100644 src/main/kotlin/dev/robustum/core/registry/RegistryEntryListCodec.kt create mode 100644 src/main/kotlin/dev/robustum/core/registry/TagEntryId.kt diff --git a/src/main/java/dev/robustum/core/mixin/recipe/IngredientAccessor.java b/src/main/java/dev/robustum/core/mixin/codec/IngredientAccessor.java similarity index 86% rename from src/main/java/dev/robustum/core/mixin/recipe/IngredientAccessor.java rename to src/main/java/dev/robustum/core/mixin/codec/IngredientAccessor.java index 7bbfefc..a17195f 100644 --- a/src/main/java/dev/robustum/core/mixin/recipe/IngredientAccessor.java +++ b/src/main/java/dev/robustum/core/mixin/codec/IngredientAccessor.java @@ -1,4 +1,4 @@ -package dev.robustum.core.mixin.recipe; +package dev.robustum.core.mixin.codec; import net.minecraft.recipe.Ingredient; import org.spongepowered.asm.mixin.Mixin; diff --git a/src/main/kotlin/dev/robustum/core/codec/KeyDispatchCodec.kt b/src/main/kotlin/dev/robustum/core/codec/KeyDispatchCodec.kt new file mode 100644 index 0000000..09d463f --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/codec/KeyDispatchCodec.kt @@ -0,0 +1,81 @@ +package dev.robustum.core.codec + +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import com.mojang.serialization.MapCodec +import com.mojang.serialization.MapDecoder +import com.mojang.serialization.MapEncoder +import com.mojang.serialization.MapLike +import com.mojang.serialization.RecordBuilder +import dev.robustum.core.extensions.isErrored +import java.util.function.Function +import java.util.stream.Stream + +class KeyDispatchCodec( + val typeKey: String, + val keyCodec: Codec, + val type: (V) -> DataResult, + val decoder: (K) -> DataResult>, + val encoder: (V) -> DataResult>, +) : MapCodec() { + companion object { + @JvmStatic + private fun getCodec( + type: (V) -> DataResult, + codec: (K) -> DataResult>, + input: V, + ): DataResult> = type(input) + .flatMap { key: K -> codec(key).map(Function.identity()) } + } + + constructor( + typeKey: String, + keyCodec: Codec, + type: (V) -> DataResult, + codec: (K) -> DataResult>, + ) : this(typeKey, keyCodec, type, codec, { input: V -> getCodec(type, codec, input) }) + + private val valueKey = "value" + + override fun keys(ops: DynamicOps): Stream = Stream.of(typeKey, valueKey).map(ops::createString) + + override fun decode(ops: DynamicOps, input: MapLike): DataResult { + val elementName: T = + input.get(typeKey) ?: return DataResult.error("Input does not contain a key [$typeKey]: $input") + return keyCodec.decode(ops, elementName).flatMap { type1: Pair -> + decoder(type1.first).flatMap { elementDecoder: MapDecoder -> + if (ops.compressMaps()) { + input + .get(ops.createString(valueKey)) + ?.let { value: T -> elementDecoder.decoder().parse(ops, value).map(Function.identity()) } + ?: return@flatMap DataResult.error("Input does not have a \"value\" entry: $input") + } else { + elementDecoder.decode(ops, input).map(Function.identity()) + } + } + } + } + + override fun encode(input: V, ops: DynamicOps, prefix: RecordBuilder): RecordBuilder { + val encodeResult: DataResult> = encoder(input) + val builder: RecordBuilder = prefix.withErrorsFrom(encodeResult) + if (encodeResult.isErrored) { + Result + return builder + } + val elementEncoder: MapEncoder = encodeResult.result().get() + return when { + ops.compressMaps() -> + prefix + .add(typeKey, type(input).flatMap { type1: K -> keyCodec.encodeStart(ops, type1) }) + .add(valueKey, elementEncoder.encoder().encodeStart(ops, input)) + + else -> + elementEncoder + .encode(input, ops, prefix) + .add(typeKey, type(input).flatMap { type1: K -> keyCodec.encodeStart(ops, type1) }) + } + } +} diff --git a/src/main/kotlin/dev/robustum/core/codec/OptionalCodec.kt b/src/main/kotlin/dev/robustum/core/codec/OptionalCodec.kt new file mode 100644 index 0000000..334e6c6 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/codec/OptionalCodec.kt @@ -0,0 +1,26 @@ +package dev.robustum.core.codec + +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import com.mojang.serialization.MapLike +import java.util.* + +class OptionalCodec(val codec: Codec) : Codec> { + override fun encode(input: Optional, ops: DynamicOps, prefix: T): DataResult = when (input.isEmpty) { + true -> DataResult.success(ops.emptyMap()) + false -> codec.encode(input.get(), ops, prefix) + } + + private fun isEmpty(ops: DynamicOps, input: T): Boolean = ops + .getMap(input) + .result() + .map { mapLike: MapLike -> mapLike.entries().findAny().isEmpty } + .orElse(false) + + override fun decode(ops: DynamicOps, input: T): DataResult, T>> = when { + isEmpty(ops, input) -> DataResult.success(Pair.of(Optional.empty(), input)) + else -> codec.decode(ops, input).map { pair: Pair -> pair.mapFirst(Optional::of) } + } +} diff --git a/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt b/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt new file mode 100644 index 0000000..0df5279 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt @@ -0,0 +1,93 @@ +package dev.robustum.core.codec + +import com.mojang.datafixers.util.Either +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import dev.robustum.core.extensions.entryOrList +import dev.robustum.core.registry.RegistryEntryList +import dev.robustum.core.registry.RegistryLookup +import dev.robustum.core.registry.TagEntryId +import net.minecraft.block.Block +import net.minecraft.entity.EntityType +import net.minecraft.fluid.Fluid +import net.minecraft.item.Item +import net.minecraft.tag.Tag +import org.apache.logging.log4j.LogManager +import org.apache.logging.log4j.Logger + +class RegistryEntryListCodec(private val lookup: RegistryLookup) : Codec> { + companion object { + @JvmField + val BLOCK: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.Companion.BLOCK) + + @JvmField + val FLUID: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.Companion.FLUID) + + @JvmField + val ENTITY_TYPE: RegistryEntryListCodec> = + RegistryEntryListCodec(RegistryLookup.Companion.ENTITY_TYPE) + + @JvmField + val ITEM: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.Companion.ITEM) + + private val logger: Logger = LogManager.getLogger(RegistryEntryListCodec::class.java) + } + + private val entryCodec: Codec>> = TagEntryId.CODEC.entryOrList() + + override fun encode(input: RegistryEntryList, ops: DynamicOps, prefix: T): DataResult = input.storage.map( + { tag: Tag -> lookup.getId(tag).map(TagEntryId::asString).map(ops::createString) }, + { entries: List -> + when (entries.size) { + 0 -> DataResult.success(ops.emptyList()) + + 1 -> lookup.getId(entries[0]).map(TagEntryId::asString).map(ops::createString) + + else -> { + val results: List = entries + .map(lookup::getId) + .map { result: DataResult -> result.getOrThrow(false, logger::error) } + .map(TagEntryId::asString) + .map(ops::createString) + val list: T? = ops.emptyList() + ops.mergeToList(list, results) + DataResult.success(list) + } + } + }, + ) + + override fun decode(ops: DynamicOps, input: T): DataResult, T>> = + entryCodec.decode(ops, input).map { pair: Pair>, T> -> + pair.mapFirst { either: Either> -> + either.map( + { entry: TagEntryId -> + when (entry.isTag) { + true -> lookup.getTag(entry.id) + false -> + lookup + .getValue(entry.id) + .map(RegistryEntryList.Companion::direct) + }.getOrThrow(false, logger::error) + }, + { entries: List -> + when { + entries.isEmpty() -> RegistryEntryList.empty() + entries.none(TagEntryId::isTag) -> { + entries + .map(TagEntryId::id) + .map(lookup::getValue) + .map { result: DataResult -> + result.getOrThrow(false, logger::error) + }.let(RegistryEntryList.Companion::direct) + } + + else -> RegistryEntryList.empty() + } + }, + ) + } + } +} diff --git a/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt new file mode 100644 index 0000000..f5754b2 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt @@ -0,0 +1,105 @@ +package dev.robustum.core.codec + +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.extensions.lazyCodec +import dev.robustum.core.extensions.optionalOf +import dev.robustum.core.extensions.validate +import dev.robustum.core.mixin.codec.IngredientAccessor +import dev.robustum.core.recipe.ItemIngredient +import dev.robustum.core.registry.RegistryEntryList +import net.minecraft.block.Block +import net.minecraft.block.Blocks +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.nbt.NbtCompound +import net.minecraft.recipe.Ingredient +import net.minecraft.util.registry.Registry +import java.util.* + +object RobustumCodecs { + // Block // + /** + * [net.minecraft.block.Blocks.AIR]を受け付けない[net.minecraft.block.Block]の[com.mojang.serialization.Codec]です。 + */ + @JvmField + val BLOCK: Codec = lazyCodec { Registry.BLOCK }.validate { block: Block -> + when (block) { + Blocks.AIR -> DataResult.error("Block must not be minecraft:air") + else -> DataResult.success(block) + } + } + + // ItemStack // + /** + * [net.minecraft.item.Items.AIR]を受け付けない[net.minecraft.item.Item]の[Codec]です。 + */ + @JvmField + val ITEM: Codec = lazyCodec { Registry.ITEM }.validate { item: Item -> + when (item) { + Items.AIR -> DataResult.error("Item must not be minecraft:air") + else -> DataResult.success(item) + } + } + + @JvmStatic + private val RAW_STACK: Codec = RecordCodecBuilder.create { instance -> + instance + .group( + ITEM.fieldOf("id").forGetter(ItemStack::getItem), + Codec.intRange(0, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemStack::getCount), + NbtCompound.CODEC + .optionalFieldOf("tag") + .forGetter { stack: ItemStack -> Optional.ofNullable(stack.tag) }, + ).apply(instance) { item: Item, count: Int, nbt: Optional -> + ItemStack(item, count).apply { nbt.ifPresent(this::setTag) } + } + } + + /** + * [ItemStack.isEmpty]を返す[ItemStack]も受け付ける[ItemStack]の[Codec]です。 + */ + @JvmField + val ITEM_STACK: Codec = RAW_STACK.optionalOf().xmap( + { it.orElse(ItemStack.EMPTY) }, + { if (it.isEmpty) Optional.empty() else Optional.of(it) }, + ) + + // Ingredient // + /** + * よりシンプルな記法で書ける[Ingredient]の[Codec]です。 + * ``` + * "minecraft:dirt" -> Ingredient.ofItems(Items.DIRT) + * ["minecraft:dirt", "minecraft:stone"] -> Ingredient.ofItems(Items.DIRT, Items.STONE) + * "#minecraft:wool" -> Ingredient.fromTag(ItemTags.WOOL) + * ``` + */ + @Suppress("KotlinConstantConditions") + @JvmField + val INGREDIENT: Codec = RegistryEntryListCodec.ITEM.xmap( + { ItemIngredient(it).vanillaIngredient }, + ) { ingredient: Ingredient -> + val empty: RegistryEntryList = RegistryEntryList.empty() + if (ingredient.isEmpty) { + empty + } else { + val entries: Array = (ingredient as IngredientAccessor).entries + entries + .runCatching { + val items: List = entries + .flatMap(Ingredient.Entry::getStacks) + .map(ItemStack::getItem) + .distinct() + when (items.size) { + 0 -> empty + + 1 -> RegistryEntryList.direct(items[0]) + + else -> RegistryEntryList.direct(items) + } + }.getOrDefault(empty) + } + } +} diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index 5ef9c26..769c583 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -1,11 +1,16 @@ package dev.robustum.core.extensions +import com.mojang.datafixers.util.Either import com.mojang.datafixers.util.Pair -import com.mojang.serialization.* +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import com.mojang.serialization.MapCodec +import dev.robustum.core.codec.KeyDispatchCodec +import dev.robustum.core.codec.OptionalCodec import net.minecraft.util.collection.DefaultedList import java.util.* import java.util.function.Function -import java.util.stream.Stream // Codec // @@ -40,90 +45,9 @@ fun Codec.dispatchPartial( codec: Function>>, ): Codec = KeyDispatchCodec(typeKey, this, type::apply, codec::apply).codec() -private class KeyDispatchCodec( - val typeKey: String, - val keyCodec: Codec, - val type: (V) -> DataResult, - val decoder: (K) -> DataResult>, - val encoder: (V) -> DataResult>, -) : MapCodec() { - companion object { - @JvmStatic - private fun getCodec( - type: (V) -> DataResult, - codec: (K) -> DataResult>, - input: V, - ): DataResult> = type(input) - .flatMap { key: K -> codec(key).map(Function.identity()) } - } - - constructor( - typeKey: String, - keyCodec: Codec, - type: (V) -> DataResult, - codec: (K) -> DataResult>, - ) : this(typeKey, keyCodec, type, codec, { input: V -> getCodec(type, codec, input) }) - - private val valueKey = "value" - - override fun keys(ops: DynamicOps): Stream = Stream.of(typeKey, valueKey).map(ops::createString) - - override fun decode(ops: DynamicOps, input: MapLike): DataResult { - val elementName: T = - input.get(typeKey) ?: return DataResult.error("Input does not contain a key [$typeKey]: $input") - return keyCodec.decode(ops, elementName).flatMap { type1: Pair -> - decoder(type1.first).flatMap { elementDecoder: MapDecoder -> - if (ops.compressMaps()) { - input - .get(ops.createString(valueKey)) - ?.let { value: T -> elementDecoder.decoder().parse(ops, value).map(Function.identity()) } - ?: return@flatMap DataResult.error("Input does not have a \"value\" entry: $input") - } else { - elementDecoder.decode(ops, input).map(Function.identity()) - } - } - } - } - - override fun encode(input: V, ops: DynamicOps, prefix: RecordBuilder): RecordBuilder { - val encodeResult: DataResult> = encoder(input) - val builder: RecordBuilder = prefix.withErrorsFrom(encodeResult) - if (encodeResult.isErrored) { - Result - return builder - } - val elementEncoder: MapEncoder = encodeResult.result().get() - return when { - ops.compressMaps() -> - prefix - .add(typeKey, type(input).flatMap { type1: K -> keyCodec.encodeStart(ops, type1) }) - .add(valueKey, elementEncoder.encoder().encodeStart(ops, input)) - - else -> - elementEncoder - .encode(input, ops, prefix) - .add(typeKey, type(input).flatMap { type1: K -> keyCodec.encodeStart(ops, type1) }) - } - } -} +fun Codec.optionalOf(): Codec> = OptionalCodec(this) -fun Codec.optionalOf(): Codec> = object : Codec> { - override fun encode(input: Optional, ops: DynamicOps, prefix: T): DataResult = when (input.isEmpty) { - true -> DataResult.success(ops.emptyMap()) - false -> this@optionalOf.encode(input.get(), ops, prefix) - } - - private fun isEmpty(ops: DynamicOps, input: T): Boolean = ops - .getMap(input) - .result() - .map { mapLike: MapLike -> mapLike.entries().findAny().isEmpty } - .orElse(false) - - override fun decode(ops: DynamicOps, input: T): DataResult, T>> = when { - isEmpty(ops, input) -> DataResult.success(Pair.of(Optional.empty(), input)) - else -> this@optionalOf.decode(ops, input).map { pair: Pair -> pair.mapFirst(Optional::of) } - } -} +fun Codec.entryOrList(): Codec>> = Codec.either(this, this.listOf()) /** * 指定された[defaultValue]を初期値に持つ[DefaultedList]を[Codec]に変換します。 diff --git a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt deleted file mode 100644 index 7ca50f7..0000000 --- a/src/main/kotlin/dev/robustum/core/extensions/RobustumCodecs.kt +++ /dev/null @@ -1,176 +0,0 @@ -package dev.robustum.core.extensions - -import com.mojang.datafixers.util.Either -import com.mojang.serialization.Codec -import com.mojang.serialization.DataResult -import com.mojang.serialization.codecs.RecordCodecBuilder -import dev.robustum.core.mixin.recipe.IngredientAccessor -import dev.robustum.core.registry.RegistryEntryList -import dev.robustum.core.registry.RegistryEntryListCodec -import net.minecraft.block.Block -import net.minecraft.block.Blocks -import net.minecraft.item.Item -import net.minecraft.item.ItemStack -import net.minecraft.item.Items -import net.minecraft.nbt.NbtCompound -import net.minecraft.recipe.Ingredient -import net.minecraft.tag.Tag -import net.minecraft.util.Identifier -import net.minecraft.util.StringIdentifiable -import net.minecraft.util.registry.Registry -import java.util.* -import kotlin.jvm.optionals.getOrNull - -object RobustumCodecs { - // Block // - /** - * [Blocks.AIR]を受け付けない[Block]の[Codec]です。 - */ - @JvmField - val BLOCK: Codec = lazyCodec { Registry.BLOCK }.validate { block: Block -> - when (block) { - Blocks.AIR -> DataResult.error("Block must not be minecraft:air") - else -> DataResult.success(block) - } - } - - // ItemStack // - /** - * [Items.AIR]を受け付けない[Item]の[Codec]です。 - */ - @JvmField - val ITEM: Codec = lazyCodec { Registry.ITEM }.validate { item: Item -> - when (item) { - Items.AIR -> DataResult.error("Item must not be minecraft:air") - else -> DataResult.success(item) - } - } - - @JvmStatic - private val RAW_STACK: Codec = RecordCodecBuilder.create { instance -> - instance - .group( - ITEM.fieldOf("id").forGetter(ItemStack::getItem), - Codec.intRange(0, Int.MAX_VALUE).optionalFieldOf("count", 1).forGetter(ItemStack::getCount), - NbtCompound.CODEC.optionalFieldOf("tag").forGetter { stack: ItemStack -> Optional.ofNullable(stack.tag) }, - ).apply(instance) { item: Item, count: Int, nbt: Optional -> - ItemStack(item, count).apply { nbt.ifPresent(this::setTag) } - } - } - - /** - * [ItemStack.isEmpty]を返す[ItemStack]も受け付ける[ItemStack]の[Codec]です。 - */ - @JvmField - val ITEM_STACK: Codec = RAW_STACK.optionalOf().xmap( - { it.orElse(ItemStack.EMPTY) }, - { if (it.isEmpty) Optional.empty() else Optional.of(it) }, - ) - - // Tag // - /** - * タグのIDを#で前置する[TagEntryId]の[Codec]です。 - */ - @JvmField - val TAG_ID: Codec = Codec.STRING.xmap({ - when (it.startsWith("#")) { - true -> TagEntryId(Identifier(it.removePrefix("#")), true) - false -> TagEntryId(Identifier(it), false) - } - }, TagEntryId::asString) - - // Ingredient // - /** - * よりシンプルな記法で書ける[Ingredient]の[Codec]です。 - * ``` - * "minecraft:dirt" -> Ingredient.ofItems(Items.DIRT) - * ["minecraft:dirt", "minecraft:stone"] -> Ingredient.ofItems(Items.DIRT, Items.STONE) - * "#minecraft:wool" -> Ingredient.fromTag(ItemTags.WOOL) - * ``` - */ - @Suppress("CAST_NEVER_SUCCEEDS") - @JvmField - val INGREDIENT: Codec = - Codec.either(RegistryEntryListCodec.ITEM, RegistryEntryListCodec.ITEM.listOf()).comapFlatMap( - { either: Either, List>> -> - either.map( - { entryList: RegistryEntryList -> - DataResult.success(entryList.storage.map(Ingredient::fromTag, Ingredient::ofItems)) - }, - { entryLists: List> -> - when { - entryLists.isEmpty() -> DataResult.success(Ingredient.EMPTY) - entryLists.all { it.storage.right().isPresent } -> - entryLists - .map(RegistryEntryList::storage) - .map { it.right() } - .mapNotNull(Optional::getOrNull) - .map(::ItemStack) - .stream() - .let(Ingredient::ofStacks) - .let(DataResult::success) - - else -> DataResult.error("Any entries do not contain tag id!") - } - }, - ) - }, - { ingredient: Ingredient -> - val empty: Either, List>> = Either.right(listOf()) - if (ingredient.isEmpty) { - empty - } else { - val entries: Array = (ingredient as IngredientAccessor).entries - entries - .runCatching { - val items: List = entries - .flatMap(Ingredient.Entry::getStacks) - .map(ItemStack::getItem) - .distinct() - when (items.size) { - 0 -> empty - - 1 -> Either.left(RegistryEntryList.of(items[0], Registry.ITEM::getEntryOrThrow)) - - else -> Either.right( - items.mapNotNull(Registry.ITEM::getEntry).map(RegistryEntryList.Companion::of), - ) - } - }.getOrDefault(empty) - } - }, - ) - - /** - * レジストリとタグのIDを共通化して扱うためのデータクラスです - */ - data class TagEntryId(val id: Identifier, val isTag: Boolean) : StringIdentifiable { - companion object { - /** - * [entry]から[RobustumCodecs.TagEntryId]を返します。 - * @param T 値のクラス - * @param transform [entry]を[Identifier]に変換するブロック - * @return [RobustumCodecs.TagEntryId.isTag]がfalseとなる[RobustumCodecs.TagEntryId] - */ - @JvmStatic - fun of(entry: T, transform: (T) -> Identifier): TagEntryId = TagEntryId(transform(entry), false) - - /** - * [tag]から[RobustumCodecs.TagEntryId]を返します。 - * @param T 値のクラス - * @param transform [tag]を[Identifier]に変換するブロック - * @return [RobustumCodecs.TagEntryId.isTag]がtrueとなる[RobustumCodecs.TagEntryId] - */ - @JvmStatic - fun ofTag(tag: Tag, transform: (Tag) -> Identifier): TagEntryId = TagEntryId(transform(tag), true) - } - - /** - * [RobustumCodecs.TagEntryId.isTag]がtrueの場合は#で[RobustumCodecs.TagEntryId.id]を前置し,それ以外の場合はそのまま返します。 - */ - override fun asString(): String = when (isTag) { - true -> "#$id" - false -> id.toString() - } - } -} diff --git a/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt index fc83af1..55ebc2f 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt @@ -2,18 +2,16 @@ package dev.robustum.core.recipe import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder -import dev.robustum.core.extensions.getEntryOrThrow +import dev.robustum.core.codec.RegistryEntryListCodec import dev.robustum.core.registry.RegistryEntryList -import dev.robustum.core.registry.RegistryEntryListCodec import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants import net.minecraft.fluid.Fluid import net.minecraft.fluid.Fluids import net.minecraft.tag.Tag -import net.minecraft.util.registry.Registry import java.util.function.BiPredicate @Suppress("UnstableApiUsage") -class FluidIngredient private constructor(val entryList: RegistryEntryList, val amount: Long) : BiPredicate { +class FluidIngredient(val entryList: RegistryEntryList, val amount: Long = FluidConstants.BUCKET) : BiPredicate { companion object { @JvmField val EMPTY = FluidIngredient(RegistryEntryList.empty(), 0) @@ -30,12 +28,9 @@ class FluidIngredient private constructor(val entryList: RegistryEntryList, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.tag(tag), amount) + constructor(tag: Tag, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.ofTag(tag), amount) - constructor(fluid: Fluid, amount: Long = FluidConstants.BUCKET) : this( - RegistryEntryList.of(fluid, Registry.FLUID::getEntryOrThrow), - amount, - ) + constructor(fluid: Fluid, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.direct(fluid), amount) val isEmpty: Boolean get() = entryList.isEmpty || amount <= 0 diff --git a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt index d980ffc..7d566bc 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt @@ -2,18 +2,16 @@ package dev.robustum.core.recipe import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder -import dev.robustum.core.extensions.getEntryOrThrow +import dev.robustum.core.codec.RegistryEntryListCodec import dev.robustum.core.extensions.isIn import dev.robustum.core.registry.RegistryEntryList -import dev.robustum.core.registry.RegistryEntryListCodec import net.minecraft.item.Item import net.minecraft.item.ItemStack import net.minecraft.recipe.Ingredient import net.minecraft.tag.Tag -import net.minecraft.util.registry.Registry import java.util.function.Predicate -class ItemIngredient private constructor(val entryList: RegistryEntryList, val count: Int) : Predicate { +class ItemIngredient(val entryList: RegistryEntryList, val count: Int = 1) : Predicate { companion object { @JvmField val EMPTY = ItemIngredient(RegistryEntryList.empty(), 0) @@ -30,18 +28,17 @@ class ItemIngredient private constructor(val entryList: RegistryEntryList, } } - constructor(tag: Tag, count: Int = 1) : this(RegistryEntryList.tag(tag), count) + constructor(tag: Tag, count: Int = 1) : this(RegistryEntryList.ofTag(tag), count) - constructor(item: Item, count: Int = 1) : this( - RegistryEntryList.of(item, Registry.ITEM::getEntryOrThrow), - count, - ) + constructor(item: Item, count: Int = 1) : this(RegistryEntryList.direct(item), count) val isEmpty: Boolean get() = entryList.isEmpty || count <= 0 val vanillaIngredient: Ingredient - get() = entryList.storage.map(Ingredient::fromTag, Ingredient::ofItems) + get() = entryList.storage.map(Ingredient::fromTag) { items: List -> + items.map(::ItemStack).stream().let(Ingredient::ofStacks) + } override fun test(stack: ItemStack): Boolean = when (stack.isEmpty) { true -> this.isEmpty diff --git a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt index 5c177e1..77e1a12 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt @@ -3,7 +3,7 @@ package dev.robustum.core.recipe import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder import dev.robustum.core.RobustumCore -import dev.robustum.core.extensions.RobustumCodecs +import dev.robustum.core.codec.RobustumCodecs import dev.robustum.core.extensions.toDefaultedList import net.minecraft.item.ItemStack import net.minecraft.recipe.* diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt index 4ccbf53..2f42d77 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryList.kt @@ -2,14 +2,14 @@ package dev.robustum.core.registry import com.mojang.datafixers.util.Either import dev.robustum.core.extensions.getSafeValue -import dev.robustum.core.registry.RegistryEntryList.Companion.tag -import net.minecraft.tag.SetTag import net.minecraft.tag.Tag +import java.util.function.Function import kotlin.random.Random /** - * [RegistryEntry]または[Tag]を持つオブジェクトです。 + * [T]値の[List]または[Tag]を持つオブジェクトです。 */ + sealed interface RegistryEntryList : Iterable { companion object { /** @@ -19,29 +19,34 @@ sealed interface RegistryEntryList : Iterable { fun empty(): RegistryEntryList = Empty() /** - * [entry]を持つ[RegistryEntryList]を返します。 + * [value]を持つ[RegistryEntryList]を返します。 + */ + @JvmStatic + fun direct(value: T): RegistryEntryList = direct(listOf(value)) + + /** + * [values]を持つ[RegistryEntryList]を返します。 */ @JvmStatic - fun of(entry: RegistryEntry): RegistryEntryList = Direct(entry) + fun direct(vararg values: T): RegistryEntryList = direct(values.toList()) /** - * [value]から[RegistryEntryList]を返します。 - * @param transform [T]を[RegistryEntry]に変換するブロック + * [values]を持つ[RegistryEntryList]を返します。 */ @JvmStatic - fun of(value: T, transform: (T) -> RegistryEntry): RegistryEntryList = of(transform(value)) + fun direct(values: List): RegistryEntryList = Direct(values) /** * [tag]を持つ[RegistryEntryList]を返します。 */ @JvmStatic - fun tag(tag: Tag): RegistryEntryList = Tagged(tag) + fun ofTag(tag: Tag): RegistryEntryList = Tagged(tag) } /** - * [Tag]または[T]を持つ[Either]を返します。 + * [Tag]または[List]を持つ[Either]を返します。 */ - val storage: Either, T> + val storage: Either, List> /** * この[RegistryEntryList]の要素が空か判定します。 @@ -49,18 +54,18 @@ sealed interface RegistryEntryList : Iterable { val isEmpty: Boolean get() = entries.isEmpty() - /** - * この[RegistryEntryList]の要素のリストを返します。 - */ - val entries: List - get() = storage.map(Tag::getSafeValue, ::listOf) - /** * この[RegistryEntryList]の要素の個数を返します。 */ val size: Int get() = entries.size + /** + * この[RegistryEntryList]の要素のリストを返します。 + */ + val entries: List + get() = storage.map(Tag::getSafeValue, Function.identity()) + /** * この[RegistryEntryList]からランダムな要素を返します。 */ @@ -69,24 +74,24 @@ sealed interface RegistryEntryList : Iterable { /** * 指定された[index]に対応する要素を返します。 */ - operator fun get(index: Int): T = entries[index] + operator fun get(index: Int): T? = entries.getOrNull(index) /** * 指定された要素[entry]が含まれるか判定します。 */ - operator fun contains(entry: T): Boolean = storage.map({ it.contains(entry) }, { it == entry }) + operator fun contains(entry: T): Boolean = entries.contains(entry) override fun iterator(): Iterator = entries.iterator() private class Empty : RegistryEntryList { - override val storage: Either, T> = Either.left(SetTag.empty()) + override val storage: Either, List> = Either.right(listOf()) } - private class Direct(entry: RegistryEntry) : RegistryEntryList { - override val storage: Either, T> = Either.right(entry.value) + private class Direct(values: List) : RegistryEntryList { + override val storage: Either, List> = Either.right(values) } private class Tagged(tag: Tag) : RegistryEntryList { - override val storage: Either, T> = Either.left(tag) + override val storage: Either, List> = Either.left(tag) } } diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntryListCodec.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryEntryListCodec.kt deleted file mode 100644 index 6732e36..0000000 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryEntryListCodec.kt +++ /dev/null @@ -1,42 +0,0 @@ -package dev.robustum.core.registry - -import com.mojang.datafixers.util.Pair -import com.mojang.serialization.Codec -import com.mojang.serialization.DataResult -import com.mojang.serialization.DynamicOps -import dev.robustum.core.extensions.RobustumCodecs -import net.minecraft.block.Block -import net.minecraft.entity.EntityType -import net.minecraft.fluid.Fluid -import net.minecraft.item.Item - -class RegistryEntryListCodec(private val lookup: RegistryLookup) : Codec> { - companion object { - @JvmField - val BLOCK: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.BLOCK) - - @JvmField - val FLUID: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.FLUID) - - @JvmField - val ENTITY_TYPE: RegistryEntryListCodec> = RegistryEntryListCodec(RegistryLookup.ENTITY_TYPE) - - @JvmField - val ITEM: RegistryEntryListCodec = RegistryEntryListCodec(RegistryLookup.ITEM) - } - - override fun encode(input: RegistryEntryList, ops: DynamicOps, prefix: T): DataResult = input.storage - .map(lookup::getId, lookup::getId) - .map(RobustumCodecs.TagEntryId::asString) - .map(ops::createString) - - override fun decode(ops: DynamicOps, input: T): DataResult, T>> = RobustumCodecs.TAG_ID - .decode(ops, input) - .flatMap { pair: Pair -> - val tagEntry: RobustumCodecs.TagEntryId = pair.first - when (tagEntry.isTag) { - true -> lookup.getTag(tagEntry.id) - false -> lookup.getEntry(tagEntry.id).map(RegistryEntryList.Companion::of) - }.map { entryList: RegistryEntryList -> Pair.of(entryList, pair.second) } - } -} diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt index 11eb08a..a672d3c 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt @@ -1,7 +1,6 @@ package dev.robustum.core.registry import com.mojang.serialization.DataResult -import dev.robustum.core.extensions.RobustumCodecs import net.minecraft.block.Block import net.minecraft.entity.EntityType import net.minecraft.fluid.Fluid @@ -23,10 +22,16 @@ interface RegistryLookup { fun getEntry(id: Identifier): DataResult> /** - * 指定された[value]から[RobustumCodecs.TagEntryId]を返します。 + * 指定された[id]から[T]を返します。 * @return 結果は[DataResult]でラップされます。 */ - fun getId(value: T): DataResult + fun getValue(id: Identifier): DataResult = getEntry(id).map(RegistryEntry::value) + + /** + * 指定された[value]から[TagEntryId]を返します。 + * @return 結果は[DataResult]でラップされます。 + */ + fun getId(value: T): DataResult /** * 指定された[id]から[RegistryEntryList]を返します。 @@ -35,10 +40,10 @@ interface RegistryLookup { fun getTag(id: Identifier): DataResult> /** - * 指定された[tag]から[RobustumCodecs.TagEntryId]を返します。 + * 指定された[tag]から[TagEntryId]を返します。 * @return 結果は[DataResult]でラップされます。 */ - fun getId(tag: Tag): DataResult + fun getId(tag: Tag): DataResult companion object { /** @@ -80,21 +85,21 @@ interface RegistryLookup { ?.let(DataResult::success) ?: DataResult.error("Unknown registry id: $id") - override fun getId(value: T): DataResult = registry + override fun getId(value: T): DataResult = registry .getId(value) - ?.let { RobustumCodecs.TagEntryId(it, false) } + ?.let { TagEntryId(it, false) } ?.let(DataResult::success) ?: DataResult.error("Unknown registry value: $value") override fun getTag(id: Identifier): DataResult> = groupGetter() .getTag(id) - ?.let(RegistryEntryList.Companion::tag) + ?.let(RegistryEntryList.Companion::ofTag) ?.let(DataResult>::success) ?: DataResult.error("Unknown tag id: $id") - override fun getId(tag: Tag): DataResult = groupGetter() + override fun getId(tag: Tag): DataResult = groupGetter() .getUncheckedTagId(tag) - ?.let { RobustumCodecs.TagEntryId(it, true) } + ?.let { TagEntryId(it, true) } ?.let(DataResult::success) ?: DataResult.error("Unknown tag: $tag") } diff --git a/src/main/kotlin/dev/robustum/core/registry/TagEntryId.kt b/src/main/kotlin/dev/robustum/core/registry/TagEntryId.kt new file mode 100644 index 0000000..90c4eb4 --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/registry/TagEntryId.kt @@ -0,0 +1,49 @@ +package dev.robustum.core.registry + +import com.mojang.serialization.Codec +import net.minecraft.tag.Tag +import net.minecraft.util.Identifier +import net.minecraft.util.StringIdentifiable +import kotlin.text.removePrefix +import kotlin.text.startsWith + +/** + * レジストリとタグのIDを共通化して扱うためのデータクラスです + */ +data class TagEntryId(val id: Identifier, val isTag: Boolean) : StringIdentifiable { + companion object { + @JvmField + val CODEC: Codec = Codec.STRING.xmap({ + when (it.startsWith("#")) { + true -> TagEntryId(Identifier(it.removePrefix("#")), true) + false -> TagEntryId(Identifier(it), false) + } + }, TagEntryId::asString) + + /** + * [entry]から[TagEntryId]を返します。 + * @param T 値のクラス + * @param transform [entry]を[Identifier]に変換するブロック + * @return [TagEntryId.isTag]がfalseとなる[TagEntryId] + */ + @JvmStatic + fun of(entry: T, transform: (T) -> Identifier): TagEntryId = TagEntryId(transform(entry), false) + + /** + * [tag]から[TagEntryId]を返します。 + * @param T 値のクラス + * @param transform [tag]を[Identifier]に変換するブロック + * @return [TagEntryId.isTag]がtrueとなる[TagEntryId] + */ + @JvmStatic + fun ofTag(tag: Tag, transform: (Tag) -> Identifier): TagEntryId = TagEntryId(transform(tag), true) + } + + /** + * [TagEntryId.isTag]がtrueの場合は#で[TagEntryId.id]を前置し,それ以外の場合はそのまま返します。 + */ + override fun asString(): String = when (isTag) { + true -> "#$id" + false -> id.toString() + } +} diff --git a/src/main/resources/robustum_core.mixins.json b/src/main/resources/robustum_core.mixins.json index 6fb5cf2..79cb119 100644 --- a/src/main/resources/robustum_core.mixins.json +++ b/src/main/resources/robustum_core.mixins.json @@ -3,7 +3,7 @@ "package": "dev.robustum.core.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ - "recipe.IngredientAccessor", + "codec.IngredientAccessor", "tag.ServerTagManagerHolderMixin", "tag.TagGroupLoaderMixin" ], From 2a015a8021e985953c8f8df0833cebeeb1b83adf Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:34:30 +0900 Subject: [PATCH 20/27] Added new codec RobustumCodecs.identifiedTagCodec --- .../dev/robustum/core/codec/RobustumCodecs.kt | 13 ++++++++ .../core/extensions/CodecExtensions.kt | 32 +++++++++++++++++++ .../core/extensions/CollectionExtensions.kt | 2 +- .../robustum/core/registry/RegistryLookup.kt | 5 +-- 4 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt index f5754b2..65f9bb0 100644 --- a/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt +++ b/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt @@ -3,8 +3,10 @@ package dev.robustum.core.codec import com.mojang.serialization.Codec import com.mojang.serialization.DataResult import com.mojang.serialization.codecs.RecordCodecBuilder +import dev.robustum.core.extensions.getIdOrNull import dev.robustum.core.extensions.lazyCodec import dev.robustum.core.extensions.optionalOf +import dev.robustum.core.extensions.toDataResult import dev.robustum.core.extensions.validate import dev.robustum.core.mixin.codec.IngredientAccessor import dev.robustum.core.recipe.ItemIngredient @@ -16,6 +18,9 @@ import net.minecraft.item.ItemStack import net.minecraft.item.Items import net.minecraft.nbt.NbtCompound import net.minecraft.recipe.Ingredient +import net.minecraft.tag.Tag +import net.minecraft.tag.TagGroup +import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry import java.util.* @@ -102,4 +107,12 @@ object RobustumCodecs { }.getOrDefault(empty) } } + + // Tag // + + @JvmStatic + fun identifiedTagCodec(groupGetter: () -> TagGroup): Codec> = Identifier.CODEC.flatXmap( + { groupGetter().getTag(it).toDataResult("Unknown tag: $it") }, + { it.getIdOrNull(groupGetter()).toDataResult("Unknown tag: $it") }, + ) } diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index 769c583..2eaffe4 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -83,3 +83,35 @@ fun DataResult.onSucceeded(action: (R) -> Unit): DataResult = ap * @param action 値が存在しない場合に実行されるブロック */ fun DataResult.onErrored(action: (DataResult.PartialResult) -> Unit): DataResult = apply { error().ifPresent(action) } + +/** + * 指定された[validator]で検証した[DataResult]を返します。 + * @param R 値のクラス + * @param validator 値を[Boolean]で評価する。 + * @param errorMessage [validator]がfalseの場合のエラー文 + * @return [validator]で評価された[DataResult] + */ +fun DataResult.validate(validator: (R) -> Boolean, errorMessage: String): DataResult = flatMap { result: R -> + when (validator(result)) { + true -> DataResult.success(result) + false -> DataResult.error(errorMessage) + } +} + +/** + * 指定された[Optional]を[DataResult]に変換します。 + * @param errorMessage [Optional]が値を保持していない場合のエラー文 + * @return [Optional]が値を保持している場合は[DataResult.success],それ以外は[DataResult.error] + */ +fun Optional.toDataResult(errorMessage: String): DataResult = + map(DataResult::success).orElse(DataResult.error(errorMessage)) + +/** + * 指定された[T]を[DataResult]に変換します。 + * @param errorMessage [T]がnullの場合のエラー文 + * @return [T]がnullでない場合は[DataResult.success],それ以外は[DataResult.error] + */ +fun T?.toDataResult(errorMessage: String): DataResult = this?.let(DataResult::success) ?: DataResult.error(errorMessage) + +fun DataResult.mapNotNull(transform: (R) -> T?): DataResult = + flatMap { result: R -> transform(result).toDataResult("Transformed value was null!") } diff --git a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt index fa0ecd8..d31ba4e 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CollectionExtensions.kt @@ -14,7 +14,7 @@ inline fun Iterable.toDefaultedList(defaultValue: T): Defau DefaultedList.copyOf(defaultValue, *this.toList().toTypedArray()) /** - * [Map]を[DefaultedList]で変換する + * [Map]を[DefaultedList]で変換します。 * @param T 値のクラス * @param defaultValue [DefaultedList]の初期値 * @param transform [Map.Entry]を[T]に変換するブロック diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt index a672d3c..c8a8be7 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt @@ -1,6 +1,7 @@ package dev.robustum.core.registry import com.mojang.serialization.DataResult +import dev.robustum.core.extensions.getIdOrNull import net.minecraft.block.Block import net.minecraft.entity.EntityType import net.minecraft.fluid.Fluid @@ -97,8 +98,8 @@ interface RegistryLookup { ?.let(DataResult>::success) ?: DataResult.error("Unknown tag id: $id") - override fun getId(tag: Tag): DataResult = groupGetter() - .getUncheckedTagId(tag) + override fun getId(tag: Tag): DataResult = tag + .getIdOrNull(groupGetter()) ?.let { TagEntryId(it, true) } ?.let(DataResult::success) ?: DataResult.error("Unknown tag: $tag") From 8d87e969e208118896d1e3db1f2b2eba3d62259f Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:43:41 +0900 Subject: [PATCH 21/27] Fixed incorrect encoding --- .../dev/robustum/core/codec/RegistryEntryListCodec.kt | 8 ++++---- src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt b/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt index 0df5279..1249f03 100644 --- a/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt +++ b/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt @@ -46,14 +46,14 @@ class RegistryEntryListCodec(private val lookup: RegistryLookup) : C 1 -> lookup.getId(entries[0]).map(TagEntryId::asString).map(ops::createString) else -> { - val results: List = entries + entries .map(lookup::getId) .map { result: DataResult -> result.getOrThrow(false, logger::error) } .map(TagEntryId::asString) .map(ops::createString) - val list: T? = ops.emptyList() - ops.mergeToList(list, results) - DataResult.success(list) + .stream() + .let(ops::createList) + .let(DataResult::success) } } }, diff --git a/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt index 65f9bb0..197b80b 100644 --- a/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt +++ b/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt @@ -81,7 +81,7 @@ object RobustumCodecs { * "#minecraft:wool" -> Ingredient.fromTag(ItemTags.WOOL) * ``` */ - @Suppress("KotlinConstantConditions") + @Suppress("CAST_NEVER_SUCCEEDS") @JvmField val INGREDIENT: Codec = RegistryEntryListCodec.ITEM.xmap( { ItemIngredient(it).vanillaIngredient }, From e86a243c9d38c9f828b8cc444e8308a263e49088 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Sun, 15 Dec 2024 14:53:33 +0900 Subject: [PATCH 22/27] Updated RecipeCodec.kt --- .../core/recipe/DelegatedRecipeSerializer.kt | 19 +++++++++++++++---- .../dev/robustum/core/recipe/RecipeCodec.kt | 4 ++-- .../core/recipe/RobustumRecipeSerializers.kt | 6 +++--- .../recipe/TestRobustumRecipeSerializers.kt | 1 + 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt b/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt index a8d87b0..5203b92 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt @@ -1,24 +1,35 @@ package dev.robustum.core.recipe import com.google.gson.JsonObject +import com.mojang.serialization.Codec import com.mojang.serialization.DataResult import com.mojang.serialization.DynamicOps import com.mojang.serialization.JsonOps +import com.mojang.serialization.codecs.RecordCodecBuilder import net.minecraft.network.PacketByteBuf import net.minecraft.recipe.Recipe import net.minecraft.recipe.RecipeSerializer import net.minecraft.util.Identifier +import net.minecraft.util.registry.Registry class DelegatedRecipeSerializer>(private val delegated: RecipeSerializer, private val recipeCodec: RecipeCodec) : RecipeSerializer { - override fun read(id: Identifier, json: JsonObject): T = recipeCodec - .createCodec(id) + private fun createCodec(id: Identifier): Codec = RecordCodecBuilder.create { instance -> + instance + .group( + Registry.RECIPE_SERIALIZER.fieldOf("type").forGetter { this }, + recipeCodec.createCodec(id).forGetter { it }, + ).apply(instance) { type: RecipeSerializer<*>, recipe: T -> + recipe + } + } + + override fun read(id: Identifier, json: JsonObject): T = createCodec(id) .parse(JsonOps.INSTANCE, json) .result() .orElseThrow() - fun write(dynamicOps: DynamicOps, recipe: T): DataResult = - recipeCodec.createCodec(recipe.id).encodeStart(dynamicOps, recipe) + fun write(dynamicOps: DynamicOps, recipe: T): DataResult = createCodec(recipe.id).encodeStart(dynamicOps, recipe) override fun read(id: Identifier, buf: PacketByteBuf): T = delegated.read(id, buf) diff --git a/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt b/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt index a3980e5..ce0d394 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt @@ -1,9 +1,9 @@ package dev.robustum.core.recipe -import com.mojang.serialization.Codec +import com.mojang.serialization.MapCodec import net.minecraft.recipe.Recipe import net.minecraft.util.Identifier fun interface RecipeCodec> { - fun createCodec(id: Identifier): Codec + fun createCodec(id: Identifier): MapCodec } diff --git a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt index 77e1a12..accef8e 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt @@ -17,7 +17,7 @@ object RobustumRecipeSerializers { "shapeless", RecipeSerializer.SHAPELESS, ) { id: Identifier -> - RecordCodecBuilder.create { instance -> + RecordCodecBuilder.mapCodec { instance -> instance .group( Codec.STRING @@ -73,7 +73,7 @@ object RobustumRecipeSerializers { "stonecutting", RecipeSerializer.STONECUTTING, ) { id: Identifier -> - RecordCodecBuilder.create { instance -> + RecordCodecBuilder.mapCodec { instance -> instance .group( Codec.STRING @@ -95,7 +95,7 @@ object RobustumRecipeSerializers { private fun createCookingRecipe( factory: (Identifier, String, Ingredient, ItemStack, Float, Int) -> T, ): RecipeCodec = RecipeCodec { id: Identifier -> - RecordCodecBuilder.create { instance -> + RecordCodecBuilder.mapCodec { instance -> instance .group( Codec.STRING diff --git a/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt b/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt index cc829c5..fb29cb0 100644 --- a/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt +++ b/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt @@ -37,6 +37,7 @@ class TestRobustumRecipeSerializers { ), ).onSucceeded { it shouldBe { + "type"("robustum_core:smelting") "output" { "id"("minecraft:diamond") } From 53d976833358b3c7584b26c0423cfd09b4972935 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Mon, 16 Dec 2024 21:37:57 +0900 Subject: [PATCH 23/27] Added more tests --- .../core/codec/RegistryEntryListCodec.kt | 2 +- .../dev/robustum/core/codec/RobustumCodecs.kt | 32 +++++--- .../core/extensions/CodecExtensions.kt | 29 +++++-- .../core/extensions/DynamicOpsExtensions.kt | 46 +++++++++++ .../core/extensions/RegistryExtensions.kt | 15 ---- .../robustum/core/recipe/ItemIngredient.kt | 7 +- .../core/recipe/RobustumRecipeSerializers.kt | 6 +- .../robustum/core/registry/RegistryEntry.kt | 12 ++- .../robustum/core/registry/RegistryLookup.kt | 2 +- .../resources/robustum_core.accesswidener | 3 + .../kotlin/test/codec/TestRobustumCodecs.kt | 77 +++++++++++++++++++ ...eSerializers.kt => TestRobustumRecipes.kt} | 8 +- .../test/registry/TestRobustumRegistries.kt | 40 ++++++++++ 13 files changed, 231 insertions(+), 48 deletions(-) create mode 100644 src/main/kotlin/dev/robustum/core/extensions/DynamicOpsExtensions.kt delete mode 100644 src/main/kotlin/dev/robustum/core/extensions/RegistryExtensions.kt create mode 100644 src/test/kotlin/test/codec/TestRobustumCodecs.kt rename src/test/kotlin/test/recipe/{TestRobustumRecipeSerializers.kt => TestRobustumRecipes.kt} (90%) create mode 100644 src/test/kotlin/test/registry/TestRobustumRegistries.kt diff --git a/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt b/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt index 1249f03..88f2dbe 100644 --- a/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt +++ b/src/main/kotlin/dev/robustum/core/codec/RegistryEntryListCodec.kt @@ -5,6 +5,7 @@ import com.mojang.datafixers.util.Pair import com.mojang.serialization.Codec import com.mojang.serialization.DataResult import com.mojang.serialization.DynamicOps +import dev.robustum.core.extensions.createList import dev.robustum.core.extensions.entryOrList import dev.robustum.core.registry.RegistryEntryList import dev.robustum.core.registry.RegistryLookup @@ -51,7 +52,6 @@ class RegistryEntryListCodec(private val lookup: RegistryLookup) : C .map { result: DataResult -> result.getOrThrow(false, logger::error) } .map(TagEntryId::asString) .map(ops::createString) - .stream() .let(ops::createList) .let(DataResult::success) } diff --git a/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt b/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt index 197b80b..aab81bf 100644 --- a/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt +++ b/src/main/kotlin/dev/robustum/core/codec/RobustumCodecs.kt @@ -3,11 +3,7 @@ package dev.robustum.core.codec import com.mojang.serialization.Codec import com.mojang.serialization.DataResult import com.mojang.serialization.codecs.RecordCodecBuilder -import dev.robustum.core.extensions.getIdOrNull -import dev.robustum.core.extensions.lazyCodec -import dev.robustum.core.extensions.optionalOf -import dev.robustum.core.extensions.toDataResult -import dev.robustum.core.extensions.validate +import dev.robustum.core.extensions.* import dev.robustum.core.mixin.codec.IngredientAccessor import dev.robustum.core.recipe.ItemIngredient import dev.robustum.core.registry.RegistryEntryList @@ -91,10 +87,20 @@ object RobustumCodecs { empty } else { val entries: Array = (ingredient as IngredientAccessor).entries - entries - .runCatching { - val items: List = entries - .flatMap(Ingredient.Entry::getStacks) + if (entries.size == 1) { + val entry: Ingredient.Entry = entries[0] + when (entry) { + is Ingredient.StackEntry -> RegistryEntryList.direct(entry.stacks.first().item) + is Ingredient.TagEntry -> RegistryEntryList.ofTag(entry.tag) + else -> empty + } + } else { + val stackEntries: List = entries.filterIsInstance() + if (stackEntries.isEmpty()) { + empty + } else { + val items: List = stackEntries + .flatMap(Ingredient.StackEntry::getStacks) .map(ItemStack::getItem) .distinct() when (items.size) { @@ -104,10 +110,16 @@ object RobustumCodecs { else -> RegistryEntryList.direct(items) } - }.getOrDefault(empty) + } + } } } + @JvmField + val NON_EMPTY_INGREDIENT: Codec = INGREDIENT.validate { ingredient: Ingredient -> + DataResult.success(ingredient).filterNot(Ingredient::isEmpty, "Empty ingredient is not allowed!") + } + // Tag // @JvmStatic diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index 2eaffe4..3e48cfb 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -82,22 +82,37 @@ fun DataResult.onSucceeded(action: (R) -> Unit): DataResult = ap * [DataResult]が値を保持していない場合は指定された[action]をその値で呼び出し、それ以外の場合は何も行いません。 * @param action 値が存在しない場合に実行されるブロック */ -fun DataResult.onErrored(action: (DataResult.PartialResult) -> Unit): DataResult = apply { error().ifPresent(action) } +fun DataResult.onErrored(action: (String) -> Unit): DataResult = + apply { error().map(DataResult.PartialResult::message).ifPresent(action) } /** - * 指定された[validator]で検証した[DataResult]を返します。 + * 指定された[predicate]で検証した[DataResult]を返します。 * @param R 値のクラス - * @param validator 値を[Boolean]で評価する。 - * @param errorMessage [validator]がfalseの場合のエラー文 - * @return [validator]で評価された[DataResult] + * @param predicate 値を[Boolean]で評価する。 + * @param errorMessage [predicate]がfalseの場合のエラー文 + * @return [predicate]で評価された[DataResult] */ -fun DataResult.validate(validator: (R) -> Boolean, errorMessage: String): DataResult = flatMap { result: R -> - when (validator(result)) { +fun DataResult.filter(predicate: (R) -> Boolean, errorMessage: String): DataResult = flatMap { result: R -> + when (predicate(result)) { true -> DataResult.success(result) false -> DataResult.error(errorMessage) } } +/** + * 指定された[predicate]で検証した[DataResult]を返します。 + * @param R 値のクラス + * @param predicate 値を[Boolean]で評価する。 + * @param errorMessage [predicate]がtrueの場合のエラー文 + * @return [predicate]で評価された[DataResult] + */ +fun DataResult.filterNot(predicate: (R) -> Boolean, errorMessage: String): DataResult = flatMap { result: R -> + when (predicate(result)) { + true -> DataResult.error(errorMessage) + false -> DataResult.success(result) + } +} + /** * 指定された[Optional]を[DataResult]に変換します。 * @param errorMessage [Optional]が値を保持していない場合のエラー文 diff --git a/src/main/kotlin/dev/robustum/core/extensions/DynamicOpsExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/DynamicOpsExtensions.kt new file mode 100644 index 0000000..6830ddd --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/extensions/DynamicOpsExtensions.kt @@ -0,0 +1,46 @@ +package dev.robustum.core.extensions + +import com.mojang.serialization.DynamicOps + +// List // + +/** + * 指定された[list]を[T]に変換します。 + * @param T 値のクラス + * @return [T]に変換された[List] + */ +fun DynamicOps.createList(list: List): T = createList(list.stream()) + +/** + * 指定された[entries]を[T]に変換します。 + * @param T 値のクラス + * @return [T]に変換された[List] + */ +fun DynamicOps.createList(vararg entries: T): T = createList(entries.toList()) + +/** + * 指定された[list]を[transform]で[T]に変換します。 + * @param T 値のクラス + * @param transform [E]を[T]に変換する + * @return [T]に変換された[List] + */ +fun DynamicOps.createList(transform: (E) -> T, list: List): T = createList(list.map(transform)) + +/** + * 指定された[entries]を[transform]で[T]に変換します。 + * @param T 値のクラス + * @param transform [E]を[T]に変換する + * @return [T]に変換された[List] + */ +fun DynamicOps.createList(transform: (E) -> T, vararg entries: E): T = createList(entries.map(transform)) + +fun DynamicOps.buildList(transform: (E) -> T, builderAction: MutableList.() -> Unit): T = + createList(buildList(builderAction).map(transform)) + +// Map // + +fun DynamicOps.buildMap( + keyTransform: (K) -> T, + valueTransform: (V) -> T, + builderAction: MutableMap.() -> Unit, +): T = createMap(buildMap(builderAction).mapKeys { keyTransform(it.key) }.mapValues { valueTransform(it.value) }) diff --git a/src/main/kotlin/dev/robustum/core/extensions/RegistryExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/RegistryExtensions.kt deleted file mode 100644 index 162392d..0000000 --- a/src/main/kotlin/dev/robustum/core/extensions/RegistryExtensions.kt +++ /dev/null @@ -1,15 +0,0 @@ -package dev.robustum.core.extensions - -import dev.robustum.core.registry.RegistryEntry -import net.minecraft.util.Identifier -import net.minecraft.util.registry.Registry - -// Registry // - -fun Registry.getEntry(id: Identifier): RegistryEntry? = get(id)?.let { RegistryEntry(id, it) } - -fun Registry.getEntryOrThrow(id: Identifier): RegistryEntry = checkNotNull(getEntry(id)) - -fun Registry.getEntry(value: T): RegistryEntry? = getId(value)?.let { RegistryEntry(it, value) } - -fun Registry.getEntryOrThrow(value: T): RegistryEntry = checkNotNull(getEntry(value)) diff --git a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt index 7d566bc..e8e8e60 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt @@ -36,8 +36,11 @@ class ItemIngredient(val entryList: RegistryEntryList, val count: Int = 1) get() = entryList.isEmpty || count <= 0 val vanillaIngredient: Ingredient - get() = entryList.storage.map(Ingredient::fromTag) { items: List -> - items.map(::ItemStack).stream().let(Ingredient::ofStacks) + get() = when (isEmpty) { + true -> Ingredient.EMPTY + false -> entryList.storage.map(Ingredient::fromTag) { items: List -> + items.map(::ItemStack).stream().let(Ingredient::ofStacks) + } } override fun test(stack: ItemStack): Boolean = when (stack.isEmpty) { diff --git a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt index accef8e..ddc88b6 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RobustumRecipeSerializers.kt @@ -23,7 +23,7 @@ object RobustumRecipeSerializers { Codec.STRING .optionalFieldOf("group", "") .forGetter(ShapelessRecipe::getGroup), - RobustumCodecs.INGREDIENT + RobustumCodecs.NON_EMPTY_INGREDIENT .listOf() .fieldOf("inputs") .forGetter(ShapelessRecipe::getIngredients), @@ -79,7 +79,7 @@ object RobustumRecipeSerializers { Codec.STRING .optionalFieldOf("group", "") .forGetter(StonecuttingRecipe::getGroup), - RobustumCodecs.INGREDIENT + RobustumCodecs.NON_EMPTY_INGREDIENT .fieldOf("input") .forGetter { it.ingredients[0] }, RobustumCodecs.ITEM_STACK @@ -101,7 +101,7 @@ object RobustumRecipeSerializers { Codec.STRING .optionalFieldOf("group", "") .forGetter { it.group }, - RobustumCodecs.INGREDIENT + RobustumCodecs.NON_EMPTY_INGREDIENT .fieldOf("input") .forGetter { it.ingredients[0] }, RobustumCodecs.ITEM_STACK diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt index 9b32174..5afb5a3 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt @@ -3,9 +3,13 @@ package dev.robustum.core.registry import net.minecraft.util.Identifier /** - * レジストリIDとその値を持つデータクラスです。 + * レジストリIDとその値を持つインターフェースです。 * @param T 値のクラス - * @param key レジストリID - * @param value [key]に対応する値 + * @see [RegistryLookup.getEntry] */ -data class RegistryEntry(val key: Identifier, val value: T) +sealed interface RegistryEntry { + val id: Identifier + val value: T +} + +internal data class RegistryEntryImpl(override val id: Identifier, override val value: T) : RegistryEntry diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt index c8a8be7..466afdf 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt @@ -82,7 +82,7 @@ interface RegistryLookup { fun of(registry: Registry, groupGetter: () -> TagGroup): RegistryLookup = object : RegistryLookup { override fun getEntry(id: Identifier): DataResult> = registry .get(id) - ?.let { RegistryEntry(id, it) } + ?.let { RegistryEntryImpl(id, it) } ?.let(DataResult::success) ?: DataResult.error("Unknown registry id: $id") diff --git a/src/main/resources/robustum_core.accesswidener b/src/main/resources/robustum_core.accesswidener index 4d09665..7c49fd5 100644 --- a/src/main/resources/robustum_core.accesswidener +++ b/src/main/resources/robustum_core.accesswidener @@ -1,3 +1,6 @@ accessWidener v2 named accessible class net/minecraft/recipe/Ingredient$Entry +accessible class net/minecraft/recipe/Ingredient$StackEntry +accessible class net/minecraft/recipe/Ingredient$TagEntry +accessible field net/minecraft/recipe/Ingredient$TagEntry tag Lnet/minecraft/tag/Tag; diff --git a/src/test/kotlin/test/codec/TestRobustumCodecs.kt b/src/test/kotlin/test/codec/TestRobustumCodecs.kt new file mode 100644 index 0000000..8fa922f --- /dev/null +++ b/src/test/kotlin/test/codec/TestRobustumCodecs.kt @@ -0,0 +1,77 @@ +package test.codec + +import com.mojang.serialization.JsonOps +import dev.robustum.core.codec.RobustumCodecs +import dev.robustum.core.extensions.onErrored +import dev.robustum.core.extensions.onSucceeded +import helper.shouldBe +import io.kotest.matchers.shouldBe +import net.minecraft.Bootstrap +import net.minecraft.SharedConstants +import net.minecraft.block.Blocks +import net.minecraft.item.ItemStack +import net.minecraft.item.Items +import net.minecraft.recipe.Ingredient +import net.minecraft.tag.ItemTags +import org.junit.jupiter.api.Test +import kotlin.test.BeforeTest + +class TestRobustumCodecs { + @BeforeTest + fun setup() { + SharedConstants.getGameVersion() + Bootstrap.initialize() + } + + @Test + fun testCodecs() { + // block + RobustumCodecs.BLOCK + .encodeStart(JsonOps.INSTANCE, Blocks.STONE) + .onSucceeded { it.asString shouldBe "minecraft:stone" } + .onErrored(::error) + + RobustumCodecs.BLOCK + .encodeStart(JsonOps.INSTANCE, Blocks.AIR) + .onErrored { it shouldBe "Block must not be minecraft:air" } + // item + RobustumCodecs.ITEM + .encodeStart(JsonOps.INSTANCE, Items.IRON_INGOT) + .onSucceeded { it.asString shouldBe "minecraft:iron_ingot" } + .onErrored(::error) + + RobustumCodecs.ITEM + .encodeStart(JsonOps.INSTANCE, Items.AIR) + .onErrored { it shouldBe "Item must not be minecraft:air" } + // item stack + RobustumCodecs.ITEM_STACK + .encodeStart(JsonOps.INSTANCE, ItemStack(Items.IRON_INGOT, 4)) + .onSucceeded { + it shouldBe { + "id"("minecraft:iron_ingot") + "count"(4) + } + }.onErrored(::error) + + RobustumCodecs.ITEM_STACK + .encodeStart(JsonOps.INSTANCE, ItemStack.EMPTY) + .onSucceeded { it shouldBe JsonOps.INSTANCE.emptyMap() } + .onErrored(::error) + // ingredient (and registry entry list) + RobustumCodecs.INGREDIENT + .encodeStart(JsonOps.INSTANCE, Ingredient.ofItems(Items.DIAMOND)) + .onSucceeded { it.asString shouldBe "minecraft:diamond" } + + RobustumCodecs.INGREDIENT + .encodeStart(JsonOps.INSTANCE, Ingredient.ofItems(Items.DIAMOND, Items.EMERALD)) + .onSucceeded { it.toString() shouldBe "[\"minecraft:diamond\",\"minecraft:emerald\"]" } + + RobustumCodecs.INGREDIENT + .encodeStart(JsonOps.INSTANCE, Ingredient.fromTag(ItemTags.LOGS)) + .onSucceeded { it.asString shouldBe "#minecraft:logs" } + + RobustumCodecs.NON_EMPTY_INGREDIENT + .encodeStart(JsonOps.INSTANCE, Ingredient.EMPTY) + .onErrored { it shouldBe "Empty ingredient is not allowed!" } + } +} diff --git a/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt b/src/test/kotlin/test/recipe/TestRobustumRecipes.kt similarity index 90% rename from src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt rename to src/test/kotlin/test/recipe/TestRobustumRecipes.kt index fb29cb0..1b934a4 100644 --- a/src/test/kotlin/test/recipe/TestRobustumRecipeSerializers.kt +++ b/src/test/kotlin/test/recipe/TestRobustumRecipes.kt @@ -15,7 +15,7 @@ import net.minecraft.recipe.SmeltingRecipe import org.junit.jupiter.api.Test import kotlin.test.BeforeTest -class TestRobustumRecipeSerializers { +class TestRobustumRecipes { @BeforeTest fun setup() { SharedConstants.getGameVersion() @@ -23,7 +23,7 @@ class TestRobustumRecipeSerializers { } @Test - fun testSmelting() { + fun testRecipes() { RobustumRecipeSerializers.SMELTING .write( JsonOps.INSTANCE, @@ -44,8 +44,6 @@ class TestRobustumRecipeSerializers { "exp"(32767.0) "input"("minecraft:dirt") } - }.onErrored { - error(it.message()) - } + }.onErrored(::error) } } diff --git a/src/test/kotlin/test/registry/TestRobustumRegistries.kt b/src/test/kotlin/test/registry/TestRobustumRegistries.kt new file mode 100644 index 0000000..cecdddd --- /dev/null +++ b/src/test/kotlin/test/registry/TestRobustumRegistries.kt @@ -0,0 +1,40 @@ +package test.registry + +import dev.robustum.core.extensions.onErrored +import dev.robustum.core.extensions.onSucceeded +import dev.robustum.core.registry.RegistryLookup +import io.kotest.matchers.shouldBe +import net.minecraft.Bootstrap +import net.minecraft.SharedConstants +import net.minecraft.block.Blocks +import net.minecraft.tag.BlockTags +import net.minecraft.util.Identifier +import org.junit.jupiter.api.Test +import kotlin.test.BeforeTest + +class TestRobustumRegistries { + @BeforeTest + fun setup() { + SharedConstants.getGameVersion() + Bootstrap.initialize() + } + + @Test + fun testRegistries() { + // lookup + RegistryLookup.BLOCK + .getId(Blocks.STONE) + .onSucceeded { it.asString() shouldBe "minecraft:stone" } + .onErrored(::error) + + RegistryLookup.BLOCK + .getValue(Identifier("diamond_block")) + .onSucceeded { it shouldBe Blocks.DIAMOND_BLOCK } + .onErrored(::error) + + RegistryLookup.BLOCK + .getId(BlockTags.SLABS) + .onSucceeded { it.asString() shouldBe "#minecraft:slabs" } + .onErrored(::error) + } +} From 416f93bff885f1bb85c154ac2cbc5a22b48a1dde Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:26:25 +0900 Subject: [PATCH 24/27] Renamed RegistryEntry.kt into IdentifiedEntry.kt --- .../registry/{RegistryEntry.kt => IdentifiedEntry.kt} | 4 ++-- .../dev/robustum/core/registry/RegistryLookup.kt | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) rename src/main/kotlin/dev/robustum/core/registry/{RegistryEntry.kt => IdentifiedEntry.kt} (61%) diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt b/src/main/kotlin/dev/robustum/core/registry/IdentifiedEntry.kt similarity index 61% rename from src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt rename to src/main/kotlin/dev/robustum/core/registry/IdentifiedEntry.kt index 5afb5a3..ac455e7 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryEntry.kt +++ b/src/main/kotlin/dev/robustum/core/registry/IdentifiedEntry.kt @@ -7,9 +7,9 @@ import net.minecraft.util.Identifier * @param T 値のクラス * @see [RegistryLookup.getEntry] */ -sealed interface RegistryEntry { +sealed interface IdentifiedEntry { val id: Identifier val value: T } -internal data class RegistryEntryImpl(override val id: Identifier, override val value: T) : RegistryEntry +internal data class IdentifiedEntryImpl(override val id: Identifier, override val value: T) : IdentifiedEntry diff --git a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt index 466afdf..318af2a 100644 --- a/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt +++ b/src/main/kotlin/dev/robustum/core/registry/RegistryLookup.kt @@ -17,16 +17,16 @@ import net.minecraft.util.registry.Registry */ interface RegistryLookup { /** - * 指定された[id]から[RegistryEntry]を返します。 + * 指定された[id]から[IdentifiedEntry]を返します。 * @return 結果は[DataResult]でラップされます。 */ - fun getEntry(id: Identifier): DataResult> + fun getEntry(id: Identifier): DataResult> /** * 指定された[id]から[T]を返します。 * @return 結果は[DataResult]でラップされます。 */ - fun getValue(id: Identifier): DataResult = getEntry(id).map(RegistryEntry::value) + fun getValue(id: Identifier): DataResult = getEntry(id).map(IdentifiedEntry::value) /** * 指定された[value]から[TagEntryId]を返します。 @@ -80,9 +80,9 @@ interface RegistryLookup { */ @JvmStatic fun of(registry: Registry, groupGetter: () -> TagGroup): RegistryLookup = object : RegistryLookup { - override fun getEntry(id: Identifier): DataResult> = registry + override fun getEntry(id: Identifier): DataResult> = registry .get(id) - ?.let { RegistryEntryImpl(id, it) } + ?.let { IdentifiedEntryImpl(id, it) } ?.let(DataResult::success) ?: DataResult.error("Unknown registry id: $id") From 7f867028f85eb8cdebcdba3c3b5677004a70979d Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Mon, 16 Dec 2024 22:26:42 +0900 Subject: [PATCH 25/27] Added new class RecipeCache.kt --- .../core/extensions/CodecExtensions.kt | 21 +++++--- .../dev/robustum/core/recipe/RecipeCache.kt | 53 +++++++++++++++++++ 2 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/dev/robustum/core/recipe/RecipeCache.kt diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index 3e48cfb..121bd26 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -14,14 +14,6 @@ import java.util.function.Function // Codec // -/** - * 指定された[validator]で検証した[Codec]を返します。 - * @param A 値のクラス - * @param validator 値を[DataResult]で評価する。 - * @return [validator]で評価された[Codec] - */ -fun Codec.validate(validator: (A) -> DataResult): Codec = flatXmap(validator, validator) - /** * 指定された[getter]で遅延評価された[Codec]を返します。 * @param A 値のクラス @@ -34,6 +26,19 @@ fun lazyCodec(getter: () -> Codec): Codec = object : Codec { override fun decode(ops: DynamicOps, input: T): DataResult> = getter().decode(ops, input) } +fun alternativeCodec(first: Codec, second: Codec): Codec = Codec.either(first, second).xmap( + { either: Either -> either.map(Function.identity(), Function.identity()) }, + Either::left, +) + +/** + * 指定された[validator]で検証した[Codec]を返します。 + * @param A 値のクラス + * @param validator 値を[DataResult]で評価する。 + * @return [validator]で評価された[Codec] + */ +fun Codec.validate(validator: (A) -> DataResult): Codec = flatXmap(validator, validator) + fun Codec.dispatch(type: Function, codec: Function>): Codec = dispatch("type", type, codec) fun Codec.dispatch(typeKey: String, type: Function, codec: Function>): Codec = diff --git a/src/main/kotlin/dev/robustum/core/recipe/RecipeCache.kt b/src/main/kotlin/dev/robustum/core/recipe/RecipeCache.kt new file mode 100644 index 0000000..4bacb7d --- /dev/null +++ b/src/main/kotlin/dev/robustum/core/recipe/RecipeCache.kt @@ -0,0 +1,53 @@ +package dev.robustum.core.recipe + +import com.mojang.serialization.DataResult +import dev.robustum.core.extensions.filter +import dev.robustum.core.extensions.onErrored +import dev.robustum.core.extensions.onSucceeded +import dev.robustum.core.extensions.toDataResult +import net.minecraft.inventory.Inventory +import net.minecraft.recipe.Recipe +import net.minecraft.recipe.RecipeManager +import net.minecraft.recipe.RecipeType +import net.minecraft.util.Identifier +import net.minecraft.world.World +import java.util.* + +/** + * 最後に一致した[Recipe]の[Identifier]を保持するクラスです。 + * @param I [Inventory]のクラス + * @param R [Recipe]のクラス + * @param recipeType [Recipe]の種類 + */ +class RecipeCache>(private val recipeType: RecipeType) { + /** + * 最後にキャッシュされた[Recipe]の[Identifier]です。 + * + * 以前のキャッシュがない場合はnullを返します。 + */ + private var id: Identifier? = null + + /** + * 指定された[inventory]と[world]に一致する最初のレシピを返します。 + * @return [id]がある場合は[RecipeManager.get]から,それ以外の場合は[RecipeManager.getFirstMatch]から取得 + */ + @Suppress("UNCHECKED_CAST") + fun getFirstMatch(inventory: I, world: World): DataResult = world.recipeManager + .let { recipeManager: RecipeManager -> + when (id) { + null -> recipeManager.getFirstMatch(recipeType, inventory, world) + else -> recipeManager.get(id).flatMap { Optional.ofNullable(it as? R) } + } + }.toDataResult("Failed to find matching recipe!") + .onSucceeded { this.id = it.id } + .onErrored { this.id = null } + + /** + * 指定された[inventory]と[world]に一致するすべてのレシピを返します。 + * @return [RecipeManager.getAllMatches]の戻り値が空の場合は[DataResult.error],それ以外は[DataResult.success] + */ + fun getAllMatches(inventory: I, world: World): DataResult> = world.recipeManager + .getAllMatches(recipeType, inventory, world) + .let(DataResult>::success) + .filter(List::isNotEmpty, "Failed to find matching recipes!") +} From 981264c7a3fc38d8e2d6e0f9c6f8d48cf1900663 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Tue, 17 Dec 2024 20:48:43 +0900 Subject: [PATCH 26/27] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=82=92=E8=A4=87=E6=95=B0=E3=81=AE=E3=83=A1?= =?UTF-8?q?=E3=82=BD=E3=83=83=E3=83=89=E3=81=AB=E5=88=86=E5=89=B2=20?= =?UTF-8?q?=E6=AC=A0=E3=81=91=E3=81=A6=E3=81=84=E3=81=9FKDoc=E3=82=92?= =?UTF-8?q?=E5=A4=A7=E4=BD=93=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/extensions/CodecExtensions.kt | 2 ++ .../robustum/core/extensions/ItemExtension.kt | 5 ++-- .../core/recipe/DelegatedRecipeSerializer.kt | 11 +++++++++ .../robustum/core/recipe/FluidIngredient.kt | 8 +++++++ .../robustum/core/recipe/ItemIngredient.kt | 11 +++++++++ .../dev/robustum/core/recipe/RecipeCodec.kt | 8 +++++++ .../robustum/core/tag/RobustumTagEvents.kt | 24 +++++++++---------- .../kotlin/test/codec/TestRobustumCodecs.kt | 17 +++++++++---- .../kotlin/test/recipe/TestRobustumRecipes.kt | 2 +- .../test/registry/TestRobustumRegistries.kt | 2 +- 10 files changed, 68 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt index 121bd26..318e27e 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/CodecExtensions.kt @@ -12,6 +12,8 @@ import net.minecraft.util.collection.DefaultedList import java.util.* import java.util.function.Function +typealias DataPair = Pair + // Codec // /** diff --git a/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt b/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt index 0d4a410..df4471a 100644 --- a/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt +++ b/src/main/kotlin/dev/robustum/core/extensions/ItemExtension.kt @@ -18,14 +18,13 @@ fun ItemStack.isOf(item: ItemConvertible): Boolean = this.item == item.asItem() // ItemUsageContext // /** - * この[ItemUsageContext]が持っている[net.minecraft.world.World]と[net.minecraft.util.math.BlockPos]から[BlockState]を取得します。 + * この[ItemUsageContext]から[BlockState]を取得します。 */ val ItemUsageContext.blockState: BlockState get() = world.getBlockState(blockPos) /** - * この[ItemUsageContext]が持っている[net.minecraft.world.World]と[net.minecraft.util.math.BlockPos]から[T]を取得します。 + * この[ItemUsageContext]から[T]を取得します。 * @param T [BlockEntity]を継承したクラス - * @return [net.minecraft.world.World.getBlockEntity]で取得した[BlockEntity]が[T]を継承していない場合はnull */ inline fun ItemUsageContext.getBlockEntity(): T? = world.getBlockEntity(blockPos) as? T diff --git a/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt b/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt index 5203b92..7bae099 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/DelegatedRecipeSerializer.kt @@ -12,6 +12,12 @@ import net.minecraft.recipe.RecipeSerializer import net.minecraft.util.Identifier import net.minecraft.util.registry.Registry +/** + * クライアントへの同期を[delegated]に委譲した[RecipeSerializer]です。 + * @param T レシピのクラス + * @param recipeCodec レシピのコーデック + * @see RobustumRecipeSerializers + */ class DelegatedRecipeSerializer>(private val delegated: RecipeSerializer, private val recipeCodec: RecipeCodec) : RecipeSerializer { private fun createCodec(id: Identifier): Codec = RecordCodecBuilder.create { instance -> @@ -29,6 +35,11 @@ class DelegatedRecipeSerializer>(private val delegated: RecipeSeri .result() .orElseThrow() + /** + * 指定された[recipe]を[dynamicOps]で[O]に変換します。 + * @param O 変換先のクラス + * @return [DataResult]で包まれた[O] + */ fun write(dynamicOps: DynamicOps, recipe: T): DataResult = createCodec(recipe.id).encodeStart(dynamicOps, recipe) override fun read(id: Identifier, buf: PacketByteBuf): T = delegated.read(id, buf) diff --git a/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt index 55ebc2f..21dec90 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/FluidIngredient.kt @@ -10,6 +10,11 @@ import net.minecraft.fluid.Fluids import net.minecraft.tag.Tag import java.util.function.BiPredicate +/** + * 液体版の[ItemIngredient]です。 + * @param entryList 条件に一致する液体のリスト + * @param amount 必要な液体量 + */ @Suppress("UnstableApiUsage") class FluidIngredient(val entryList: RegistryEntryList, val amount: Long = FluidConstants.BUCKET) : BiPredicate { companion object { @@ -32,6 +37,9 @@ class FluidIngredient(val entryList: RegistryEntryList, val amount: Long constructor(fluid: Fluid, amount: Long = FluidConstants.BUCKET) : this(RegistryEntryList.direct(fluid), amount) + /** + * この素材が有効かどうか判定します。 + */ val isEmpty: Boolean get() = entryList.isEmpty || amount <= 0 diff --git a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt index e8e8e60..5b32876 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/ItemIngredient.kt @@ -11,6 +11,11 @@ import net.minecraft.recipe.Ingredient import net.minecraft.tag.Tag import java.util.function.Predicate +/** + * 個数を受け取る[Ingredient]のクラスです。 + * @param entryList 条件に一致するアイテムのリスト + * @param count 必要な個数 + */ class ItemIngredient(val entryList: RegistryEntryList, val count: Int = 1) : Predicate { companion object { @JvmField @@ -32,9 +37,15 @@ class ItemIngredient(val entryList: RegistryEntryList, val count: Int = 1) constructor(item: Item, count: Int = 1) : this(RegistryEntryList.direct(item), count) + /** + * この素材が有効かどうか判定します。 + */ val isEmpty: Boolean get() = entryList.isEmpty || count <= 0 + /** + * この素材をバニラの[Ingredient]に変換します。 + */ val vanillaIngredient: Ingredient get() = when (isEmpty) { true -> Ingredient.EMPTY diff --git a/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt b/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt index ce0d394..4df8ba0 100644 --- a/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt +++ b/src/main/kotlin/dev/robustum/core/recipe/RecipeCodec.kt @@ -4,6 +4,14 @@ import com.mojang.serialization.MapCodec import net.minecraft.recipe.Recipe import net.minecraft.util.Identifier +/** + * レシピの[MapCodec]を提供するインターフェースです。 + * @param T レシピのクラス + */ fun interface RecipeCodec> { + /** + * 指定された[id]をコンストラクタに渡すような[MapCodec]を返します。 + * @see RobustumRecipeSerializers + */ fun createCodec(id: Identifier): MapCodec } diff --git a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt index 9c34f66..866f197 100644 --- a/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt +++ b/src/main/kotlin/dev/robustum/core/tag/RobustumTagEvents.kt @@ -13,7 +13,9 @@ import java.util.function.BiConsumer object RobustumTagEvents { /** - * [net.minecraft.tag.TagGroupLoader.prepareReload]の最後で呼び出される + * 動的に[Tag]を登録するイベントです。 + * + * [net.minecraft.tag.TagGroupLoader.prepareReload]の最後で呼び出されます。 */ @JvmField val REGISTER: Event = @@ -22,7 +24,9 @@ object RobustumTagEvents { } /** - * [net.minecraft.tag.ServerTagManagerHolder.setTagManager],[net.minecraft.client.network.ClientPlayNetworkHandler.onSynchronizeTags]の最後でそれぞれ呼び出される + * [TagManager]がリロードされた時に呼び出されるイベントです。 + * + * [net.minecraft.tag.ServerTagManagerHolder.setTagManager],[net.minecraft.client.network.ClientPlayNetworkHandler.onSynchronizeTags]の最後でそれぞれ呼び出されます。 */ @JvmField val RELOAD: Event = EventFactory.createArrayBacked(Reload::class.java) { callbacks: Array -> @@ -38,14 +42,15 @@ object RobustumTagEvents { // Helper // /** + * 動的なタグの登録を補助するクラスです。 * @param registry 現在のレジストリ - * @param consumer 渡されたタグの[Identifier]とそのエントリ[Tag.Entry]を受け取る + * @param consumer 渡されたタグの[Identifier]とそのエントリ[Tag.Entry]を受け取るブロック */ class Helper(private val registry: Registry<*>, private val consumer: BiConsumer) { /** + * [Tag]から[Identifier]を取得して登録します。 * @param registryKey 登録しようとしているレジストリのキー - * @param tag 登録しようとしているタグ,[Tag.Identified]を実装している必要がある - * @param values 指定したタグに紐づけようとしている値 + * @param tag [Tag.Identified]を実装している必要があります。 */ fun add(registryKey: RegistryKey>, tag: Tag, vararg values: T) { val tagId: Identifier = tag.idOrNull ?: return @@ -53,9 +58,8 @@ object RobustumTagEvents { } /** + * [tagId]に[values]を登録します。 * @param registryKey 登録しようとしているレジストリのキー - * @param tagId 登録しようとしているタグの[Identifier] - * @param values 指定したタグに紐づけようとしている値 */ @Suppress("UNCHECKED_CAST") fun add(registryKey: RegistryKey>, tagId: Identifier, vararg values: T) { @@ -71,14 +75,10 @@ object RobustumTagEvents { // Reload // - /** - * @see [net.minecraft.tag.ServerTagManagerHolder.setTagManager] - * @see [net.minecraft.client.network.ClientPlayNetworkHandler.onSynchronizeTags] - */ fun interface Reload { /** * @param manager 各サイドにおける[TagManager] - * @param environment 各サイドにおける[EnvType] + * @param environment [net.minecraft.tag.ServerTagManagerHolder]では[EnvType.SERVER],[net.minecraft.client.network.ClientPlayNetworkHandler.onSynchronizeTags]では[EnvType.CLIENT] */ fun onReload(manager: TagManager, environment: EnvType) } diff --git a/src/test/kotlin/test/codec/TestRobustumCodecs.kt b/src/test/kotlin/test/codec/TestRobustumCodecs.kt index 8fa922f..5100cc1 100644 --- a/src/test/kotlin/test/codec/TestRobustumCodecs.kt +++ b/src/test/kotlin/test/codec/TestRobustumCodecs.kt @@ -24,8 +24,7 @@ class TestRobustumCodecs { } @Test - fun testCodecs() { - // block + fun testBlock() { RobustumCodecs.BLOCK .encodeStart(JsonOps.INSTANCE, Blocks.STONE) .onSucceeded { it.asString shouldBe "minecraft:stone" } @@ -34,7 +33,10 @@ class TestRobustumCodecs { RobustumCodecs.BLOCK .encodeStart(JsonOps.INSTANCE, Blocks.AIR) .onErrored { it shouldBe "Block must not be minecraft:air" } - // item + } + + @Test + fun testItem() { RobustumCodecs.ITEM .encodeStart(JsonOps.INSTANCE, Items.IRON_INGOT) .onSucceeded { it.asString shouldBe "minecraft:iron_ingot" } @@ -43,7 +45,9 @@ class TestRobustumCodecs { RobustumCodecs.ITEM .encodeStart(JsonOps.INSTANCE, Items.AIR) .onErrored { it shouldBe "Item must not be minecraft:air" } - // item stack + } + + fun testItemStack() { RobustumCodecs.ITEM_STACK .encodeStart(JsonOps.INSTANCE, ItemStack(Items.IRON_INGOT, 4)) .onSucceeded { @@ -57,7 +61,10 @@ class TestRobustumCodecs { .encodeStart(JsonOps.INSTANCE, ItemStack.EMPTY) .onSucceeded { it shouldBe JsonOps.INSTANCE.emptyMap() } .onErrored(::error) - // ingredient (and registry entry list) + } + + @Test + fun testIngredient() { RobustumCodecs.INGREDIENT .encodeStart(JsonOps.INSTANCE, Ingredient.ofItems(Items.DIAMOND)) .onSucceeded { it.asString shouldBe "minecraft:diamond" } diff --git a/src/test/kotlin/test/recipe/TestRobustumRecipes.kt b/src/test/kotlin/test/recipe/TestRobustumRecipes.kt index 1b934a4..93420df 100644 --- a/src/test/kotlin/test/recipe/TestRobustumRecipes.kt +++ b/src/test/kotlin/test/recipe/TestRobustumRecipes.kt @@ -23,7 +23,7 @@ class TestRobustumRecipes { } @Test - fun testRecipes() { + fun testRecipe() { RobustumRecipeSerializers.SMELTING .write( JsonOps.INSTANCE, diff --git a/src/test/kotlin/test/registry/TestRobustumRegistries.kt b/src/test/kotlin/test/registry/TestRobustumRegistries.kt index cecdddd..ef3465f 100644 --- a/src/test/kotlin/test/registry/TestRobustumRegistries.kt +++ b/src/test/kotlin/test/registry/TestRobustumRegistries.kt @@ -20,7 +20,7 @@ class TestRobustumRegistries { } @Test - fun testRegistries() { + fun testRegistry() { // lookup RegistryLookup.BLOCK .getId(Blocks.STONE) From 4c7e7c6cfa4179872de31d440fe15dfb016401c7 Mon Sep 17 00:00:00 2001 From: Hiiragi Russell Tsubasa <97942736+Hiiragi283@users.noreply.github.com> Date: Tue, 17 Dec 2024 20:56:07 +0900 Subject: [PATCH 27/27] =?UTF-8?q?=E6=AC=A0=E3=81=91=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=9F@Test=E3=82=A2=E3=83=8E=E3=83=86=E3=83=BC=E3=82=B7?= =?UTF-8?q?=E3=83=A7=E3=83=B3=E3=82=92TestRobustumCodecs.testItemStack?= =?UTF-8?q?=E3=81=AB=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/kotlin/test/codec/TestRobustumCodecs.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/kotlin/test/codec/TestRobustumCodecs.kt b/src/test/kotlin/test/codec/TestRobustumCodecs.kt index 5100cc1..6b74ddf 100644 --- a/src/test/kotlin/test/codec/TestRobustumCodecs.kt +++ b/src/test/kotlin/test/codec/TestRobustumCodecs.kt @@ -47,6 +47,7 @@ class TestRobustumCodecs { .onErrored { it shouldBe "Item must not be minecraft:air" } } + @Test fun testItemStack() { RobustumCodecs.ITEM_STACK .encodeStart(JsonOps.INSTANCE, ItemStack(Items.IRON_INGOT, 4))