aboutsummaryrefslogtreecommitdiff
path: root/runtime-engine/default-runtime-plugin/src/main
diff options
context:
space:
mode:
authorshedaniel <daniel@shedaniel.me>2022-07-27 23:25:27 +0800
committershedaniel <daniel@shedaniel.me>2022-08-26 10:52:27 +0900
commit05069aa62b09f02a8cd6e526ec58a30347a56500 (patch)
treeacb90d01f0a06de7c6b540eefeeee8259016f8ac /runtime-engine/default-runtime-plugin/src/main
parent685861c91bbb8a8a882da51381d392f1310d061d (diff)
downloadRoughlyEnoughItems-05069aa62b09f02a8cd6e526ec58a30347a56500.tar.gz
RoughlyEnoughItems-05069aa62b09f02a8cd6e526ec58a30347a56500.tar.bz2
RoughlyEnoughItems-05069aa62b09f02a8cd6e526ec58a30347a56500.zip
WIP Module
Diffstat (limited to 'runtime-engine/default-runtime-plugin/src/main')
-rw-r--r--runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java316
-rw-r--r--runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java382
-rw-r--r--runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java56
-rw-r--r--runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java105
4 files changed, 859 insertions, 0 deletions
diff --git a/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java
new file mode 100644
index 000000000..de9bf4d6e
--- /dev/null
+++ b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/FluidEntryDefinition.java
@@ -0,0 +1,316 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.base.Suppliers;
+import com.google.common.collect.Lists;
+import com.mojang.blaze3d.vertex.PoseStack;
+import dev.architectury.fluid.FluidStack;
+import dev.architectury.hooks.fluid.FluidStackHooks;
+import dev.architectury.platform.Platform;
+import dev.architectury.utils.Env;
+import dev.architectury.utils.EnvExecutor;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.api.client.entry.renderer.AbstractEntryRenderer;
+import me.shedaniel.rei.api.client.entry.renderer.BatchedEntryRenderer;
+import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer;
+import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
+import me.shedaniel.rei.api.client.gui.widgets.TooltipContext;
+import me.shedaniel.rei.api.client.util.SpriteRenderer;
+import me.shedaniel.rei.api.common.entry.EntrySerializer;
+import me.shedaniel.rei.api.common.entry.EntryStack;
+import me.shedaniel.rei.api.common.entry.comparison.ComparisonContext;
+import me.shedaniel.rei.api.common.entry.comparison.FluidComparatorRegistry;
+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 net.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.ChatFormatting;
+import net.minecraft.CrashReport;
+import net.minecraft.CrashReportCategory;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.renderer.MultiBufferSource;
+import net.minecraft.client.renderer.RenderType;
+import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
+import net.minecraft.client.renderer.texture.OverlayTexture;
+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.TagKey;
+import net.minecraft.util.Mth;
+import net.minecraft.world.inventory.InventoryMenu;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.material.FlowingFluid;
+import net.minecraft.world.level.material.Fluid;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.function.Supplier;
+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";
+ @Environment(EnvType.CLIENT)
+ private EntryRenderer<FluidStack> renderer;
+
+ public FluidEntryDefinition() {
+ EnvExecutor.runInEnv(Env.CLIENT, () -> () -> Client.init(this));
+ }
+
+ @Environment(EnvType.CLIENT)
+ private static class Client {
+ private static void init(FluidEntryDefinition definition) {
+ definition.renderer = new FluidEntryRenderer();
+ }
+ }
+
+ @Override
+ public Class<FluidStack> getValueType() {
+ return FluidStack.class;
+ }
+
+ @Override
+ public EntryType<FluidStack> getType() {
+ return VanillaEntryTypes.FLUID;
+ }
+
+ @Override
+ @Environment(EnvType.CLIENT)
+ 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) {
+ Fluid fluid = value.getFluid();
+ if (fluid instanceof FlowingFluid flowingFluid) fluid = flowingFluid.getSource();
+ return FluidStack.create(fluid, FluidStack.bucketAmount(), value.getTag());
+ }
+
+ @Override
+ public FluidStack wildcard(EntryStack<FluidStack> entry, FluidStack value) {
+ Fluid fluid = value.getFluid();
+ if (fluid instanceof FlowingFluid) fluid = ((FlowingFluid) fluid).getSource();
+ return FluidStack.create(fluid, FluidStack.bucketAmount());
+ }
+
+ @Override
+ @Nullable
+ public ItemStack cheatsAs(EntryStack<FluidStack> entry, FluidStack value) {
+ if (value.isEmpty()) return ItemStack.EMPTY;
+ Item bucket = value.getFluid().getBucket();
+ if (bucket == null) return ItemStack.EMPTY;
+ return new ItemStack(bucket);
+ }
+
+ @Nullable
+ @Override
+ public FluidStack add(FluidStack o1, FluidStack o2) {
+ return o1.copyWithAmount(o1.getAmount() + o2.getAmount());
+ }
+
+ @Override
+ public long hash(EntryStack<FluidStack> entry, FluidStack value, ComparisonContext context) {
+ int code = 1;
+ code = 31 * code + value.getFluid().hashCode();
+ code = 31 * code + Long.hashCode(FluidComparatorRegistry.getInstance().hashOf(context, value));
+ return code;
+ }
+
+ @Override
+ public boolean equals(FluidStack o1, FluidStack o2, ComparisonContext context) {
+ if (o1.getFluid() != o2.getFluid())
+ return false;
+ return FluidComparatorRegistry.getInstance().hashOf(context, o1) == FluidComparatorRegistry.getInstance().hashOf(context, o2);
+ }
+
+ @Override
+ @Nullable
+ public EntrySerializer<FluidStack> getSerializer() {
+ return this;
+ }
+
+ @Override
+ public boolean supportSaving() {
+ return true;
+ }
+
+ @Override
+ public boolean supportReading() {
+ return true;
+ }
+
+ @Override
+ public boolean acceptsNull() {
+ return false;
+ }
+
+ @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.getName();
+ }
+
+ @Override
+ public Stream<? extends TagKey<?>> getTagsFor(EntryStack<FluidStack> entry, FluidStack value) {
+ return value.getFluid().builtInRegistryHolder().tags();
+ }
+
+ @Override
+ public void fillCrashReport(CrashReport report, CrashReportCategory category, EntryStack<FluidStack> entry) {
+ EntryDefinition.super.fillCrashReport(report, category, entry);
+ FluidStack stack = entry.getValue();
+ category.setDetail("Fluid Type", () -> String.valueOf(Registry.FLUID.getKey(stack.getFluid())));
+ category.setDetail("Fluid Amount", () -> String.valueOf(stack.getAmount()));
+ category.setDetail("Fluid NBT", () -> String.valueOf(stack.getTag()));
+ }
+
+ @Environment(EnvType.CLIENT)
+ public static class FluidEntryRenderer extends AbstractEntryRenderer<FluidStack> implements BatchedEntryRenderer<FluidStack, TextureAtlasSprite> {
+ private static final Supplier<TextureAtlasSprite> MISSING_SPRITE = Suppliers.memoize(() -> {
+ TextureAtlas atlas = Minecraft.getInstance().getModelManager().getAtlas(TextureAtlas.LOCATION_BLOCKS);
+ return atlas.getSprite(MissingTextureAtlasSprite.getLocation());
+ });
+
+ @Override
+ public TextureAtlasSprite getExtraData(EntryStack<FluidStack> entry) {
+ FluidStack stack = entry.getValue();
+ if (stack.isEmpty()) return null;
+ return FluidStackHooks.getStillTexture(stack);
+ }
+
+ private TextureAtlasSprite missingTexture() {
+ return MISSING_SPRITE.get();
+ }
+
+ @Override
+ public int getBatchIdentifier(EntryStack<FluidStack> entry, Rectangle bounds, TextureAtlasSprite extraData) {
+ return 0;
+ }
+
+ @Override
+ public void startBatch(EntryStack<FluidStack> entry, TextureAtlasSprite extraData, PoseStack matrices, float delta) {}
+
+ @Override
+ public void renderBase(EntryStack<FluidStack> entry, TextureAtlasSprite sprite, PoseStack matrices, MultiBufferSource.BufferSource immediate, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ TextureAtlasSprite s = sprite == null ? missingTexture() : sprite;
+ SpriteRenderer.beginPass()
+ .setup(immediate, RenderType.solid())
+ .sprite(s)
+ .color(sprite == null ? 0xFFFFFF : FluidStackHooks.getColor(entry.getValue()))
+ .light(0x00f000f0)
+ .overlay(OverlayTexture.NO_OVERLAY)
+ .alpha(0xff)
+ .normal(matrices.last().normal(), 0, 0, 0)
+ .position(matrices.last().pose(), bounds.x, bounds.getMaxY() - bounds.height * Mth.clamp(entry.get(EntryStack.Settings.FLUID_RENDER_RATIO), 0, 1), bounds.getMaxX(), bounds.getMaxY(), entry.getZ())
+ .next(s.atlas().location());
+ }
+
+ @Override
+ public void afterBase(EntryStack<FluidStack> entry, TextureAtlasSprite extraData, PoseStack matrices, float delta) {}
+
+ @Override
+ public void renderOverlay(EntryStack<FluidStack> entry, TextureAtlasSprite extraData, PoseStack matrices, MultiBufferSource.BufferSource immediate, Rectangle bounds, int mouseX, int mouseY, float delta) {}
+
+ @Override
+ public void endBatch(EntryStack<FluidStack> entry, TextureAtlasSprite extraData, PoseStack matrices, float delta) {}
+
+ @Override
+ public void render(EntryStack<FluidStack> entry, PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ FluidStack stack = entry.getValue();
+ if (stack.isEmpty()) return;
+ TextureAtlasSprite sprite = FluidStackHooks.getStillTexture(stack);
+ if (sprite == null) return;
+ int color = FluidStackHooks.getColor(stack);
+
+ MultiBufferSource.BufferSource immediate = Minecraft.getInstance().renderBuffers().bufferSource();
+
+ SpriteRenderer.beginPass()
+ .setup(immediate, RenderType.solid())
+ .sprite(sprite)
+ .color(color)
+ .light(0x00f000f0)
+ .overlay(OverlayTexture.NO_OVERLAY)
+ .alpha(0xff)
+ .normal(matrices.last().normal(), 0, 0, 0)
+ .position(matrices.last().pose(), bounds.x, bounds.getMaxY() - bounds.height * Mth.clamp(entry.get(EntryStack.Settings.FLUID_RENDER_RATIO), 0, 1), bounds.getMaxX(), bounds.getMaxY(), entry.getZ())
+ .next(InventoryMenu.BLOCK_ATLAS);
+
+ immediate.endBatch();
+ }
+
+ @Override
+ @Nullable
+ public Tooltip getTooltip(EntryStack<FluidStack> entry, TooltipContext context) {
+ if (entry.isEmpty())
+ return null;
+ List<Component> toolTip = Lists.newArrayList(entry.asFormattedText());
+ long amount = entry.getValue().getAmount();
+ if (amount >= 0 && entry.get(EntryStack.Settings.FLUID_AMOUNT_VISIBLE)) {
+ String amountTooltip = I18n.get(FLUID_AMOUNT, 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-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java
new file mode 100644
index 000000000..40e61a461
--- /dev/null
+++ b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/client/entry/ItemEntryDefinition.java
@@ -0,0 +1,382 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 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 dev.architectury.hooks.item.ItemStackHooks;
+import dev.architectury.utils.Env;
+import dev.architectury.utils.EnvExecutor;
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
+import it.unimi.dsi.fastutil.objects.ReferenceSet;
+import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.api.client.entry.renderer.AbstractEntryRenderer;
+import me.shedaniel.rei.api.client.entry.renderer.BatchedEntryRenderer;
+import me.shedaniel.rei.api.client.entry.renderer.EntryRenderer;
+import me.shedaniel.rei.api.client.gui.widgets.Tooltip;
+import me.shedaniel.rei.api.client.gui.widgets.TooltipContext;
+import me.shedaniel.rei.api.common.entry.EntrySerializer;
+import me.shedaniel.rei.api.common.entry.EntryStack;
+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.fabricmc.api.EnvType;
+import net.fabricmc.api.Environment;
+import net.minecraft.CrashReport;
+import net.minecraft.CrashReportCategory;
+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.TagKey;
+import net.minecraft.world.inventory.tooltip.TooltipComponent;
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+public class ItemEntryDefinition implements EntryDefinition<ItemStack>, EntrySerializer<ItemStack> {
+ @Environment(EnvType.CLIENT)
+ private EntryRenderer<ItemStack> renderer;
+
+ public ItemEntryDefinition() {
+ EnvExecutor.runInEnv(Env.CLIENT, () -> () -> Client.init(this));
+ }
+
+ @Environment(EnvType.CLIENT)
+ private static class Client {
+ private static void init(ItemEntryDefinition definition) {
+ definition.renderer = definition.new ItemEntryRenderer();
+ }
+ }
+
+ @Override
+ public Class<ItemStack> getValueType() {
+ return ItemStack.class;
+ }
+
+ @Override
+ public EntryType<ItemStack> getType() {
+ return VanillaEntryTypes.ITEM;
+ }
+
+ @Override
+ @Environment(EnvType.CLIENT)
+ 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 ItemStack wildcard(EntryStack<ItemStack> entry, ItemStack value) {
+ return new ItemStack(value.getItem(), 1);
+ }
+
+ @Override
+ @Nullable
+ public ItemStack cheatsAs(EntryStack<ItemStack> entry, ItemStack value) {
+ return value.copy();
+ }
+
+ @Nullable
+ @Override
+ public ItemStack add(ItemStack o1, ItemStack o2) {
+ return ItemStackHooks.copyWithCount(o1, o1.getCount() + o2.getCount());
+ }
+
+ @Override
+ public long hash(EntryStack<ItemStack> entry, ItemStack value, ComparisonContext context) {
+ int code = 1;
+ code = 31 * code + System.identityHashCode(value.getItem());
+ code = 31 * code + Long.hashCode(ItemComparatorRegistry.getInstance().hashOf(context, value));
+ return code;
+ }
+
+ @Override
+ public boolean equals(ItemStack o1, ItemStack o2, ComparisonContext context) {
+ if (o1.getItem() != o2.getItem())
+ return false;
+ return ItemComparatorRegistry.getInstance().hashOf(context, o1) == ItemComparatorRegistry.getInstance().hashOf(context, o2);
+ }
+
+ @Override
+ @Nullable
+ public EntrySerializer<ItemStack> getSerializer() {
+ return this;
+ }
+
+ @Override
+ public boolean supportSaving() {
+ return true;
+ }
+
+ @Override
+ public boolean supportReading() {
+ return true;
+ }
+
+ @Override
+ public boolean acceptsNull() {
+ return false;
+ }
+
+ @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) {
+ return asFormattedText(entry, value, TooltipContext.of());
+ }
+
+ @Override
+ public Component asFormattedText(EntryStack<ItemStack> entry, ItemStack value, TooltipContext context) {
+ if (!SEARCH_BLACKLISTED.contains(value.getItem()))
+ try {
+ return value.getHoverName();
+ } catch (Throwable e) {
+ if (context != null && context.isSearch()) throw 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 Stream<? extends TagKey<?>> getTagsFor(EntryStack<ItemStack> entry, ItemStack value) {
+ return value.getTags();
+ }
+
+ @Environment(EnvType.CLIENT)
+ private List<Component> tryGetItemStackToolTip(EntryStack<ItemStack> entry, ItemStack value, TooltipContext context) {
+ if (!SEARCH_BLACKLISTED.contains(value.getItem()))
+ try {
+ return value.getTooltipLines(Minecraft.getInstance().player, context.getFlag());
+ } catch (Throwable e) {
+ if (context.isSearch()) throw e;
+ e.printStackTrace();
+ SEARCH_BLACKLISTED.add(value.getItem());
+ }
+ return Lists.newArrayList(asFormattedText(entry, value, context));
+ }
+
+ @Override
+ public void fillCrashReport(CrashReport report, CrashReportCategory category, EntryStack<ItemStack> entry) {
+ EntryDefinition.super.fillCrashReport(report, category, entry);
+ ItemStack stack = entry.getValue();
+ category.setDetail("Item Type", () -> String.valueOf(stack.getItem()));
+ category.setDetail("Item Damage", () -> String.valueOf(stack.getDamageValue()));
+ category.setDetail("Item NBT", () -> String.valueOf(stack.getTag()));
+ category.setDetail("Item Foil", () -> String.valueOf(stack.hasFoil()));
+ }
+
+ @Environment(EnvType.CLIENT)
+ public class ItemEntryRenderer extends AbstractEntryRenderer<ItemStack> implements BatchedEntryRenderer<ItemStack, BakedModel> {
+ private static final float SCALE = 20.0F;
+ public static final int ITEM_LIGHT = 0xf000f0;
+
+ @Override
+ public BakedModel getExtraData(EntryStack<ItemStack> entry) {
+ return Minecraft.getInstance().getItemRenderer().getModel(entry.getValue(), null, null, 0);
+ }
+
+ @Override
+ public void render(EntryStack<ItemStack> entry, PoseStack matrices, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ BakedModel model = getExtraData(entry);
+ setupGL(entry, model);
+ if (!entry.isEmpty()) {
+ ItemStack value = entry.getValue();
+ matrices.pushPose();
+ matrices.mulPoseMatrix(RenderSystem.getModelViewMatrix());
+ matrices.translate(bounds.getCenterX(), bounds.getCenterY(), entry.getZ());
+ matrices.scale(bounds.getWidth(), (bounds.getWidth() + bounds.getHeight()) / -2f, 1.0F);
+ PoseStack modelViewStack = RenderSystem.getModelViewStack();
+ modelViewStack.pushPose();
+ modelViewStack.last().pose().load(matrices.last().pose());
+ RenderSystem.applyModelViewMatrix();
+ MultiBufferSource.BufferSource immediate = Minecraft.getInstance().renderBuffers().bufferSource();
+ Minecraft.getInstance().getItemRenderer().render(value, ItemTransforms.TransformType.GUI, false, new PoseStack(), immediate,
+ ITEM_LIGHT, OverlayTexture.NO_OVERLAY, model);
+ immediate.endBatch();
+ matrices.popPose();
+ modelViewStack.popPose();
+ RenderSystem.applyModelViewMatrix();
+ }
+ PoseStack modelViewStack = RenderSystem.getModelViewStack();
+ modelViewStack.pushPose();
+ modelViewStack.mulPoseMatrix(matrices.last().pose());
+ modelViewStack.translate(bounds.x, bounds.y, 0);
+ modelViewStack.scale(bounds.width / 16f, (bounds.getWidth() + bounds.getHeight()) / 2f / 16f, 1.0F);
+ RenderSystem.applyModelViewMatrix();
+ renderOverlay(entry, bounds);
+ modelViewStack.popPose();
+ endGL(entry, model);
+ RenderSystem.applyModelViewMatrix();
+ }
+
+ @Override
+ public int getBatchIdentifier(EntryStack<ItemStack> entry, Rectangle bounds, BakedModel model) {
+ return 1738923 + (model.usesBlockLight() ? 1 : 0);
+ }
+
+ @Override
+ public void startBatch(EntryStack<ItemStack> entry, BakedModel model, PoseStack matrices, float delta) {
+ setupGL(entry, model);
+ PoseStack modelViewStack = RenderSystem.getModelViewStack();
+ modelViewStack.pushPose();
+ modelViewStack.scale(SCALE, -SCALE, 1.0F);
+ RenderSystem.applyModelViewMatrix();
+ }
+
+ public void setupGL(EntryStack<ItemStack> entry, BakedModel model) {
+ Minecraft.getInstance().getTextureManager().getTexture(TextureAtlas.LOCATION_BLOCKS).setFilter(false, false);
+ RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_BLOCKS);
+ RenderSystem.enableBlend();
+ RenderSystem.blendFunc(GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA);
+ RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
+ boolean sideLit = model.usesBlockLight();
+ if (!sideLit) Lighting.setupForFlatItems();
+ }
+
+ @Override
+ public void renderBase(EntryStack<ItemStack> entry, BakedModel model, PoseStack matrices, MultiBufferSource.BufferSource immediate, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ if (!entry.isEmpty()) {
+ ItemStack value = entry.getValue();
+ matrices.pushPose();
+ matrices.translate(bounds.getCenterX() / SCALE, bounds.getCenterY() / -SCALE, entry.getZ());
+ matrices.scale(bounds.getWidth() / SCALE, (bounds.getWidth() + bounds.getHeight()) / 2f / SCALE, 1.0F);
+ Minecraft.getInstance().getItemRenderer().render(value, ItemTransforms.TransformType.GUI, false, matrices, immediate,
+ ITEM_LIGHT, OverlayTexture.NO_OVERLAY, model);
+ matrices.popPose();
+ }
+ }
+
+ @Override
+ public void afterBase(EntryStack<ItemStack> entry, BakedModel model, PoseStack matrices, float delta) {
+ endGL(entry, model);
+ RenderSystem.getModelViewStack().popPose();
+ RenderSystem.applyModelViewMatrix();
+ }
+
+ @Override
+ public void renderOverlay(EntryStack<ItemStack> entry, BakedModel model, PoseStack matrices, MultiBufferSource.BufferSource immediate, Rectangle bounds, int mouseX, int mouseY, float delta) {
+ PoseStack modelViewStack = RenderSystem.getModelViewStack();
+ modelViewStack.pushPose();
+ modelViewStack.mulPoseMatrix(matrices.last().pose());
+ modelViewStack.translate(bounds.x, bounds.y, 0);
+ modelViewStack.scale(bounds.width / 16f, (bounds.getWidth() + bounds.getHeight()) / 2f / 16f, 1.0F);
+ RenderSystem.applyModelViewMatrix();
+ renderOverlay(entry, bounds);
+ modelViewStack.popPose();
+ RenderSystem.applyModelViewMatrix();
+ }
+
+ public void renderOverlay(EntryStack<ItemStack> entry, Rectangle bounds) {
+ if (!entry.isEmpty()) {
+ Minecraft.getInstance().getItemRenderer().blitOffset = entry.getZ();
+ Minecraft.getInstance().getItemRenderer().renderGuiItemDecorations(Minecraft.getInstance().font, entry.getValue(), 0, 0, null);
+ Minecraft.getInstance().getItemRenderer().blitOffset = 0.0F;
+ }
+ }
+
+ @Override
+ public void endBatch(EntryStack<ItemStack> entry, BakedModel model, PoseStack matrices, float delta) {
+ }
+
+ public void endGL(EntryStack<ItemStack> entry, BakedModel model) {
+ RenderSystem.enableDepthTest();
+ boolean sideLit = model.usesBlockLight();
+ if (!sideLit) Lighting.setupFor3DItems();
+ }
+
+ @Override
+ @Nullable
+ public Tooltip getTooltip(EntryStack<ItemStack> entry, TooltipContext context) {
+ if (entry.isEmpty())
+ return null;
+ Tooltip tooltip = Tooltip.create();
+ Optional<TooltipComponent> component = entry.getValue().getTooltipImage();
+ List<Component> components = tryGetItemStackToolTip(entry, entry.getValue(), context);
+ if (!components.isEmpty()) {
+ tooltip.add(components.get(0));
+ }
+ component.ifPresent(tooltip::add);
+ for (int i = 1; i < components.size(); i++) {
+ tooltip.add(components.get(i));
+ }
+ return tooltip;
+ }
+ }
+}
diff --git a/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java
new file mode 100644
index 000000000..533af546a
--- /dev/null
+++ b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/common/runtime/DefaultRuntimePlugin.java
@@ -0,0 +1,56 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020, 2021, 2022 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.common.runtime;
+
+import dev.architectury.event.CompoundEventResult;
+import dev.architectury.fluid.FluidStack;
+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.fluid.FluidSupportProvider;
+import me.shedaniel.rei.api.common.plugins.REIServerPlugin;
+import me.shedaniel.rei.plugin.client.entry.FluidEntryDefinition;
+import me.shedaniel.rei.plugin.client.entry.ItemEntryDefinition;
+import net.minecraft.resources.ResourceLocation;
+import org.jetbrains.annotations.ApiStatus;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+@ApiStatus.Internal
+public class DefaultRuntimePlugin implements REIServerPlugin {
+ @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 CompoundEventResult.pass();
+ }
+ return CompoundEventResult.interruptTrue(stream.get());
+ });
+ }
+}
diff --git a/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlugin.java
new file mode 100644
index 000000000..7eed62ba2
--- /dev/null
+++ b/runtime-engine/default-runtime-plugin/src/main/java/me/shedaniel/rei/plugin/test/REITestPlug