HookLib with anchors

7,099
324
1,509
Всем привет!
Это форк всем известной хуклибы. Содержит мои авторские улучшения
Использование такое же([Гайд][Легко][1.6+] Модификация чужого кода при запуске (трансфомеры))
Изменения и дополнения:
  • Добавлены якоря, позволяющие вставлять хуки в середину метода без костылей, вроде номера строки
  • Вставка возвратных хуков в начало конструктора(return до инициализации final-полей) вызывает предупреждения в логе
Пока не густо, но первая фича мощная. По мере возникновения своих потребностей или предложений юзеров буду добавлять еще че-нить.

Исходный код: hohserg1/HookLib

Пример использования якорей:
В тайле воронки есть баг интерграции с некоторыми инвентарями из модов:
Java:
private boolean isInventoryFull(IInventory inventoryIn, EnumFacing side)
    {
        if (inventoryIn instanceof ISidedInventory)
        {
            ISidedInventory isidedinventory = (ISidedInventory)inventoryIn;
            int[] aint = isidedinventory.getSlotsForFace(side);//may be null

            for (int k : aint)
            {
                ItemStack itemstack1 = isidedinventory.getStackInSlot(k);

                if (itemstack1.isEmpty() || itemstack1.getCount() != itemstack1.getMaxStackSize())
                {
                    return false;
                }
            }
        }
Раньше через хуки это можно было пофиксить заменив полностью метод и вставив в середину проверку !=null, либо продублировать первую половину кода до aint и юзать ReturnCondition.ON_TRUE, чтобы выходить из метода в начале, если aint==null
С якорями можно вставить проверку сразу в середину, избежав копипасты кода
Java:
Hook(at = @At(point = InjectionPoint.METHOD_CALL, target = "getSlotsForFace"), returnCondition = ReturnCondition.ON_TRUE, booleanReturnConstant = true)
public static boolean isInventoryFull(TileEntityHopper tile, IInventory inventoryIn, EnumFacing side)
{
    return ((ISidedInventory)inventoryIn).getSlotsForFace(side)==null;
}
Еще пример:
Scala:
//В рендере слотов теперь будет показан индекс слота(для разработки контейнеров)
@Hook(at = new At(point = InjectionPoint.RETURN))
def drawSlot (gui:GuiContainer, slotIn: Slot):Unit = {
    val i = slotIn.xPos
    val j = slotIn.yPos
    Minecraft.getMinecraft.fontRenderer.drawString(slotIn.getSlotIndex.toString,i,j,0xff00ff)
}
В общем, штука полезная и удобная.

@GloomyFolken, примешь pull request?)
 
Последнее редактирование:
1,200
37
237
А если несколько будет одноимённых вызовов? Заменит первый?
 
7,099
324
1,509
1,200
37
237
Поле с названием уже есть, доделать поле с его позицией (первое упоминание — 0, второе — 1 и т. д.) можешь?
 
7,099
324
1,509
Есть ordinal в аннотации, не реализована поддержка еще
 
Последнее редактирование:
7,099
324
1,509
Появилась реализация ordinal)
 
7,099
324
1,509
  • Исправлен краш
HTML:
[00:15:58] [main/INFO]: [HOOKLIB]  Obfuscated: true
[00:15:58] [main/ERROR]: Unable to launch
java.lang.RuntimeException: An error occurred trying to configure the Minecraft home at D:\Games\Minecraft\Profiles\MyMod for Forge Mod Loader
    at net.minecraftforge.fml.relauncher.FMLLaunchHandler.setupHome(FMLLaunchHandler.java:111) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.relauncher.FMLLaunchHandler.setupClient(FMLLaunchHandler.java:81) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.relauncher.FMLLaunchHandler.configureForClientLaunch(FMLLaunchHandler.java:42) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.common.launcher.FMLTweaker.injectIntoClassLoader(FMLTweaker.java:139) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraft.launchwrapper.Launch.launch(Launch.java:115) [launchwrapper-1.12.jar:?]
    at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?]
Caused by: java.lang.ExceptionInInitializerError
    at java.lang.Class.forName0(Native Method) ~[?:1.8.0_51]
    at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_51]
    at net.minecraftforge.fml.relauncher.CoreModManager.loadCoreMod(CoreModManager.java:526) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.relauncher.CoreModManager.discoverCoreMods(CoreModManager.java:450) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.relauncher.CoreModManager.handleLaunch(CoreModManager.java:264) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.relauncher.FMLLaunchHandler.setupHome(FMLLaunchHandler.java:107) ~[forge-1.12.2-14.23.5.2768.jar:?]
    ... 5 more
