Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix gt tile entities not rendering in AE2 pattern outputs #2319

Merged
merged 4 commits into from
Jan 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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);
}
}
}
Loading