Add all missing inventory hooks

Fixes #110
This commit is contained in:
DBotThePony 2022-10-11 19:51:00 +07:00
parent 5cc05fa038
commit ba52af00fb
Signed by: DBot
GPG Key ID: DCC23B5715498507
4 changed files with 220 additions and 70 deletions

View File

@ -129,7 +129,6 @@ public final class OverdriveThatMatters {
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerChangeDimensionEvent); EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerChangeDimensionEvent);
EVENT_BUS.addListener(EventPriority.LOWEST, MatteryPlayerCapability.Companion::onPlayerDeath); EVENT_BUS.addListener(EventPriority.LOWEST, MatteryPlayerCapability.Companion::onPlayerDeath);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerCloneEvent); EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::onPlayerCloneEvent);
EVENT_BUS.addListener(EventPriority.HIGHEST, MatteryPlayerCapability.Companion::onLivingDrops);
EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::canEntitySpawn); EVENT_BUS.addListener(EventPriority.NORMAL, MatteryPlayerCapability.Companion::canEntitySpawn);
EVENT_BUS.addListener(EventPriority.LOW, MatterDataKt::serverStartData); EVENT_BUS.addListener(EventPriority.LOW, MatterDataKt::serverStartData);

View File

@ -129,26 +129,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
field = value field = value
} }
fun dropExoSuitInventory(): List<ItemEntity> {
val result = ArrayList<ItemEntity>()
val oldCaptureDrops = ply.captureDrops(result) as MutableCollection<ItemEntity>?
val iterator = exoSuitContainer.iterator().nonEmpty()
for (item in iterator) {
if (!hasVanishingCurse(item)) {
ply.drop(item, true, false)
}
iterator.remove()
}
ply.captureDrops(oldCaptureDrops)
oldCaptureDrops?.addAll(result)
return result
}
var isExoSuitCraftingUpgraded by synchronizer.bool(setter = setter@{ value, access, _ -> var isExoSuitCraftingUpgraded by synchronizer.bool(setter = setter@{ value, access, _ ->
if (value != access.read()) { if (value != access.read()) {
access.write(value) access.write(value)
@ -768,23 +748,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
.ifPresentK { it.invalidateNetworkState() } .ifPresentK { it.invalidateNetworkState() }
} }
private val waitingToDie = ArrayList<Pair<LivingEntity, MatteryPlayerCapability>>()
fun onLivingDrops(event: LivingDropsEvent) {
val indexOf = waitingToDie.indexOfFirst { event.entity == it.first }
if (indexOf == -1)
return
val drops = waitingToDie[indexOf].second.dropExoSuitInventory()
if (event.entity.captureDrops() == null) {
event.drops.addAll(drops)
}
waitingToDie.removeAt(indexOf)
}
fun onPlayerDeath(event: LivingDeathEvent) { fun onPlayerDeath(event: LivingDeathEvent) {
val ply = event.entity as? Player ?: return val ply = event.entity as? Player ?: return
val mattery = ply.matteryPlayer ?: return val mattery = ply.matteryPlayer ?: return
@ -795,21 +758,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return return
} }
if (mattery.hasExoSuit && !ply.level.gameRules.getBoolean(GameRules.RULE_KEEPINVENTORY)) {
waitingToDie.add(ply to mattery)
onceServer {
val index = waitingToDie.indexOfFirst { it.first == ply }
if (index != -1) {
waitingToDie.removeAt(index)
mattery.dropExoSuitInventory().forEach { ply.level.addFreshEntity(it) }
LOGGER.warn("Unable to 'properly' drop $ply's ExoSuit inventory contents")
LOGGER.warn("I blame Forge.")
}
}
}
if (!mattery.isAndroid) { if (!mattery.isAndroid) {
return return
} }
@ -901,7 +849,26 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return return
} }
val leftover = it.exoSuitContainer.addItem(item, false) val leftover = it.exoSuitContainer.addItem(item, false, popTime = 5)
item.count = leftover.count
}
/**
* this method is hooked through coremod transformer
*/
@JvmStatic
fun inventoryAddItemHookPre(inventory: Inventory, item: ItemStack) {
if (item.isEmpty) {
return
}
val it = inventory.player.matteryPlayer ?: return
if (!it.hasExoSuit) {
return
}
val leftover = it.exoSuitContainer.addItem(item, simulate = false, onlyIntoExisting = true, popTime = 5)
item.count = leftover.count item.count = leftover.count
} }
@ -916,5 +883,42 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
inventoryAddItemHook(inventory, item) inventoryAddItemHook(inventory, item)
} }
@JvmStatic
fun inventoryDropAll(inventory: Inventory) {
if (inventory.player.matteryPlayer?.hasExoSuit == false) {
return
}
val iterator = inventory.player.matteryPlayer?.exoSuitContainer?.iterator()?.nonEmpty() ?: return
for (item in iterator) {
inventory.player.drop(item, true, false)
}
}
@JvmStatic
fun inventoryClearContent(inventory: Inventory) {
if (inventory.player.matteryPlayer?.hasExoSuit == false) {
return
}
inventory.player.matteryPlayer?.exoSuitContainer?.clearContent()
}
@JvmStatic
fun playerDestroyVanishingCursedItems(player: Player) {
if (player.matteryPlayer?.hasExoSuit == false) {
return
}
val iterator = player.matteryPlayer?.exoSuitContainer?.iterator()?.nonEmpty() ?: return
for (item in iterator) {
if (hasVanishingCurse(item)) {
iterator.remove()
}
}
}
} }
} }

