aboutsummaryrefslogtreecommitdiff
path: root/runtime/src/main/java/me/shedaniel/rei/plugin/client
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2021-03-25 03:55:36 +0800
committershedaniel <daniel@shedaniel.me>2021-03-25 03:55:36 +0800
commit995b8b58aa8c890c9181ae479e12a4facfa05a25 (patch)
treea16149371fc4b69a73e2ab13e2d96cd2c324b43a /runtime/src/main/java/me/shedaniel/rei/plugin/client
parenta34a748d2b6cdb1f70f176f1ec1bd27cbc2a98cf (diff)
downloadRoughlyEnoughItems-995b8b58aa8c890c9181ae479e12a4facfa05a25.tar.gz
RoughlyEnoughItems-995b8b58aa8c890c9181ae479e12a4facfa05a25.tar.bz2
RoughlyEnoughItems-995b8b58aa8c890c9181ae479e12a4facfa05a25.zip
Relocate most of the internal classes to match the api
Signed-off-by: shedaniel <daniel@shedaniel.me>
Diffstat (limited to 'runtime/src/main/java/me/shedaniel/rei/plugin/client')
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientRuntimePlugin.java250
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java210
-rw-r--r--runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java252
3 files changed, 712 insertions, 0 deletions
diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientRuntimePlugin.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientRuntimePlugin.java
new file mode 100644
index 000000000..d1a88efc7
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/DefaultClientRuntimePlugin.java
@@ -0,0 +1,250 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.plugin.client;
+
+import com.google.gson.JsonObject;
+import com.mojang.blaze3d.vertex.PoseStack;
+import me.shedaniel.architectury.fluid.FluidStack;
+import me.shedaniel.math.Point;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.api.client.ClientHelper;
+import me.shedaniel.rei.api.client.favorites.FavoriteEntry;
+import me.shedaniel.rei.api.client.favorites.FavoriteEntryType;
+import me.shedaniel.rei.api.client.gui.AbstractRenderer;
+import me.shedaniel.rei.api.client.gui.Renderer;
+import me.shedaniel.rei.api.client.gui.widgets.Panel;
+import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
+import me.shedaniel.rei.api.client.util.ClientEntryStacks;
+import me.shedaniel.rei.api.client.plugins.REIClientPlugin;
+import me.shedaniel.rei.api.client.registry.entry.EntryRegistry;
+import me.shedaniel.rei.api.client.registry.screen.DisplayBoundsProvider;
+import me.shedaniel.rei.api.client.registry.screen.ExclusionZones;
+import me.shedaniel.rei.api.client.registry.screen.ScreenRegistry;
+import me.shedaniel.rei.api.client.registry.transfer.TransferHandlerRegistry;
+import me.shedaniel.rei.api.common.fluid.FluidSupportProvider;
+import me.shedaniel.rei.api.common.entry.EntryStack;
+import me.shedaniel.rei.api.common.entry.type.EntryTypeRegistry;
+import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
+import me.shedaniel.rei.api.common.util.EntryStacks;
+import me.shedaniel.rei.impl.client.gui.screen.AbstractDisplayViewingScreen;
+import me.shedaniel.rei.impl.client.gui.ContainerScreenOverlay;
+import me.shedaniel.rei.impl.client.gui.screen.DefaultDisplayViewingScreen;
+import me.shedaniel.rei.impl.client.gui.widget.FavoritesListWidget;
+import me.shedaniel.rei.impl.client.ClientHelperImpl;
+import me.shedaniel.rei.plugin.autocrafting.DefaultCategoryHandler;
+import me.shedaniel.rei.plugin.client.entry.FluidEntryDefinition;
+import me.shedaniel.rei.plugin.client.entry.ItemEntryDefinition;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.network.chat.TextComponent;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.util.GsonHelper;
+import net.minecraft.world.InteractionResult;
+import net.minecraft.world.InteractionResultHolder;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collections;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+@ApiStatus.Internal
+@Environment(EnvType.CLIENT)
+public class DefaultClientRuntimePlugin implements REIClientPlugin {
+ public static final ResourceLocation PLUGIN = new ResourceLocation("roughlyenoughitems", "default_runtime_plugin");
+
+ @Override
+ public void registerEntryTypes(EntryTypeRegistry registry) {
+ registry.register(VanillaEntryTypes.ITEM, new ItemEntryDefinition());
+ registry.register(VanillaEntryTypes.FLUID, new FluidEntryDefinition());
+
+ registry.registerBridge(VanillaEntryTypes.ITEM, VanillaEntryTypes.FLUID, input -> {
+ Optional<Stream<EntryStack<FluidStack>>> stream = FluidSupportProvider.getInstance().itemToFluids(input);
+ if (!stream.isPresent()) {
+ return InteractionResultHolder.pass(Stream.empty());
+ }
+ return InteractionResultHolder.success(stream.get());
+ });
+ }
+
+ @Override
+ public void registerEntries(EntryRegistry registry) {
+ if (ClientHelperImpl.getInstance().isAprilFools.get()) {
+ registry.registerEntry(ClientEntryStacks.of(new AbstractRenderer() {
+ private ResourceLocation id = new ResourceLocation("roughlyenoughitems", "textures/gui/kirb.png");
+
+ @Override
+ public void render(PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ Minecraft.getInstance().getTextureManager().bind(id);
+ innerBlit(matrices.last().pose(), bounds.x, bounds.getMaxX(), bounds.y, bounds.getMaxY(), getBlitOffset(), 0, 1, 0, 1);
+ }
+
+ @Override
+ public @Nullable Tooltip getTooltip(Point point) {
+ return Tooltip.create(new TextComponent("Kirby"), ClientHelper.getInstance().getFormattedModFromModId("Dream Land"));
+ }
+ }));
+ }
+ }
+
+ @Override
+ public void registerScreens(ScreenRegistry registry) {
+ ExclusionZones zones = registry.exclusionZones();
+ zones.register(DefaultDisplayViewingScreen.class, screen -> {
+ Panel widget = screen.getWorkingStationsBaseWidget();
+ if (widget == null)
+ return Collections.emptyList();
+ return Collections.singletonList(widget.getBounds().clone());
+ });
+ zones.register(Screen.class, screen -> {
+ FavoritesListWidget widget = ContainerScreenOverlay.getFavoritesListWidget();
+ if (widget != null) {
+ if (widget.favoritePanelButton.isVisible()) {
+ return Collections.singletonList(widget.favoritePanelButton.bounds);
+ }
+ }
+ return Collections.emptyList();
+ });
+ registry.registerDecider(new DisplayBoundsProvider<AbstractDisplayViewingScreen>() {
+ @Override
+ public Rectangle getScreenBounds(AbstractDisplayViewingScreen screen) {
+ return screen.getBounds();
+ }
+
+ @Override
+ public <R extends Screen> boolean isHandingScreen(Class<R> screen) {
+ return AbstractDisplayViewingScreen.class.isAssignableFrom(screen);
+ }
+
+ @Override
+ public InteractionResult shouldScreenBeOverlaid(Class<?> screen) {
+ return InteractionResult.SUCCESS;
+ }
+ });
+ }
+
+ @Override
+ public void registerFavorites(FavoriteEntryType.Registry registry) {
+ registry.register(EntryStackFavoriteType.INSTANCE.id, EntryStackFavoriteType.INSTANCE);
+ }
+
+ @Override
+ public void registerTransferHandlers(TransferHandlerRegistry registry) {
+ registry.register(new DefaultCategoryHandler());
+ }
+
+ private enum EntryStackFavoriteType implements FavoriteEntryType<EntryStackFavoriteEntry> {
+ INSTANCE(FavoriteEntryType.ENTRY_STACK);
+
+ private final String key = "data";
+ private ResourceLocation id;
+
+ EntryStackFavoriteType(ResourceLocation id) {
+ this.id = id;
+ }
+
+ @Override
+ public EntryStackFavoriteEntry fromJson(JsonObject object) {
+ return new EntryStackFavoriteEntry(EntryStack.readFromJson(GsonHelper.getAsJsonObject(object, key)));
+ }
+
+ @Override
+ public EntryStackFavoriteEntry fromArgs(Object... args) {
+ return new EntryStackFavoriteEntry((EntryStack<?>) args[0]);
+ }
+
+ @Override
+ public JsonObject toJson(EntryStackFavoriteEntry entry, JsonObject object) {
+ object.add(key, entry.stack.toJson());
+ return object;
+ }
+ }
+
+ private static class EntryStackFavoriteEntry extends FavoriteEntry {
+ private static final Function<EntryStack<?>, String> CANCEL_FLUID_AMOUNT = s -> null;
+ private final EntryStack<?> stack;
+ private final int hashIgnoreAmount;
+
+ public EntryStackFavoriteEntry(EntryStack<?> stack) {
+ this.stack = stack.normalize();
+ this.hashIgnoreAmount = EntryStacks.hashExact(this.stack);
+ }
+
+ @Override
+ public boolean isInvalid() {
+ return this.stack.isEmpty();
+ }
+
+ @Override
+ public Renderer getRenderer(boolean showcase) {
+ return this.stack;
+ }
+
+ @Override
+ public boolean doAction(int button) {
+ if (!ClientHelper.getInstance().isCheating()) return false;
+ EntryStack<?> entry = stack.copy();
+ if (!entry.isEmpty()) {
+ if (entry.getValueType() == FluidStack.class) {
+ Item bucketItem = ((FluidStack) entry.getValue()).getFluid().getBucket();
+ if (bucketItem != null) {
+ entry = EntryStacks.of(bucketItem);
+ }
+ }
+ if (entry.getType() == VanillaEntryTypes.ITEM)
+ entry.<ItemStack>cast().getValue().setCount(button != 1 && !Screen.hasShiftDown() ? 1 : ((ItemStack) entry.getValue()).getMaxStackSize());
+ return ClientHelper.getInstance().tryCheatingEntry(entry);
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashIgnoreAmount() {
+ return hashIgnoreAmount;
+ }
+
+ @Override
+ public FavoriteEntry copy() {
+ return new EntryStackFavoriteEntry(stack.normalize());
+ }
+
+ @Override
+ public ResourceLocation getType() {
+ return EntryStackFavoriteType.INSTANCE.id;
+ }
+
+ @Override
+ public boolean isSame(FavoriteEntry other) {
+ if (!(other instanceof EntryStackFavoriteEntry)) return false;
+ EntryStackFavoriteEntry that = (EntryStackFavoriteEntry) other;
+ return EntryStacks.equalsExact(stack, that.stack);
+ }
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java
new file mode 100644
index 000000000..ad2373811
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java
@@ -0,0 +1,210 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.plugin.client.entry;
+
+import com.google.common.collect.Lists;
+import com.mojang.blaze3d.vertex.BufferBuilder;
+import com.mojang.blaze3d.vertex.DefaultVertexFormat;
+import com.mojang.blaze3d.vertex.PoseStack;
+import com.mojang.blaze3d.vertex.Tesselator;
+import com.mojang.math.Matrix4f;
+import me.shedaniel.architectury.fluid.FluidStack;
+import me.shedaniel.architectury.hooks.FluidStackHooks;
+import me.shedaniel.architectury.platform.Platform;
+import me.shedaniel.architectury.utils.Fraction;
+import me.shedaniel.math.Point;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
+import me.shedaniel.rei.api.client.entry.renderer.AbstractEntryRenderer;
+import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer;
+import me.shedaniel.rei.api.common.entry.EntryStack;
+import me.shedaniel.rei.api.common.entry.EntrySerializer;
+import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext;
+import me.shedaniel.rei.api.common.entry.type.EntryDefinition;
+import me.shedaniel.rei.api.common.entry.type.EntryType;
+import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
+import me.shedaniel.rei.api.common.util.EntryStacks;
+import net.minecraft.ChatFormatting;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.texture.TextureAtlas;
+import net.minecraft.client.renderer.texture.TextureAtlasSprite;
+import net.minecraft.client.resources.language.I18n;
+import net.minecraft.core.Registry;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.TextComponent;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.tags.TagCollection;
+import net.minecraft.world.level.material.Fluid;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class FluidEntryDefinition implements EntryDefinition<FluidStack>, EntrySerializer<FluidStack> {
+ private static final String FLUID_AMOUNT = Platform.isForge() ? "tooltip.rei.fluid_amount.forge" : "tooltip.rei.fluid_amount";
+ private final EntryRenderer<FluidStack> renderer = new FluidEntryRenderer();
+
+ @Override
+ public Class<FluidStack> getValueType() {
+ return FluidStack.class;
+ }
+
+ @Override
+ public EntryType<FluidStack> getType() {
+ return VanillaEntryTypes.FLUID;
+ }
+
+ @Override
+ public EntryRenderer<FluidStack> getRenderer() {
+ return renderer;
+ }
+
+ @Override
+ @Nullable
+ public ResourceLocation getIdentifier(EntryStack<FluidStack> entry, FluidStack value) {
+ return Registry.FLUID.getKey(value.getFluid());
+ }
+
+ @Override
+ public boolean isEmpty(EntryStack<FluidStack> entry, FluidStack value) {
+ return value.isEmpty();
+ }
+
+ @Override
+ public FluidStack copy(EntryStack<FluidStack> entry, FluidStack value) {
+ return value.copy();
+ }
+
+ @Override
+ public FluidStack normalize(EntryStack<FluidStack> entry, FluidStack value) {
+ FluidStack copy = value.copy();
+ copy.setAmount(FluidStack.bucketAmount());
+ return copy;
+ }
+
+ @Override
+ public int hash(EntryStack<FluidStack> entry, FluidStack value, ComparisonContext context) {
+ int code = 1;
+ code = 31 * code + value.getFluid().hashCode();
+ code = 31 * code + (context.isFuzzy() || !value.hasTag() ? 0 : value.getTag().hashCode());
+ return code;
+ }
+
+ @Override
+ public boolean equals(FluidStack o1, FluidStack o2, ComparisonContext context) {
+ if (o1.getFluid() != o2.getFluid())
+ return false;
+ return context.isFuzzy() || isTagEqual(o1, o2);
+ }
+
+ private boolean isTagEqual(FluidStack o1, FluidStack o2) {
+ CompoundTag tag1 = o1.getTag();
+ CompoundTag tag2 = o2.getTag();
+ return Objects.equals(tag1, tag2);
+ }
+
+ @Override
+ @Nullable
+ public EntrySerializer<FluidStack> getSerializer() {
+ return this;
+ }
+
+ @Override
+ public boolean supportSaving() {
+ return true;
+ }
+
+ @Override
+ public boolean supportReading() {
+ return true;
+ }
+
+ @Override
+ public CompoundTag save(EntryStack<FluidStack> entry, FluidStack value) {
+ return value.write(new CompoundTag());
+ }
+
+ @Override
+ public FluidStack read(CompoundTag tag) {
+ return FluidStack.read(tag);
+ }
+
+ @Override
+ public Component asFormattedText(EntryStack<FluidStack> entry, FluidStack value) {
+ return value.getFluid().defaultFluidState().createLegacyBlock().getBlock().getName();
+ }
+
+ @Override
+ public Collection<ResourceLocation> getTagsFor(EntryStack<FluidStack> entry, FluidStack value) {
+ TagCollection<Fluid> collection = Minecraft.getInstance().getConnection().getTags().getFluids();
+ return collection == null ? Collections.emptyList() : collection.getMatchingTags(value.getFluid());
+ }
+
+ public static class FluidEntryRenderer extends AbstractEntryRenderer<FluidStack> {
+ @Override
+ public void render(EntryStack<FluidStack> entry, PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ FluidStack stack = entry.getValue();
+ TextureAtlasSprite sprite = FluidStackHooks.getStillTexture(stack);
+ int color = FluidStackHooks.getColor(stack);
+ int a = 255;
+ int r = (color >> 16 & 255);
+ int g = (color >> 8 & 255);
+ int b = (color & 255);
+ Minecraft.getInstance().getTextureManager().bind(TextureAtlas.LOCATION_BLOCKS);
+ Tesselator tesselator = Tesselator.getInstance();
+ BufferBuilder builder = tesselator.getBuilder();
+ Matrix4f matrix = matrices.last().pose();
+ builder.begin(7, DefaultVertexFormat.POSITION_TEX_COLOR);
+ int z = entry.getZ();
+ builder.vertex(matrix, bounds.getMaxX(), bounds.y, z).uv(sprite.getU1(), sprite.getV0()).color(r, g, b, a).endVertex();
+ builder.vertex(matrix, bounds.x, bounds.y, z).uv(sprite.getU0(), sprite.getV0()).color(r, g, b, a).endVertex();
+ builder.vertex(matrix, bounds.x, bounds.getMaxY(), z).uv(sprite.getU0(), sprite.getV1()).color(r, g, b, a).endVertex();
+ builder.vertex(matrix, bounds.getMaxX(), bounds.getMaxY(), z).uv(sprite.getU1(), sprite.getV1()).color(r, g, b, a).endVertex();
+ tesselator.end();
+ }
+
+ @Override
+ public @Nullable Tooltip getTooltip(EntryStack<FluidStack> entry, Point mouse) {
+ if (entry.isEmpty())
+ return null;
+ List<Component> toolTip = Lists.newArrayList(entry.asFormattedText());
+ Fraction amount = entry.getValue().getAmount();
+ if (!amount.isLessThan(Fraction.zero())) {
+ String amountTooltip = I18n.get(FLUID_AMOUNT, EntryStacks.simplifyAmount(entry).getValue().getAmount());
+ if (amountTooltip != null)
+ toolTip.addAll(Stream.of(amountTooltip.split("\n")).map(TextComponent::new).collect(Collectors.toList()));
+ }
+ if (Minecraft.getInstance().options.advancedItemTooltips) {
+ ResourceLocation fluidId = Registry.FLUID.getKey(entry.getValue().getFluid());
+ toolTip.add((new TextComponent(fluidId.toString())).withStyle(ChatFormatting.DARK_GRAY));
+ }
+ return Tooltip.create(toolTip);
+ }
+ }
+}
diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java b/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java
new file mode 100644
index 000000000..2445f687a
--- /dev/null
+++ b/runtime/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java
@@ -0,0 +1,252 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.plugin.client.entry;
+
+import com.google.common.collect.Lists;
+import com.mojang.blaze3d.platform.GlStateManager;
+import com.mojang.blaze3d.platform.Lighting;
+import com.mojang.blaze3d.systems.RenderSystem;
+import com.mojang.blaze3d.vertex.PoseStack;
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
+import it.unimi.dsi.fastutil.objects.ReferenceSet;
+import me.shedaniel.math.Point;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
+import me.shedaniel.rei.api.client.entry.renderer.AbstractEntryRenderer;
+import me.shedaniel.rei.api.client.entry.renderer.BatchEntryRenderer;
+import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer;
+import me.shedaniel.rei.api.common.entry.EntryStack;
+import me.shedaniel.rei.api.common.entry.EntrySerializer;
+import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext;
+import me.shedaniel.rei.api.common.entry.comparison.ItemComparatorRegistry;
+import me.shedaniel.rei.api.common.entry.type.EntryDefinition;
+import me.shedaniel.rei.api.common.entry.type.EntryType;
+import me.shedaniel.rei.api.common.entry.type.VanillaEntryTypes;
+import me.shedaniel.rei.api.common.util.ImmutableTextComponent;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.block.model.ItemTransforms;
+import net.minecraft.client.renderer.texture.OverlayTexture;
+import net.minecraft.client.renderer.texture.TextureAtlas;
+import net.minecraft.client.resources.language.I18n;
+import net.minecraft.client.resources.model.BakedModel;
+import net.minecraft.core.Registry;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.chat.Component;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.tags.TagCollection;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.TooltipFlag;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+public class ItemEntryDefinition implements EntryDefinition<ItemStack>, EntrySerializer<ItemStack> {
+ private final EntryRenderer<ItemStack> renderer = new ItemEntryRenderer();
+
+ @Override
+ public Class<ItemStack> getValueType() {
+ return ItemStack.class;
+ }
+
+ @Override
+ public EntryType<ItemStack> getType() {
+ return VanillaEntryTypes.ITEM;
+ }
+
+ @Override
+ public EntryRenderer<ItemStack> getRenderer() {
+ return renderer;
+ }
+
+ @Override
+ @Nullable
+ public ResourceLocation getIdentifier(EntryStack<ItemStack> entry, ItemStack value) {
+ return Registry.ITEM.getKey(value.getItem());
+ }
+
+ @Override
+ public boolean isEmpty(EntryStack<ItemStack> entry, ItemStack value) {
+ return value.isEmpty();
+ }
+
+ @Override
+ public ItemStack copy(EntryStack<ItemStack> entry, ItemStack value) {
+ return value.copy();
+ }
+
+ @Override
+ public ItemStack normalize(EntryStack<ItemStack> entry, ItemStack value) {
+ ItemStack copy = value.copy();
+ copy.setCount(1);
+ return copy;
+ }
+
+ @Override
+ public int hash(EntryStack<ItemStack> entry, ItemStack value, ComparisonContext context) {
+ int code = 1;
+ code = 31 * code + System.identityHashCode(value.getItem());
+ code = 31 * code + (context.isFuzzy() ? 0 : Long.hashCode(ItemComparatorRegistry.getInstance().hashOf(value)));
+ return code;
+ }
+
+ @Override
+ public boolean equals(ItemStack o1, ItemStack o2, ComparisonContext context) {
+ if (o1.getItem() != o2.getItem())
+ return false;
+ return context.isFuzzy() || ItemComparatorRegistry.getInstance().hashOf(o1) == ItemComparatorRegistry.getInstance().hashOf(o2);
+ }
+
+ @Override
+ @Nullable
+ public EntrySerializer<ItemStack> getSerializer() {
+ return this;
+ }
+
+ @Override
+ public boolean supportSaving() {
+ return true;
+ }
+
+ @Override
+ public boolean supportReading() {
+ return true;
+ }
+
+ @Override
+ public CompoundTag save(EntryStack<ItemStack> entry, ItemStack value) {
+ return value.save(new CompoundTag());
+ }
+
+ @Override
+ public ItemStack read(CompoundTag tag) {
+ return ItemStack.of(tag);
+ }
+
+ private static final ReferenceSet<Item> SEARCH_BLACKLISTED = new ReferenceOpenHashSet<>();
+
+ @Override
+ public Component asFormattedText(EntryStack<ItemStack> entry, ItemStack value) {
+ if (!SEARCH_BLACKLISTED.contains(value.getItem()))
+ try {
+ return value.getHoverName();
+ } catch (Throwable e) {
+ e.printStackTrace();
+ SEARCH_BLACKLISTED.add(value.getItem());
+ }
+ try {
+ return new ImmutableTextComponent(I18n.get("item." + Registry.ITEM.getKey(value.getItem()).toString().replace(":", ".")));
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ return new ImmutableTextComponent("ERROR");
+ }
+
+ @Override
+ public Collection<ResourceLocation> getTagsFor(EntryStack<ItemStack> entry, ItemStack value) {
+ TagCollection<Item> collection = Minecraft.getInstance().getConnection().getTags().getItems();
+ return collection == null ? Collections.emptyList() : collection.getMatchingTags(value.getItem());
+ }
+
+ private List<Component> tryGetItemStackToolTip(EntryStack<ItemStack> entry, ItemStack value, boolean careAboutAdvanced) {
+ if (!SEARCH_BLACKLISTED.contains(value.getItem()))
+ try {
+ return value.getTooltipLines(Minecraft.getInstance().player, careAboutAdvanced && Minecraft.getInstance().options.advancedItemTooltips ? TooltipFlag.Default.ADVANCED : TooltipFlag.Default.NORMAL);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ SEARCH_BLACKLISTED.add(value.getItem());
+ }
+ return Lists.newArrayList(asFormattedText(entry, value));
+ }
+
+ @SuppressWarnings("deprecation")
+ public class ItemEntryRenderer extends AbstractEntryRenderer<ItemStack> implements BatchEntryRenderer<ItemStack> {
+ @Override
+ public int getBatchId(EntryStack<ItemStack> entry) {
+ return 1738923 + (getModelFromStack(entry.getValue()).usesBlockLight() ? 1 : 0);
+ }
+
+ private BakedModel getModelFromStack(ItemStack stack) {
+ return Minecraft.getInstance().getItemRenderer().getModel(stack, null, null);
+ }
+
+ @Override
+ public void startBatch(EntryStack<ItemStack> entry, PoseStack matrices, float delta) {
+ Minecraft.getInstance().getTextureManager().bind(TextureAtlas.LOCATION_BLOCKS);
+ Minecraft.getInstance().getTextureManager().getTexture(TextureAtlas.LOCATION_BLOCKS).setFilter(false, false);
+ RenderSystem.pushMatrix();
+ RenderSystem.enableRescaleNormal();
+ RenderSystem.enableAlphaTest();
+ RenderSystem.defaultAlphaFunc();
+ RenderSystem.enableBlend();
+ RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
+ RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
+ boolean sideLit = getModelFromStack(entry.getValue()).usesBlockLight();
+ if (!sideLit)
+ Lighting.setupForFlatItems();
+ }
+
+ @Override
+ public void renderBase(EntryStack<ItemStack> entry, PoseStack matrices, MultiBufferSource.BufferSource immediate, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ if (!entry.isEmpty()) {
+ ItemStack stack = entry.getValue();
+ matrices.pushPose();
+ matrices.translate(bounds.getCenterX(), bounds.getCenterY(), 100.0F + entry.getZ());
+ matrices.scale(bounds.getWidth(), (bounds.getWidth() + bounds.getHeight()) / -2f, bounds.getHeight());
+ Minecraft.getInstance().getItemRenderer().render(stack, ItemTransforms.TransformType.GUI, false, matrices, immediate, 15728880, OverlayTexture.NO_OVERLAY, getModelFromStack(stack));
+ matrices.popPose();
+ }
+ }
+
+ @Override
+ public void renderOverlay(EntryStack<ItemStack> entry, PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ if (!entry.isEmpty()) {
+ Minecraft.getInstance().getItemRenderer().blitOffset = entry.getZ();
+ Minecraft.getInstance().getItemRenderer().renderGuiItemDecorations(Minecraft.getInstance().font, entry.getValue(), bounds.x, bounds.y, null);
+ Minecraft.getInstance().getItemRenderer().blitOffset = 0.0F;
+ }
+ }
+
+ @Override
+ public void endBatch(EntryStack<ItemStack> entry, PoseStack matrices, float delta) {
+ RenderSystem.enableDepthTest();
+ RenderSystem.disableAlphaTest();
+ RenderSystem.disableRescaleNormal();
+ boolean sideLit = getModelFromStack(entry.getValue()).usesBlockLight();
+ if (!sideLit)
+ Lighting.setupFor3DItems();
+ RenderSystem.popMatrix();
+ }
+
+ @Override
+ public @Nullable Tooltip getTooltip(EntryStack<ItemStack> entry, Point mouse) {
+ if (entry.isEmpty())
+ return null;
+ return Tooltip.create(tryGetItemStackToolTip(entry, entry.getValue(), true));
+ }
+ }
+}