Skip to content

Commit

Permalink
Slowly working on supporting capabilities a little better
Browse files Browse the repository at this point in the history
  • Loading branch information
BluSpring committed Dec 5, 2023
1 parent 059ddb0 commit 56c4e63
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 109 deletions.
14 changes: 10 additions & 4 deletions patches/net/minecraftforge/items/ItemHandlerHelper.java.diff
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
--- ItemHandlerHelper.java
+++ ItemHandlerHelper.java
@@ -42,5 +42,5 @@
@@ -13,4 +13,5 @@
import net.minecraft.util.Mth;
import net.minecraft.world.level.Level;
+import net.minecraftforge.common.capabilities.CapabilityProvider;
import net.minecraftforge.items.wrapper.PlayerMainInvWrapper;
import org.jetbrains.annotations.NotNull;
@@ -42,5 +43,5 @@
return false;

- return (!a.hasTag() || a.getTag().equals(b.getTag())) && a.areCapsCompatible(b);
+ return (!a.hasTag() || a.getTag().equals(b.getTag())) && a.areCapsCompatible(b.getWorkaround());
+ return (!a.hasTag() || a.getTag().equals(b.getTag())) && a.areCapsCompatible((CapabilityProvider<ItemStack>) (Object) b);
}

@@ -67,5 +67,5 @@
@@ -67,5 +68,5 @@
return false;

- return (!a.hasTag() || a.getTag().equals(b.getTag())) && a.areCapsCompatible(b);
+ return (!a.hasTag() || a.getTag().equals(b.getTag())) && a.areCapsCompatible(b.getWorkaround());
+ return (!a.hasTag() || a.getTag().equals(b.getTag())) && a.areCapsCompatible((CapabilityProvider<ItemStack>) (Object) b);
}

