Дополнительная броня.

svk

1,185
3
Сделал я дополнительную бронь для игрока.

Как мне в эвенте получения урона (сейчас использую LivingHurtEvent) высчитать чистый (урон - защита брони, эффекты и т.п.) урон который получит энтити, и сделать его меньше?
 
Свой хук на выход из метода ставить. Только так можно получить урон после всех расчетов.
 
Хватит лепить костыли. Имплементишь ISpecialArmor на предмете и делаешь нормально.
 
Nichie написал(а):
Свой хук на выход из метода ставить. Только так можно получить урон после всех расчетов.
А как мне это сделать? Сделал при помощи либы глуми:
Код:
    @Hook
    public static void hurt(LivingHurtEvent e) 
    {
        System.out.println("+");
    }
В ответ получил:
Код:
[13:57:05] [Server thread/INFO] [STDOUT]: [gloomyfolken.hooklib.asm.HookLogger$SystemOutLogger:debug:20]: [DEBUG] Injecting hooks into class net.minecraftforge.event.entity.living.LivingHurtEvent
[13:57:05] [Server thread/INFO] [STDOUT]: [gloomyfolken.hooklib.asm.HookLogger$SystemOutLogger:debug:20]: [DEBUG] Successfully injected 0 hooks
[13:57:05] [Server thread/INFO] [STDOUT]: [gloomyfolken.hooklib.asm.HookLogger$SystemOutLogger:warning:25]: [WARNING] Can not found target method of hook AsmHook: net.minecraftforge.event.entity.living.LivingHurtEvent#hurt() -> gloomyfolken.hooklib.example.AnnotationHooks#hurt(Lnet/minecraftforge/event/entity/living/LivingHurtEvent;)V, ReturnCondition=NEVER, ReturnValue=VOID, InjectorFactory: gloomyfolken.hooklib.asm.HookInjectorFactory$MethodEnter
 
Я чёт ваще не понимаю :D
Он типо хукает метод с таким-же названием и аргументами? Но в коде же может быть 2 таких метада в разных классах.
 
Т.е. ты хранишь переменную, и после того, как рассчитается весь урон, который должен пройти по игроку, ты хочешь уменьшить его?
 
А почему ты не можешь сразу урезать урон? А после дать майну уменьшить его еще сильнее, с учетом брони и зелий? (Все в том же LivingHurtEvent)
 
Nichie написал(а):
Т.е. ты хранишь переменную, и после того, как рассчитается весь урон, который должен пройти по игроку, ты хочешь уменьшить его?
 
А почему ты не можешь сразу урезать урон? А после дать майну уменьшить его еще сильнее, с учетом брони и зелий? (Все в том же LivingHurtEvent)
1 - да
2 - потому-что это броня как дополнительные жизни, если контрить по началу, то 7 брони законтрят лишь 1 удар на 7хп, а если в конце, то с учётом брони игрока, 7 ударов.
 
Тогда не все так просто.

Во первых. Хук тебе нужно ставить на выход из метода 'damageEntity' в классе 'EntityPlayer', а не в ивент.

А во вторых.. ASMHook тебе тут не поможет. Нужно ставить ручками хук. 
С помощью ASMHook'a ты не сможешь вставить в метод такой код:

Код:
damage = MyHookClass.foo(damage);

Если умеешь ставить хук ручками, то это хорошо.

Вкратце, для таких штук я юзаю TreeNode, ибо с ним легче.
У тебя есть метод 'transform' в твоем трансформере.
В нем проверяешь на имя класса. Если это игрок - (или обф. имя класса) трансформишь.

В нем инициализируешь ClassReader, загружаешь в него байты класса. Вообщем, база выглядит так:

Код:
private byte[] transformEntityPlayer(byte[] bytecode, boolean obf) {
        ClassNode classNode = new ClassNode();
        ClassReader classReader = new ClassReader(bytecode);
        classReader.accept(classNode, 0);

        // Тут твоя логика

        ClassWriter writer = new ClassWriter(0);
        classNode.accept(writer);
        return writer.toByteArray();
}

В логике ты проходишь по всем методам. Определяешь, что он = 'damageEntity'.
Пором проходишь по всей инструкции. Если это выход из метода - перед ним вставляешь свою инструкцию.
Твоя инструкция должна вставлять код, который я написал в самом верху.

Если юзаешь IDEA, советую юзать плагин ASM Bytecode *что-то там*. Показывает, какие действия надо сделать, чтобы вставить хук.

TreeNode не самый быстрый способ все реализовать. Можно делать это так, как сделал Клевалин в ASMHook'либе, но для этого нужно свой ClassReader дописать. Я не хочу париться об этом. Все-равно хук встает во время загрузки игры.
 
Nichie написал(а):
Тогда не все так просто.