Caused by: java.lang.NullPointerException
    at net.minecraftforge.fml.common.asm.transformers.DeobfuscationTransformer.<init>(DeobfuscationTransformer.java:61) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at author.hooklib.minecraft.HookLoader.<clinit>(HookLoader.java:24) ~[HookLoader.class:?]
    at java.lang.Class.forName0(Native Method) ~[?:1.8.0_51]
    at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_51]
    at net.minecraftforge.fml.relauncher.CoreModManager.loadCoreMod(CoreModManager.java:526) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.relauncher.CoreModManager.discoverCoreMods(CoreModManager.java:450) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.relauncher.CoreModManager.handleLaunch(CoreModManager.java:264) ~[forge-1.12.2-14.23.5.2768.jar:?]
    at net.minecraftforge.fml.relauncher.FMLLaunchHandler.setupHome(FMLLaunchHandler.java:107) ~[forge-1.12.2-14.23.5.2768.jar:?]
    ... 5 more
[00:15:58] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:1052]: net.minecraftforge.fml.relauncher.FMLSecurityManager$ExitTrappedException
[00:15:58] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:1052]:     at net.minecraftforge.fml.relauncher.FMLSecurityManager.checkPermission(FMLSecurityManager.java:49)
[00:15:58] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:1052]:     at java.lang.SecurityManager.checkExit(SecurityManager.java:761)
[00:15:58] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:1052]:     at java.lang.Runtime.exit(Runtime.java:107)
[00:15:58] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:1052]:     at java.lang.System.exit(System.java:971)
[00:15:58] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:1052]:     at net.minecraft.launchwrapper.Launch.launch(Launch.java:138)
[00:15:58] [main/INFO]: [java.lang.ThreadGroup:uncaughtException:1052]:     at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
  • Удалено использование deprecated api
 
7,099
324
1,509
Неа(
 
7,099
324
1,509
Добавил функциональность для шифта - теперь можно настраивать сдвиги относительно точки инъекции

Большое спасибо @JustAGod за консультацию)
 

tox1cozZ

aka Agravaine
8,454
598
2,890
Больше нельзя вставлять возвратные хуки в начало конструктора(return до инициализации final-полей)
Зачем? Бесячая штука. Нужно полностью заменить конструктор, финальных полей нет, а он все равно не даёт. Как быть? Может там сделать как-то чтобы он просто после всех финальных полей вставлялся?
 
7,099
324
1,509
позволяющие вставлять хуки в середину метода без костылей, вроде номера строки
Мне интересно каким образом? вставлять хук после вызова какого-то опкода?
 
7,099
324
1,509
7,099
324
1,509
Слишком скупое описание? Но они разбиты на довольно маленькие кусочки, там особо описывать нечего в каждом по отдельности
 
7,099
324
1,509
Добавил methods.bin для 1.12.2
 

tox1cozZ

aka Agravaine
8,454
598
2,890
Когда там уже Shift завезешь? Я намутил, но вот INSTEAD ломает вообще код...
Java:
@Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf){
            if(hook.getAnchorPoint() == METHOD_CALL && hook.getAnchorTarget().equals(name)){
                if(hook.getAnchorShift() == Shift.BEFORE){
                    visitOrderedHook();
                    super.visitMethodInsn(opcode, owner, name, desc, itf);
                }else if(hook.getAnchorShift() == Shift.INSTEAD){
//                    System.out.println(opcode + " :: " + name + " :: " + owner);
//                    if(checkOrder()){
//                        visitHook();
//                    }else{
//                        super.visitMethodInsn(opcode, owner, name, desc, itf);
//                    }
                    super.visitMethodInsn(opcode, owner, name, desc, itf);
                }else if(hook.getAnchorShift() == Shift.AFTER){
                    super.visitMethodInsn(opcode, owner, name, desc, itf);
                    visitOrderedHook();
                }
            }else{
                super.visitMethodInsn(opcode, owner, name, desc, itf);
            }
        }

        public boolean checkOrder(){
            if(ordinal == 0){
                ordinal = -2;
                return true;
            }else if(ordinal == -1){
                return true;
            }else if(ordinal > 0){
                ordinal -= 1;
                return false;
            }
            return false;
        }
        
        private void visitOrderedHook(){
            if(checkOrder()){
                visitHook();
            }
        }
 
Сверху