From c4d683fe7bcfc92c16556190936d712eecaea4a8 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Oct 2022 20:39:57 +0700 Subject: [PATCH] Energy sword now has innate sweeping edge mechanics Fixes #54 --- .../mc/otm/datagen/lang/English.kt | 2 + .../mc/otm/item/EnergySwordItem.kt | 32 +++++- src/main/resources/coremods/code_injector.js | 106 +++++++++++++++--- 3 files changed, 120 insertions(+), 20 deletions(-) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 67baa4b7a..03e95f990 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -446,6 +446,8 @@ private fun items(provider: MatteryLanguageProvider) { add(MItems.ENERGY_SWORD, "Powered Cake Slicer") add(MItems.ENERGY_SWORD, "desc", "Needs power to operate") add(MItems.ENERGY_SWORD, "desc2", "Deals extra damage to androids when powered") + add(MItems.ENERGY_SWORD, "desc3", "Always strikes surrounding enemies with full damage if empowered") + add(MItems.ENERGY_SWORD, "desc4", "Does not benefit from Sweeping Edge enchantment") add(MItems.PORTABLE_CONDENSATION_DRIVE, "Portable Condensation Drive") add(MItems.PORTABLE_DENSE_CONDENSATION_DRIVE, "Portable Dense Condensation Drive") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/EnergySwordItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/EnergySwordItem.kt index 6588a376a..74ce2c70a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/EnergySwordItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/EnergySwordItem.kt @@ -39,6 +39,18 @@ import ru.dbotthepony.mc.otm.core.ifPresentK import ru.dbotthepony.mc.otm.core.orNull import ru.dbotthepony.mc.otm.registry.EMPDamageSource +/** + * This is called from [net.minecraft.world.item.enchantment.EnchantmentHelper.getSweepingDamageRatio] + * by coremod patch + */ +fun getSweepingDamageRatioHook(ply: LivingEntity): Float? { + if (ply.mainHandItem.item is EnergySwordItem && ply.mainHandItem.matteryEnergy?.extractEnergyInnerExact(EnergySwordItem.ENERGY_PER_SWING, true)?.isPositive == true) { + return 1f + } + + return null +} + class EnergySwordItem : Item(Properties().stacksTo(1).rarity(Rarity.RARE).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { val chargedAttributes: Multimap val dischargedAttributes: Multimap @@ -83,6 +95,12 @@ class EnergySwordItem : Item(Properties().stacksTo(1).rarity(Rarity.RARE).tab(Ov override fun hurtEnemy(itemStack: ItemStack, victim: LivingEntity, attacker: LivingEntity): Boolean { if (attacker is Player && attacker.isCreative) { + victim.matteryPlayer?.let { + if (it.isAndroid) { + victim.hurt(EMPDamageSource(attacker), 8f) + } + } + return true } @@ -124,6 +142,8 @@ class EnergySwordItem : Item(Properties().stacksTo(1).rarity(Rarity.RARE).tab(Ov p_41423_.add(DESCRIPTION) p_41423_.add(DESCRIPTION2) + p_41423_.add(DESCRIPTION3) + p_41423_.add(DESCRIPTION4) } override fun mineBlock( @@ -179,13 +199,15 @@ class EnergySwordItem : Item(Properties().stacksTo(1).rarity(Rarity.RARE).tab(Ov } companion object { - private val MAX_ENERGY = ImpreciseFraction(500_000) - private val ENERGY_ZAP = ImpreciseFraction(4_000) - private val ENERGY_PER_SWING = ImpreciseFraction(2_000) - private val COBWEB_POWER_COST = ImpreciseFraction(2_500) - private val PLANT_POWER_COST = ImpreciseFraction(500) + val MAX_ENERGY = ImpreciseFraction(500_000) + val ENERGY_ZAP = ImpreciseFraction(4_000) + val ENERGY_PER_SWING = ImpreciseFraction(2_000) + val COBWEB_POWER_COST = ImpreciseFraction(2_500) + val PLANT_POWER_COST = ImpreciseFraction(500) private val DESCRIPTION = TranslatableComponent("item.overdrive_that_matters.energy_sword.desc").withStyle(ChatFormatting.DARK_GRAY) private val DESCRIPTION2 = TranslatableComponent("item.overdrive_that_matters.energy_sword.desc2").withStyle(ChatFormatting.DARK_GRAY) + private val DESCRIPTION3 = TranslatableComponent("item.overdrive_that_matters.energy_sword.desc3").withStyle(ChatFormatting.DARK_GRAY) + private val DESCRIPTION4 = TranslatableComponent("item.overdrive_that_matters.energy_sword.desc4").withStyle(ChatFormatting.DARK_GRAY) } } diff --git a/src/main/resources/coremods/code_injector.js b/src/main/resources/coremods/code_injector.js index 45562a52d..87af24ebd 100644 --- a/src/main/resources/coremods/code_injector.js +++ b/src/main/resources/coremods/code_injector.js @@ -4,6 +4,10 @@ var AbstractInsnNode = Java.type('org.objectweb.asm.tree.AbstractInsnNode') var Opcodes = Java.type('org.objectweb.asm.Opcodes') var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode') var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode') +var JumpInsnNode = Java.type('org.objectweb.asm.tree.JumpInsnNode') +var LabelNode = Java.type('org.objectweb.asm.tree.LabelNode') +var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode') +var Label = Java.type('org.objectweb.asm.Label') var opcodesRemapped = { 'aaload': 50, @@ -510,21 +514,21 @@ function initializeCoreMod() { 'transformer': function(node) { // If item is not "damaged": - // 113: invokevirtual #144 // Method addResource:(ILnet/minecraft/world/item/ItemStack;)I - // 116: invokevirtual #158 // Method net/minecraft/world/item/ItemStack.setCount:(I)V - // 119: aload_2 - // 120: invokevirtual #57 // Method net/minecraft/world/item/ItemStack.isEmpty:()Z - // 123: ifne 134 - // 126: aload_2 - // 127: invokevirtual #68 // Method net/minecraft/world/item/ItemStack.getCount:()I - // 130: iload_3 - // 131: if_icmplt 87 - // <-- our target - // 134: aload_2 - // 135: invokevirtual #68 // Method net/minecraft/world/item/ItemStack.getCount:()I - // 138: iload_3 - // 139: if_icmpne 162 - // 142: aload_0 + // 113: invokevirtual #144 // Method addResource:(ILnet/minecraft/world/item/ItemStack;)I + // 116: invokevirtual #158 // Method net/minecraft/world/item/ItemStack.setCount:(I)V + // 119: aload_2 + // 120: invokevirtual #57 // Method net/minecraft/world/item/ItemStack.isEmpty:()Z + // 123: ifne 134 + // 126: aload_2 + // 127: invokevirtual #68 // Method net/minecraft/world/item/ItemStack.getCount:()I + // 130: iload_3 + // 131: if_icmplt 87 + // <-- our target + // 134: aload_2 + // 135: invokevirtual #68 // Method net/minecraft/world/item/ItemStack.getCount:()I + // 138: iload_3 + // 139: if_icmpne 162 + // 142: aload_0 // If item returned that it is damaged: // 10: invokevirtual #97 // Method net/minecraft/world/item/ItemStack.isDamaged:()Z @@ -593,6 +597,78 @@ function initializeCoreMod() { return node } + }, + + 'EnchantmentHelper#getSweepingDamageRatio patch for energy sword': { + 'target': { + 'type': 'METHOD', + 'class': 'net.minecraft.world.item.enchantment.EnchantmentHelper', + 'methodName': ASMAPI.mapMethod('m_44821_'), // getSweepingDamageRatio + 'methodDesc': '(Lnet/minecraft/world/entity/LivingEntity;)F' + }, + + 'transformer': function(node) { + // 0: getstatic #237 // Field net/minecraft/world/item/enchantment/Enchantments.SWEEPING_EDGE:Lnet/minecraft/world/item/enchantment/Enchantment; + // 3: aload_0 + // 4: invokestatic #243 // Method getEnchantmentLevel:(Lnet/minecraft/world/item/enchantment/Enchantment;Lnet/minecraft/world/entity/LivingEntity;)I + // 7: istore_1 + // 8: iload_1 + // 9: ifle 19 + // 12: iload_1 + // 13: invokestatic #246 // Method net/minecraft/world/item/enchantment/SweepingEdgeEnchantment.getSweepingDamageRatio:(I)F + // 16: goto 20 + // 19: fconst_0 + // 20: freturn + + var instructions = node.instructions + + var last = new VarInsnNode(opcodesRemapped.aload, 0) + instructions.insert(last) // load player onto stack + + var next = new MethodInsnNode( + opcodesRemapped.invokestatic, + 'ru/dbotthepony/mc/otm/item/EnergySwordItemKt', + 'getSweepingDamageRatioHook', + '(Lnet/minecraft/world/entity/LivingEntity;)Ljava/lang/Float;', + false + ) // call hook + + instructions.insert(last, next) + last = next + + var label = new Label() + var labelNode = new LabelNode(label) + + // add label to jump to if our hook returns null + instructions.insert(last, labelNode) + + // duplicate our value, so `ifnull` can safely pop it from stack + next = new InsnNode(opcodesRemapped.dup) + instructions.insert(last, next) + last = next + + // jump to original code if we returned null + next = new JumpInsnNode(opcodesRemapped.ifnull, labelNode) + instructions.insert(last, next) + last = next + + // unbox float + next = new MethodInsnNode( + opcodesRemapped.invokevirtual, + 'java/lang/Float', + 'floatValue', + '()F', + false + ) + + instructions.insert(last, next) + last = next + + // return float + next = new InsnNode(opcodesRemapped.freturn) + instructions.insert(last, next) + last = next + } } } }