2 changes: 2 additions & 0 deletions src/main/java/xyz/bluspring/kilt/TestingMoreShit.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public TestingMoreShit(IForgeRegistry<Block> registry) {

public boolean moreRandomShit(Item item) {
var quack = new Item(new Item.Properties().durability(0));
var test = Item.class;
System.out.println(test);
//return ((EnchantmentCategoryInjection) (Object) this).getDelegate().test(item);
return quack.equals("a");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package xyz.bluspring.kilt.forgeinjects.world.item;

import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
import net.minecraftforge.common.capabilities.*;
import net.minecraftforge.common.capabilities.CapabilityProvider;
import net.minecraftforge.common.extensions.IForgeItemStack;
import net.minecraftforge.common.util.LazyOptional;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -19,14 +16,13 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import xyz.bluspring.kilt.helpers.mixin.CreateInitializer;
import xyz.bluspring.kilt.helpers.mixin.Extends;
import xyz.bluspring.kilt.injections.CapabilityProviderInjection;
import xyz.bluspring.kilt.injections.capabilities.ItemStackCapabilityProviderImpl;
import xyz.bluspring.kilt.injections.item.ItemStackInjection;
import xyz.bluspring.kilt.workarounds.CapabilityProviderWorkaround;

import java.util.function.Supplier;

@Mixin(ItemStack.class)
@Extends(CapabilityProvider.class)
public abstract class ItemStackInject implements IForgeItemStack, CapabilityProviderInjection, ItemStackCapabilityProviderImpl, ItemStackInjection {
private CompoundTag capNBT;

Expand All @@ -43,13 +39,6 @@ public CompoundTag getCapNBT() {

@Shadow public abstract Item getItem();

private final CapabilityProviderWorkaround<ItemStack> workaround = new CapabilityProviderWorkaround<>(ItemStack.class, (ItemStack) (Object) this);

@Override
public CapabilityProviderWorkaround<ItemStack> getWorkaround() {
return workaround;
}

public ItemStackInject(ItemLike item, int count) {}

@CreateInitializer
Expand Down Expand Up @@ -80,73 +69,6 @@ public ItemStackInject(ItemLike item, int count, CompoundTag tag) {
}
}

@Override
public @NotNull <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
return workaround.getCapability(cap, side);
}

@Override
public void gatherCapabilities() {
workaround.invokeGatherCapabilities();
}

@Override
public void gatherCapabilities(@Nullable ICapabilityProvider parent) {
workaround.invokeGatherCapabilities(parent);
}

@Override
public void gatherCapabilities(@Nullable Supplier<ICapabilityProvider> parent) {
workaround.invokeGatherCapabilities(parent);
}

@Nullable
@Override
public CapabilityDispatcher getCapabilities() {
return workaround.invokeGetCapabilities();
}

@Nullable
@Override
public CompoundTag serializeCaps() {
return workaround.invokeSerializeCaps();
}

@Override
public void deserializeCaps(CompoundTag tag) {
workaround.invokeDeserializeCaps(tag);
}

@Override
public boolean areCapsCompatible(CapabilityProvider<ItemStack> other) {
return workaround.areCapsCompatible(other);
}

@Override
public boolean areCapsCompatible(ICapabilityProviderImpl<ItemStack> stack) {
if (stack instanceof ItemStackCapabilityProviderImpl stackWorkaround)
return workaround.areCapsCompatible(stackWorkaround.getWorkaround());
else if (stack instanceof CapabilityProvider<ItemStack> provider)
return workaround.areCapsCompatible(provider);
else
return false;
}

@Override
public boolean areCapsCompatible(@Nullable CapabilityDispatcher other) {
return workaround.areCapsCompatible(other);
}

@Override
public void invalidateCaps() {
workaround.invalidateCaps();
}

@Override
public void reviveCaps() {
workaround.reviveCaps();
}

@Override
public void deserializeNBT(CompoundTag nbt) {
var itemStack = ItemStack.of(nbt);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package xyz.bluspring.kilt.helpers.mixin;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Opcodes;

import java.util.HashMap;
import java.util.Map;

public class AnnotationValueVisitor extends AnnotationVisitor {
public AnnotationValueVisitor() {
super(Opcodes.ASM9);
}

public final Map<String, Object> values = new HashMap<>();

@Override
public void visit(String name, Object value) {
super.visit(name, value);
this.values.put(name, value);
}
}
12 changes: 12 additions & 0 deletions src/main/java/xyz/bluspring/kilt/helpers/mixin/Extends.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package xyz.bluspring.kilt.helpers.mixin;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Extends {
Class<?> value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.jetbrains.annotations.ApiStatus;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import org.spongepowered.asm.util.Annotations;
Expand All @@ -11,6 +12,24 @@
public final class MixinExtensionHelper {
// This should be executed in the mixin plugin with the corresponding method.
// This is only separated into this class for anyone who wants to use this code.
private static boolean containsOpcode(InsnList list, int opcode) {
for (AbstractInsnNode node : list) {
if (node.getOpcode() == opcode)
return true;
}

return false;
}

private static boolean containsThisCall(ClassNode classNode, InsnList list) {
for (AbstractInsnNode node : list) {
if (node.getOpcode() == Opcodes.INVOKESPECIAL && node instanceof MethodInsnNode methodInsnNode && methodInsnNode.owner.equals(classNode.name))
return true;
}

return false;
}

@ApiStatus.Internal
public static void apply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
var classNode = mixinInfo.getClassNode(0);
Expand All @@ -20,6 +39,17 @@ public static void apply(String targetClassName, ClassNode targetClass, String m
var fieldsToRemove = new ArrayList<FieldNode>();
var methodsToRemove = new ArrayList<MethodNode>();

var extend = Annotations.getVisible(classNode, Extends.class);
if (extend != null) {
if (targetClass.superName != null && !targetClass.superName.equals("java/lang/Object"))
throw new IllegalStateException(String.format("Class %s should not already have a super class! (tried extend by %s, has %s)", targetClassName, mixinClassName, classNode.superName));

var visitor = new AnnotationValueVisitor();
extend.accept(visitor);
var className = ((Type) visitor.values.get("value")).getClassName();
targetClass.superName = className.replace(".", "/");
}

for (FieldNode fieldNode : classNode.fields) {
if (Annotations.getVisible(fieldNode, CreateStatic.class) == null)
continue;
Expand Down Expand Up @@ -124,6 +154,31 @@ public static void apply(String targetClassName, ClassNode targetClass, String m
}
}

if (extend != null) {
if (targetClass.superName.equals("net/minecraftforge/common/capabilities/CapabilityProvider")) {
for (MethodNode node : targetClass.methods.stream().filter((node) -> node.name.equals("<init>")).toList()) {
if (containsThisCall(targetClass, node.instructions))
continue;

var aload = node.instructions.get(2);
var invoke = node.instructions.get(3);
var firstInsn = node.instructions.get(4);

// remove Object.<init> call
node.instructions.remove(aload);
node.instructions.remove(invoke);

var insnList = new InsnList();
insnList.add(new VarInsnNode(Opcodes.ALOAD, 0));
insnList.add(new LdcInsnNode(Type.getObjectType(targetClass.name)));
insnList.add(new InsnNode(Opcodes.ICONST_0));
insnList.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, targetClass.superName, "<init>", "(Ljava/lang/Class;Z)V"));

node.instructions.insertBefore(firstInsn, insnList);
}
}
}

for (FieldNode fieldNode : fieldsToRemove) {
classNode.fields.remove(fieldNode);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
package xyz.bluspring.kilt.injections.capabilities;

import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.ICapabilityProviderImpl;
import xyz.bluspring.kilt.workarounds.CapabilityProviderWorkaround;

public interface BlockEntityCapabilityProviderImpl extends ICapabilityProviderImpl<BlockEntity> {
default CapabilityProviderWorkaround<BlockEntity> getWorkaround() {
throw new IllegalStateException("should be overridden by mixin");
}
public interface BlockEntityCapabilityProviderImpl extends ICapabilityProviderImplWithWorkaround<BlockEntity> {
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package xyz.bluspring.kilt.injections.capabilities;

import net.minecraft.world.entity.Entity;
import net.minecraftforge.common.capabilities.ICapabilityProviderImpl;
import xyz.bluspring.kilt.workarounds.CapabilityProviderWorkaround;

public interface EntityCapabilityProviderImpl extends ICapabilityProviderImpl<Entity> {
CapabilityProviderWorkaround<Entity> getWorkaround();
public interface EntityCapabilityProviderImpl extends ICapabilityProviderImplWithWorkaround<Entity> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package xyz.bluspring.kilt.injections.capabilities;

import net.minecraftforge.common.capabilities.ICapabilityProviderImpl;
import xyz.bluspring.kilt.workarounds.CapabilityProviderWorkaround;

public interface ICapabilityProviderImplWithWorkaround<B extends ICapabilityProviderImpl<B>> extends ICapabilityProviderImpl<B> {
default CapabilityProviderWorkaround<B> getWorkaround() {
throw new IllegalStateException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@

import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.ICapabilityProviderImpl;
import xyz.bluspring.kilt.workarounds.CapabilityProviderWorkaround;

public interface ItemStackCapabilityProviderImpl extends ICapabilityProviderImpl<ItemStack> {
default CapabilityProviderWorkaround<ItemStack> getWorkaround() {
throw new IllegalStateException();
}

default boolean areCapsCompatible(ICapabilityProviderImpl<ItemStack> stack) {
throw new IllegalStateException();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package xyz.bluspring.kilt.injections.capabilities;

import net.minecraft.world.level.Level;
import net.minecraftforge.common.capabilities.ICapabilityProviderImpl;
import xyz.bluspring.kilt.workarounds.CapabilityProviderWorkaround;

public interface LevelCapabilityProviderImpl extends ICapabilityProviderImpl<Level> {
CapabilityProviderWorkaround<Level> getWorkaround();
public interface LevelCapabilityProviderImpl extends ICapabilityProviderImplWithWorkaround<Level> {
}
3 changes: 2 additions & 1 deletion src/main/kotlin/xyz/bluspring/kilt/loader/KiltLoader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ class KiltLoader {
// it.annotationData["bus"] as Mod.EventBusSubscriber.Bus

try {
val modId = it.annotationData["modid"] as String
val modId = it.annotationData["modid"] as String? ?: mod.modId

if (modId != mod.modId)
return@forEach
Expand All @@ -551,6 +551,7 @@ class KiltLoader {

Kilt.logger.info("Automatically registered event ${it.clazz.className} from mod ID $modId under bus ${busType.name}")
} catch (e: Exception) {
Kilt.logger.error("Failed to register event ${it.clazz.className} from mod ${mod.modId}!")
e.printStackTrace()
exceptions.add(e)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import java.util.function.Supplier

// Due to a mixin issue where you can't extend new classes in it, this is a
// little workaround to help redirect method calls to CapabilityProvider.
class CapabilityProviderWorkaround<B : ICapabilityProviderImpl<B>>(baseClass: Class<B>, isLazy: Boolean, val base: B) : CapabilityProvider<B>(baseClass, isLazy) {
class CapabilityProviderWorkaround<B : ICapabilityProviderImpl<B>>(val baseClass: Class<B>, isLazy: Boolean, val base: B) : CapabilityProvider<B>(baseClass, isLazy) {
constructor(baseClass: Class<B>, base: B) : this(baseClass, false, base)

fun invokeGatherCapabilities() {
Expand Down

0 comments on commit 56c4e63

Please sign in to comment.