diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b35d7e57..afca303c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - Resources in the Grid that are autocraftable now display an orange backdrop and tooltip to indicate whether the resource is autocraftable at a glance. - Slots used in the Pattern Grid for pattern encoding and Crafting Grid crafting matrix slots now display an orange backdrop and tooltip to indicate whether the item is autocraftable at a glance. This checks patterns from your network and from your inventory. - Added help tooltip for filtering based on recipe items in the Crafting Grid. +- The crafting amount and crafting preview screens have been merged. Changing the amount will update the live preview. +- The numbers on the crafting preview screen are now compacted with units. +- When requesting autocrafting multiple resources at once, which can happen via a recipe mod, all the crafting requests are now listed on the side of the GUI. +- You can now request autocrafting from the Storage Monitor if the resource count reaches zero. ### Fixed diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreview.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreview.java new file mode 100644 index 000000000..e11e56a4f --- /dev/null +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreview.java @@ -0,0 +1,6 @@ +package com.refinedmods.refinedstorage.api.autocrafting; + +import java.util.List; + +public record AutocraftingPreview(AutocraftingPreviewType type, List items) { +} diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewItem.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewItem.java new file mode 100644 index 000000000..82919b373 --- /dev/null +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewItem.java @@ -0,0 +1,6 @@ +package com.refinedmods.refinedstorage.api.autocrafting; + +import com.refinedmods.refinedstorage.api.resource.ResourceKey; + +public record AutocraftingPreviewItem(ResourceKey resource, long available, long missing, long toCraft) { +} diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewProvider.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewProvider.java new file mode 100644 index 000000000..207a0d2fd --- /dev/null +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewProvider.java @@ -0,0 +1,11 @@ +package com.refinedmods.refinedstorage.api.autocrafting; + +import com.refinedmods.refinedstorage.api.resource.ResourceKey; + +import java.util.Optional; + +public interface AutocraftingPreviewProvider { + Optional getPreview(ResourceKey resource, long amount); + + boolean start(ResourceKey resource, long amount); +} diff --git a/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewType.java b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewType.java new file mode 100644 index 000000000..3d1832829 --- /dev/null +++ b/refinedstorage-autocrafting-api/src/main/java/com/refinedmods/refinedstorage/api/autocrafting/AutocraftingPreviewType.java @@ -0,0 +1,7 @@ +package com.refinedmods.refinedstorage.api.autocrafting; + +public enum AutocraftingPreviewType { + SUCCESS, + MISSING_RESOURCES +} + diff --git a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/RefinedStorageApi.java b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/RefinedStorageApi.java index a96e5fb72..73afb28de 100644 --- a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/RefinedStorageApi.java +++ b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/RefinedStorageApi.java @@ -7,6 +7,7 @@ import com.refinedmods.refinedstorage.api.network.energy.EnergyStorage; import com.refinedmods.refinedstorage.api.network.node.NetworkNode; import com.refinedmods.refinedstorage.api.network.security.SecurityPolicy; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.common.api.constructordestructor.ConstructorStrategyFactory; import com.refinedmods.refinedstorage.common.api.constructordestructor.DestructorStrategyFactory; @@ -46,6 +47,7 @@ import com.refinedmods.refinedstorage.common.api.wirelesstransmitter.WirelessTransmitterRangeModifier; import java.util.Collection; +import java.util.List; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; @@ -203,4 +205,6 @@ EnergyStorage asBlockItemEnergyStorage( boolean canPlaceNetworkNode(ServerPlayer player, Level level, BlockPos pos, BlockState state); Optional getPattern(ItemStack stack, Level level); + + void openCraftingPreview(List requests); } diff --git a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/RefinedStorageApiProxy.java b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/RefinedStorageApiProxy.java index 24c147598..267910bd2 100644 --- a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/RefinedStorageApiProxy.java +++ b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/RefinedStorageApiProxy.java @@ -7,6 +7,7 @@ import com.refinedmods.refinedstorage.api.network.energy.EnergyStorage; import com.refinedmods.refinedstorage.api.network.node.NetworkNode; import com.refinedmods.refinedstorage.api.network.security.SecurityPolicy; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.common.api.constructordestructor.ConstructorStrategyFactory; import com.refinedmods.refinedstorage.common.api.constructordestructor.DestructorStrategyFactory; @@ -46,6 +47,7 @@ import com.refinedmods.refinedstorage.common.api.wirelesstransmitter.WirelessTransmitterRangeModifier; import java.util.Collection; +import java.util.List; import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; @@ -401,6 +403,11 @@ public Optional getPattern(final ItemStack stack, final Level level) { return ensureLoaded().getPattern(stack, level); } + @Override + public void openCraftingPreview(final List requests) { + ensureLoaded().openCraftingPreview(requests); + } + private RefinedStorageApi ensureLoaded() { if (delegate == null) { throw new IllegalStateException("API not loaded yet"); diff --git a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/grid/Grid.java b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/grid/Grid.java index a493a55c0..e02e7412e 100644 --- a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/grid/Grid.java +++ b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/grid/Grid.java @@ -1,5 +1,6 @@ package com.refinedmods.refinedstorage.common.api.grid; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewProvider; import com.refinedmods.refinedstorage.api.grid.operations.GridOperations; import com.refinedmods.refinedstorage.api.grid.watcher.GridWatcher; import com.refinedmods.refinedstorage.api.storage.Actor; @@ -15,7 +16,7 @@ import org.apiguardian.api.API; @API(status = API.Status.STABLE, since = "2.0.0-milestone.3.0") -public interface Grid { +public interface Grid extends AutocraftingPreviewProvider { void addWatcher(GridWatcher watcher, Class actorType); void removeWatcher(GridWatcher watcher); diff --git a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/grid/view/PlatformGridResource.java b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/grid/view/PlatformGridResource.java index 0b062d6fd..2b692f2fb 100644 --- a/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/grid/view/PlatformGridResource.java +++ b/refinedstorage-common-api/src/main/java/com/refinedmods/refinedstorage/common/api/grid/view/PlatformGridResource.java @@ -3,6 +3,7 @@ import com.refinedmods.refinedstorage.api.grid.operations.GridExtractMode; import com.refinedmods.refinedstorage.api.grid.view.GridResource; import com.refinedmods.refinedstorage.api.grid.view.GridView; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.common.api.grid.GridScrollMode; import com.refinedmods.refinedstorage.common.api.grid.strategy.GridExtractionStrategy; import com.refinedmods.refinedstorage.common.api.grid.strategy.GridScrollingStrategy; @@ -47,6 +48,9 @@ void onScroll(GridScrollMode scrollMode, List getExtractionHints(ItemStack carriedStack, GridView view); + @Nullable + ResourceAmount getAutocraftingRequest(); + @Nullable @API(status = API.Status.INTERNAL) PlatformResourceKey getResourceForRecipeMods(); diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/AbstractClientModInitializer.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/AbstractClientModInitializer.java index c1cc720b8..30fd6efb1 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/AbstractClientModInitializer.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/AbstractClientModInitializer.java @@ -5,6 +5,8 @@ import com.refinedmods.refinedstorage.common.api.upgrade.UpgradeMapping; import com.refinedmods.refinedstorage.common.autocrafting.CrafterScreen; import com.refinedmods.refinedstorage.common.autocrafting.PatternGridScreen; +import com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingPreviewContainerMenu; +import com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingPreviewScreen; import com.refinedmods.refinedstorage.common.constructordestructor.ConstructorScreen; import com.refinedmods.refinedstorage.common.constructordestructor.DestructorScreen; import com.refinedmods.refinedstorage.common.content.Items; @@ -93,6 +95,15 @@ protected static void registerScreens(final ScreenRegistration registration) { registration.register(Menus.INSTANCE.getRelay(), RelayScreen::new); registration.register(Menus.INSTANCE.getDiskInterface(), DiskInterfaceScreen::new); registration.register(Menus.INSTANCE.getCrafter(), CrafterScreen::new); + registration.register(Menus.INSTANCE.getAutocraftingStorageMonitor(), + new ScreenConstructor() { + @Override + public AutocraftingPreviewScreen create(final AutocraftingPreviewContainerMenu menu, + final Inventory inventory, + final Component title) { + return new AutocraftingPreviewScreen(menu, inventory, title); + } + }); } protected static void registerAlternativeGridHints() { diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/AbstractModInitializer.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/AbstractModInitializer.java index 75373db79..b6b25841c 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/AbstractModInitializer.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/AbstractModInitializer.java @@ -121,6 +121,7 @@ import com.refinedmods.refinedstorage.common.storage.storageblock.StorageBlockLootItemFunction; import com.refinedmods.refinedstorage.common.storage.storagedisk.FluidStorageDiskItem; import com.refinedmods.refinedstorage.common.storage.storagedisk.ItemStorageDiskItem; +import com.refinedmods.refinedstorage.common.storagemonitor.AutocraftingStorageMonitorContainerMenu; import com.refinedmods.refinedstorage.common.storagemonitor.FluidStorageMonitorExtractionStrategy; import com.refinedmods.refinedstorage.common.storagemonitor.FluidStorageMonitorInsertionStrategy; import com.refinedmods.refinedstorage.common.storagemonitor.ItemStorageMonitorExtractionStrategy; @@ -136,6 +137,7 @@ import com.refinedmods.refinedstorage.common.support.network.component.PlatformStorageNetworkComponent; import com.refinedmods.refinedstorage.common.support.resource.FluidResourceContainerInsertStrategy; import com.refinedmods.refinedstorage.common.support.resource.FluidResourceFactory; +import com.refinedmods.refinedstorage.common.support.resource.ResourceCodecs; import com.refinedmods.refinedstorage.common.support.resource.ResourceContainerData; import com.refinedmods.refinedstorage.common.support.resource.ResourceTypes; import com.refinedmods.refinedstorage.common.support.slotreference.InventorySlotReferenceFactory; @@ -745,6 +747,13 @@ protected final void registerMenus(final RegistryCallback> callback, ContentIds.STORAGE_MONITOR, () -> extendedMenuTypeFactory.create(StorageMonitorContainerMenu::new, ResourceContainerData.STREAM_CODEC) )); + Menus.INSTANCE.setAutocraftingStorageMonitor(callback.register( + createIdentifier("autocrafting_storage_monitor"), + () -> extendedMenuTypeFactory.create( + (syncId, playerInventory, data) -> new AutocraftingStorageMonitorContainerMenu(syncId, data), + ResourceCodecs.STREAM_CODEC + ) + )); Menus.INSTANCE.setNetworkTransmitter(callback.register( ContentIds.NETWORK_TRANSMITTER, () -> extendedMenuTypeFactory.create(NetworkTransmitterContainerMenu::new, diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/RefinedStorageApiImpl.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/RefinedStorageApiImpl.java index 41ccefd5e..1daca02e8 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/RefinedStorageApiImpl.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/RefinedStorageApiImpl.java @@ -10,6 +10,7 @@ import com.refinedmods.refinedstorage.api.network.impl.NetworkFactory; import com.refinedmods.refinedstorage.api.network.node.NetworkNode; import com.refinedmods.refinedstorage.api.network.security.SecurityPolicy; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; import com.refinedmods.refinedstorage.common.api.autocrafting.PatternProviderItem; @@ -49,6 +50,8 @@ import com.refinedmods.refinedstorage.common.api.support.slotreference.SlotReferenceProvider; import com.refinedmods.refinedstorage.common.api.upgrade.UpgradeRegistry; import com.refinedmods.refinedstorage.common.api.wirelesstransmitter.WirelessTransmitterRangeModifier; +import com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingPreviewScreen; +import com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingRequest; import com.refinedmods.refinedstorage.common.grid.NoopGridSynchronizer; import com.refinedmods.refinedstorage.common.grid.screen.hint.GridInsertionHintsImpl; import com.refinedmods.refinedstorage.common.grid.screen.hint.ItemGridInsertionHint; @@ -99,12 +102,14 @@ import java.util.stream.Collectors; import javax.annotation.Nullable; +import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.Item; @@ -595,4 +600,21 @@ public Optional getPattern(final ItemStack stack, final Level level) { i -> providerItem.getPattern(stack, level).orElse(null) )); } + + @Override + public void openCraftingPreview(final List requests) { + if (requests.isEmpty()) { + return; + } + final Minecraft minecraft = Minecraft.getInstance(); + if (minecraft.screen == null || minecraft.player == null) { + return; + } + final Inventory inventory = minecraft.player.getInventory(); + minecraft.setScreen(new AutocraftingPreviewScreen( + minecraft.screen, + inventory, + requests.stream().map(AutocraftingRequest::of).toList() + )); + } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/AlternativeContainerMenu.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/AlternativeContainerMenu.java index 9af4991ba..b17189322 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/AlternativeContainerMenu.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/AlternativeContainerMenu.java @@ -22,7 +22,7 @@ import static com.refinedmods.refinedstorage.common.autocrafting.AlternativesScreen.ALTERNATIVE_ROW_HEIGHT; import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.getTagTranslationKey; -public class AlternativeContainerMenu extends AbstractResourceContainerMenu { +class AlternativeContainerMenu extends AbstractResourceContainerMenu { private final List alternatives; private final ResourceSlot amountSlot; diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/AlternativesScreen.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/AlternativesScreen.java index e23aa3dcc..743e92a7d 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/AlternativesScreen.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/AlternativesScreen.java @@ -493,7 +493,7 @@ protected ResourceLocation getTexture() { } @Override - protected void accept(final Double amount) { + protected boolean confirm(final Double amount) { slot.changeAmountOnClient(amount); final Set allowedAlternatives = new HashSet<>(); for (int i = 0; i < alternativeCheckboxes.size(); ++i) { @@ -502,6 +502,7 @@ protected void accept(final Double amount) { } } getMenu().sendAllowedAlternatives(allowedAlternatives); + return true; } @Override diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CrafterBlockEntity.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CrafterBlockEntity.java index 533cccb20..71d997548 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CrafterBlockEntity.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CrafterBlockEntity.java @@ -40,6 +40,7 @@ import static com.refinedmods.refinedstorage.common.support.AbstractDirectionalBlock.tryExtractDirection; +// TODO: More energy usage for more patterns. public class CrafterBlockEntity extends AbstractBaseNetworkNodeContainerBlockEntity implements ExtendedMenuProvider, BlockEntityWithDrops, PatternInventory.Listener { static final int PATTERNS = 9; diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPatternClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPatternClientTooltipComponent.java index 9987552f7..b431f29ce 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPatternClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/CraftingPatternClientTooltipComponent.java @@ -20,7 +20,6 @@ import static com.refinedmods.refinedstorage.common.support.Sprites.LIGHT_ARROW_WIDTH; import static com.refinedmods.refinedstorage.common.support.Sprites.SLOT; import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createIdentifier; -import static java.util.Objects.requireNonNullElse; class CraftingPatternClientTooltipComponent implements ClientTooltipComponent { private static final long CYCLE_MS = 1000; @@ -78,7 +77,7 @@ public void renderImage(final Font font, final int x, final int y, final GuiGrap cycleStart = now; } if (outputText != null) { - graphics.drawString(font, outputText, x, y, requireNonNullElse(ChatFormatting.GRAY.getColor(), 15)); + graphics.drawString(font, outputText, x, y, 0xAAAAAA); } renderInputSlots(x, y + 9 + 2, graphics); renderArrow(x, y + 9 + 2, graphics); diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternClientTooltipComponent.java index 742cefdf6..06afaf280 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/ProcessingPatternClientTooltipComponent.java @@ -19,7 +19,6 @@ import static com.refinedmods.refinedstorage.common.support.Sprites.LIGHT_ARROW_HEIGHT; import static com.refinedmods.refinedstorage.common.support.Sprites.LIGHT_ARROW_WIDTH; import static com.refinedmods.refinedstorage.common.support.Sprites.SLOT; -import static java.util.Objects.requireNonNullElse; class ProcessingPatternClientTooltipComponent implements ClientTooltipComponent { private static final long CYCLE_MS = 1000; @@ -162,7 +161,7 @@ private void renderOutputText(final Font font, final int x, final int y, final G outputTexts.get(i), x, y + (i * 9), - requireNonNullElse(ChatFormatting.GRAY.getColor(), 15) + 0xAAAAAA ); } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePatternClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePatternClientTooltipComponent.java index e9c4bc3cc..71ad06504 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePatternClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/SmithingTablePatternClientTooltipComponent.java @@ -14,7 +14,6 @@ import static com.refinedmods.refinedstorage.common.support.Sprites.LIGHT_ARROW; import static com.refinedmods.refinedstorage.common.support.Sprites.LIGHT_ARROW_HEIGHT; import static com.refinedmods.refinedstorage.common.support.Sprites.LIGHT_ARROW_WIDTH; -import static java.util.Objects.requireNonNullElse; class SmithingTablePatternClientTooltipComponent implements ClientTooltipComponent { private static final int ARROW_SPACING = 8; @@ -29,7 +28,7 @@ class SmithingTablePatternClientTooltipComponent implements ClientTooltipCompone @Override public void renderImage(final Font font, final int x, final int y, final GuiGraphics graphics) { - graphics.drawString(font, outputText, x, y, requireNonNullElse(ChatFormatting.GRAY.getColor(), 15)); + graphics.drawString(font, outputText, x, y, 0xAAAAAA); final int slotsY = y + 9 + 2; graphics.blitSprite(Sprites.SLOT, x, slotsY, 18, 18); final ResourceRendering rendering = RefinedStorageApi.INSTANCE.getResourceRendering(ItemResource.class); diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPatternClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPatternClientTooltipComponent.java index b749148dd..5e32c883c 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPatternClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/StonecutterPatternClientTooltipComponent.java @@ -15,7 +15,6 @@ import static com.refinedmods.refinedstorage.common.support.Sprites.LIGHT_ARROW_HEIGHT; import static com.refinedmods.refinedstorage.common.support.Sprites.LIGHT_ARROW_WIDTH; import static com.refinedmods.refinedstorage.common.support.Sprites.SLOT; -import static java.util.Objects.requireNonNullElse; class StonecutterPatternClientTooltipComponent implements ClientTooltipComponent { private static final int ARROW_SPACING = 8; @@ -32,7 +31,7 @@ class StonecutterPatternClientTooltipComponent implements ClientTooltipComponent @Override public void renderImage(final Font font, final int x, final int y, final GuiGraphics graphics) { - graphics.drawString(font, outputText, x, y, requireNonNullElse(ChatFormatting.GRAY.getColor(), 15)); + graphics.drawString(font, outputText, x, y, 0xAAAAAA); graphics.blitSprite(SLOT, x, y + 9 + 2, 18, 18); final ResourceRendering rendering = RefinedStorageApi.INSTANCE.getResourceRendering(ItemResource.class); rendering.render(input, graphics, x + 1, y + 9 + 2 + 1); diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewContainerMenu.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewContainerMenu.java new file mode 100644 index 000000000..2b9bc38d9 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewContainerMenu.java @@ -0,0 +1,104 @@ +package com.refinedmods.refinedstorage.common.autocrafting.preview; + +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; +import com.refinedmods.refinedstorage.common.api.support.resource.ResourceContainer; +import com.refinedmods.refinedstorage.common.support.containermenu.AbstractResourceContainerMenu; +import com.refinedmods.refinedstorage.common.support.containermenu.DisabledResourceSlot; +import com.refinedmods.refinedstorage.common.support.containermenu.ResourceSlotType; +import com.refinedmods.refinedstorage.common.support.resource.ResourceContainerImpl; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.annotation.Nullable; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.inventory.MenuType; + +public class AutocraftingPreviewContainerMenu extends AbstractResourceContainerMenu { + private final List requests; + + private AutocraftingRequest currentRequest; + @Nullable + private AutocraftingPreviewListener listener; + + AutocraftingPreviewContainerMenu(final List requests) { + this(null, 0, requests); + } + + public AutocraftingPreviewContainerMenu(@Nullable final MenuType type, + final int syncId, + final List requests) { + super(type, syncId); + this.requests = new ArrayList<>(requests); + this.currentRequest = requests.getFirst(); + final ResourceContainer resourceContainer = ResourceContainerImpl.createForFilter(1); + resourceContainer.set(0, new ResourceAmount(requests.getFirst().getResource(), 1)); + addSlot(new DisabledResourceSlot( + resourceContainer, + 0, + Component.empty(), + 157, + 48, + ResourceSlotType.FILTER + )); + } + + void setListener(final AutocraftingPreviewListener listener) { + this.listener = listener; + } + + List getRequests() { + return requests; + } + + AutocraftingRequest getCurrentRequest() { + return currentRequest; + } + + void setCurrentRequest(final AutocraftingRequest request) { + this.currentRequest = request; + if (listener != null) { + listener.requestChanged(request); + } + } + + void amountChanged(final double amount) { + if (currentRequest.trySendRequest(amount) && listener != null) { + listener.previewChanged(null); + } + } + + public void previewResponseReceived(final UUID id, final AutocraftingPreview preview) { + if (currentRequest.previewReceived(id, preview) && listener != null) { + listener.previewChanged(preview); + } + } + + void loadCurrentRequest() { + if (listener != null) { + currentRequest.clearPreview(); + listener.requestChanged(currentRequest); + } + } + + void startRequest(final double amount) { + currentRequest.start(amount); + } + + boolean requestStarted(final UUID id) { + if (currentRequest.isStarted(id)) { + if (listener != null) { + listener.requestRemoved(currentRequest); + } + requests.remove(currentRequest); + if (!requests.isEmpty()) { + setCurrentRequest(requests.getFirst()); + return false; + } + return true; + } + return false; + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewListener.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewListener.java new file mode 100644 index 000000000..5ba959f4e --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewListener.java @@ -0,0 +1,13 @@ +package com.refinedmods.refinedstorage.common.autocrafting.preview; + +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; + +import javax.annotation.Nullable; + +interface AutocraftingPreviewListener { + void requestChanged(AutocraftingRequest request); + + void previewChanged(@Nullable AutocraftingPreview preview); + + void requestRemoved(AutocraftingRequest request); +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewScreen.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewScreen.java new file mode 100644 index 000000000..fabe0d70a --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingPreviewScreen.java @@ -0,0 +1,499 @@ +package com.refinedmods.refinedstorage.common.autocrafting.preview; + +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewItem; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewType; +import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; +import com.refinedmods.refinedstorage.common.api.support.resource.ResourceRendering; +import com.refinedmods.refinedstorage.common.support.amount.AbstractAmountScreen; +import com.refinedmods.refinedstorage.common.support.amount.AmountScreenConfiguration; +import com.refinedmods.refinedstorage.common.support.amount.DoubleAmountOperations; +import com.refinedmods.refinedstorage.common.support.tooltip.SmallText; +import com.refinedmods.refinedstorage.common.support.widget.ScrollbarWidget; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import javax.annotation.Nullable; + +import com.google.common.util.concurrent.RateLimiter; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.Rect2i; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import org.joml.Vector3f; + +import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createIdentifier; +import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createTranslation; + +public class AutocraftingPreviewScreen extends AbstractAmountScreen + implements AutocraftingPreviewListener { + static final int REQUEST_BUTTON_HEIGHT = 96 / 4; + static final int REQUEST_BUTTON_WIDTH = 64; + + private static final ResourceLocation TEXTURE = createIdentifier("textures/gui/autocrafting_preview.png"); + private static final MutableComponent TITLE = createTranslation("gui", "autocrafting_preview.title"); + private static final MutableComponent START = createTranslation("gui", "autocrafting_preview.start"); + private static final MutableComponent PENDING = createTranslation("gui", "autocrafting_preview.pending"); + private static final MutableComponent MISSING_RESOURCES = createTranslation( + "gui", + "autocrafting_preview.start.missing_resources" + ); + private static final ResourceLocation ROW = createIdentifier("autocrafting_preview/row"); + private static final ResourceLocation CRAFTING_REQUESTS = createIdentifier("autocrafting_preview/requests"); + + private static final int ROWS_VISIBLE = 4; + private static final int COLUMNS = 3; + private static final int PREVIEW_AREA_HEIGHT = 119; + + private static final int ROW_HEIGHT = 30; + private static final int ROW_WIDTH = 221; + + private static final int REQUESTS_WIDTH = 91; + private static final int REQUESTS_HEIGHT = 111; + private static final int REQUESTS_INNER_WIDTH = 64; + private static final int REQUESTS_INNER_HEIGHT = 96; + private static final int REQUESTS_VISIBLE = 4; + + @Nullable + private ScrollbarWidget previewItemsScrollbar; + @Nullable + private ScrollbarWidget requestButtonsScrollbar; + + private final List requestButtons = new ArrayList<>(); + private final boolean requestsButtonsVisible; + + private final RateLimiter requestRateLimiter = RateLimiter.create(1); + + @Nullable + private Double changedAmount; + + public AutocraftingPreviewScreen(final Screen parent, + final Inventory playerInventory, + final List requests) { + this(new AutocraftingPreviewContainerMenu(requests), parent, playerInventory); + } + + public AutocraftingPreviewScreen(final AutocraftingPreviewContainerMenu menu, + final Inventory playerInventory, + final Component title) { + this(menu, null, playerInventory); + } + + public AutocraftingPreviewScreen(final AutocraftingPreviewContainerMenu menu, + @Nullable final Screen parent, + final Inventory playerInventory) { + super( + menu, + parent, + playerInventory, + TITLE, + AmountScreenConfiguration.AmountScreenConfigurationBuilder.create() + .withInitialAmount(1D) + .withIncrementsTop(1, 10, 64) + .withIncrementsTopStartPosition(new Vector3f(80, 20, 0)) + .withIncrementsBottom(-1, -10, -64) + .withIncrementsBottomStartPosition(new Vector3f(80, 71, 0)) + .withAmountFieldPosition(new Vector3f(77, 51, 0)) + .withActionButtonsStartPosition(new Vector3f(7, 222, 0)) + .withHorizontalActionButtons(true) + .withMinAmount(1D) + .withResetAmount(1D) + .withConfirmButtonText(START) + .build(), + DoubleAmountOperations.INSTANCE + ); + this.imageWidth = 254; + this.imageHeight = 249; + this.requestsButtonsVisible = getMenu().getRequests().size() > 1; + getMenu().setListener(this); + } + + @Override + protected void init() { + super.init(); + previewItemsScrollbar = new ScrollbarWidget( + leftPos + 235, + topPos + 98, + ScrollbarWidget.Type.NORMAL, + PREVIEW_AREA_HEIGHT + ); + previewItemsScrollbar.setEnabled(false); + if (requestsButtonsVisible) { + initRequestButtons(); + } + if (confirmButton != null) { + setStartDisabled(); + } + getMenu().loadCurrentRequest(); + getExclusionZones().add(new Rect2i( + leftPos - REQUESTS_WIDTH + 4, + topPos, + REQUESTS_WIDTH, + REQUESTS_HEIGHT + )); + } + + private void initRequestButtons() { + requestButtons.clear(); + requestButtonsScrollbar = new ScrollbarWidget( + leftPos - 17 + 4, + getRequestButtonsInnerY(), + ScrollbarWidget.Type.NORMAL, + 96 + ); + requestButtonsScrollbar.setListener(value -> { + final int scrollOffset = requestButtonsScrollbar.isSmoothScrolling() + ? (int) requestButtonsScrollbar.getOffset() + : (int) requestButtonsScrollbar.getOffset() * REQUEST_BUTTON_HEIGHT; + for (int i = 0; i < requestButtons.size(); i++) { + final AutocraftingRequestButton requestButton = requestButtons.get(i); + final int y = getCraftingRequestButtonY(i) - scrollOffset; + requestButton.setY(y); + requestButton.visible = isCraftingRequestButtonVisible(y); + } + }); + updateRequestsScrollbar(); + for (int i = 0; i < getMenu().getRequests().size(); ++i) { + final AutocraftingRequest request = getMenu().getRequests().get(i); + final int buttonY = getCraftingRequestButtonY(i); + final AutocraftingRequestButton button = new AutocraftingRequestButton( + getRequestButtonsInnerX(), + buttonY, + request, + this::changeCurrentRequest + ); + button.visible = isCraftingRequestButtonVisible(buttonY); + requestButtons.add(addWidget(button)); + } + } + + private boolean isCraftingRequestButtonVisible(final int y) { + final int innerY = getRequestButtonsInnerY(); + return y >= innerY - REQUEST_BUTTON_HEIGHT && y <= innerY + REQUESTS_INNER_HEIGHT; + } + + private int getCraftingRequestButtonY(final int i) { + return getRequestButtonsInnerY() + (i * REQUEST_BUTTON_HEIGHT); + } + + private void changeCurrentRequest(final AutocraftingRequest request) { + getMenu().setCurrentRequest(request); + } + + private void setRequest(final AutocraftingRequest request) { + for (final AutocraftingRequestButton requestButton : requestButtons) { + requestButton.active = requestButton.getRequest() != request; + } + updateAmount(request.getAmount()); + setPreview(request.getPreview()); + } + + private void setPreview(@Nullable final AutocraftingPreview preview) { + if (previewItemsScrollbar == null || confirmButton == null) { + return; + } + if (preview == null) { + previewItemsScrollbar.setEnabled(false); + previewItemsScrollbar.setMaxOffset(0); + setStartDisabled(); + return; + } + final int items = preview.items().size(); + final int rows = Math.ceilDiv(items, COLUMNS) - ROWS_VISIBLE; + previewItemsScrollbar.setMaxOffset(previewItemsScrollbar.isSmoothScrolling() ? rows * ROW_HEIGHT : rows); + previewItemsScrollbar.setEnabled(rows > 0); + confirmButton.setMessage(START); + confirmButton.active = preview.type() == AutocraftingPreviewType.SUCCESS; + confirmButton.setError(preview.type() != AutocraftingPreviewType.SUCCESS); + confirmButton.setTooltip(preview.type() == AutocraftingPreviewType.MISSING_RESOURCES + ? Tooltip.create(MISSING_RESOURCES) + : null); + } + + @Override + public void render(final GuiGraphics graphics, final int mouseX, final int mouseY, final float partialTicks) { + super.render(graphics, mouseX, mouseY, partialTicks); + if (previewItemsScrollbar != null) { + previewItemsScrollbar.render(graphics, mouseX, mouseY, partialTicks); + } + if (requestButtonsScrollbar != null) { + requestButtonsScrollbar.render(graphics, mouseX, mouseY, partialTicks); + } + if (requestsButtonsVisible) { + final int requestsInnerX = getRequestButtonsInnerX(); + final int requestsInnerY = getRequestButtonsInnerY(); + graphics.enableScissor( + requestsInnerX, + requestsInnerY, + requestsInnerX + REQUESTS_INNER_WIDTH, + requestsInnerY + REQUESTS_INNER_HEIGHT + ); + for (final AutocraftingRequestButton requestButton : requestButtons) { + requestButton.render(graphics, mouseX, mouseY, partialTicks); + } + graphics.disableScissor(); + } + } + + @Override + protected void renderBg(final GuiGraphics graphics, final float delta, final int mouseX, final int mouseY) { + super.renderBg(graphics, delta, mouseX, mouseY); + if (requestsButtonsVisible) { + graphics.blitSprite(CRAFTING_REQUESTS, leftPos - REQUESTS_WIDTH + 4, topPos, REQUESTS_WIDTH, + REQUESTS_HEIGHT); + } + final AutocraftingRequest request = getMenu().getCurrentRequest(); + final AutocraftingPreview preview = request.getPreview(); + if (preview == null || previewItemsScrollbar == null) { + return; + } + final int x = leftPos + 8; + final int y = topPos + 98; + graphics.enableScissor(x, y, x + 221, y + PREVIEW_AREA_HEIGHT); + final List items = preview.items(); + final int rows = Math.ceilDiv(items.size(), COLUMNS); + for (int i = 0; i < rows; ++i) { + final int scrollOffset = previewItemsScrollbar.isSmoothScrolling() + ? (int) previewItemsScrollbar.getOffset() + : (int) previewItemsScrollbar.getOffset() * ROW_HEIGHT; + final int yy = y + (i * ROW_HEIGHT) - scrollOffset; + renderRow(graphics, x, yy, i, items, mouseX, mouseY); + } + graphics.disableScissor(); + } + + private void renderRow(final GuiGraphics graphics, + final int x, + final int y, + final int i, + final List items, + final double mouseX, + final double mouseY) { + if (y <= topPos + 98 - ROW_HEIGHT || y > topPos + 98 + PREVIEW_AREA_HEIGHT) { + return; + } + graphics.blitSprite(ROW, x, y, ROW_WIDTH, ROW_HEIGHT); + for (int column = i * COLUMNS; column < Math.min(i * COLUMNS + COLUMNS, items.size()); ++column) { + final AutocraftingPreviewItem item = items.get(column); + final int xx = x + (column % COLUMNS) * 74; + renderCell(graphics, xx, y, item, mouseX, mouseY); + } + } + + private void renderCell(final GuiGraphics graphics, + final int x, + final int y, + final AutocraftingPreviewItem item, + final double mouseX, + final double mouseY) { + if (item.missing() > 0) { + graphics.fill(x, y, x + 73, y + 29, 0xFFF2DEDE); + } + int xx = x + 2; + final ResourceRendering rendering = RefinedStorageApi.INSTANCE.getResourceRendering(item.resource().getClass()); + int yy = y + 7; + rendering.render(item.resource(), graphics, xx, yy); + if (isHovering(xx - leftPos, yy - topPos, 16, 16, mouseX, mouseY) + && isHoveringOverPreviewArea(mouseX, mouseY)) { + setTooltipForNextRenderPass(rendering.getTooltip(item.resource()).stream() + .map(Component::getVisualOrderText) + .toList()); + } + if (!SmallText.isSmall()) { + yy -= 2; + } + xx += 16 + 3; + if (item.missing() > 0) { + renderCellText(graphics, "missing", rendering, xx, yy, item.missing()); + yy += 7; + } + if (item.available() > 0) { + renderCellText(graphics, "available", rendering, xx, yy, item.available()); + yy += 7; + } + if (item.toCraft() > 0) { + renderCellText(graphics, "to_craft", rendering, xx, yy, item.toCraft()); + } + } + + private void renderCellText(final GuiGraphics graphics, + final String type, + final ResourceRendering rendering, + final int x, + final int y, + final long amount) { + SmallText.render( + graphics, + font, + createTranslation("gui", "autocrafting_preview." + type, rendering.formatAmount(amount, true)) + .getVisualOrderText(), + x, + y, + 0x404040, + false + ); + } + + @Override + public boolean mouseClicked(final double mouseX, final double mouseY, final int clickedButton) { + if (previewItemsScrollbar != null && previewItemsScrollbar.mouseClicked(mouseX, mouseY, clickedButton)) { + return true; + } + if (requestButtonsScrollbar != null && requestButtonsScrollbar.mouseClicked(mouseX, mouseY, clickedButton)) { + return true; + } + return super.mouseClicked(mouseX, mouseY, clickedButton); + } + + @Override + public void mouseMoved(final double mx, final double my) { + if (previewItemsScrollbar != null) { + previewItemsScrollbar.mouseMoved(mx, my); + } + if (requestButtonsScrollbar != null) { + requestButtonsScrollbar.mouseMoved(mx, my); + } + super.mouseMoved(mx, my); + } + + @Override + public boolean mouseReleased(final double mx, final double my, final int button) { + if (previewItemsScrollbar != null && previewItemsScrollbar.mouseReleased(mx, my, button)) { + return true; + } + if (requestButtonsScrollbar != null && requestButtonsScrollbar.mouseReleased(mx, my, button)) { + return true; + } + return super.mouseReleased(mx, my, button); + } + + @Override + public boolean mouseScrolled(final double x, final double y, final double z, final double delta) { + final boolean didPreviewItemsScrollbar = previewItemsScrollbar != null + && isHoveringOverPreviewArea(x, y) + && previewItemsScrollbar.mouseScrolled(x, y, z, delta); + final boolean didRequestButtonsScrollbar = !didPreviewItemsScrollbar + && requestButtonsScrollbar != null + && isHoveringOverRequestButtons(x, y) + && requestButtonsScrollbar.mouseScrolled(x, y, z, delta); + return didPreviewItemsScrollbar || didRequestButtonsScrollbar || super.mouseScrolled(x, y, z, delta); + } + + private boolean isHoveringOverPreviewArea(final double x, final double y) { + return isHovering(7, 97, 241, 121, x, y); + } + + private boolean isHoveringOverRequestButtons(final double x, final double y) { + final int requestsInnerX = getRequestButtonsInnerX() - 1; + final int requestsInnerY = getRequestButtonsInnerY() - 1; + return isHovering(requestsInnerX - leftPos, requestsInnerY - topPos, 80, 98, x, y); + } + + private int getRequestButtonsInnerY() { + return topPos + 8; + } + + private int getRequestButtonsInnerX() { + return leftPos - 83 + 4; + } + + @Override + protected ResourceLocation getTexture() { + return TEXTURE; + } + + @Override + protected void onAmountFieldChanged() { + if (amountField == null || confirmButton == null) { + return; + } + getAndValidateAmount().ifPresentOrElse(amount -> { + setPending(); + changedAmount = amount; + amountField.setTextColor(0xFFFFFF); + }, () -> { + setStartDisabled(); + amountField.setTextColor(0xFF5555); + }); + } + + private void setPending() { + confirmButton.active = false; + confirmButton.setError(false); + confirmButton.setTooltip(null); + confirmButton.setMessage(PENDING); + } + + private void setStartDisabled() { + confirmButton.active = false; + confirmButton.setError(false); + confirmButton.setTooltip(null); + confirmButton.setMessage(START); + } + + @Override + protected void containerTick() { + super.containerTick(); + if (changedAmount != null && requestRateLimiter.tryAcquire()) { + getMenu().amountChanged(changedAmount); + changedAmount = null; + } + } + + @Override + protected void reset() { + updateAmount(getMenu().getCurrentRequest().getAmount()); + } + + @Override + protected boolean confirm(final Double amount) { + setPending(); + getMenu().startRequest(amount); + return false; + } + + @Override + public void requestChanged(final AutocraftingRequest request) { + setRequest(request); + } + + @Override + public void previewChanged(@Nullable final AutocraftingPreview preview) { + setPreview(preview); + } + + @Override + public void requestRemoved(final AutocraftingRequest request) { + requestButtons.removeIf(requestButton -> requestButton.getRequest() == request); + updateRequestsScrollbar(); + for (int i = 0; i < requestButtons.size(); ++i) { + final AutocraftingRequestButton requestButton = requestButtons.get(i); + final int buttonY = getCraftingRequestButtonY(i); + requestButton.setY(buttonY); + requestButton.visible = isCraftingRequestButtonVisible(buttonY); + } + } + + private void updateRequestsScrollbar() { + if (requestButtonsScrollbar == null) { + return; + } + final int totalRequestButtons = getMenu().getRequests().size() - REQUESTS_VISIBLE; + final int maxOffset = requestButtonsScrollbar.isSmoothScrolling() + ? totalRequestButtons * REQUEST_BUTTON_HEIGHT + : totalRequestButtons; + requestButtonsScrollbar.setEnabled(maxOffset > 0); + requestButtonsScrollbar.setMaxOffset(maxOffset); + } + + public void responseReceived(final UUID id, final boolean started) { + if (started && getMenu().requestStarted(id)) { + close(); + } + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingRequest.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingRequest.java new file mode 100644 index 000000000..f93798dd7 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingRequest.java @@ -0,0 +1,85 @@ +package com.refinedmods.refinedstorage.common.autocrafting.preview; + +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; +import com.refinedmods.refinedstorage.api.resource.ResourceKey; +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage.common.support.packet.c2s.C2SPackets; + +import java.util.UUID; +import javax.annotation.Nullable; + +public class AutocraftingRequest { + private final UUID id; + private final ResourceKey resource; + private final double amount; + @Nullable + private AutocraftingPreview preview; + private long pendingPreviewAmount; + + private AutocraftingRequest(final UUID id, final ResourceKey resource, final double amount) { + this.id = id; + this.resource = resource; + this.amount = amount; + } + + public static AutocraftingRequest of(final ResourceAmount resourceAmount) { + final double displayAmount = resourceAmount.resource() instanceof PlatformResourceKey platformResourceKey + ? platformResourceKey.getResourceType().getDisplayAmount(resourceAmount.amount()) + : resourceAmount.amount(); + return new AutocraftingRequest(UUID.randomUUID(), resourceAmount.resource(), displayAmount); + } + + boolean trySendRequest(final double amountRequested) { + if (!(resource instanceof PlatformResourceKey resourceKey)) { + return false; + } + final long normalizedAmount = resourceKey.getResourceType().normalizeAmount(amountRequested); + if (normalizedAmount == pendingPreviewAmount) { + return false; + } + this.preview = null; + this.pendingPreviewAmount = normalizedAmount; + C2SPackets.sendAutocraftingPreviewRequest(id, resourceKey, normalizedAmount); + return true; + } + + void start(final double amountRequested) { + if (!(resource instanceof PlatformResourceKey resourceKey)) { + return; + } + final long normalizedAmount = resourceKey.getResourceType().normalizeAmount(amountRequested); + C2SPackets.sendAutocraftingRequest(id, resourceKey, normalizedAmount); + } + + ResourceKey getResource() { + return resource; + } + + double getAmount() { + return amount; + } + + @Nullable + AutocraftingPreview getPreview() { + return preview; + } + + boolean previewReceived(final UUID idReceived, final AutocraftingPreview previewReceived) { + if (id.equals(idReceived)) { + pendingPreviewAmount = 0; + preview = previewReceived; + return true; + } + return false; + } + + void clearPreview() { + pendingPreviewAmount = 0; + preview = null; + } + + boolean isStarted(final UUID startedId) { + return id.equals(startedId); + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingRequestButton.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingRequestButton.java new file mode 100644 index 000000000..050bdc89a --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/AutocraftingRequestButton.java @@ -0,0 +1,73 @@ +package com.refinedmods.refinedstorage.common.autocrafting.preview; + +import com.refinedmods.refinedstorage.api.resource.ResourceKey; +import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage.common.api.support.resource.ResourceRendering; +import com.refinedmods.refinedstorage.common.support.tooltip.SmallText; +import com.refinedmods.refinedstorage.common.support.widget.TextMarquee; + +import java.util.function.Consumer; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractButton; +import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.network.chat.Component; + +import static com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingPreviewScreen.REQUEST_BUTTON_HEIGHT; +import static com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingPreviewScreen.REQUEST_BUTTON_WIDTH; + +class AutocraftingRequestButton extends AbstractButton { + private final AutocraftingRequest request; + private final TextMarquee text; + private final Consumer onPress; + + AutocraftingRequestButton(final int x, + final int y, + final AutocraftingRequest request, + final Consumer onPress) { + super(x, y, REQUEST_BUTTON_WIDTH, REQUEST_BUTTON_HEIGHT, Component.empty()); + this.request = request; + final ResourceKey resource = request.getResource(); + final long normalizedAmount = resource instanceof PlatformResourceKey platformResourceKey + ? platformResourceKey.getResourceType().normalizeAmount(request.getAmount()) + : 0; + final ResourceRendering rendering = RefinedStorageApi.INSTANCE.getResourceRendering(resource.getClass()); + this.text = new TextMarquee(Component.literal(rendering.formatAmount(normalizedAmount, true)) + .append(" ") + .append(rendering.getDisplayName(resource)), + REQUEST_BUTTON_WIDTH - 16 - 4 - 4 - 4, + 0xFFFFFF, + true, + true); + this.onPress = onPress; + } + + AutocraftingRequest getRequest() { + return request; + } + + @Override + protected void renderWidget(final GuiGraphics graphics, + final int mouseX, + final int mouseY, + final float partialTick) { + super.renderWidget(graphics, mouseX, mouseY, partialTick); + final ResourceKey resource = request.getResource(); + final ResourceRendering rendering = RefinedStorageApi.INSTANCE.getResourceRendering(resource.getClass()); + rendering.render(resource, graphics, getX() + 3, getY() + 4); + final int yOffset = SmallText.isSmall() ? 8 : 5; + text.render(graphics, getX() + 3 + 16 + 3, getY() + yOffset, Minecraft.getInstance().font, isHovered); + } + + @Override + public void onPress() { + onPress.accept(request); + } + + @Override + protected void updateWidgetNarration(final NarrationElementOutput narrationElementOutput) { + // no op + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/package-info.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/package-info.java new file mode 100644 index 000000000..b10fddc11 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/autocrafting/preview/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@FieldsAndMethodsAreNonnullByDefault +package com.refinedmods.refinedstorage.common.autocrafting.preview; + +import com.refinedmods.refinedstorage.api.core.FieldsAndMethodsAreNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/content/Menus.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/content/Menus.java index eba2dc15d..57d8771d3 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/content/Menus.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/content/Menus.java @@ -2,6 +2,7 @@ import com.refinedmods.refinedstorage.common.autocrafting.CrafterContainerMenu; import com.refinedmods.refinedstorage.common.autocrafting.PatternGridContainerMenu; +import com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingPreviewContainerMenu; import com.refinedmods.refinedstorage.common.constructordestructor.ConstructorContainerMenu; import com.refinedmods.refinedstorage.common.constructordestructor.DestructorContainerMenu; import com.refinedmods.refinedstorage.common.controller.ControllerContainerMenu; @@ -75,6 +76,8 @@ public final class Menus { @Nullable private Supplier> storageMonitor; @Nullable + private Supplier> autocraftingStorageMonitor; + @Nullable private Supplier> networkTransmitter; @Nullable private Supplier> portableGridBlock; @@ -240,6 +243,16 @@ public void setStorageMonitor(final Supplier getAutocraftingStorageMonitor() { + return requireNonNull(autocraftingStorageMonitor).get(); + } + + public void setAutocraftingStorageMonitor( + final Supplier> supplier + ) { + this.autocraftingStorageMonitor = supplier; + } + public MenuType getNetworkTransmitter() { return requireNonNull(networkTransmitter).get(); } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/AbstractGridBlockEntity.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/AbstractGridBlockEntity.java index c29cc6df3..30988fee3 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/AbstractGridBlockEntity.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/AbstractGridBlockEntity.java @@ -1,5 +1,6 @@ package com.refinedmods.refinedstorage.common.grid; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; import com.refinedmods.refinedstorage.api.grid.operations.GridOperations; import com.refinedmods.refinedstorage.api.grid.watcher.GridWatcher; import com.refinedmods.refinedstorage.api.network.Network; @@ -7,6 +8,7 @@ import com.refinedmods.refinedstorage.api.network.impl.node.container.NetworkNodeContainerPriorities; import com.refinedmods.refinedstorage.api.network.impl.node.grid.GridNetworkNode; import com.refinedmods.refinedstorage.api.network.storage.StorageNetworkComponent; +import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.api.storage.Actor; import com.refinedmods.refinedstorage.api.storage.Storage; import com.refinedmods.refinedstorage.api.storage.TrackedResourceAmount; @@ -23,6 +25,7 @@ import com.refinedmods.refinedstorage.common.support.network.ColoredConnectionStrategy; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -97,6 +100,22 @@ public void removeWatcher(final GridWatcher watcher) { mainNetworkNode.removeWatcher(watcher); } + @Override + public Optional getPreview(final ResourceKey resource, final long amount) { + return Optional.ofNullable(mainNetworkNode.getNetwork()) + .map(network -> network.getComponent(AutocraftingNetworkComponent.class)) + .flatMap(component -> component.getPreview(resource, amount)); + } + + @Override + public boolean start(final ResourceKey resource, final long amount) { + final Network network = mainNetworkNode.getNetwork(); + if (network == null) { + return false; + } + return network.getComponent(AutocraftingNetworkComponent.class).start(resource, amount); + } + @Override protected boolean doesBlockStateChangeWarrantNetworkNodeUpdate(final BlockState oldBlockState, final BlockState newBlockState) { diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/AbstractGridContainerMenu.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/AbstractGridContainerMenu.java index 8599226c3..158af2302 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/AbstractGridContainerMenu.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/AbstractGridContainerMenu.java @@ -1,5 +1,7 @@ package com.refinedmods.refinedstorage.common.grid; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewProvider; import com.refinedmods.refinedstorage.api.autocrafting.Pattern; import com.refinedmods.refinedstorage.api.autocrafting.PatternRepository; import com.refinedmods.refinedstorage.api.autocrafting.PatternRepositoryImpl; @@ -42,6 +44,7 @@ import com.refinedmods.refinedstorage.query.parser.ParserOperatorMappings; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.function.BiPredicate; import javax.annotation.Nullable; @@ -58,7 +61,8 @@ import static java.util.Objects.requireNonNull; public abstract class AbstractGridContainerMenu extends AbstractResourceContainerMenu - implements GridWatcher, GridInsertionStrategy, GridExtractionStrategy, GridScrollingStrategy, ScreenSizeListener { + implements GridWatcher, GridInsertionStrategy, GridExtractionStrategy, GridScrollingStrategy, ScreenSizeListener, + AutocraftingPreviewProvider { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractGridContainerMenu.class); private static final GridQueryParserImpl QUERY_PARSER = new GridQueryParserImpl( LexerTokenMappings.DEFAULT_MAPPINGS, @@ -483,6 +487,16 @@ protected ResourceKey getResourceForAutocraftableHint(final Slot slot) { return null; } + @Override + public Optional getPreview(final ResourceKey resource, final long amount) { + return requireNonNull(grid).getPreview(resource, amount); + } + + @Override + public boolean start(final ResourceKey resource, final long amount) { + return requireNonNull(grid).start(resource, amount); + } + public boolean isLargeSlot(final Slot slot) { return false; } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/WirelessGrid.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/WirelessGrid.java index e471c6e77..765b3a92e 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/WirelessGrid.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/WirelessGrid.java @@ -1,12 +1,15 @@ package com.refinedmods.refinedstorage.common.grid; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; import com.refinedmods.refinedstorage.api.grid.operations.GridOperations; import com.refinedmods.refinedstorage.api.grid.operations.NoopGridOperations; import com.refinedmods.refinedstorage.api.grid.watcher.GridWatcher; import com.refinedmods.refinedstorage.api.grid.watcher.GridWatcherManager; import com.refinedmods.refinedstorage.api.grid.watcher.GridWatcherManagerImpl; +import com.refinedmods.refinedstorage.api.network.autocrafting.AutocraftingNetworkComponent; import com.refinedmods.refinedstorage.api.network.energy.EnergyNetworkComponent; import com.refinedmods.refinedstorage.api.network.storage.StorageNetworkComponent; +import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.api.storage.Actor; import com.refinedmods.refinedstorage.api.storage.NoopStorage; import com.refinedmods.refinedstorage.api.storage.Storage; @@ -100,4 +103,18 @@ private GridOperations createGridOperations(final ResourceType resourceType, final GridOperations operations = resourceType.createGridOperations(rootStorage, playerActor); return new SecuredGridOperations(player, securityNetworkComponent, operations); } + + @Override + public Optional getPreview(final ResourceKey resource, final long amount) { + return context.resolveNetwork() + .map(network -> network.getComponent(AutocraftingNetworkComponent.class)) + .flatMap(component -> component.getPreview(resource, amount)); + } + + @Override + public boolean start(final ResourceKey resource, final long amount) { + return context.resolveNetwork() + .map(network -> network.getComponent(AutocraftingNetworkComponent.class).start(resource, amount)) + .orElse(false); + } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/screen/AbstractGridScreen.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/screen/AbstractGridScreen.java index 89ba11179..9747967b0 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/screen/AbstractGridScreen.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/screen/AbstractGridScreen.java @@ -4,6 +4,7 @@ import com.refinedmods.refinedstorage.api.grid.operations.GridInsertMode; import com.refinedmods.refinedstorage.api.grid.view.GridResource; import com.refinedmods.refinedstorage.api.grid.view.GridView; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.api.storage.tracked.TrackedResource; import com.refinedmods.refinedstorage.common.Platform; @@ -493,9 +494,13 @@ public boolean mouseClicked(final double mouseX, final double mouseY, final int final ItemStack carriedStack = getMenu().getCarried(); final PlatformGridResource resource = getCurrentGridResource(); - if (resource != null && resource.canExtract(carriedStack, getMenu().getView())) { - mouseClickedInGrid(clickedButton, resource); - return true; + if (resource != null) { + if (resource.canExtract(carriedStack, getMenu().getView()) && !hasControlDown()) { + mouseClickedInGrid(clickedButton, resource); + return true; + } else if (resource.isCraftable() && tryStartAutocrafting(resource)) { + return true; + } } if (isOverStorageArea((int) mouseX, (int) mouseY) @@ -507,6 +512,24 @@ public boolean mouseClicked(final double mouseX, final double mouseY, final int return super.mouseClicked(mouseX, mouseY, clickedButton); } + private static boolean tryStartAutocrafting(final PlatformGridResource resource) { + final ResourceAmount request = resource.getAutocraftingRequest(); + if (request == null) { + return false; + } + final List requests = new ArrayList<>(); + requests.add(request); + // TODO: Remove - temporary code + if (hasShiftDown()) { + requests.add(new ResourceAmount(request.resource(), request.amount() * 2)); + requests.add(new ResourceAmount(request.resource(), request.amount() * 3)); + requests.add(new ResourceAmount(request.resource(), request.amount() * 4)); + requests.add(new ResourceAmount(request.resource(), request.amount() * 4)); + } + RefinedStorageApi.INSTANCE.openCraftingPreview(requests); + return true; + } + private void mouseClickedInGrid(final int clickedButton) { final GridInsertMode mode = clickedButton == 1 ? GridInsertMode.SINGLE_RESOURCE diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/screen/GridSearchBoxWidget.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/screen/GridSearchBoxWidget.java index 94f5ac1ac..46f461841 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/screen/GridSearchBoxWidget.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/screen/GridSearchBoxWidget.java @@ -12,7 +12,6 @@ import java.util.HashSet; import java.util.List; -import java.util.Objects; import java.util.Set; import java.util.function.Consumer; @@ -85,9 +84,6 @@ public void addListener(final Consumer listener) { @Override public void setValid(final boolean valid) { this.valid = valid; - setTextColor(valid - ? Objects.requireNonNullElse(ChatFormatting.WHITE.getColor(), 15) - : Objects.requireNonNullElse(ChatFormatting.RED.getColor(), 15) - ); + setTextColor(valid ? 0xFFFFFF : 0xFF5555); } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/view/FluidGridResource.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/view/FluidGridResource.java index 0ffecdb6e..3b11cc868 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/view/FluidGridResource.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/view/FluidGridResource.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import javax.annotation.Nullable; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; @@ -61,6 +62,12 @@ public List getExtractionHints(final ItemStack carriedSt )).stream().toList(); } + @Nullable + @Override + public ResourceAmount getAutocraftingRequest() { + return new ResourceAmount(resource, Platform.INSTANCE.getBucketAmount()); + } + private Optional tryFillFluidContainer(final ItemStack carriedStack) { final ResourceAmount toFill = new ResourceAmount(resource, Platform.INSTANCE.getBucketAmount()); return carriedStack.isEmpty() @@ -70,6 +77,9 @@ private Optional tryFillFluidContainer(final ItemStack car @Override public boolean canExtract(final ItemStack carriedStack, final GridView view) { + if (getAmount(view) == 0) { + return false; + } if (carriedStack.isEmpty()) { return true; } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/view/ItemGridResource.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/view/ItemGridResource.java index 0bc1a01d1..dd56b2a55 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/view/ItemGridResource.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/grid/view/ItemGridResource.java @@ -3,6 +3,7 @@ import com.refinedmods.refinedstorage.api.grid.operations.GridExtractMode; import com.refinedmods.refinedstorage.api.grid.view.GridResourceAttributeKey; import com.refinedmods.refinedstorage.api.grid.view.GridView; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.common.api.grid.GridScrollMode; import com.refinedmods.refinedstorage.common.api.grid.strategy.GridExtractionStrategy; import com.refinedmods.refinedstorage.common.api.grid.strategy.GridScrollingStrategy; @@ -16,6 +17,7 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import javax.annotation.Nullable; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -78,9 +80,15 @@ public List getExtractionHints(final ItemStack carriedSt ); } + @Nullable + @Override + public ResourceAmount getAutocraftingRequest() { + return new ResourceAmount(itemResource, 1); + } + @Override public boolean canExtract(final ItemStack carriedStack, final GridView view) { - return carriedStack.isEmpty(); + return getAmount(view) > 0 && carriedStack.isEmpty(); } @Override diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storage/portablegrid/PortableGrid.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storage/portablegrid/PortableGrid.java index f7455d5fc..f38d75ae6 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storage/portablegrid/PortableGrid.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storage/portablegrid/PortableGrid.java @@ -1,5 +1,6 @@ package com.refinedmods.refinedstorage.common.storage.portablegrid; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; import com.refinedmods.refinedstorage.api.core.Action; import com.refinedmods.refinedstorage.api.grid.operations.GridOperations; import com.refinedmods.refinedstorage.api.grid.operations.NoopGridOperations; @@ -7,6 +8,7 @@ import com.refinedmods.refinedstorage.api.grid.watcher.GridWatcherManager; import com.refinedmods.refinedstorage.api.grid.watcher.GridWatcherManagerImpl; import com.refinedmods.refinedstorage.api.network.energy.EnergyStorage; +import com.refinedmods.refinedstorage.api.resource.ResourceKey; import com.refinedmods.refinedstorage.api.storage.Actor; import com.refinedmods.refinedstorage.api.storage.NoopStorage; import com.refinedmods.refinedstorage.api.storage.StateTrackedStorage; @@ -23,6 +25,7 @@ import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.Set; import javax.annotation.Nullable; @@ -126,4 +129,14 @@ public GridOperations createOperations(final ResourceType resourceType, final Se final GridOperations operations = resourceType.createGridOperations(rootStorage, new PlayerActor(player)); return new PortableGridOperations(operations, energyStorage); } + + @Override + public Optional getPreview(final ResourceKey resource, final long amount) { + return Optional.empty(); + } + + @Override + public boolean start(final ResourceKey resource, final long amount) { + return false; + } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/AutocraftingStorageMonitorContainerMenu.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/AutocraftingStorageMonitorContainerMenu.java new file mode 100644 index 000000000..5cb83aa86 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/AutocraftingStorageMonitorContainerMenu.java @@ -0,0 +1,50 @@ +package com.refinedmods.refinedstorage.common.storagemonitor; + +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewProvider; +import com.refinedmods.refinedstorage.api.resource.ResourceAmount; +import com.refinedmods.refinedstorage.api.resource.ResourceKey; +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingPreviewContainerMenu; +import com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingRequest; +import com.refinedmods.refinedstorage.common.content.Menus; + +import java.util.List; +import java.util.Optional; +import javax.annotation.Nullable; + +import static java.util.Objects.requireNonNull; + +public class AutocraftingStorageMonitorContainerMenu extends AutocraftingPreviewContainerMenu + implements AutocraftingPreviewProvider { + @Nullable + private final StorageMonitorBlockEntity storageMonitor; + + public AutocraftingStorageMonitorContainerMenu(final int syncId, final PlatformResourceKey resource) { + super(Menus.INSTANCE.getAutocraftingStorageMonitor(), syncId, getRequests(resource)); + this.storageMonitor = null; + } + + AutocraftingStorageMonitorContainerMenu(final int syncId, + final PlatformResourceKey resource, + final StorageMonitorBlockEntity storageMonitor) { + super(Menus.INSTANCE.getAutocraftingStorageMonitor(), syncId, getRequests(resource)); + this.storageMonitor = storageMonitor; + } + + private static List getRequests(final PlatformResourceKey resource) { + return List.of(AutocraftingRequest.of( + new ResourceAmount(resource, resource.getResourceType().normalizeAmount(1.0D)) + )); + } + + @Override + public Optional getPreview(final ResourceKey resource, final long amount) { + return requireNonNull(storageMonitor).getPreview(resource, amount); + } + + @Override + public boolean start(final ResourceKey resource, final long amount) { + return requireNonNull(storageMonitor).start(resource, amount); + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/AutocraftingStorageMonitorExtendedMenuProvider.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/AutocraftingStorageMonitorExtendedMenuProvider.java new file mode 100644 index 000000000..876db6b15 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/AutocraftingStorageMonitorExtendedMenuProvider.java @@ -0,0 +1,46 @@ +package com.refinedmods.refinedstorage.common.storagemonitor; + +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage.common.content.ContentNames; +import com.refinedmods.refinedstorage.common.support.containermenu.ExtendedMenuProvider; +import com.refinedmods.refinedstorage.common.support.resource.ResourceCodecs; + +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.StreamEncoder; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; + +class AutocraftingStorageMonitorExtendedMenuProvider implements ExtendedMenuProvider { + private final PlatformResourceKey resource; + private final StorageMonitorBlockEntity blockEntity; + + AutocraftingStorageMonitorExtendedMenuProvider(final PlatformResourceKey resource, + final StorageMonitorBlockEntity blockEntity) { + this.resource = resource; + this.blockEntity = blockEntity; + } + + @Override + public AbstractContainerMenu createMenu(final int syncId, + final Inventory inventory, + final Player player) { + return new AutocraftingStorageMonitorContainerMenu(syncId, resource, blockEntity); + } + + @Override + public Component getDisplayName() { + return ContentNames.STORAGE_MONITOR; + } + + @Override + public PlatformResourceKey getMenuData() { + return resource; + } + + @Override + public StreamEncoder getMenuCodec() { + return ResourceCodecs.STREAM_CODEC; + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/StorageMonitorBlock.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/StorageMonitorBlock.java index 6168adf7b..ddf44f1b0 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/StorageMonitorBlock.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/StorageMonitorBlock.java @@ -15,6 +15,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.entity.player.Player; @@ -96,7 +97,7 @@ public void attack(final BlockState state, final Level level, final BlockPos pos if (hitDirection != direction.asDirection()) { return; } - storageMonitor.extract(player); + storageMonitor.extract((ServerPlayer) player); } private Direction getHitDirection(final Level level, final Player player) { diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/StorageMonitorBlockEntity.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/StorageMonitorBlockEntity.java index 8b8925d9c..ec255feac 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/StorageMonitorBlockEntity.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/storagemonitor/StorageMonitorBlockEntity.java @@ -1,6 +1,9 @@ package com.refinedmods.refinedstorage.common.storagemonitor; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewProvider; import com.refinedmods.refinedstorage.api.network.Network; +import com.refinedmods.refinedstorage.api.network.autocrafting.AutocraftingNetworkComponent; import com.refinedmods.refinedstorage.api.network.impl.node.SimpleNetworkNode; import com.refinedmods.refinedstorage.api.network.storage.StorageNetworkComponent; import com.refinedmods.refinedstorage.api.resource.ResourceKey; @@ -9,6 +12,7 @@ import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; import com.refinedmods.refinedstorage.common.api.storage.PlayerActor; import com.refinedmods.refinedstorage.common.api.storage.root.FuzzyRootStorage; +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; import com.refinedmods.refinedstorage.common.api.support.resource.ResourceContainer; import com.refinedmods.refinedstorage.common.content.BlockEntities; import com.refinedmods.refinedstorage.common.content.ContentNames; @@ -21,6 +25,7 @@ import com.refinedmods.refinedstorage.common.support.resource.ResourceContainerImpl; import com.refinedmods.refinedstorage.common.util.PlatformUtil; +import java.util.Optional; import javax.annotation.Nullable; import com.google.common.util.concurrent.RateLimiter; @@ -31,6 +36,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.codec.StreamEncoder; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; @@ -44,7 +50,7 @@ import org.slf4j.LoggerFactory; public class StorageMonitorBlockEntity extends AbstractBaseNetworkNodeContainerBlockEntity - implements NetworkNodeExtendedMenuProvider { + implements NetworkNodeExtendedMenuProvider, AutocraftingPreviewProvider { private static final Logger LOGGER = LoggerFactory.getLogger(StorageMonitorBlockEntity.class); private static final String TAG_CLIENT_FILTER = "cf"; @@ -57,6 +63,7 @@ public class StorageMonitorBlockEntity extends AbstractBaseNetworkNodeContainerB private long currentAmount; private boolean currentlyActive; + private long lastExtractTime; public StorageMonitorBlockEntity(final BlockPos pos, final BlockState state) { super(BlockEntities.INSTANCE.getStorageMonitor(), pos, state, new SimpleNetworkNode( @@ -109,7 +116,7 @@ private long getAmount(final Network network, final ResourceKey configuredResour .sum(); } - public void extract(final Player player) { + public void extract(final ServerPlayer player) { if (level == null) { return; } @@ -117,14 +124,34 @@ public void extract(final Player player) { if (network == null) { return; } - final ResourceKey configuredResource = getConfiguredResource(); + final PlatformResourceKey configuredResource = getConfiguredResource(); if (configuredResource == null) { return; } - doExtract(level, player, configuredResource, network); + final boolean extracted = doExtract(level, player, configuredResource, network); + if (extracted) { + lastExtractTime = System.currentTimeMillis(); + } + if (!extracted && System.currentTimeMillis() - lastExtractTime > 250) { + tryAutocrafting(player, network, configuredResource); + } } - private void doExtract( + private void tryAutocrafting(final ServerPlayer player, + final Network network, + final PlatformResourceKey configuredResource) { + final boolean autocraftable = network.getComponent(AutocraftingNetworkComponent.class) + .getOutputs() + .contains(configuredResource); + if (autocraftable) { + Platform.INSTANCE.getMenuOpener().openMenu( + player, + new AutocraftingStorageMonitorExtendedMenuProvider(configuredResource, this) + ); + } + } + + private boolean doExtract( final Level level, final Player player, final ResourceKey configuredResource, @@ -138,7 +165,7 @@ private void doExtract( network ); if (!success) { - return; + return false; } sendDisplayUpdate(); level.playSound( @@ -149,6 +176,7 @@ private void doExtract( .2f, ((level.random.nextFloat() - level.random.nextFloat()) * .7f + 1) * 2 ); + return true; } public void insert(final Player player, final InteractionHand hand) { @@ -249,7 +277,7 @@ public void setFuzzyMode(final boolean fuzzyMode) { } @Nullable - public ResourceKey getConfiguredResource() { + public PlatformResourceKey getConfiguredResource() { return filter.getFilterContainer().getResource(0); } @@ -337,4 +365,20 @@ protected boolean doesBlockStateChangeWarrantNetworkNodeUpdate(final BlockState final BlockState newBlockState) { return AbstractDirectionalBlock.didDirectionChange(oldBlockState, newBlockState); } + + @Override + public Optional getPreview(final ResourceKey resource, final long amount) { + return Optional.ofNullable(mainNetworkNode.getNetwork()) + .map(network -> network.getComponent(AutocraftingNetworkComponent.class)) + .flatMap(component -> component.getPreview(resource, amount)); + } + + @Override + public boolean start(final ResourceKey resource, final long amount) { + final Network network = mainNetworkNode.getNetwork(); + if (network == null) { + return false; + } + return network.getComponent(AutocraftingNetworkComponent.class).start(resource, amount); + } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/ResourceSlotRendering.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/ResourceSlotRendering.java index 4cd868c58..4c4d8d604 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/ResourceSlotRendering.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/ResourceSlotRendering.java @@ -6,13 +6,10 @@ import com.refinedmods.refinedstorage.common.support.containermenu.ResourceSlot; import com.mojang.blaze3d.vertex.PoseStack; -import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; -import static java.util.Objects.requireNonNullElse; - public final class ResourceSlotRendering { private ResourceSlotRendering() { } @@ -58,7 +55,7 @@ public static void renderAmount(final GuiGraphics graphics, x, y, rendering.formatAmount(amount, true), - requireNonNullElse(ChatFormatting.WHITE.getColor(), 15), + 0xFFFFFF, true ); } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AbstractAmountScreen.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AbstractAmountScreen.java index e6a0e0a26..1743e4589 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AbstractAmountScreen.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AbstractAmountScreen.java @@ -3,11 +3,9 @@ import com.refinedmods.refinedstorage.common.autocrafting.AlternativesScreen; import com.refinedmods.refinedstorage.common.support.AbstractBaseScreen; -import java.util.Objects; import java.util.Optional; import javax.annotation.Nullable; -import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; @@ -22,28 +20,29 @@ import org.joml.Vector3f; import org.lwjgl.glfw.GLFW; +import static com.refinedmods.refinedstorage.common.support.amount.ConfirmButton.ERROR_SIZE; import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createTranslation; public abstract class AbstractAmountScreen extends AbstractBaseScreen { - private static final MutableComponent SET_TEXT = createTranslation("gui", "configure_amount.set"); private static final MutableComponent RESET_TEXT = createTranslation("gui", "configure_amount.reset"); private static final MutableComponent CANCEL_TEXT = Component.translatable("gui.cancel"); private static final int INCREMENT_BUTTON_WIDTH = 30; - private static final int ACTION_BUTTON_WIDTH = 50; private static final int ACTION_BUTTON_HEIGHT = 20; + private static final int ACTION_BUTTON_WIDTH = 50; + private static final int ACTION_BUTTON_SPACING = 20; + + @Nullable + protected ConfirmButton confirmButton; + @Nullable + protected EditBox amountField; @Nullable private final Screen parent; private final AmountScreenConfiguration configuration; private final AmountOperations amountOperations; - @Nullable - private EditBox amountField; - @Nullable - private Button confirmButton; - protected AbstractAmountScreen(final T containerMenu, @Nullable final Screen parent, final Inventory playerInventory, @@ -69,36 +68,50 @@ protected void init() { private void addActionButtons() { final Vector3f pos = configuration.getActionButtonsStartPosition(); if (configuration.isHorizontalActionButtons()) { - final int xIncrement = ACTION_BUTTON_WIDTH + 3; - addCancelButton((int) pos.x, (int) pos.y); - addResetButton((int) pos.x + xIncrement, (int) pos.y); - addConfirmButton((int) pos.x + xIncrement * 2, (int) pos.y); + final int spacing = 3; + final Button cancelButton = addCancelButton((int) pos.x, (int) pos.y); + final Button resetButton = addResetButton((int) pos.x + cancelButton.getWidth() + spacing, (int) pos.y); + addConfirmButton((int) pos.x + cancelButton.getWidth() + spacing + resetButton.getWidth() + spacing, + (int) pos.y); } else { - final int yIncrement = 24; + final int spacing = 24; addResetButton((int) pos.x, (int) pos.y); - addConfirmButton((int) pos.x, (int) pos.y + yIncrement); - addCancelButton((int) pos.x, (int) pos.y + yIncrement * 2); + addConfirmButton((int) pos.x, (int) pos.y + spacing); + addCancelButton((int) pos.x, (int) pos.y + spacing * 2); } } - private void addResetButton(final int x, final int y) { - addRenderableWidget(Button.builder(RESET_TEXT, btn -> reset()) + private Button addResetButton(final int x, final int y) { + final int width = configuration.isHorizontalActionButtons() + ? font.width(RESET_TEXT) + ACTION_BUTTON_SPACING + : ACTION_BUTTON_WIDTH; + return addRenderableWidget(Button.builder(RESET_TEXT, btn -> reset()) .pos(leftPos + x, topPos + y) - .size(ACTION_BUTTON_WIDTH, ACTION_BUTTON_HEIGHT) + .size(width, ACTION_BUTTON_HEIGHT) .build()); } private void addConfirmButton(final int x, final int y) { - confirmButton = addRenderableWidget(Button.builder(SET_TEXT, btn -> tryConfirmAndCloseToParent()) - .pos(leftPos + x, topPos + y) - .size(ACTION_BUTTON_WIDTH, ACTION_BUTTON_HEIGHT) - .build()); + final int width = configuration.isHorizontalActionButtons() + ? font.width(configuration.getConfirmButtonText()) + ACTION_BUTTON_SPACING + ERROR_SIZE + : ACTION_BUTTON_WIDTH; + confirmButton = addRenderableWidget(new ConfirmButton( + leftPos + x, + topPos + y, + width, + ACTION_BUTTON_HEIGHT, + configuration.getConfirmButtonText(), + btn -> tryConfirmAndCloseToParent() + )); } - private void addCancelButton(final int x, final int y) { - addRenderableWidget(Button.builder(CANCEL_TEXT, btn -> tryCloseToParent()) + private Button addCancelButton(final int x, final int y) { + final int width = configuration.isHorizontalActionButtons() + ? font.width(CANCEL_TEXT) + ACTION_BUTTON_SPACING + : ACTION_BUTTON_WIDTH; + return addRenderableWidget(Button.builder(CANCEL_TEXT, btn -> close()) .pos(leftPos + x, topPos + y) - .size(ACTION_BUTTON_WIDTH, ACTION_BUTTON_HEIGHT) + .size(width, ACTION_BUTTON_HEIGHT) .build()); } @@ -114,29 +127,39 @@ private void addAmountField() { ); amountField.setBordered(false); if (configuration.getInitialAmount() != null) { - amountField.setValue(amountOperations.format(configuration.getInitialAmount())); + updateAmount(configuration.getInitialAmount()); } amountField.setVisible(true); amountField.setCanLoseFocus(this instanceof AlternativesScreen); amountField.setFocused(true); - amountField.setResponder(value -> { - final boolean valid = getAndValidateAmount().isPresent(); - if (confirmButton != null) { - confirmButton.active = valid; - } else { - tryConfirm(); - } - amountField.setTextColor(valid - ? Objects.requireNonNullElse(ChatFormatting.WHITE.getColor(), 15) - : Objects.requireNonNullElse(ChatFormatting.RED.getColor(), 15) - ); - }); - amountField.setTextColor(Objects.requireNonNullElse(ChatFormatting.WHITE.getColor(), 15)); + amountField.setResponder(value -> onAmountFieldChanged()); + amountField.setTextColor(0xFFFFFF); setFocused(amountField); addRenderableWidget(amountField); } + protected final void updateAmount(final N amount) { + if (amountField == null) { + return; + } + amountField.setValue(amountOperations.format(amount)); + } + + protected void onAmountFieldChanged() { + if (amountField == null) { + return; + } + final boolean valid = getAndValidateAmount().isPresent(); + if (confirmButton != null) { + confirmButton.active = valid; + confirmButton.setError(!valid); + } else { + tryConfirm(); + } + amountField.setTextColor(valid ? 0xFFFFFF : 0xFF5555); + } + private void addIncrementButtons() { final Vector3f incrementsTopPos = configuration.getIncrementsTopStartPosition(); addIncrementButtons( @@ -160,7 +183,7 @@ private void addIncrementButtons(final int[] increments, final int x, final int } } - protected abstract void accept(N amount); + protected abstract boolean confirm(N amount); private Button createIncrementButton(final int x, final int y, final int increment) { final Component text = Component.literal((increment > 0 ? "+" : "") + increment); @@ -182,7 +205,7 @@ private void changeAmount(final int delta) { configuration.getMinAmount(), configuration.getMaxAmount() ); - amountField.setValue(amountOperations.format(newAmount)); + updateAmount(newAmount); }); } @@ -236,9 +259,7 @@ public boolean keyPressed(final int key, final int scanCode, final int modifiers protected final boolean tryClose(final int key) { if (key == GLFW.GLFW_KEY_ESCAPE) { - if (!tryCloseToParent()) { - onClose(); - } + close(); return true; } return false; @@ -248,17 +269,18 @@ protected void reset() { if (amountField == null || configuration.getResetAmount() == null) { return; } - amountField.setValue(amountOperations.format(configuration.getResetAmount())); + updateAmount(configuration.getResetAmount()); } private void tryConfirm() { - getAndValidateAmount().ifPresent(this::accept); + getAndValidateAmount().ifPresent(this::confirm); } private void tryConfirmAndCloseToParent() { getAndValidateAmount().ifPresent(value -> { - accept(value); - tryCloseToParent(); + if (confirm(value)) { + tryCloseToParent(); + } }); } @@ -270,7 +292,13 @@ private boolean tryCloseToParent() { return false; } - private Optional getAndValidateAmount() { + protected final void close() { + if (!tryCloseToParent()) { + onClose(); + } + } + + protected final Optional getAndValidateAmount() { if (amountField == null) { return Optional.empty(); } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AbstractSingleAmountScreen.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AbstractSingleAmountScreen.java index 24b0c03a4..37b707b9c 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AbstractSingleAmountScreen.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AbstractSingleAmountScreen.java @@ -38,8 +38,9 @@ protected AbstractSingleAmountScreen(final T containerMenu, } @Override - protected void accept(final Double amount) { + protected boolean confirm(final Double amount) { getMenu().changeAmountOnClient(amount); + return true; } @Override diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AmountScreenConfiguration.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AmountScreenConfiguration.java index 3f24f8552..b51cfa8c4 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AmountScreenConfiguration.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/AmountScreenConfiguration.java @@ -2,9 +2,15 @@ import javax.annotation.Nullable; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; import org.joml.Vector3f; +import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createTranslation; + public final class AmountScreenConfiguration { + private static final MutableComponent SET_TEXT = createTranslation("gui", "configure_amount.set"); + @Nullable private final T initialAmount; private final int[] incrementsTop; @@ -16,6 +22,7 @@ public final class AmountScreenConfiguration { private final Vector3f actionButtonsStartPosition; private final boolean horizontalActionButtons; private final boolean actionButtonsEnabled; + private final Component confirmButtonText; @Nullable private final T minAmount; @Nullable @@ -33,6 +40,7 @@ private AmountScreenConfiguration(@Nullable final T initialAmount, final Vector3f actionButtonsStartPosition, final boolean horizontalActionButtons, final boolean actionButtonsEnabled, + final Component confirmButtonText, @Nullable final T minAmount, @Nullable final T maxAmount, @Nullable final T resetAmount) { @@ -46,6 +54,7 @@ private AmountScreenConfiguration(@Nullable final T initialAmount, this.actionButtonsStartPosition = actionButtonsStartPosition; this.horizontalActionButtons = horizontalActionButtons; this.actionButtonsEnabled = actionButtonsEnabled; + this.confirmButtonText = confirmButtonText; this.minAmount = minAmount; this.maxAmount = maxAmount; this.resetAmount = resetAmount; @@ -92,6 +101,10 @@ public boolean isActionButtonsEnabled() { return actionButtonsEnabled; } + public Component getConfirmButtonText() { + return confirmButtonText; + } + @Nullable public T getMinAmount() { return minAmount; @@ -118,6 +131,7 @@ public static final class AmountScreenConfigurationBuilder { private Vector3f amountFieldPosition = new Vector3f(0, 0, 0); private Vector3f actionButtonsStartPosition = new Vector3f(0, 0, 0); private boolean horizontalActionButtons = false; + private Component confirmButtonText = SET_TEXT; private boolean actionButtonsEnabled = true; @Nullable private T minAmount; @@ -182,6 +196,13 @@ public AmountScreenConfigurationBuilder withHorizontalActionButtons( return this; } + public AmountScreenConfigurationBuilder withConfirmButtonText( + final Component newConfirmButtonText + ) { + this.confirmButtonText = newConfirmButtonText; + return this; + } + public AmountScreenConfigurationBuilder withActionButtonsEnabled( final boolean newActionButtonsEnabled ) { @@ -216,6 +237,7 @@ public AmountScreenConfiguration build() { actionButtonsStartPosition, horizontalActionButtons, actionButtonsEnabled, + confirmButtonText, minAmount, maxAmount, resetAmount diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/ConfirmButton.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/ConfirmButton.java new file mode 100644 index 000000000..b4998c387 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/ConfirmButton.java @@ -0,0 +1,52 @@ +package com.refinedmods.refinedstorage.common.support.amount; + +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createIdentifier; + +public class ConfirmButton extends Button { + static final int ERROR_SIZE = 12; + + private static final ResourceLocation ERROR_ICON = createIdentifier("error"); + + private boolean error; + + public ConfirmButton(final int x, + final int y, + final int width, + final int height, + final Component message, + final OnPress onPress) { + super(x, y, width, height, message, onPress, DEFAULT_NARRATION); + } + + @Override + protected void renderWidget(final GuiGraphics graphics, + final int mouseX, + final int mouseY, + final float partialTick) { + super.renderWidget(graphics, mouseX, mouseY, partialTick); + if (error) { + graphics.blitSprite(ERROR_ICON, getX() + 4, getY() + 4, ERROR_SIZE, ERROR_SIZE); + } + } + + @Override + protected void renderScrollingString(final GuiGraphics graphics, + final Font font, + final int width, + final int color) { + final int offset = error ? (ERROR_SIZE - 6) : 0; + final int start = offset + getX() + width; + final int end = offset + getX() + getWidth() - width; + renderScrollingString(graphics, font, getMessage(), start, getY(), end, getY() + getHeight(), color); + } + + public void setError(final boolean error) { + this.error = error; + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/PriorityScreen.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/PriorityScreen.java index bf53e52dc..2e008372c 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/PriorityScreen.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/PriorityScreen.java @@ -43,8 +43,9 @@ public PriorityScreen(final ClientProperty property, } @Override - protected void accept(final Integer amount) { + protected boolean confirm(final Integer amount) { property.setValue(amount); + return true; } @Override diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/ResourceAmountScreen.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/ResourceAmountScreen.java index 3035986b6..104e9584a 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/ResourceAmountScreen.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/amount/ResourceAmountScreen.java @@ -46,8 +46,9 @@ public ResourceAmountScreen(final Screen parent, final Inventory playerInventory } @Override - protected void accept(final Double amount) { + protected boolean confirm(final Double amount) { slot.changeAmountOnClient(amount); + return true; } @Override diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/AutocraftingPreviewRequestPacket.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/AutocraftingPreviewRequestPacket.java new file mode 100644 index 000000000..c7e7fb8d3 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/AutocraftingPreviewRequestPacket.java @@ -0,0 +1,49 @@ +package com.refinedmods.refinedstorage.common.support.packet.c2s; + +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewProvider; +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage.common.support.packet.PacketContext; +import com.refinedmods.refinedstorage.common.support.packet.s2c.S2CPackets; +import com.refinedmods.refinedstorage.common.support.resource.ResourceCodecs; + +import java.util.UUID; + +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; + +import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createIdentifier; + +public record AutocraftingPreviewRequestPacket(UUID id, + PlatformResourceKey resource, + long amount) implements CustomPacketPayload { + public static final CustomPacketPayload.Type + PACKET_TYPE = new CustomPacketPayload.Type<>( + createIdentifier("autocrafting_preview_request") + ); + public static final StreamCodec STREAM_CODEC = + StreamCodec + .composite( + UUIDUtil.STREAM_CODEC, AutocraftingPreviewRequestPacket::id, + ResourceCodecs.STREAM_CODEC, AutocraftingPreviewRequestPacket::resource, + ByteBufCodecs.VAR_LONG, AutocraftingPreviewRequestPacket::amount, + AutocraftingPreviewRequestPacket::new + ); + + public static void handle(final AutocraftingPreviewRequestPacket packet, final PacketContext ctx) { + if (ctx.getPlayer().containerMenu instanceof AutocraftingPreviewProvider provider) { + final ServerPlayer player = (ServerPlayer) ctx.getPlayer(); + provider.getPreview(packet.resource(), packet.amount()).ifPresent( + preview -> S2CPackets.sendAutocraftingPreviewResponse(player, packet.id, preview) + ); + } + } + + @Override + public CustomPacketPayload.Type type() { + return PACKET_TYPE; + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/AutocraftingRequestPacket.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/AutocraftingRequestPacket.java new file mode 100644 index 000000000..18ba3b302 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/AutocraftingRequestPacket.java @@ -0,0 +1,46 @@ +package com.refinedmods.refinedstorage.common.support.packet.c2s; + +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewProvider; +import com.refinedmods.refinedstorage.common.api.support.resource.PlatformResourceKey; +import com.refinedmods.refinedstorage.common.support.packet.PacketContext; +import com.refinedmods.refinedstorage.common.support.packet.s2c.S2CPackets; +import com.refinedmods.refinedstorage.common.support.resource.ResourceCodecs; + +import java.util.UUID; + +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; + +import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createIdentifier; + +public record AutocraftingRequestPacket(UUID id, + PlatformResourceKey resource, + long amount) implements CustomPacketPayload { + public static final Type PACKET_TYPE = new Type<>( + createIdentifier("autocrafting_request") + ); + public static final StreamCodec STREAM_CODEC = + StreamCodec + .composite( + UUIDUtil.STREAM_CODEC, AutocraftingRequestPacket::id, + ResourceCodecs.STREAM_CODEC, AutocraftingRequestPacket::resource, + ByteBufCodecs.VAR_LONG, AutocraftingRequestPacket::amount, + AutocraftingRequestPacket::new + ); + + public static void handle(final AutocraftingRequestPacket packet, final PacketContext ctx) { + if (ctx.getPlayer().containerMenu instanceof AutocraftingPreviewProvider provider) { + final boolean started = provider.start(packet.resource(), packet.amount()); + S2CPackets.sendAutocraftingResponse((ServerPlayer) ctx.getPlayer(), packet.id, started); + } + } + + @Override + public Type type() { + return PACKET_TYPE; + } +} diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/C2SPackets.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/C2SPackets.java index 618e09aef..bc20c2224 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/C2SPackets.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/c2s/C2SPackets.java @@ -131,4 +131,16 @@ public static void sendPatternGridSmithingTableRecipeTransfer(final List PACKET_TYPE = new Type<>( + createIdentifier("autocrafting_preview_response") + ); + private static final StreamCodec PREVIEW_ITEM_STREAM_CODEC = + StreamCodec.composite( + ResourceCodecs.STREAM_CODEC, item -> (PlatformResourceKey) item.resource(), + ByteBufCodecs.VAR_LONG, AutocraftingPreviewItem::available, + ByteBufCodecs.VAR_LONG, AutocraftingPreviewItem::missing, + ByteBufCodecs.VAR_LONG, AutocraftingPreviewItem::toCraft, + AutocraftingPreviewItem::new + ); + private static final StreamCodec PREVIEW_STREAM_CODEC = + StreamCodec.composite( + enumStreamCodec(AutocraftingPreviewType.values()), AutocraftingPreview::type, + ByteBufCodecs.collection(ArrayList::new, PREVIEW_ITEM_STREAM_CODEC), AutocraftingPreview::items, + AutocraftingPreview::new + ); + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite( + UUIDUtil.STREAM_CODEC, AutocraftingPreviewResponsePacket::id, + PREVIEW_STREAM_CODEC, AutocraftingPreviewResponsePacket::preview, + AutocraftingPreviewResponsePacket::new + ); + + public static void handle(final AutocraftingPreviewResponsePacket packet) { + ClientPlatformUtil.autocraftingPreviewResponseReceived(packet.id, packet.preview); + } + + @Override + public Type type() { + return PACKET_TYPE; + } +} + diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/s2c/AutocraftingResponsePacket.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/s2c/AutocraftingResponsePacket.java new file mode 100644 index 000000000..1b1467d63 --- /dev/null +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/s2c/AutocraftingResponsePacket.java @@ -0,0 +1,36 @@ +package com.refinedmods.refinedstorage.common.support.packet.s2c; + +import com.refinedmods.refinedstorage.common.util.ClientPlatformUtil; + +import java.util.UUID; + +import net.minecraft.core.UUIDUtil; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; + +import static com.refinedmods.refinedstorage.common.util.IdentifierUtil.createIdentifier; + +public record AutocraftingResponsePacket(UUID id, boolean started) implements CustomPacketPayload { + public static final Type PACKET_TYPE = new Type<>( + createIdentifier("autocrafting_response") + ); + + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite( + UUIDUtil.STREAM_CODEC, AutocraftingResponsePacket::id, + ByteBufCodecs.BOOL, AutocraftingResponsePacket::started, + AutocraftingResponsePacket::new + ); + + public static void handle(final AutocraftingResponsePacket packet) { + ClientPlatformUtil.autocraftingResponseReceived(packet.id, packet.started); + } + + @Override + public Type type() { + return PACKET_TYPE; + } +} + diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/s2c/S2CPackets.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/s2c/S2CPackets.java index 2cc191708..08b365c36 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/s2c/S2CPackets.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/packet/s2c/S2CPackets.java @@ -1,5 +1,6 @@ package com.refinedmods.refinedstorage.common.support.packet.s2c; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; import com.refinedmods.refinedstorage.api.resource.ResourceAmount; import com.refinedmods.refinedstorage.api.storage.tracked.TrackedResource; import com.refinedmods.refinedstorage.common.Platform; @@ -85,4 +86,16 @@ public static void sendPatternGridAllowedAlternativesUpdate(final ServerPlayer p public static void sendCrafterNameUpdate(final ServerPlayer player, final Component name) { Platform.INSTANCE.sendPacketToClient(player, new CrafterNameUpdatePacket(name)); } + + public static void sendAutocraftingPreviewResponse(final ServerPlayer player, + final UUID id, + final AutocraftingPreview preview) { + Platform.INSTANCE.sendPacketToClient(player, new AutocraftingPreviewResponsePacket(id, preview)); + } + + public static void sendAutocraftingResponse(final ServerPlayer player, + final UUID id, + final boolean started) { + Platform.INSTANCE.sendPacketToClient(player, new AutocraftingResponsePacket(id, started)); + } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/tooltip/ResourceClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/tooltip/ResourceClientTooltipComponent.java index ecff0219d..526fa8153 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/tooltip/ResourceClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/tooltip/ResourceClientTooltipComponent.java @@ -4,9 +4,6 @@ import com.refinedmods.refinedstorage.common.api.RefinedStorageApi; import com.refinedmods.refinedstorage.common.api.support.resource.ResourceRendering; -import java.util.Objects; - -import net.minecraft.ChatFormatting; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; @@ -44,7 +41,7 @@ public void renderImage(final Font font, final int x, final int y, final GuiGrap name, x + 16 + 4, y + 4, - Objects.requireNonNullElse(ChatFormatting.GRAY.getColor(), 11184810) + 0xAAAAAA ); } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/tooltip/SmallText.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/tooltip/SmallText.java index a4756a8c2..d84fcc952 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/tooltip/SmallText.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/tooltip/SmallText.java @@ -2,6 +2,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.util.FormattedCharSequence; import org.joml.Matrix4f; @@ -50,4 +51,18 @@ public static void render(final Font font, 15728880 ); } + + public static void render(final GuiGraphics graphics, + final Font font, + final FormattedCharSequence text, + final int x, + final int y, + final int color, + final boolean dropShadow) { + final float scale = getScale(); + graphics.pose().pushPose(); + graphics.pose().scale(scale, scale, 1); + graphics.drawString(font, text, (int) (x / scale), (int) (y / scale) + 1, color, dropShadow); + graphics.pose().popPose(); + } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/widget/TextMarquee.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/widget/TextMarquee.java index dcf34b4b6..16532eab6 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/widget/TextMarquee.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/support/widget/TextMarquee.java @@ -1,20 +1,36 @@ package com.refinedmods.refinedstorage.common.support.widget; +import com.refinedmods.refinedstorage.common.support.tooltip.SmallText; + import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; public class TextMarquee { private final int maxWidth; + private final int color; + private final boolean dropShadow; + private final boolean small; private Component text; private int offset; private int stateTicks; private State state = State.MOVING_LEFT; - public TextMarquee(final Component text, final int maxWidth) { + public TextMarquee(final Component text, + final int maxWidth, + final int color, + final boolean dropShadow, + final boolean small) { this.text = text; this.maxWidth = maxWidth; + this.color = color; + this.dropShadow = dropShadow; + this.small = small; + } + + public TextMarquee(final Component text, final int maxWidth) { + this(text, maxWidth, 4210752, false, false); } public int getEffectiveWidth(final Font font) { @@ -27,17 +43,41 @@ public void render(final GuiGraphics graphics, final int x, final int y, final F state = State.MOVING_LEFT; stateTicks = 0; } - final int width = font.width(text); + final int width = (int) (font.width(text) * (small ? SmallText.getScale() : 1F)); if (width > maxWidth) { final int overflow = width - maxWidth; if (hovering) { updateMarquee(overflow); } graphics.enableScissor(x, y, x + maxWidth, y + font.lineHeight); - graphics.drawString(font, text, x + offset, y, 4210752, false); + if (small) { + SmallText.render( + graphics, + font, + text.getVisualOrderText(), + x + offset, + y, + color, + dropShadow + ); + } else { + graphics.drawString(font, text, x + offset, y, color, dropShadow); + } graphics.disableScissor(); } else { - graphics.drawString(font, text, x, y, 4210752, false); + if (small) { + SmallText.render( + graphics, + font, + text.getVisualOrderText(), + x, + y, + color, + dropShadow + ); + } else { + graphics.drawString(font, text, x, y, color, dropShadow); + } } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/upgrade/UpgradeDestinationClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/upgrade/UpgradeDestinationClientTooltipComponent.java index 1895b2dac..ae68aedf3 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/upgrade/UpgradeDestinationClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/upgrade/UpgradeDestinationClientTooltipComponent.java @@ -2,7 +2,6 @@ import com.refinedmods.refinedstorage.common.api.upgrade.UpgradeMapping; -import java.util.Objects; import java.util.Set; import net.minecraft.ChatFormatting; @@ -45,7 +44,7 @@ private void renderMapping(final Font font, mapping.destinationDisplayName().copy().withStyle(ChatFormatting.GRAY), x + 16 + 4, y + 4, - Objects.requireNonNullElse(ChatFormatting.GRAY.getColor(), 7) + 0xAAAAAA ); } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/upgrade/UpgradeItemClientTooltipComponent.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/upgrade/UpgradeItemClientTooltipComponent.java index 737db9d77..be000cacc 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/upgrade/UpgradeItemClientTooltipComponent.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/upgrade/UpgradeItemClientTooltipComponent.java @@ -3,9 +3,6 @@ import com.refinedmods.refinedstorage.common.api.upgrade.UpgradeMapping; -import java.util.Objects; - -import net.minecraft.ChatFormatting; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; @@ -36,7 +33,7 @@ public void renderImage(final Font font, final int x, final int y, final GuiGrap mapping.upgradeDisplayName(), x + 16 + 4, y + 4, - Objects.requireNonNullElse(ChatFormatting.WHITE.getColor(), 15) + 0xFFFFFF ); } } diff --git a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/util/ClientPlatformUtil.java b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/util/ClientPlatformUtil.java index 72bf0d0dd..8d3f95629 100644 --- a/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/util/ClientPlatformUtil.java +++ b/refinedstorage-common/src/main/java/com/refinedmods/refinedstorage/common/util/ClientPlatformUtil.java @@ -1,5 +1,9 @@ package com.refinedmods.refinedstorage.common.util; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; +import com.refinedmods.refinedstorage.common.autocrafting.preview.AutocraftingPreviewScreen; + +import java.util.UUID; import javax.annotation.Nullable; import net.minecraft.client.Minecraft; @@ -30,4 +34,16 @@ public static void addNoPermissionToast(final Component message) { message ); } + + public static void autocraftingPreviewResponseReceived(final UUID id, final AutocraftingPreview preview) { + if (Minecraft.getInstance().screen instanceof AutocraftingPreviewScreen screen) { + screen.getMenu().previewResponseReceived(id, preview); + } + } + + public static void autocraftingResponseReceived(final UUID id, final boolean started) { + if (Minecraft.getInstance().screen instanceof AutocraftingPreviewScreen screen) { + screen.responseReceived(id, started); + } + } } diff --git a/refinedstorage-common/src/main/resources/assets/refinedstorage/lang/en_us.json b/refinedstorage-common/src/main/resources/assets/refinedstorage/lang/en_us.json index f278e5e54..23b21ddc2 100644 --- a/refinedstorage-common/src/main/resources/assets/refinedstorage/lang/en_us.json +++ b/refinedstorage-common/src/main/resources/assets/refinedstorage/lang/en_us.json @@ -206,6 +206,13 @@ "gui.refinedstorage.crafter.chained.head_help": "This crafter is the head of the chain.", "gui.refinedstorage.crafter.not_chained": "Not chained", "gui.refinedstorage.crafter.not_chained.help": "If another crafter is facing this one, they'll form a chain, allowing you to have more patterns going into a single machine.", + "gui.refinedstorage.autocrafting_preview.title": "Autocrafting", + "gui.refinedstorage.autocrafting_preview.start": "Start", + "gui.refinedstorage.autocrafting_preview.pending": "Pending", + "gui.refinedstorage.autocrafting_preview.start.missing_resources": "There are missing resources.", + "gui.refinedstorage.autocrafting_preview.available": "Available: %s", + "gui.refinedstorage.autocrafting_preview.to_craft": "To craft: %s", + "gui.refinedstorage.autocrafting_preview.missing": "Missing: %s", "item.refinedstorage.controller.help": "Provides the storage network with energy. Multiple are allowed in a single storage network.", "item.refinedstorage.creative_controller.help": "Provides the storage network with an infinite source of energy.", "item.refinedstorage.disk_drive.help": "Accepts storage disks to provide the storage network with storage space.", diff --git a/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/autocrafting_preview.png b/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/autocrafting_preview.png new file mode 100644 index 000000000..6f801a9a2 Binary files /dev/null and b/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/autocrafting_preview.png differ diff --git a/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/autocrafting_preview/requests.png b/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/autocrafting_preview/requests.png new file mode 100644 index 000000000..dce1ee2e3 Binary files /dev/null and b/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/autocrafting_preview/requests.png differ diff --git a/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/autocrafting_preview/row.png b/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/autocrafting_preview/row.png new file mode 100644 index 000000000..5a8dc29c6 Binary files /dev/null and b/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/autocrafting_preview/row.png differ diff --git a/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/error.png b/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/error.png new file mode 100644 index 000000000..7ee9da4ea Binary files /dev/null and b/refinedstorage-common/src/main/resources/assets/refinedstorage/textures/gui/sprites/error.png differ diff --git a/refinedstorage-fabric/src/main/java/com/refinedmods/refinedstorage/fabric/ClientModInitializerImpl.java b/refinedstorage-fabric/src/main/java/com/refinedmods/refinedstorage/fabric/ClientModInitializerImpl.java index fe960a80f..37e89fd79 100644 --- a/refinedstorage-fabric/src/main/java/com/refinedmods/refinedstorage/fabric/ClientModInitializerImpl.java +++ b/refinedstorage-fabric/src/main/java/com/refinedmods/refinedstorage/fabric/ClientModInitializerImpl.java @@ -19,6 +19,8 @@ import com.refinedmods.refinedstorage.common.storagemonitor.StorageMonitorBlockEntityRenderer; import com.refinedmods.refinedstorage.common.support.network.item.NetworkItemPropertyFunction; import com.refinedmods.refinedstorage.common.support.packet.PacketHandler; +import com.refinedmods.refinedstorage.common.support.packet.s2c.AutocraftingPreviewResponsePacket; +import com.refinedmods.refinedstorage.common.support.packet.s2c.AutocraftingResponsePacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.CrafterNameUpdatePacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.EnergyInfoPacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.GridActivePacket; @@ -290,6 +292,14 @@ private void registerPacketHandlers() { CrafterNameUpdatePacket.PACKET_TYPE, wrapHandler(CrafterNameUpdatePacket::handle) ); + ClientPlayNetworking.registerGlobalReceiver( + AutocraftingPreviewResponsePacket.PACKET_TYPE, + wrapHandler((packet, ctx) -> AutocraftingPreviewResponsePacket.handle(packet)) + ); + ClientPlayNetworking.registerGlobalReceiver( + AutocraftingResponsePacket.PACKET_TYPE, + wrapHandler((packet, ctx) -> AutocraftingResponsePacket.handle(packet)) + ); } private static ClientPlayNetworking.PlayPayloadHandler wrapHandler( diff --git a/refinedstorage-fabric/src/main/java/com/refinedmods/refinedstorage/fabric/ModInitializerImpl.java b/refinedstorage-fabric/src/main/java/com/refinedmods/refinedstorage/fabric/ModInitializerImpl.java index 92e3255ca..dc3f23626 100644 --- a/refinedstorage-fabric/src/main/java/com/refinedmods/refinedstorage/fabric/ModInitializerImpl.java +++ b/refinedstorage-fabric/src/main/java/com/refinedmods/refinedstorage/fabric/ModInitializerImpl.java @@ -29,6 +29,8 @@ import com.refinedmods.refinedstorage.common.storage.portablegrid.PortableGridType; import com.refinedmods.refinedstorage.common.support.AbstractBaseBlock; import com.refinedmods.refinedstorage.common.support.packet.PacketHandler; +import com.refinedmods.refinedstorage.common.support.packet.c2s.AutocraftingPreviewRequestPacket; +import com.refinedmods.refinedstorage.common.support.packet.c2s.AutocraftingRequestPacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.CrafterNameChangePacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.CraftingGridClearPacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.CraftingGridRecipeTransferPacket; @@ -53,6 +55,8 @@ import com.refinedmods.refinedstorage.common.support.packet.c2s.SingleAmountChangePacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.StorageInfoRequestPacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.UseSlotReferencedItemPacket; +import com.refinedmods.refinedstorage.common.support.packet.s2c.AutocraftingPreviewResponsePacket; +import com.refinedmods.refinedstorage.common.support.packet.s2c.AutocraftingResponsePacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.CrafterNameUpdatePacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.EnergyInfoPacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.GridActivePacket; @@ -443,6 +447,14 @@ private void registerServerToClientPackets() { CrafterNameUpdatePacket.PACKET_TYPE, CrafterNameUpdatePacket.STREAM_CODEC ); + PayloadTypeRegistry.playS2C().register( + AutocraftingPreviewResponsePacket.PACKET_TYPE, + AutocraftingPreviewResponsePacket.STREAM_CODEC + ); + PayloadTypeRegistry.playS2C().register( + AutocraftingResponsePacket.PACKET_TYPE, + AutocraftingResponsePacket.STREAM_CODEC + ); } private void registerClientToServerPackets() { @@ -530,6 +542,14 @@ private void registerClientToServerPackets() { CrafterNameChangePacket.PACKET_TYPE, CrafterNameChangePacket.STREAM_CODEC ); + PayloadTypeRegistry.playC2S().register( + AutocraftingPreviewRequestPacket.PACKET_TYPE, + AutocraftingPreviewRequestPacket.STREAM_CODEC + ); + PayloadTypeRegistry.playC2S().register( + AutocraftingRequestPacket.PACKET_TYPE, + AutocraftingRequestPacket.STREAM_CODEC + ); } private void registerPacketHandlers() { @@ -629,6 +649,14 @@ private void registerPacketHandlers() { CrafterNameChangePacket.PACKET_TYPE, wrapHandler(CrafterNameChangePacket::handle) ); + ServerPlayNetworking.registerGlobalReceiver( + AutocraftingPreviewRequestPacket.PACKET_TYPE, + wrapHandler(AutocraftingPreviewRequestPacket::handle) + ); + ServerPlayNetworking.registerGlobalReceiver( + AutocraftingRequestPacket.PACKET_TYPE, + wrapHandler(AutocraftingRequestPacket::handle) + ); } private static ServerPlayNetworking.PlayPayloadHandler wrapHandler( diff --git a/refinedstorage-neoforge/src/main/java/com/refinedmods/refinedstorage/neoforge/ModInitializer.java b/refinedstorage-neoforge/src/main/java/com/refinedmods/refinedstorage/neoforge/ModInitializer.java index 537ae459f..a8b9ebd5a 100644 --- a/refinedstorage-neoforge/src/main/java/com/refinedmods/refinedstorage/neoforge/ModInitializer.java +++ b/refinedstorage-neoforge/src/main/java/com/refinedmods/refinedstorage/neoforge/ModInitializer.java @@ -29,6 +29,8 @@ import com.refinedmods.refinedstorage.common.storage.portablegrid.PortableGridType; import com.refinedmods.refinedstorage.common.support.AbstractBaseBlock; import com.refinedmods.refinedstorage.common.support.packet.PacketHandler; +import com.refinedmods.refinedstorage.common.support.packet.c2s.AutocraftingPreviewRequestPacket; +import com.refinedmods.refinedstorage.common.support.packet.c2s.AutocraftingRequestPacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.CrafterNameChangePacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.CraftingGridClearPacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.CraftingGridRecipeTransferPacket; @@ -53,6 +55,8 @@ import com.refinedmods.refinedstorage.common.support.packet.c2s.SingleAmountChangePacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.StorageInfoRequestPacket; import com.refinedmods.refinedstorage.common.support.packet.c2s.UseSlotReferencedItemPacket; +import com.refinedmods.refinedstorage.common.support.packet.s2c.AutocraftingPreviewResponsePacket; +import com.refinedmods.refinedstorage.common.support.packet.s2c.AutocraftingResponsePacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.CrafterNameUpdatePacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.EnergyInfoPacket; import com.refinedmods.refinedstorage.common.support.packet.s2c.GridActivePacket; @@ -631,6 +635,16 @@ private static void registerServerToClientPackets(final PayloadRegistrar registr CrafterNameUpdatePacket.STREAM_CODEC, wrapHandler(CrafterNameUpdatePacket::handle) ); + registrar.playToClient( + AutocraftingPreviewResponsePacket.PACKET_TYPE, + AutocraftingPreviewResponsePacket.STREAM_CODEC, + wrapHandler((packet, ctx) -> AutocraftingPreviewResponsePacket.handle(packet)) + ); + registrar.playToClient( + AutocraftingResponsePacket.PACKET_TYPE, + AutocraftingResponsePacket.STREAM_CODEC, + wrapHandler((packet, ctx) -> AutocraftingResponsePacket.handle(packet)) + ); } private static void registerClientToServerPackets(final PayloadRegistrar registrar) { @@ -754,6 +768,16 @@ private static void registerClientToServerPackets(final PayloadRegistrar registr CrafterNameChangePacket.STREAM_CODEC, wrapHandler(CrafterNameChangePacket::handle) ); + registrar.playToServer( + AutocraftingPreviewRequestPacket.PACKET_TYPE, + AutocraftingPreviewRequestPacket.STREAM_CODEC, + wrapHandler(AutocraftingPreviewRequestPacket::handle) + ); + registrar.playToServer( + AutocraftingRequestPacket.PACKET_TYPE, + AutocraftingRequestPacket.STREAM_CODEC, + wrapHandler(AutocraftingRequestPacket::handle) + ); } private static IPayloadHandler wrapHandler(final PacketHandler handler) { diff --git a/refinedstorage-network-api/src/main/java/com/refinedmods/refinedstorage/api/network/autocrafting/AutocraftingNetworkComponent.java b/refinedstorage-network-api/src/main/java/com/refinedmods/refinedstorage/api/network/autocrafting/AutocraftingNetworkComponent.java index 392287596..8bca0a60a 100644 --- a/refinedstorage-network-api/src/main/java/com/refinedmods/refinedstorage/api/network/autocrafting/AutocraftingNetworkComponent.java +++ b/refinedstorage-network-api/src/main/java/com/refinedmods/refinedstorage/api/network/autocrafting/AutocraftingNetworkComponent.java @@ -1,10 +1,11 @@ package com.refinedmods.refinedstorage.api.network.autocrafting; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewProvider; import com.refinedmods.refinedstorage.api.autocrafting.PatternRepository; import com.refinedmods.refinedstorage.api.network.NetworkComponent; import org.apiguardian.api.API; @API(status = API.Status.STABLE, since = "2.0.0-milestone.4.8") -public interface AutocraftingNetworkComponent extends NetworkComponent, PatternRepository { +public interface AutocraftingNetworkComponent extends NetworkComponent, PatternRepository, AutocraftingPreviewProvider { } diff --git a/refinedstorage-network/src/main/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImpl.java b/refinedstorage-network/src/main/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImpl.java index 6d3db761e..0e7fe1329 100644 --- a/refinedstorage-network/src/main/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImpl.java +++ b/refinedstorage-network/src/main/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImpl.java @@ -1,5 +1,8 @@ package com.refinedmods.refinedstorage.api.network.impl.autocrafting; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreview; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewItem; +import com.refinedmods.refinedstorage.api.autocrafting.AutocraftingPreviewType; import com.refinedmods.refinedstorage.api.autocrafting.Pattern; import com.refinedmods.refinedstorage.api.autocrafting.PatternRepository; import com.refinedmods.refinedstorage.api.network.autocrafting.AutocraftingNetworkComponent; @@ -7,6 +10,9 @@ import com.refinedmods.refinedstorage.api.network.node.container.NetworkNodeContainer; import com.refinedmods.refinedstorage.api.resource.ResourceKey; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import java.util.Set; public class AutocraftingNetworkComponentImpl implements AutocraftingNetworkComponent { @@ -44,4 +50,26 @@ public void remove(final Pattern pattern) { public Set getOutputs() { return patternRepository.getOutputs(); } + + @Override + public Optional getPreview(final ResourceKey resource, final long amount) { + final List items = new ArrayList<>(); + final boolean missing = amount == 404; + for (int i = 0; i < 31; ++i) { + items.add(new AutocraftingPreviewItem( + resource, + (i + 1), + (i % 2 == 0 && missing) ? amount : 0, + i % 2 == 0 ? 0 : amount + )); + } + return Optional.of(new AutocraftingPreview(missing + ? AutocraftingPreviewType.MISSING_RESOURCES + : AutocraftingPreviewType.SUCCESS, items)); + } + + @Override + public boolean start(final ResourceKey resource, final long amount) { + return true; + } } diff --git a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImplTest.java b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImplTest.java index 2b4b0a7b8..791020b50 100644 --- a/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImplTest.java +++ b/refinedstorage-network/src/test/java/com/refinedmods/refinedstorage/api/network/impl/autocrafting/AutocraftingNetworkComponentImplTest.java @@ -73,4 +73,14 @@ void shouldRemovePatternManually() { // Assert assertThat(sut.getOutputs()).usingRecursiveFieldByFieldElementComparator().isEmpty(); } + + @Test + void shouldStart() { + sut.start(FakeResources.A, 10); + } + + @Test + void shouldGetPreview() { + sut.getPreview(FakeResources.A, 10); + } }