diff options
| author | shedaniel <daniel@shedaniel.me> | 2021-03-25 03:55:36 +0800 |
|---|---|---|
| committer | shedaniel <daniel@shedaniel.me> | 2021-03-25 03:55:36 +0800 |
| commit | 995b8b58aa8c890c9181ae479e12a4facfa05a25 (patch) | |
| tree | a16149371fc4b69a73e2ab13e2d96cd2c324b43a /runtime/src/main/java/me/shedaniel/rei/plugin | |
| parent | a34a748d2b6cdb1f70f176f1ec1bd27cbc2a98cf (diff) | |
| download | RoughlyEnoughItems-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')
4 files changed, 785 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)); + } + } +} diff --git a/runtime/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java b/runtime/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java new file mode 100644 index 000000000..f2f3a9ec8 --- /dev/null +++ b/runtime/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java @@ -0,0 +1,73 @@ +/* + * 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.test; + +import me.shedaniel.rei.api.client.plugins.REIClientPlugin; +import me.shedaniel.rei.api.client.registry.entry.EntryRegistry; +import me.shedaniel.rei.api.common.entry.EntryStack; +import me.shedaniel.rei.api.common.util.EntryStacks; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.core.Registry; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import org.apache.logging.log4j.LogManager; +import org.jetbrains.annotations.TestOnly; + +import java.util.Random; + +@TestOnly +@Environment(EnvType.CLIENT) +public class REITestPlugin implements REIClientPlugin { + private Random random = new Random(); + + @Override + public void preRegister() { + LogManager.getLogger().error("REI Test Plugin is enabled! If you see this unintentionally, please report this!"); + } + + @Override + public void registerEntries(EntryRegistry registry) { + int times = 10; + for (Item item : Registry.ITEM) { + for (int i = 0; i < times; i++) + registry.registerEntryAfter(EntryStacks.of(item), transformStack(EntryStacks.of(item))); + try { + for (ItemStack stack : registry.appendSt |
