From 87fe6c4ea384962cab0044869def443167c02730 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 12:08:36 +0000 Subject: [PATCH 1/6] Initial plan From 62b7781440bb76d33b87be395e9d749772e832da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 12:13:56 +0000 Subject: [PATCH 2/6] feat: summarize version differences and address review items Agent-Logs-Url: https://github.com/P-nutsK/ReplicatedIntegration/sessions/d3fdb185-e5ea-4d85-b1d6-fc4fdebbc1d2 Co-authored-by: P-nutsK <107553542+P-nutsK@users.noreply.github.com> --- .../adapter/vanilla/BuiltinNodeResolver.kt | 48 +++++++++-- .../client/MatterIndexScreen.kt | 14 ++-- .../adapter/vanilla/BuiltinNodeResolver.kt | 48 +++++++++-- .../client/MatterIndexScreen.kt | 19 +++-- .../selector/MatterSelectorMaterializer.kt | 7 +- .../selector/MatterSelectorStorageCodec.kt | 4 +- .../api/selector/MutableMatterSelectors.kt | 7 +- .../test/kotlin/MatterSelectorOrderingTest.kt | 81 +++++++++++++++++++ docs/1.20.1-1.21.1-spec-differences.md | 33 ++++++++ 9 files changed, 229 insertions(+), 32 deletions(-) create mode 100644 common/src/test/kotlin/MatterSelectorOrderingTest.kt create mode 100644 docs/1.20.1-1.21.1-spec-differences.md diff --git a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index 00296ea..96b4632 100644 --- a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -11,9 +11,17 @@ import net.minecraft.tags.TagKey import net.minecraft.world.item.ItemStack import net.minecraftforge.fluids.FluidStack import net.minecraftforge.registries.ForgeRegistries +import java.util.concurrent.ConcurrentHashMap @Suppress("unused") object BuiltinNodeResolver { + private val itemNodesByMod = ConcurrentHashMap>() + private val fluidNodesByMod = ConcurrentHashMap>() + private var itemNodeCacheSize = -1 + private var fluidNodeCacheSize = -1 + private var allItemNodesCache: List = emptyList() + private var allFluidNodesCache: List = emptyList() + fun itemNode(stack: ItemStack): NodeKey? { if (stack.isEmpty) { return null @@ -62,19 +70,24 @@ object BuiltinNodeResolver { .orElse(emptyList()) fun allItemNodes(): List = - BuiltInRegistries.ITEM - .map { item -> MatterNodes.item(BuiltInRegistries.ITEM.getKey(item).toLite()) } + refreshItemCacheIfNeeded().let { allItemNodesCache } fun allFluidNodes(): List = - BuiltInRegistries.FLUID - .filter { fluid -> fluid != net.minecraft.world.level.material.Fluids.EMPTY } - .map { fluid -> MatterNodes.fluid(BuiltInRegistries.FLUID.getKey(fluid).toLite()) } + refreshFluidCacheIfNeeded().let { allFluidNodesCache } fun itemNodesInMod(modId: String): List = - allItemNodes().filter { it.id.namespace == modId } + refreshItemCacheIfNeeded().let { + itemNodesByMod.computeIfAbsent(modId) { id -> + allItemNodesCache.filter { it.id.namespace == id } + } + } fun fluidNodesInMod(modId: String): List = - allFluidNodes().filter { it.id.namespace == modId } + refreshFluidCacheIfNeeded().let { + fluidNodesByMod.computeIfAbsent(modId) { id -> + allFluidNodesCache.filter { it.id.namespace == id } + } + } fun itemAmount(stack: ItemStack): NodeAmount? = itemNode(stack)?.let { NodeAmount(it, stack.count.coerceAtLeast(1).toLong()) } @@ -82,6 +95,27 @@ object BuiltinNodeResolver { fun fluidAmount(stack: FluidStack): NodeAmount? = fluidNode(stack)?.takeIf { stack.amount > 0 }?.let { NodeAmount(it, stack.amount.toLong()) } + private fun refreshItemCacheIfNeeded() { + val size = BuiltInRegistries.ITEM.size() + if (size != itemNodeCacheSize) { + itemNodeCacheSize = size + allItemNodesCache = BuiltInRegistries.ITEM.map { item -> MatterNodes.item(BuiltInRegistries.ITEM.getKey(item).toLite()) } + itemNodesByMod.clear() + } + } + + private fun refreshFluidCacheIfNeeded() { + val size = BuiltInRegistries.FLUID.size() + if (size != fluidNodeCacheSize) { + fluidNodeCacheSize = size + allFluidNodesCache = + BuiltInRegistries.FLUID + .filter { fluid -> fluid != net.minecraft.world.level.material.Fluids.EMPTY } + .map { fluid -> MatterNodes.fluid(BuiltInRegistries.FLUID.getKey(fluid).toLite()) } + fluidNodesByMod.clear() + } + } + private fun ResourceLocation.toLite(): LiteResourceLocation = LiteResourceLocation.of(namespace, path) diff --git a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/client/MatterIndexScreen.kt b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/client/MatterIndexScreen.kt index a27fcd1..f7126fa 100644 --- a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/client/MatterIndexScreen.kt +++ b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/client/MatterIndexScreen.kt @@ -27,6 +27,8 @@ class MatterIndexScreen( private val focusedItemId: String? = null, ) : Screen(Component.literal("Replication Index")) { private val entries: List = loadEntries() + private val entryRecords: List = entries.map { it.record } + private val entriesById: Map = entries.associateBy { it.record.itemId } private val matterTypes: List = entries .flatMap { it.record.matterValues.keys } @@ -487,18 +489,16 @@ class MatterIndexScreen( private fun visibleEntries(): List { val query = MatterIndexFiltering.parseQuery(searchBox.value, replicatableOnly, disintegratableOnly) - val ordered = MatterIndexFiltering.filterAndSort(entries.map { it.record }, query, sort, ::displayAmount) - val byId = entries.associateBy { it.record.itemId } - return ordered.mapNotNull { byId[it.itemId] } + val ordered = MatterIndexFiltering.filterAndSort(entryRecords, query, sort, ::displayAmount) + return ordered.mapNotNull { entriesById[it.itemId] } } private fun selectedEntry(): MatterIndexEntry? = - entries.firstOrNull { it.record.itemId == selectedItemId } + selectedItemId?.let { entriesById[it] } private fun equivalentEntries(): List { - val records = MatterIndexFiltering.equivalentRecords(entries.map { it.record }, selectedEntry()?.record, ::displayAmount) - val byId = entries.associateBy { it.record.itemId } - return records.mapNotNull { byId[it.itemId] } + val records = MatterIndexFiltering.equivalentRecords(entryRecords, selectedEntry()?.record, ::displayAmount) + return records.mapNotNull { entriesById[it.itemId] } } private fun columns(layout: Layout): Columns { diff --git a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index 5fad1cf..d0a5f64 100644 --- a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -10,8 +10,16 @@ import net.minecraft.resources.ResourceLocation import net.minecraft.tags.TagKey import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.fluids.FluidStack +import java.util.concurrent.ConcurrentHashMap object BuiltinNodeResolver { + private val itemNodesByMod = ConcurrentHashMap>() + private val fluidNodesByMod = ConcurrentHashMap>() + private var itemNodeCacheSize = -1 + private var fluidNodeCacheSize = -1 + private var allItemNodesCache: List = emptyList() + private var allFluidNodesCache: List = emptyList() + fun itemNode(stack: ItemStack): NodeKey? { if (stack.isEmpty) { return null @@ -60,19 +68,24 @@ object BuiltinNodeResolver { .orElse(emptyList()) fun allItemNodes(): List = - BuiltInRegistries.ITEM - .map { item -> MatterNodes.item(BuiltInRegistries.ITEM.getKey(item).toLite()) } + refreshItemCacheIfNeeded().let { allItemNodesCache } fun allFluidNodes(): List = - BuiltInRegistries.FLUID - .filter { fluid -> fluid != net.minecraft.world.level.material.Fluids.EMPTY } - .map { fluid -> MatterNodes.fluid(BuiltInRegistries.FLUID.getKey(fluid).toLite()) } + refreshFluidCacheIfNeeded().let { allFluidNodesCache } fun itemNodesInMod(modId: String): List = - allItemNodes().filter { it.id.namespace == modId } + refreshItemCacheIfNeeded().let { + itemNodesByMod.computeIfAbsent(modId) { id -> + allItemNodesCache.filter { it.id.namespace == id } + } + } fun fluidNodesInMod(modId: String): List = - allFluidNodes().filter { it.id.namespace == modId } + refreshFluidCacheIfNeeded().let { + fluidNodesByMod.computeIfAbsent(modId) { id -> + allFluidNodesCache.filter { it.id.namespace == id } + } + } fun itemAmount(stack: ItemStack): NodeAmount? = itemNode(stack)?.let { NodeAmount(it, stack.count.coerceAtLeast(1).toLong()) } @@ -80,6 +93,27 @@ object BuiltinNodeResolver { fun fluidAmount(stack: FluidStack): NodeAmount? = fluidNode(stack)?.takeIf { stack.amount > 0 }?.let { NodeAmount(it, stack.amount.toLong()) } + private fun refreshItemCacheIfNeeded() { + val size = BuiltInRegistries.ITEM.size() + if (size != itemNodeCacheSize) { + itemNodeCacheSize = size + allItemNodesCache = BuiltInRegistries.ITEM.map { item -> MatterNodes.item(BuiltInRegistries.ITEM.getKey(item).toLite()) } + itemNodesByMod.clear() + } + } + + private fun refreshFluidCacheIfNeeded() { + val size = BuiltInRegistries.FLUID.size() + if (size != fluidNodeCacheSize) { + fluidNodeCacheSize = size + allFluidNodesCache = + BuiltInRegistries.FLUID + .filter { fluid -> fluid != net.minecraft.world.level.material.Fluids.EMPTY } + .map { fluid -> MatterNodes.fluid(BuiltInRegistries.FLUID.getKey(fluid).toLite()) } + fluidNodesByMod.clear() + } + } + private fun ResourceLocation.toLite(): LiteResourceLocation = LiteResourceLocation.of(namespace, path) diff --git a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/client/MatterIndexScreen.kt b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/client/MatterIndexScreen.kt index ce41e8d..97a5921 100644 --- a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/client/MatterIndexScreen.kt +++ b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/client/MatterIndexScreen.kt @@ -27,6 +27,8 @@ class MatterIndexScreen( private val focusedItemId: String? = null, ) : Screen(Component.literal("Replication Index")) { private val entries: List = loadEntries() + private val entryRecords: List = entries.map { it.record } + private val entriesById: Map = entries.associateBy { it.record.itemId } private val matterTypes: List = entries .flatMap { it.record.matterValues.keys } @@ -89,6 +91,10 @@ class MatterIndexScreen( ) } + override fun tick() { + searchBox.tick() + } + override fun render(guiGraphics: GuiGraphics, mouseX: Int, mouseY: Int, partialTick: Float) { hoveredStack = ItemStack.EMPTY hoveredAmountTooltip = emptyList() @@ -566,19 +572,16 @@ class MatterIndexScreen( private fun visibleEntries(): List { val query = MatterIndexFiltering.parseQuery(searchBox.value, replicatableOnly, disintegratableOnly) - val ordered = MatterIndexFiltering.filterAndSort(entries.map { it.record }, query, sort, ::displayAmount) - val byId = entries.associateBy { it.record.itemId } - return ordered.mapNotNull { byId[it.itemId] } + val ordered = MatterIndexFiltering.filterAndSort(entryRecords, query, sort, ::displayAmount) + return ordered.mapNotNull { entriesById[it.itemId] } } private fun selectedEntry(): MatterIndexEntry? = - entries.firstOrNull { it.record.itemId == selectedItemId } + selectedItemId?.let { entriesById[it] } private fun equivalentEntries(): List { - val records = - MatterIndexFiltering.equivalentRecords(entries.map { it.record }, selectedEntry()?.record, ::displayAmount) - val byId = entries.associateBy { it.record.itemId } - return records.mapNotNull { byId[it.itemId] } + val records = MatterIndexFiltering.equivalentRecords(entryRecords, selectedEntry()?.record, ::displayAmount) + return records.mapNotNull { entriesById[it.itemId] } } private fun columns(layout: Layout): Columns { diff --git a/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MatterSelectorMaterializer.kt b/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MatterSelectorMaterializer.kt index be56c14..96f34c2 100644 --- a/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MatterSelectorMaterializer.kt +++ b/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MatterSelectorMaterializer.kt @@ -29,7 +29,12 @@ object MatterSelectorMaterializer { ): Map { val values = linkedMapOf() val expansion = MatterRuleExpansion(expandTag, expandMod, allNodes, rawValue) - for (rule in rules.sortedWith(compareBy { it.source.priority })) { + val orderedRules = + rules.withIndex().sortedWith( + compareBy> { it.value.source.priority } + .thenBy { it.index }, + ) + for ((_, rule) in orderedRules) { val targets = rule.selector.expand(expansion) for (target in targets) { values[target] = rule.value diff --git a/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MatterSelectorStorageCodec.kt b/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MatterSelectorStorageCodec.kt index 0fd7fbc..4bb88c4 100644 --- a/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MatterSelectorStorageCodec.kt +++ b/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MatterSelectorStorageCodec.kt @@ -92,7 +92,9 @@ object MatterSelectorStorageCodec { val root = JsonObject() val entries = JsonArray() for (rule in rules) { - val selector = rule.selector.staticKey ?: continue + val selector = + rule.selector.staticKey + ?: throw IllegalArgumentException("Cannot save non-static selector: ${rule.selector}") val value = rule.value val json = JsonObject() json.addProperty("selector", selector.kind.name.lowercase()) diff --git a/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MutableMatterSelectors.kt b/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MutableMatterSelectors.kt index bbef69d..36b9d55 100644 --- a/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MutableMatterSelectors.kt +++ b/common/src/main/kotlin/com/p_nsk/replicated_integration/api/selector/MutableMatterSelectors.kt @@ -41,7 +41,12 @@ class MutableMatterSelectors { fun snapshot(): Map { val values = linkedMapOf() - for (rule in rules.sortedWith(compareBy { it.source.priority })) { + val orderedRules = + rules.withIndex().sortedWith( + compareBy> { it.value.source.priority } + .thenBy { it.index }, + ) + for ((_, rule) in orderedRules) { val key = rule.selector.staticKey ?: continue values[key] = rule.value } diff --git a/common/src/test/kotlin/MatterSelectorOrderingTest.kt b/common/src/test/kotlin/MatterSelectorOrderingTest.kt new file mode 100644 index 0000000..f14e6a2 --- /dev/null +++ b/common/src/test/kotlin/MatterSelectorOrderingTest.kt @@ -0,0 +1,81 @@ +package com.p_nsk.replicated_integration.api + +import com.p_nsk.replicated_integration.api.model.ExplicitMatterSource +import com.p_nsk.replicated_integration.api.model.ExplicitMatterValue +import com.p_nsk.replicated_integration.api.model.LiteMatterCompound +import com.p_nsk.replicated_integration.api.model.LiteResourceLocation +import com.p_nsk.replicated_integration.api.node.NodeKey +import com.p_nsk.replicated_integration.api.selector.AnyMatterRuleSelector +import com.p_nsk.replicated_integration.api.selector.MatterRule +import com.p_nsk.replicated_integration.api.selector.MatterSelectorKey +import com.p_nsk.replicated_integration.api.selector.MatterSelectorKind +import com.p_nsk.replicated_integration.api.selector.MatterSelectorMaterializer +import com.p_nsk.replicated_integration.api.selector.MatterSelectorStorageCodec +import com.p_nsk.replicated_integration.api.selector.MutableMatterSelectors +import com.p_nsk.replicated_integration.api.selector.asRuleSelector +import java.nio.file.Files +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith + +class MatterSelectorOrderingTest { + @Test + fun materializerKeepsInsertionOrderForSamePriority() { + val type = LiteResourceLocation.of("replicated_integration", "item") + val id = LiteResourceLocation.of("minecraft", "stone") + val selector = MatterSelectorKey(MatterSelectorKind.NODE, type, id).asRuleSelector() + val firstValue = + ExplicitMatterValue.Set( + LiteMatterCompound(mapOf(LiteResourceLocation.of("replication", "earth") to 1.0)), + ExplicitMatterSource.CONFIG, + ) + val secondValue = + ExplicitMatterValue.Set( + LiteMatterCompound(mapOf(LiteResourceLocation.of("replication", "earth") to 2.0)), + ExplicitMatterSource.CONFIG, + ) + val rules = listOf(MatterRule(selector, firstValue), MatterRule(selector, secondValue)) + + val materialized = + MatterSelectorMaterializer.materialize( + rules, + expandTag = { _, _ -> emptyList() }, + ) + + assertEquals(secondValue, materialized[NodeKey(type, id)]) + } + + @Test + fun snapshotKeepsInsertionOrderForSamePriority() { + val type = LiteResourceLocation.of("replicated_integration", "item") + val id = LiteResourceLocation.of("minecraft", "stone") + val key = MatterSelectorKey(MatterSelectorKind.NODE, type, id) + val selectors = MutableMatterSelectors() + val firstCompound = LiteMatterCompound(mapOf(LiteResourceLocation.of("replication", "earth") to 1.0)) + val secondCompound = LiteMatterCompound(mapOf(LiteResourceLocation.of("replication", "earth") to 2.0)) + + selectors.put(key, firstCompound, ExplicitMatterSource.CONFIG) + selectors.put(key, secondCompound, ExplicitMatterSource.CONFIG) + + val snapshot = selectors.snapshot() + + assertEquals(ExplicitMatterValue.Set(secondCompound, ExplicitMatterSource.CONFIG), snapshot[key]) + } + + @Test + fun saveRulesRejectsNonStaticSelectors() { + val type = LiteResourceLocation.of("replicated_integration", "item") + val id = LiteResourceLocation.of("minecraft", "stone") + val staticSelector = MatterSelectorKey(MatterSelectorKind.NODE, type, id).asRuleSelector() + val rule = + MatterRule( + AnyMatterRuleSelector(listOf(staticSelector)), + ExplicitMatterValue.Deny(ExplicitMatterSource.CONFIG), + ) + val path = Files.createTempDirectory("repint").resolve("rules.json") + + assertFailsWith { + MatterSelectorStorageCodec.saveRules(path, listOf(rule)) + } + } +} diff --git a/docs/1.20.1-1.21.1-spec-differences.md b/docs/1.20.1-1.21.1-spec-differences.md new file mode 100644 index 0000000..dde939f --- /dev/null +++ b/docs/1.20.1-1.21.1-spec-differences.md @@ -0,0 +1,33 @@ +# 1.20.1 (Forge) と 1.21.1 (NeoForge) の仕様差分まとめ + +v0.2.0 リリース前の品質保証向けに、1.20.1 と 1.21.1 の実装差分を整理したメモです。 + +## ローダー / プラットフォーム + +- イベントバス: 1.20.1 は `net.minecraftforge.*` 系の Forge イベント、1.21.1 は `net.neoforged.*` 系の NeoForge イベント。 +- Reload hook: `AddReloadListenerEvent` は 1.21.1 で `net.neoforged.neoforge.event.AddReloadListenerEvent` に移動。 +- Fluid API: `FluidStack` が `net.minecraftforge.fluids.FluidStack` から `net.neoforged.neoforge.fluids.FluidStack` に変更。 +- Mod 検索: `ModList` が `net.minecraftforge.fml.ModList` から `net.neoforged.fml.ModList` に変更。 + +## Replication 連携差分 + +- `ReplicationCalculation.DEFAULT_MATTER_RECIPE` が 1.21.1 では `RecipeHolder` を保持。 +- `ReplicationCalculation.DEFAULT_MATTER_COMPOUND` のキーが文字列 ID から `Item` に変更。 +- `MatterCompound.serializeNBT` が 1.21.1 では `RegistryAccess` を要求。 +- Mixin でフックするメソッドが `calculateRecipes()` → `calculateRecipes(RegistryAccess)` に変更。 +- 1.21.1 ではサーバ起動前に `calculateRecipes(RegistryAccess)` が走る場合があるため、サーバ起動後に再計算するフックが必要。 +- `MatterValueRecipe` の JSON は 1.21.1 で `amount` フィールドを使用(独自 node-value JSON は従来通り `value`)。 +- Datapack のレシピパスが `recipes/...` から `data//recipe/...` に変更。 +- 共有タグが `forge:` から `c:` に変更。 + +## Mekanism 連携差分 + +- `mekanism.api.recipes.chemical.*` の複数クラスが 1.21.1 では `mekanism.api.recipes.*` 配下へ移動。 +- 圧縮レシピ判定: 1.20.1 は `ItemStackGasToItemStackRecipe` を使うが、1.21.1 では公開されないため `MekanismRecipeTypes.TYPE_COMPRESSING` を使用。 +- 化学溶解の出力: 1.20.1 は JEI 出力ラッパーの `chemicalStack` を参照、1.21.1 は `outputDefinition` で `ChemicalStack` を直接参照。 +- Rotary 関連は 1.21.1 API 名称に合わせ、fluid/chemical ベースの命名へ統一。 + +## 追加データ(1.21.1 側に持ち込み済み) + +- `data/replicated_integration/recipe/matter_values/c/tags/gems/fluorite.json` +- `data/replicated_integration/replicated_integration/matter_node_values/minecraft/fluids/water.json` From fa83ebc57f359118220e70ea5f7fa835ea1a9ef5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 12:15:02 +0000 Subject: [PATCH 3/6] style: wrap resolver cache formatting Agent-Logs-Url: https://github.com/P-nutsK/ReplicatedIntegration/sessions/d3fdb185-e5ea-4d85-b1d6-fc4fdebbc1d2 Co-authored-by: P-nutsK <107553542+P-nutsK@users.noreply.github.com> --- .../adapter/vanilla/BuiltinNodeResolver.kt | 9 +++++++-- .../adapter/vanilla/BuiltinNodeResolver.kt | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index 96b4632..a55ff9c 100644 --- a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -99,7 +99,10 @@ object BuiltinNodeResolver { val size = BuiltInRegistries.ITEM.size() if (size != itemNodeCacheSize) { itemNodeCacheSize = size - allItemNodesCache = BuiltInRegistries.ITEM.map { item -> MatterNodes.item(BuiltInRegistries.ITEM.getKey(item).toLite()) } + allItemNodesCache = + BuiltInRegistries.ITEM.map { item -> + MatterNodes.item(BuiltInRegistries.ITEM.getKey(item).toLite()) + } itemNodesByMod.clear() } } @@ -111,7 +114,9 @@ object BuiltinNodeResolver { allFluidNodesCache = BuiltInRegistries.FLUID .filter { fluid -> fluid != net.minecraft.world.level.material.Fluids.EMPTY } - .map { fluid -> MatterNodes.fluid(BuiltInRegistries.FLUID.getKey(fluid).toLite()) } + .map { fluid -> + MatterNodes.fluid(BuiltInRegistries.FLUID.getKey(fluid).toLite()) + } fluidNodesByMod.clear() } } diff --git a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index d0a5f64..f511947 100644 --- a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -97,7 +97,10 @@ object BuiltinNodeResolver { val size = BuiltInRegistries.ITEM.size() if (size != itemNodeCacheSize) { itemNodeCacheSize = size - allItemNodesCache = BuiltInRegistries.ITEM.map { item -> MatterNodes.item(BuiltInRegistries.ITEM.getKey(item).toLite()) } + allItemNodesCache = + BuiltInRegistries.ITEM.map { item -> + MatterNodes.item(BuiltInRegistries.ITEM.getKey(item).toLite()) + } itemNodesByMod.clear() } } @@ -109,7 +112,9 @@ object BuiltinNodeResolver { allFluidNodesCache = BuiltInRegistries.FLUID .filter { fluid -> fluid != net.minecraft.world.level.material.Fluids.EMPTY } - .map { fluid -> MatterNodes.fluid(BuiltInRegistries.FLUID.getKey(fluid).toLite()) } + .map { fluid -> + MatterNodes.fluid(BuiltInRegistries.FLUID.getKey(fluid).toLite()) + } fluidNodesByMod.clear() } } From 41bd062198bf96d151319da7245e3a3a481749da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 12:16:06 +0000 Subject: [PATCH 4/6] refactor: simplify resolver cache access Agent-Logs-Url: https://github.com/P-nutsK/ReplicatedIntegration/sessions/d3fdb185-e5ea-4d85-b1d6-fc4fdebbc1d2 Co-authored-by: P-nutsK <107553542+P-nutsK@users.noreply.github.com> --- .../adapter/vanilla/BuiltinNodeResolver.kt | 32 +++++++++++-------- .../adapter/vanilla/BuiltinNodeResolver.kt | 32 +++++++++++-------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index a55ff9c..22b436e 100644 --- a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -69,25 +69,29 @@ object BuiltinNodeResolver { } .orElse(emptyList()) - fun allItemNodes(): List = - refreshItemCacheIfNeeded().let { allItemNodesCache } + fun allItemNodes(): List { + refreshItemCacheIfNeeded() + return allItemNodesCache + } - fun allFluidNodes(): List = - refreshFluidCacheIfNeeded().let { allFluidNodesCache } + fun allFluidNodes(): List { + refreshFluidCacheIfNeeded() + return allFluidNodesCache + } - fun itemNodesInMod(modId: String): List = - refreshItemCacheIfNeeded().let { - itemNodesByMod.computeIfAbsent(modId) { id -> - allItemNodesCache.filter { it.id.namespace == id } - } + fun itemNodesInMod(modId: String): List { + refreshItemCacheIfNeeded() + return itemNodesByMod.computeIfAbsent(modId) { id -> + allItemNodesCache.filter { it.id.namespace == id } } + } - fun fluidNodesInMod(modId: String): List = - refreshFluidCacheIfNeeded().let { - fluidNodesByMod.computeIfAbsent(modId) { id -> - allFluidNodesCache.filter { it.id.namespace == id } - } + fun fluidNodesInMod(modId: String): List { + refreshFluidCacheIfNeeded() + return fluidNodesByMod.computeIfAbsent(modId) { id -> + allFluidNodesCache.filter { it.id.namespace == id } } + } fun itemAmount(stack: ItemStack): NodeAmount? = itemNode(stack)?.let { NodeAmount(it, stack.count.coerceAtLeast(1).toLong()) } diff --git a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index f511947..2c5daed 100644 --- a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -67,25 +67,29 @@ object BuiltinNodeResolver { } .orElse(emptyList()) - fun allItemNodes(): List = - refreshItemCacheIfNeeded().let { allItemNodesCache } + fun allItemNodes(): List { + refreshItemCacheIfNeeded() + return allItemNodesCache + } - fun allFluidNodes(): List = - refreshFluidCacheIfNeeded().let { allFluidNodesCache } + fun allFluidNodes(): List { + refreshFluidCacheIfNeeded() + return allFluidNodesCache + } - fun itemNodesInMod(modId: String): List = - refreshItemCacheIfNeeded().let { - itemNodesByMod.computeIfAbsent(modId) { id -> - allItemNodesCache.filter { it.id.namespace == id } - } + fun itemNodesInMod(modId: String): List { + refreshItemCacheIfNeeded() + return itemNodesByMod.computeIfAbsent(modId) { id -> + allItemNodesCache.filter { it.id.namespace == id } } + } - fun fluidNodesInMod(modId: String): List = - refreshFluidCacheIfNeeded().let { - fluidNodesByMod.computeIfAbsent(modId) { id -> - allFluidNodesCache.filter { it.id.namespace == id } - } + fun fluidNodesInMod(modId: String): List { + refreshFluidCacheIfNeeded() + return fluidNodesByMod.computeIfAbsent(modId) { id -> + allFluidNodesCache.filter { it.id.namespace == id } } + } fun itemAmount(stack: ItemStack): NodeAmount? = itemNode(stack)?.let { NodeAmount(it, stack.count.coerceAtLeast(1).toLong()) } From 45b527a319ff1a9b686338a58adf37f96eeefedc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 12:17:02 +0000 Subject: [PATCH 5/6] fix: synchronize resolver cache refresh Agent-Logs-Url: https://github.com/P-nutsK/ReplicatedIntegration/sessions/d3fdb185-e5ea-4d85-b1d6-fc4fdebbc1d2 Co-authored-by: P-nutsK <107553542+P-nutsK@users.noreply.github.com> --- .../adapter/vanilla/BuiltinNodeResolver.kt | 2 ++ .../adapter/vanilla/BuiltinNodeResolver.kt | 2 ++ 2 files changed, 4 insertions(+) diff --git a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index 22b436e..f105c11 100644 --- a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -99,6 +99,7 @@ object BuiltinNodeResolver { fun fluidAmount(stack: FluidStack): NodeAmount? = fluidNode(stack)?.takeIf { stack.amount > 0 }?.let { NodeAmount(it, stack.amount.toLong()) } + @Synchronized private fun refreshItemCacheIfNeeded() { val size = BuiltInRegistries.ITEM.size() if (size != itemNodeCacheSize) { @@ -111,6 +112,7 @@ object BuiltinNodeResolver { } } + @Synchronized private fun refreshFluidCacheIfNeeded() { val size = BuiltInRegistries.FLUID.size() if (size != fluidNodeCacheSize) { diff --git a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index 2c5daed..1bde293 100644 --- a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -97,6 +97,7 @@ object BuiltinNodeResolver { fun fluidAmount(stack: FluidStack): NodeAmount? = fluidNode(stack)?.takeIf { stack.amount > 0 }?.let { NodeAmount(it, stack.amount.toLong()) } + @Synchronized private fun refreshItemCacheIfNeeded() { val size = BuiltInRegistries.ITEM.size() if (size != itemNodeCacheSize) { @@ -109,6 +110,7 @@ object BuiltinNodeResolver { } } + @Synchronized private fun refreshFluidCacheIfNeeded() { val size = BuiltInRegistries.FLUID.size() if (size != fluidNodeCacheSize) { From e57e14d9ed06fc2418ccdfc49b4d7c2d073a4af1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 23 May 2026 12:17:56 +0000 Subject: [PATCH 6/6] fix: make resolver caches volatile Agent-Logs-Url: https://github.com/P-nutsK/ReplicatedIntegration/sessions/d3fdb185-e5ea-4d85-b1d6-fc4fdebbc1d2 Co-authored-by: P-nutsK <107553542+P-nutsK@users.noreply.github.com> --- .../adapter/vanilla/BuiltinNodeResolver.kt | 7 +++++++ .../adapter/vanilla/BuiltinNodeResolver.kt | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index f105c11..ec0506c 100644 --- a/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.20.1-forge/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -17,9 +17,16 @@ import java.util.concurrent.ConcurrentHashMap object BuiltinNodeResolver { private val itemNodesByMod = ConcurrentHashMap>() private val fluidNodesByMod = ConcurrentHashMap>() + @Volatile private var itemNodeCacheSize = -1 + + @Volatile private var fluidNodeCacheSize = -1 + + @Volatile private var allItemNodesCache: List = emptyList() + + @Volatile private var allFluidNodesCache: List = emptyList() fun itemNode(stack: ItemStack): NodeKey? { diff --git a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt index 1bde293..d7ff00c 100644 --- a/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt +++ b/1.21.1-neo/src/main/kotlin/com/p_nsk/replicated_integration/adapter/vanilla/BuiltinNodeResolver.kt @@ -15,9 +15,16 @@ import java.util.concurrent.ConcurrentHashMap object BuiltinNodeResolver { private val itemNodesByMod = ConcurrentHashMap>() private val fluidNodesByMod = ConcurrentHashMap>() + @Volatile private var itemNodeCacheSize = -1 + + @Volatile private var fluidNodeCacheSize = -1 + + @Volatile private var allItemNodesCache: List = emptyList() + + @Volatile private var allFluidNodesCache: List = emptyList() fun itemNode(stack: ItemStack): NodeKey? {