Во первых. Хук тебе нужно ставить на выход из метода 'damageEntity' в классе 'EntityPlayer', а не в ивент.

А во вторых.. ASMHook тебе тут не поможет. Нужно ставить ручками хук. 
С помощью ASMHook'a ты не сможешь вставить в метод такой код:

Код:
damage = MyHookClass.foo(damage);

Если умеешь ставить хук ручками, то это хорошо.
Нет, я с таким дело не имел. Но очень надо, помоги пожалуйста :)
[merge_posts_bbcode]Добавлено: 03.03.2016 19:10:14[/merge_posts_bbcode]

Что-то типо этого?
Код:
HookLoader.registerHook(AsmHook.newBuilder()
        .setTargetClass("net.minecraft.client.renderer.texture.TextureManager")
        .setTargetMethod("bindTexture")
        .addTargetMethodParameters("net.minecraft.util.ResourceLocation")
        .setHookClass(HOOKS_CLASS)
        .setHookMethod("bindTexture")
        .addHookMethodParameter("net.minecraft.util.ResourceLocation", 1)
        .setReturnCondition(ReturnCondition.ALWAYS)
        .build());

 Подскажи как :)
 
// См выше, я прошлый коммент дополнил. :/

Могу попробовать еще подробнее расписать, кек
Но если ты не знаком с ASM, то сложно будет
 
В итоге так ничего и не понял...
Это методами всё делается? 
Как пройтись по методам, как определить название? 
Как проходить по инструкции и что это вообще такое? Как определить что это выход из метода? :D
 
y-6yGGwYRsI.jpg
 
А нельзя просто пререписать все из метода damageEntity в [font=Verdana, Helvetica, Arial, sans-serif]LivingHurtEvent и там уменьшить[/font]
 
Вот так надо:

Код:
    @Override
    public byte[] transform(String className, String s1, byte[] bytecode) {

        if(className.equals("net.minecraft.entity.player.EntityPlayer")) {
            bytecode = transformEntityPlayer(bytecode, false);
        }
        // TODO: Тут тебе еще нужно проверять на обф. имя класса. В таком случае вызывать с аргументом true.

        return bytecode;
    }

 private byte[] transformEntityPlayer(byte[] bytecode, boolean obf) {
        ClassNode classNode = new ClassNode();
        ClassReader classReader = new ClassReader(bytecode);
        classReader.accept(classNode, 0);

        String methodDamageEntity = obf ? "OBF ИМЯ МЕТОДА ТУТ" : "damageEntity";
        String methodDamageEntityDesc = obf ? "Замени пути к классам на обф имена классов. Типо Lnet.minecraft.ItemStack; на Ladd;"
                : "(Lnet/minecraft/util/DamageSource;F)V";
        for (MethodNode method : classNode.methods) {
            if(method.name.equals(methodDamageEntity) && method.desc.equals(methodDamageEntityDesc)) {
                for(int i = 0; i < method.instructions.size(); i+=4) {

                    AbstractInsnNode currentLine;
                    if((currentLine = method.instructions.get(i)).getOpcode() == Opcodes.ALOAD &&
                            currentLine.getNext().getOpcode() == Opcodes.ALOAD &&
                            currentLine.getNext().getNext().getOpcode() == Opcodes.INVOKEVIRTUAL &&
                            currentLine.getNext().getNext().getNext().getOpcode() == Opcodes.INVOKEVIRTUAL) {

                        method.instructions.insertBefore(currentLine, new VarInsnNode(Opcodes.ALOAD, 0));
                        method.instructions.insertBefore(currentLine, new VarInsnNode(Opcodes.ALOAD, 1));
                        method.instructions.insertBefore(currentLine, new VarInsnNode(Opcodes.ALOAD, 2));
                        method.instructions.insertBefore(currentLine, new MethodInsnNode(Opcodes.INVOKESTATIC, "nichiecode/coremod/asm/NichieTransformer", "entityPlayer_recalcDamage",
                                // TODO: Тут тоже нужно проверять на obf и менять имена классов на их обфусцированные имена
                                "(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/DamageSource;F)F", false));
                        method.instructions.insertBefore(currentLine, new VarInsnNode(Opcodes.FSTORE, 2));

                        break;
                    }
                }
            }
        }

        ClassWriter writer = new ClassWriter(0);
        classNode.accept(writer);
        return writer.toByteArray();
    }


   // Твой метод. Высчитывай урон как хочешь
    public static float entityPlayer_recalcDamage(EntityPlayer p, DamageSource src, float srcDamage) {
        return srcDamage / 2;
    }

Прикрепил скрин того, как встает хук. На другие хуки не смотри, смотри только на выделенную строку.


Обф. имена ищи сам. Метод transform есть у тебя в классе-трансформере.
 
Назад
Сверху