forked from GregTechCEu/GregTech
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix gt tile entities not rendering in AE2 pattern outputs (GregTechCE…
- Loading branch information
1 parent
b4f7e17
commit 6ebe74d
Showing
8 changed files
with
199 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
170 changes: 170 additions & 0 deletions
170
src/main/java/gregtech/client/utils/ItemRenderCompat.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} | ||
} |