чудеса ASM и многократной потери рассудка #193

This commit is contained in:
YuRaNnNzZZ 2023-06-28 15:40:33 +03:00
parent fced3058d5
commit 2f59edd606
Signed by: YuRaNnNzZZ
GPG Key ID: 5F71738C85A6006D
4 changed files with 126 additions and 22 deletions

View File

@ -36,8 +36,8 @@ import ru.dbotthepony.mc.otm.client.render.blockentity.BatteryBankRenderer;
import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer;
import ru.dbotthepony.mc.otm.compat.adastra.AdAstraCompatKt;
import ru.dbotthepony.mc.otm.compat.curios.CuriosCompatKt;
import ru.dbotthepony.mc.otm.compat.mekanism.MekanismHooks;
import ru.dbotthepony.mc.otm.compat.mekanism.QIOKt;
import ru.dbotthepony.mc.otm.compat.mekanism.TooltipsKt;
import ru.dbotthepony.mc.otm.config.AndroidConfig;
import ru.dbotthepony.mc.otm.config.ClientConfig;
import ru.dbotthepony.mc.otm.config.ItemsConfig;
@ -244,7 +244,7 @@ public final class OverdriveThatMatters {
EVENT_BUS.addListener(EventPriority.NORMAL, QuantumBatteryItem.Companion::clientDisconnect);
if (ModList.get().isLoaded("mekanism")) {
EVENT_BUS.addListener(EventPriority.NORMAL, TooltipsKt::tooltipEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, MekanismHooks::tooltipEvent);
}
EVENT_BUS.addListener(EventPriority.NORMAL, AndroidMenuKeyMapping.INSTANCE::onRenderGuiEvent);

View File

@ -0,0 +1,49 @@
package ru.dbotthepony.mc.otm.compat.mekanism
import mekanism.api.Action
import mekanism.api.AutomationType
import mekanism.common.capabilities.energy.MachineEnergyContainer
import mekanism.common.registries.MekanismItems
import mekanism.common.tile.TileEntityChargepad
import net.minecraft.ChatFormatting
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraftforge.event.entity.player.ItemTooltipEvent
import ru.dbotthepony.mc.otm.capability.isMekanismLoaded
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.core.TranslatableComponent
object MekanismHooks {
@JvmStatic
fun chargeAndroidFromPadHook(container: MachineEnergyContainer<TileEntityChargepad>, entity: LivingEntity) {
if (entity !is Player) return
if (entity.matteryPlayer?.isAndroid == true) {
val androidEnergy = entity.matteryPlayer!!.androidEnergy
val expectedAmount = container.energyPerTick
val remaining = androidEnergy.receiveEnergy(expectedAmount.toDecimal(), true).toFloatingLong()
if (remaining.smallerThan(expectedAmount)) {
val extracted = container.extract(expectedAmount.subtract(remaining), Action.EXECUTE, AutomationType.INTERNAL)
if (!extracted.isZero) {
androidEnergy.receiveEnergy(extracted.toDecimal(), false)
}
}
}
}
private val BLACKHOLE_IMMUNITY = TranslatableComponent("otm.item.blackhole_immunity").withStyle(ChatFormatting.DARK_GRAY)
@JvmStatic
fun tooltipEvent(event: ItemTooltipEvent) {
if (!isMekanismLoaded) {
throw IllegalStateException("Mekanism is not loaded!")
}
if (event.itemStack.`is`(MekanismItems.MODULE_GRAVITATIONAL_MODULATING.get())) {
event.toolTip.add(BLACKHOLE_IMMUNITY)
}
}
}

View File

@ -1,20 +0,0 @@
package ru.dbotthepony.mc.otm.compat.mekanism
import mekanism.common.registries.MekanismItems
import net.minecraft.ChatFormatting
import net.minecraftforge.event.entity.player.ItemTooltipEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.isMekanismLoaded
private val BLACKHOLE_IMMUNITY = TranslatableComponent("otm.item.blackhole_immunity").withStyle(ChatFormatting.DARK_GRAY)
fun tooltipEvent(event: ItemTooltipEvent) {
if (!isMekanismLoaded) {
throw IllegalStateException("Mekanism is not loaded!")
}
if (event.itemStack.`is`(MekanismItems.MODULE_GRAVITATIONAL_MODULATING.get())) {
event.toolTip.add(BLACKHOLE_IMMUNITY)
}
}

View File

@ -2,6 +2,7 @@
var ASMAPI = Java.type('net.minecraftforge.coremod.api.ASMAPI')
var AbstractInsnNode = Java.type('org.objectweb.asm.tree.AbstractInsnNode')
var Opcodes = Java.type('org.objectweb.asm.Opcodes')
var FieldInsnNode = Java.type('org.objectweb.asm.tree.FieldInsnNode')
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')
@ -727,6 +728,80 @@ function initializeCoreMod() {
}
}
return node
}
},
'Mekanism Chargepad Android Charge': {
'target': {
'type': 'METHOD',
'class': 'mekanism.common.tile.TileEntityChargepad',
'methodName': 'onUpdateServer',
'methodDesc': '()V'
},
'transformer': function(node) {
var skipLabel = new Label()
var skipLabelNode = new LabelNode(skipLabel)
var labelIteratorEndNode
for (i = 0; i < node.instructions.size(); i++) {
var insn = node.instructions.get(i)
if (insn && insn.getOpcode() == opcodesRemapped.getfield && insn.name == 'CuriosLoaded') {
var nextInsn = node.instructions.get(i + 1) // IFEQ
labelIteratorEndNode = nextInsn.label
break
}
}
if (!labelIteratorEndNode) return node
for (i = 0; i < node.instructions.size(); i++) {
var insn = node.instructions.get(i)
if (insn && insn.getType() == AbstractInsnNode.LABEL) {
if (insn == labelIteratorEndNode) {
putInstructions(node, insn, [
new VarInsnNode(opcodesRemapped.aload, 0),
new FieldInsnNode(
opcodesRemapped.getfield,
'mekanism/common/tile/TileEntityChargepad',
'energyContainer',
'Lmekanism/common/capabilities/energy/MachineEnergyContainer;'
),
new VarInsnNode(opcodesRemapped.aload, 4),
new MethodInsnNode(
opcodesRemapped.invokestatic,
'ru/dbotthepony/mc/otm/compat/mekanism/MekanismHooks',
'chargeAndroidFromPadHook',
'(Lmekanism/common/capabilities/energy/MachineEnergyContainer;Lnet/minecraft/world/entity/LivingEntity;)V'
),
skipLabelNode
])
break
}
}
}
for (i = 0; i < node.instructions.size(); i++) {
var insn = node.instructions.get(i)
if (insn && insn.getOpcode() == opcodesRemapped.invokevirtual && insn.name == 'chargeHandler' && insn.desc == '(Ljava/util/Optional;)Z') {
var nextInsn = node.instructions.get(i + 1) // curios call is POP, pre-curios check call is IFNE; both need to redirect to loop skip label
if (nextInsn && (nextInsn.getOpcode() == opcodesRemapped.pop || nextInsn.getOpcode() == opcodesRemapped.ifne && nextInsn.label == labelIteratorEndNode)) {
node.instructions.set(nextInsn, new JumpInsnNode(opcodesRemapped.ifne, skipLabelNode))
continue
}
}
}
return node
}
}