From c82be3092b06db4704312baef070956dd81cf980 Mon Sep 17 00:00:00 2001 From: 90 Date: Tue, 29 Aug 2023 17:19:03 +0100 Subject: [PATCH] Bring back old multipliers but pad the overall chain to fix bugs The longs approach was a fucking disaster --- .../megacells/datagen/CommonTagProvider.java | 22 +- .../_90/megacells/definition/MEGATags.java | 3 + .../item/cell/BulkCellInventory.java | 16 +- .../megacells/service/CompressionService.java | 200 ++++++++++++------ .../service/DecompressionService.java | 2 +- .../megacells/datagen/MEGADataGenerators.java | 4 +- .../megacells/datagen/MEGADataGenerators.java | 4 +- 7 files changed, 159 insertions(+), 92 deletions(-) diff --git a/common/src/data/java/gripe/_90/megacells/datagen/CommonTagProvider.java b/common/src/data/java/gripe/_90/megacells/datagen/CommonTagProvider.java index cee72b78..6314518b 100644 --- a/common/src/data/java/gripe/_90/megacells/datagen/CommonTagProvider.java +++ b/common/src/data/java/gripe/_90/megacells/datagen/CommonTagProvider.java @@ -8,7 +8,8 @@ import net.minecraft.data.PackOutput; import net.minecraft.data.tags.IntrinsicHolderTagsProvider; import net.minecraft.data.tags.ItemTagsProvider; -import net.minecraft.tags.BlockTags; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; import appeng.api.features.P2PTunnelAttunement; @@ -18,8 +19,8 @@ import gripe._90.megacells.definition.MEGATags; public class CommonTagProvider { - public static class Items extends ItemTagsProvider { - public Items( + public static class ItemTags extends ItemTagsProvider { + public ItemTags( PackOutput output, CompletableFuture registries, CompletableFuture> blockTags) { @@ -36,11 +37,20 @@ protected void addTags(HolderLookup.Provider provider) { tag(MEGATags.MEGA_PATTERN_PROVIDER) .add(MEGABlocks.MEGA_PATTERN_PROVIDER.asItem()) .add(MEGAItems.MEGA_PATTERN_PROVIDER.asItem()); + + tag(MEGATags.COMPRESSION_OVERRIDES) + .add(Items.QUARTZ) + .add(Items.AMETHYST_SHARD) + .add(Items.GLOWSTONE_DUST) + .add(Items.CLAY_BALL) + .add(Items.MELON_SLICE) + .add(Items.MAGMA_CREAM) + .addOptionalTag(new ResourceLocation("functionalstorage", "ignore_crafting_check")); } } - public static class Blocks extends IntrinsicHolderTagsProvider { - public Blocks(PackOutput packOutput, CompletableFuture registries) { + public static class BlockTags extends IntrinsicHolderTagsProvider { + public BlockTags(PackOutput packOutput, CompletableFuture registries) { super(packOutput, Registries.BLOCK, registries, block -> BuiltInRegistries.BLOCK .getResourceKey(block) .orElseThrow()); @@ -49,7 +59,7 @@ public Blocks(PackOutput packOutput, CompletableFuture re @Override protected void addTags(HolderLookup.Provider provider) { for (var block : MEGABlocks.getBlocks()) { - tag(BlockTags.MINEABLE_WITH_PICKAXE).add(block.block()); + tag(net.minecraft.tags.BlockTags.MINEABLE_WITH_PICKAXE).add(block.block()); } tag(MEGATags.SKY_STEEL_BLOCK).add(MEGABlocks.SKY_STEEL_BLOCK.block()); diff --git a/common/src/main/java/gripe/_90/megacells/definition/MEGATags.java b/common/src/main/java/gripe/_90/megacells/definition/MEGATags.java index 1b27627f..bb01379e 100644 --- a/common/src/main/java/gripe/_90/megacells/definition/MEGATags.java +++ b/common/src/main/java/gripe/_90/megacells/definition/MEGATags.java @@ -27,4 +27,7 @@ public final class MEGATags { public static final TagKey MEGA_PATTERN_PROVIDER = TagKey.create(Registries.ITEM, MEGACells.makeId("mega_pattern_provider")); + + public static final TagKey COMPRESSION_OVERRIDES = + TagKey.create(Registries.ITEM, MEGACells.makeId("compression_overrides")); } diff --git a/common/src/main/java/gripe/_90/megacells/item/cell/BulkCellInventory.java b/common/src/main/java/gripe/_90/megacells/item/cell/BulkCellInventory.java index 6648bb4c..13123ef3 100644 --- a/common/src/main/java/gripe/_90/megacells/item/cell/BulkCellInventory.java +++ b/common/src/main/java/gripe/_90/megacells/item/cell/BulkCellInventory.java @@ -24,7 +24,6 @@ import appeng.api.storage.cells.CellState; import appeng.api.storage.cells.ISaveProvider; import appeng.api.storage.cells.StorageCell; -import appeng.util.prioritylist.IPartitionList; import gripe._90.megacells.item.MEGABulkCell; import gripe._90.megacells.service.CompressionService; @@ -38,7 +37,6 @@ public class BulkCellInventory implements StorageCell { private AEItemKey storedItem; private final AEItemKey filterItem; - private final IPartitionList partitionList; private final Object2IntMap compressed; private final Object2IntMap decompressed; @@ -53,13 +51,7 @@ public BulkCellInventory(MEGABulkCell cell, ItemStack o, ISaveProvider container this.i = o; this.container = container; - var config = cell.getConfigInventory(i); - this.filterItem = (AEItemKey) config.getKey(0); - - var builder = IPartitionList.builder(); - builder.addAll(config.keySet()); - this.partitionList = builder.build(); - + this.filterItem = (AEItemKey) cell.getConfigInventory(i).getKey(0); this.compressed = CompressionService.getVariants(filterItem, false); this.decompressed = CompressionService.getVariants(filterItem, true); this.unitFactor = decompressed.values().intStream().asLongStream().reduce(1, Math::multiplyExact); @@ -125,12 +117,12 @@ public long insert(AEKey what, long amount, Actionable mode, IActionSource sourc return 0; } - if (!compressionEnabled && (!partitionList.isListed(what) || storedItem != null && !storedItem.equals(what))) { + if (!compressionEnabled && (!filterItem.equals(what) || storedItem != null && !storedItem.equals(what))) { return 0; } if (compressionEnabled - && !partitionList.isListed(what) + && !filterItem.equals(what) && !compressed.containsKey(item) && !decompressed.containsKey(item)) { return 0; @@ -288,7 +280,7 @@ public void getAvailableStacks(KeyCounter out) { @Override public boolean isPreferredStorageFor(AEKey what, IActionSource source) { return what instanceof AEItemKey item - && (partitionList.isListed(item) || compressed.containsKey(item) || decompressed.containsKey(item)); + && (filterItem.equals(what) || compressed.containsKey(item) || decompressed.containsKey(item)); } @Override diff --git a/common/src/main/java/gripe/_90/megacells/service/CompressionService.java b/common/src/main/java/gripe/_90/megacells/service/CompressionService.java index 8ee04212..8ab4a2fb 100644 --- a/common/src/main/java/gripe/_90/megacells/service/CompressionService.java +++ b/common/src/main/java/gripe/_90/megacells/service/CompressionService.java @@ -1,9 +1,13 @@ package gripe._90.megacells.service; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; @@ -13,19 +17,26 @@ import net.minecraft.core.RegistryAccess; import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.CraftingRecipe; import net.minecraft.world.item.crafting.RecipeManager; import net.minecraft.world.item.crafting.RecipeType; import appeng.api.stacks.AEItemKey; +import gripe._90.megacells.definition.MEGATags; + public class CompressionService { - // Each chain is an ordered map with the items themselves as the keys and the values being the amount of either: - // - the item itself, needed to compress to its next variant - // - the next variant, when decompressing the item - // This value is typically either 4 or 9 for any given item. + // Each chain is an ordered map with the items themselves as the keys and the values being how much of the smallest + // "unit" item in the chain makes up each subsequent variant item. + // e.g. 1 nugget -> 9 nuggets per ingot -> 81 nuggets per block -> etc. private static final Set> compressionChains = new ObjectLinkedOpenHashSet<>(); + // It may be desirable for some items to be included as variants in a chain in spite of any recipes involving those + // items not being reversible. Hence, we override any reversibility checks and generate a variant for such an item + // based on its usually irreversible recipe. + private static final Set overrides = new ObjectLinkedOpenHashSet<>(); + public static Optional> getChain(AEItemKey key) { return compressionChains.stream() .filter(chain -> chain.containsKey(key)) @@ -43,9 +54,14 @@ public static Object2IntMap getVariants(AEItemKey key, boolean decomp } // Split variant chain into separate compressed/decompressed chains, omitting the initial variant - // provided + // provided but retaining the appropriate multipliers in the case of decompression var variants = new Object2IntLinkedOpenHashMap(); - keys.subList(keys.indexOf(key) + 1, keys.size()).forEach(k -> variants.put(k, chain.getInt(k))); + + for (var i = keys.indexOf(key) + 1; i < keys.size(); i++) { + var multiplierIndex = i - (decompress ? 1 : 0); + variants.put(keys.get(i), chain.getInt(keys.get(multiplierIndex))); + } + return variants; }) .orElseGet(Object2IntLinkedOpenHashMap::new); @@ -54,6 +70,7 @@ public static Object2IntMap getVariants(AEItemKey key, boolean decomp public static void loadRecipes(RecipeManager recipeManager, RegistryAccess access) { // Clear old variant cache in case of the server restarting or recipes being reloaded compressionChains.clear(); + overrides.clear(); // Retrieve all available "compression" and "decompression" recipes from the current server's recipe manager var allRecipes = recipeManager.getAllRecipesFor(RecipeType.CRAFTING); @@ -74,33 +91,119 @@ public static void loadRecipes(RecipeManager recipeManager, RegistryAccess acces .toList(); // Pull all available compression chains from the recipe shortlist and add these to the cache - for (var recipe : compressed) { + for (var recipe : + Stream.concat(compressed.stream(), decompressed.stream()).toList()) { var baseVariant = recipe.getResultItem(access).getItem(); if (compressionChains.stream().noneMatch(chain -> chain.containsKey(AEItemKey.of(baseVariant)))) { - var newChain = generateChain(baseVariant, compressed, decompressed, access); + compressionChains.add(generateChain(baseVariant, compressed, decompressed, access)); + } + } + } + + private static Object2IntMap generateChain( + Item baseVariant, + List compressed, + List decompressed, + RegistryAccess access) { + var variants = new LinkedList(); + var multipliers = new LinkedList(); + + variants.addFirst(AEItemKey.of(baseVariant)); + + for (var lower = getNextVariant(baseVariant, decompressed, false, access); lower != null; ) { + variants.addFirst(AEItemKey.of(lower.key())); + multipliers.addFirst(lower.value()); + lower = getNextVariant(lower.key(), decompressed, false, access); + } + + multipliers.addFirst(1); + + var chain = IntStream.range(0, variants.size()) + .boxed() + .collect(Collectors.toMap( + variants::get, multipliers::get, (i, j) -> i, Object2IntLinkedOpenHashMap::new)); + + for (var higher = getNextVariant(baseVariant, compressed, true, access); higher != null; ) { + chain.put(AEItemKey.of(higher.key()), (int) higher.value()); + higher = getNextVariant(higher.key(), compressed, true, access); + } - if (!newChain.isEmpty()) { - compressionChains.add(newChain); + return chain; + } + + private static Pair getNextVariant( + Item item, List recipes, boolean compressed, RegistryAccess access) { + for (var override : overrides) { + if (override.smaller.equals(item) && compressed) { + return Pair.of(override.larger, override.factor); + } + + if (override.larger.equals(item) && !compressed) { + return Pair.of(override.smaller, override.factor); + } + } + + for (var recipe : recipes) { + for (var input : recipe.getIngredients().get(0).getItems()) { + if (input.getItem().equals(item)) { + return Pair.of( + recipe.getResultItem(access).getItem(), + compressed + ? recipe.getIngredients().size() + : recipe.getResultItem(access).getCount()); } } } + + return null; + } + + private static boolean isDecompressionRecipe(CraftingRecipe recipe, RegistryAccess access) { + return recipe.getIngredients().size() == 1 + && Set.of(4, 9).contains(recipe.getResultItem(access).getCount()); } private static boolean isCompressionRecipe(CraftingRecipe recipe, RegistryAccess access) { - return (recipe.getIngredients().size() == 4 || recipe.getIngredients().size() == 9) - && recipe.getIngredients().stream().distinct().count() <= 1 - && recipe.getResultItem(access).getCount() == 1; + return sameIngredient(recipe) + && recipe.getResultItem(access).getCount() == 1 + && Set.of(4, 9).contains(recipe.getIngredients().size()); } - private static boolean isDecompressionRecipe(CraftingRecipe recipe, RegistryAccess access) { - return (recipe.getResultItem(access).getCount() == 4 - || recipe.getResultItem(access).getCount() == 9) - && recipe.getIngredients().size() == 1; + // All this for some fucking melons. + private static boolean sameIngredient(CraftingRecipe recipe) { + var ingredients = new ObjectArrayList<>(recipe.getIngredients()); + + if (ingredients.isEmpty()) { + return false; + } + + var first = ingredients.remove(0).getItems(); + if (first.length == 0) return false; + + for (var ingredient : ingredients) { + var stacks = ingredient.getItems(); + + if (stacks.length != first.length) { + return false; + } + + for (var i = 0; i < stacks.length; i++) { + if (!ItemStack.isSameItemSameTags(stacks[i], first[i])) { + return false; + } + } + } + + return true; } private static boolean isReversibleRecipe( CraftingRecipe recipe, List candidates, RegistryAccess access) { + if (overrideRecipe(recipe, access)) { + return true; + } + var compressible = false; var decompressible = false; @@ -126,61 +229,20 @@ private static boolean isReversibleRecipe( return false; } - private static Object2IntMap generateChain( - Item baseVariant, - List compressed, - List decompressed, - RegistryAccess access) { - var decompressionChain = new Object2IntLinkedOpenHashMap(); - - for (var lower = getNextVariant(baseVariant, decompressed, access); lower != null; ) { - decompressionChain.put(AEItemKey.of(lower.first()), (int) lower.second()); - lower = getNextVariant(lower.first(), decompressed, access); - } - - var compressionChain = new Object2IntLinkedOpenHashMap(); - - for (var higher = getNextVariant(baseVariant, compressed, access); higher != null; ) { - compressionChain.put(AEItemKey.of(higher.first()), (int) higher.second()); - higher = getNextVariant(higher.first(), compressed, access); - } - - // Collate decompression and compression chains together with base variant - var fullChain = new Object2IntLinkedOpenHashMap(); - - // In theory this shouldn't even be happening by this point - if (compressionChain.isEmpty() && decompressionChain.isEmpty()) return fullChain; + private static boolean overrideRecipe(CraftingRecipe recipe, RegistryAccess access) { + for (var item : recipe.getIngredients().get(0).getItems()) { + if (item.is(MEGATags.COMPRESSION_OVERRIDES)) { + var variant = recipe.getResultItem(access); + var compressed = isCompressionRecipe(recipe, access); + var factor = compressed ? recipe.getIngredients().size() : variant.getCount(); - // By default, full chains go from the smallest "unit" variant to the most compressed, so reverse the - // decompression chain and add it first - var decompressionKeys = new ObjectArrayList<>(decompressionChain.keySet()); - Collections.reverse(decompressionKeys); - decompressionKeys.forEach(k -> fullChain.put(k, decompressionChain.getInt(k))); - - // Retrieve appropriate multiplier for base variant for completion's sake - fullChain.put( - AEItemKey.of(baseVariant), - fullChain.isEmpty() - ? compressionChain.getInt(compressionChain.firstKey()) - : fullChain.getInt(fullChain.lastKey())); - - fullChain.putAll(compressionChain); - return fullChain; - } - - private static Pair getNextVariant(Item item, List recipes, RegistryAccess access) { - for (var recipe : recipes) { - for (var input : recipe.getIngredients().get(0).getItems()) { - if (input.getItem().equals(item)) { - return Pair.of( - recipe.getResultItem(access).getItem(), - isCompressionRecipe(recipe, access) - ? recipe.getIngredients().size() - : recipe.getResultItem(access).getCount()); - } + overrides.add(new Override(item.getItem(), variant.getItem(), compressed, factor)); + return true; } } - return null; + return false; } + + private record Override(Item smaller, Item larger, boolean compressed, int factor) {} } diff --git a/common/src/main/java/gripe/_90/megacells/service/DecompressionService.java b/common/src/main/java/gripe/_90/megacells/service/DecompressionService.java index c85a630d..945a84b1 100644 --- a/common/src/main/java/gripe/_90/megacells/service/DecompressionService.java +++ b/common/src/main/java/gripe/_90/megacells/service/DecompressionService.java @@ -88,7 +88,7 @@ public Set getDecompressionPatterns(Object2IntMap compress var pattern = new ItemStack(MEGAItems.DECOMPRESSION_PATTERN); var decompressed = variants.get(variants.indexOf(variant) + 1); - var factor = compressionChain.getInt(decompressed); + var factor = compressionChain.getInt(variant); DecompressionPatternEncoding.encode(pattern.getOrCreateTag(), variant, decompressed, factor); patterns.add(AEItemKey.of(pattern)); diff --git a/fabric/src/data/java/gripe/_90/megacells/datagen/MEGADataGenerators.java b/fabric/src/data/java/gripe/_90/megacells/datagen/MEGADataGenerators.java index 3003ca5d..949269b6 100644 --- a/fabric/src/data/java/gripe/_90/megacells/datagen/MEGADataGenerators.java +++ b/fabric/src/data/java/gripe/_90/megacells/datagen/MEGADataGenerators.java @@ -14,9 +14,9 @@ public void onInitializeDataGenerator(FabricDataGenerator generator) { var pack = generator.createPack(); var registries = CompletableFuture.supplyAsync(VanillaRegistries::createLookup, Util.backgroundExecutor()); - var blockTags = pack.addProvider((FabricDataOutput output) -> new CommonTagProvider.Blocks(output, registries)); + var blocks = pack.addProvider((FabricDataOutput output) -> new CommonTagProvider.BlockTags(output, registries)); pack.addProvider((FabricDataOutput output) -> - new CommonTagProvider.Items(output, registries, blockTags.contentsGetter())); + new CommonTagProvider.ItemTags(output, registries, blocks.contentsGetter())); pack.addProvider(ModelProvider::new); pack.addProvider(RecipeProvider::new); diff --git a/forge/src/data/java/gripe/_90/megacells/datagen/MEGADataGenerators.java b/forge/src/data/java/gripe/_90/megacells/datagen/MEGADataGenerators.java index 0689ae3b..32fd4e2d 100644 --- a/forge/src/data/java/gripe/_90/megacells/datagen/MEGADataGenerators.java +++ b/forge/src/data/java/gripe/_90/megacells/datagen/MEGADataGenerators.java @@ -19,8 +19,8 @@ public static void onGatherData(GatherDataEvent event) { var existing = event.getExistingFileHelper(); var registries = CompletableFuture.supplyAsync(VanillaRegistries::createLookup, Util.backgroundExecutor()); - var blockTags = pack.addProvider(output -> new CommonTagProvider.Blocks(output, registries)); - pack.addProvider(output -> new CommonTagProvider.Items(output, registries, blockTags.contentsGetter())); + var blockTags = pack.addProvider(output -> new CommonTagProvider.BlockTags(output, registries)); + pack.addProvider(output -> new CommonTagProvider.ItemTags(output, registries, blockTags.contentsGetter())); pack.addProvider(output -> new ModelProvider.Items(output, existing)); pack.addProvider(output -> new ModelProvider.Blocks(output, existing));