Skip to content

Commit

Permalink
fix gt tile entities not rendering in AE2 pattern outputs (#2319)
Browse files Browse the repository at this point in the history
  • Loading branch information
TechLord22 authored and serenibyss committed Jan 21, 2024
1 parent 47a7da3 commit ebde142
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 67 deletions.
3 changes: 2 additions & 1 deletion src/main/java/gregtech/api/GTValues.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,8 @@ public class GTValues {
MODID_TCON = "tconstruct",
MODID_PROJRED_CORE = "projectred-core",
MODID_RC = "railcraft",
MODID_CHISEL = "chisel";
MODID_CHISEL = "chisel",
MODID_RS = "refinedstorage";

private static Boolean isClient;

Expand Down
60 changes: 8 additions & 52 deletions src/main/java/gregtech/api/util/ModCompatibility.java
Original file line number Diff line number Diff line change
@@ -1,66 +1,22 @@
package gregtech.api.util;

import gregtech.api.util.world.DummyWorld;
import gregtech.client.utils.ItemRenderCompat;

import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import org.jetbrains.annotations.ApiStatus;

@SideOnly(Side.CLIENT)
public class ModCompatibility {

private static RefinedStorage refinedStorage;

public static void initCompat() {
try {
Class<?> itemClass = Class.forName("com.raoulvdberge.refinedstorage.item.ItemPattern");
refinedStorage = new RefinedStorage(itemClass);
GTLog.logger.info("RefinedStorage found; enabling integration.");
} catch (ClassNotFoundException ignored) {
GTLog.logger.info("RefinedStorage not found; skipping integration.");
} catch (Throwable exception) {
GTLog.logger.error("Failed to enable RefinedStorage integration", exception);
}
}

/**
* @deprecated Use {@link ItemRenderCompat#getRepresentedStack(ItemStack)}
*/
@ApiStatus.ScheduledForRemoval(inVersion = "2.10")
@Deprecated
public static ItemStack getRealItemStack(ItemStack itemStack) {
if (refinedStorage != null && RefinedStorage.canHandleItemStack(itemStack)) {
return refinedStorage.getRealItemStack(itemStack);
}
return itemStack;
}

private static class RefinedStorage {

private final Method getPatternFromCacheMethod;
private final Method getOutputsMethod;

public RefinedStorage(Class<?> itemPatternClass) throws ReflectiveOperationException {
this.getPatternFromCacheMethod = itemPatternClass.getMethod("getPatternFromCache", World.class,
ItemStack.class);
this.getOutputsMethod = getPatternFromCacheMethod.getReturnType().getMethod("getOutputs");
}

public static boolean canHandleItemStack(ItemStack itemStack) {
ResourceLocation registryName = Objects.requireNonNull(itemStack.getItem().getRegistryName());
return registryName.getNamespace().equals("refinedstorage") &&
registryName.getPath().equals("pattern");
}

public ItemStack getRealItemStack(ItemStack itemStack) {
try {
Object craftingPattern = getPatternFromCacheMethod.invoke(null, DummyWorld.INSTANCE, itemStack);
List<ItemStack> outputs = (List<ItemStack>) getOutputsMethod.invoke(craftingPattern);
return outputs.isEmpty() ? itemStack : outputs.get(0);
} catch (ReflectiveOperationException ex) {
throw new RuntimeException("Failed to obtain item from ItemPattern", ex);
}
}
return ItemRenderCompat.getRepresentedStack(itemStack);
}
}
11 changes: 8 additions & 3 deletions src/main/java/gregtech/client/ClientProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@
import gregtech.api.unification.stack.UnificationEntry;
import gregtech.api.util.FluidTooltipUtil;
import gregtech.api.util.IBlockOre;
import gregtech.api.util.ModCompatibility;
import gregtech.client.model.customtexture.CustomTextureModelHandler;
import gregtech.client.model.customtexture.MetadataSectionCTM;
import gregtech.client.renderer.handler.FacadeRenderer;
import gregtech.client.renderer.handler.MetaTileEntityRenderer;
import gregtech.client.renderer.pipe.*;
import gregtech.client.renderer.pipe.CableRenderer;
import gregtech.client.renderer.pipe.FluidPipeRenderer;
import gregtech.client.renderer.pipe.ItemPipeRenderer;
import gregtech.client.renderer.pipe.LaserPipeRenderer;
import gregtech.client.renderer.pipe.OpticalPipeRenderer;
import gregtech.client.renderer.pipe.PipeRenderer;
import gregtech.client.utils.ItemRenderCompat;
import gregtech.client.utils.TooltipHelper;
import gregtech.common.CommonProxy;
import gregtech.common.ConfigHolder;
Expand Down Expand Up @@ -101,7 +106,7 @@ public void onLoad() {
public void onPostLoad() {
super.onPostLoad();
TerminalRegistry.initTerminalFiles();
ModCompatibility.initCompat();
ItemRenderCompat.init();
FacadeRenderer.init();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import gregtech.api.util.GTLog;
import gregtech.api.util.GTUtility;
import gregtech.api.util.ModCompatibility;
import gregtech.client.renderer.ICCLBlockRenderer;
import gregtech.client.renderer.texture.Textures;
import gregtech.client.utils.ItemRenderCompat;

import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
Expand Down Expand Up @@ -60,10 +60,10 @@ public void onModelsBake(ModelBakeEvent event) {

@Override
public void renderItem(ItemStack rawStack, ItemCameraTransforms.TransformType transformType) {
ItemStack stack = ModCompatibility.getRealItemStack(rawStack);
if (stack.getItem() instanceof ItemBlock &&
((ItemBlock) stack.getItem()).getBlock() instanceof ICCLBlockRenderer) {
((ICCLBlockRenderer) ((ItemBlock) stack.getItem()).getBlock()).renderItem(stack, transformType);
ItemStack stack = ItemRenderCompat.getRepresentedStack(rawStack);
if (stack.getItem() instanceof ItemBlock itemBlock &&
itemBlock.getBlock() instanceof ICCLBlockRenderer renderer) {
renderer.renderItem(stack, transformType);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

import gregtech.api.cover.CoverUtil;
import gregtech.api.items.metaitem.MetaItem;
import gregtech.api.util.ModCompatibility;
import gregtech.client.model.pipeline.VertexLighterFlatSpecial;
import gregtech.client.model.pipeline.VertexLighterSmoothAoSpecial;
import gregtech.client.utils.AdvCCRSConsumer;
import gregtech.client.utils.FacadeBlockAccess;
import gregtech.client.utils.ItemRenderCompat;
import gregtech.common.covers.facade.FacadeHelper;
import gregtech.common.items.behaviors.FacadeItem;

Expand Down Expand Up @@ -82,7 +82,7 @@ public static void init() {

@Override
public void renderItem(ItemStack rawStack, ItemCameraTransforms.TransformType transformType) {
ItemStack itemStack = ModCompatibility.getRealItemStack(rawStack);
ItemStack itemStack = ItemRenderCompat.getRepresentedStack(rawStack);
if (!(itemStack.getItem() instanceof MetaItem<?>)) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.api.util.GTLog;
import gregtech.api.util.GTUtility;
import gregtech.api.util.ModCompatibility;
import gregtech.client.renderer.CubeRendererState;
import gregtech.client.renderer.texture.Textures;
import gregtech.client.utils.ItemRenderCompat;

import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.BufferBuilder;
Expand Down Expand Up @@ -72,7 +72,7 @@ public void onModelsBake(ModelBakeEvent event) {

@Override
public void renderItem(ItemStack rawStack, TransformType transformType) {
ItemStack stack = ModCompatibility.getRealItemStack(rawStack);
ItemStack stack = ItemRenderCompat.getRepresentedStack(rawStack);
MetaTileEntity metaTileEntity = GTUtility.getMetaTileEntity(stack);
if (metaTileEntity == null) {
return;
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/gregtech/client/renderer/pipe/PipeRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
import gregtech.api.unification.material.Material;
import gregtech.api.unification.material.info.MaterialIconType;
import gregtech.api.util.GTUtility;
import gregtech.api.util.ModCompatibility;
import gregtech.client.renderer.CubeRendererState;
import gregtech.client.renderer.texture.Textures;
import gregtech.client.utils.ItemRenderCompat;

import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
Expand Down Expand Up @@ -150,7 +150,7 @@ public abstract void buildRenderer(PipeRenderContext renderContext, BlockPipe<?,

@Override
public void renderItem(ItemStack rawItemStack, TransformType transformType) {
ItemStack stack = ModCompatibility.getRealItemStack(rawItemStack);
ItemStack stack = ItemRenderCompat.getRepresentedStack(rawItemStack);
if (!(stack.getItem() instanceof ItemBlockPipe)) {
return;
}
Expand Down
170 changes: 170 additions & 0 deletions src/main/java/gregtech/client/utils/ItemRenderCompat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package gregtech.client.utils;

import gregtech.api.GTValues;
import gregtech.api.util.GTLog;
import gregtech.api.util.world.DummyWorld;

import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.fml.common.Loader;

import appeng.items.misc.ItemEncodedPattern;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.List;

public final class ItemRenderCompat {

private static @Nullable ItemRenderCompat.RepresentativeStackExtractor rsHandler;
private static @Nullable ItemRenderCompat.RepresentativeStackExtractor ae2Handler;

private ItemRenderCompat() {}

@ApiStatus.Internal
public static void init() {
ae2Handler = AE2StackExtractor.create();
rsHandler = RSStackExtractor.create();
}

/**
* Attempts to retrieve the actual ItemStack another stack represents.
* <p>
* Primarily used to retrieve the output stack from AE2 or RS Patterns.
*
* @param stack the stack to retrieve from
* @return the actual represented ItemStack
*/
public static @NotNull ItemStack getRepresentedStack(@NotNull ItemStack stack) {
if (ae2Handler != null && ae2Handler.canHandleStack(stack)) {
return ae2Handler.getActualStack(stack);
}
if (rsHandler != null && rsHandler.canHandleStack(stack)) {
return rsHandler.getActualStack(stack);
}
return stack;
}

/**
* An extractor to retrieve a represented stack from an ItemStack
*/
public interface RepresentativeStackExtractor {

/**
* @param stack the stack to test
* @return if the extractor can handle the stack
*/
boolean canHandleStack(@NotNull ItemStack stack);

/**
* @param stack the stack to retrieve from
* @return the represented stack
*/
@NotNull
ItemStack getActualStack(@NotNull ItemStack stack);
}

/**
* Extracts the output stack from AE2 Patterns
*/
private static final class AE2StackExtractor implements RepresentativeStackExtractor {

public static @Nullable ItemRenderCompat.AE2StackExtractor create() {
if (!Loader.isModLoaded(GTValues.MODID_APPENG)) return null;
GTLog.logger.info("AppliedEnergistics2 found; enabling render integration.");
return new AE2StackExtractor();
}

@Override
public boolean canHandleStack(@NotNull ItemStack stack) {
return stack.getItem() instanceof ItemEncodedPattern;
}

@Override
public @NotNull ItemStack getActualStack(@NotNull ItemStack stack) {
if (stack.isEmpty()) return ItemStack.EMPTY;
if (stack.getItem() instanceof ItemEncodedPattern encodedPattern) {
return encodedPattern.getOutput(stack);
}
return stack;
}
}

/**
* Extracts the output stack from RS Patterns
*/
@SuppressWarnings("ClassCanBeRecord")
private static final class RSStackExtractor implements RepresentativeStackExtractor {

private final MethodHandle getPatternFromCacheHandle;
private final MethodHandle getOutputsHandle;
private final Class<?> itemPatternClass;

private RSStackExtractor(MethodHandle getPatternFromCacheHandle, MethodHandle getOutputsHandle,
Class<?> itemPatternClass) {
this.getPatternFromCacheHandle = getPatternFromCacheHandle;
this.getOutputsHandle = getOutputsHandle;
this.itemPatternClass = itemPatternClass;
}

public static @Nullable ItemRenderCompat.RSStackExtractor create() {
if (!Loader.isModLoaded(GTValues.MODID_RS)) return null;

Class<?> clazz;
try {
clazz = Class.forName("com.raoulvdberge.refinedstorage.item.ItemPattern");
GTLog.logger.info("RefinedStorage found; enabling render integration.");
} catch (ClassNotFoundException ignored) {
GTLog.logger.error("RefinedStorage classes not found; skipping render integration.");
return null;
}

try {
Method method = clazz.getMethod("getPatternFromCache", World.class, ItemStack.class);

MethodHandles.Lookup lookup = MethodHandles.publicLookup();

MethodHandle getPatternFromCacheHandle = lookup.unreflect(method);

method = method.getReturnType().getMethod("getOutputs");
MethodHandle getOutputsHandle = lookup.unreflect(method);

return new RSStackExtractor(getPatternFromCacheHandle, getOutputsHandle, clazz);
} catch (NoSuchMethodException | IllegalAccessException e) {
GTLog.logger.error("Failed to enable RefinedStorage integration", e);
return null;
}
}

@Override
public boolean canHandleStack(@NotNull ItemStack stack) {
return itemPatternClass.isAssignableFrom(stack.getItem().getClass());
}

@SuppressWarnings("unchecked")
@Override
public @NotNull ItemStack getActualStack(@NotNull ItemStack stack) {
if (stack.isEmpty()) return ItemStack.EMPTY;

List<ItemStack> outputs;
try {
// ItemPattern.getPatternFromCache: (World, ItemStack) -> CraftingPattern
Object craftingPattern = getPatternFromCacheHandle.invoke(DummyWorld.INSTANCE, stack);
// CraftingPattern#getOutputs: () -> List<ItemStack>
outputs = (List<ItemStack>) getOutputsHandle.invoke(craftingPattern);
} catch (Throwable e) {
GTLog.logger.error("Failed to obtain item from ItemPattern", e);
return stack;
}

if (outputs.isEmpty()) {
return stack;
}
return outputs.get(0);
}
}
}

0 comments on commit ebde142

Please sign in to comment.