View File

@ -147,7 +147,7 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont
} }
@JvmOverloads @JvmOverloads
fun addItem(stack: ItemStack, range: IntRange, simulate: Boolean = false): ItemStack { fun addItem(stack: ItemStack, range: IntRange, simulate: Boolean = false, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack {
if (range.last >= size || range.first < 0) if (range.last >= size || range.first < 0)
throw IllegalArgumentException("Invalid range: $range") throw IllegalArgumentException("Invalid range: $range")
@ -171,6 +171,10 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont
slotStack.count = newCount slotStack.count = newCount
trackedSlots[slot] = slotStack.copy() trackedSlots[slot] = slotStack.copy()
setChanged(slot, slotStack, old) setChanged(slot, slotStack, old)
if (popTime != null) {
slotStack.popTime = popTime
}
} }
copy.shrink(diff) copy.shrink(diff)
@ -182,21 +186,27 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont
} }
} }
// двигаем в пустые слоты if (!onlyIntoExisting) {
for (slot in range) { // двигаем в пустые слоты
if (slots[slot].isEmpty) { for (slot in range) {
val diff = copy.count.coerceAtMost(getMaxStackSize(slot).coerceAtMost(copy.maxStackSize)) if (slots[slot].isEmpty) {
val diff = copy.count.coerceAtMost(getMaxStackSize(slot).coerceAtMost(copy.maxStackSize))
if (!simulate) { if (!simulate) {
val copyToPut = copy.copy() val copyToPut = copy.copy()
copyToPut.count = diff copyToPut.count = diff
this[slot] = copyToPut this[slot] = copyToPut
}
copy.shrink(diff) if (popTime != null) {
copyToPut.popTime = popTime
}
}
if (copy.isEmpty) { copy.shrink(diff)
return copy
if (copy.isEmpty) {
return copy
}
} }
} }
} }
@ -204,8 +214,8 @@ open class MatteryContainer(val watcher: Runnable, private val size: Int) : Cont
return copy return copy
} }
fun addItem(stack: ItemStack, simulate: Boolean): ItemStack { fun addItem(stack: ItemStack, simulate: Boolean, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack {
return addItem(stack, 0 until size, simulate) return addItem(stack, 0 until size, simulate, onlyIntoExisting = onlyIntoExisting, popTime = popTime)
} }
@JvmOverloads @JvmOverloads

View File

@ -462,6 +462,92 @@ function test(instructionList, instructions, offset) {
return i == instructionList.length ? offset : -1 return i == instructionList.length ? offset : -1
} }
function method(path, transform) {
var split = path.split('.')
var methodName = split.pop()
var indexOf = methodName.indexOf('(')
var classname = split.join('.')
return {
'target': {
'type': 'METHOD',
'class': classname,
'methodName': ASMAPI.mapMethod(methodName.substring(0, indexOf)),
'methodDesc': methodName.substring(indexOf)
},
'transformer': transform
}
}
function injectAtHead(path, instructions) {
return method(path, function(node) {
var last = undefined
var next
for (var i = 0; i < instructions.length; i++) {
next = instructions[i]
if (last === undefined) {
node.instructions.insert(next)
} else {
node.instructions.insert(last, next)
}
last = next
}
return node
})
}
var returnCodes = [
opcodesRemapped.return,
opcodesRemapped.areturn,
opcodesRemapped.freturn,
opcodesRemapped.ireturn,
opcodesRemapped.dreturn,
opcodesRemapped.lreturn,
]
function injectAtTail(path, instructions) {
return method(path, function(node) {
for (var instr = node.instructions.size() - 1; instr >= 0; instr--) {
if (includes(returnCodes, node.instructions.get(instr).getOpcode())) {
var last = node.instructions.get(instr > 0 ? --instr : instr)
var next
for (var i = 0; i < instructions.length; i++) {
next = instructions[i]
node.instructions.insert(last, next)
last = next
}
return node
}
}
print('[Overdrive That Matters Coremod] Unable to find tail of ' + path + ', injecting at beginning!')
var last = undefined
var next
for (var i = 0; i < instructions.length; i++) {
next = instructions[i]
if (last === undefined) {
node.instructions.insert(next)
} else {
node.instructions.insert(last, next)
}
last = next
}
return node
})
}
function injectInventoryInsertHook( function injectInventoryInsertHook(
instructions, instructions,
determinedOffset, determinedOffset,
@ -530,6 +616,30 @@ function patchBlendFunc(node) {
function initializeCoreMod() { function initializeCoreMod() {
return { return {
'Inventory#dropAll': injectAtTail(
'net.minecraft.world.entity.player.Inventory.m_36071_()V',
[
new VarInsnNode(opcodesRemapped.aload, 0),
new MethodInsnNode(opcodesRemapped.invokestatic, 'ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability', 'inventoryDropAll', '(Lnet/minecraft/world/entity/player/Inventory;)V', false)
]
),
'Inventory#clearContent': injectAtTail(
'net.minecraft.world.entity.player.Inventory.m_6211_()V',
[
new VarInsnNode(opcodesRemapped.aload, 0),
new MethodInsnNode(opcodesRemapped.invokestatic, 'ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability', 'inventoryClearContent', '(Lnet/minecraft/world/entity/player/Inventory;)V', false)
]
),
'Player#destroyVanishingCursedItems': injectAtTail(
'net.minecraft.world.entity.player.Player.m_36345_()V',
[
new VarInsnNode(opcodesRemapped.aload, 0),
new MethodInsnNode(opcodesRemapped.invokestatic, 'ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability', 'playerDestroyVanishingCursedItems', '(Lnet/minecraft/world/entity/player/Player;)V', false)
]
),
'blend func lock 1': { 'blend func lock 1': {
'target': { 'target': {
'type': 'METHOD', 'type': 'METHOD',
@ -635,7 +745,34 @@ function initializeCoreMod() {
var i var i
// patch "not damaged" // 83: iconst_1
// 84: ireturn
// 85: iconst_0
// 86: ireturn
// 87: aload_2
// 88: invokevirtual #68 // Method net/minecraft/world/item/ItemStack.getCount:()I
// patch "not damaged" before loop
for (i = 0; i < node.instructions.size(); i++) {
var determinedOffset = test([
opcodesRemapped.iconst_1,
opcodesRemapped.ireturn,
opcodesRemapped.iconst_0,
opcodesRemapped.ireturn,
opcodesRemapped.aload,
opcodesRemapped.invokevirtual,
], node.instructions, i)
if (determinedOffset != -1) {
injectInventoryInsertHook(node.instructions, determinedOffset - 1,
'inventoryAddItemHookPre',
'(Lnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/item/ItemStack;)V')
break
}
}
// patch "not damaged" after loop
for (i = 0; i < node.instructions.size(); i++) { for (i = 0; i < node.instructions.size(); i++) {
var determinedOffset = test([ var determinedOffset = test([
opcodesRemapped.invokevirtual, opcodesRemapped.invokevirtual,