Inventory filters preview
This commit is contained in:
parent
3354c698c4
commit
30f07e2fed
@ -0,0 +1,49 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.CrashReport;
|
||||||
|
import net.minecraft.CrashReportCategory;
|
||||||
|
import net.minecraft.ReportedException;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraftforge.registries.ForgeRegistries;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||||
|
|
||||||
|
@Mixin(Inventory.class)
|
||||||
|
public class MixinInventory {
|
||||||
|
@Shadow Player player;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "add(ILnet/minecraft/world/item/ItemStack;)Z",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void add(int pSlot, ItemStack pStack, CallbackInfoReturnable<Boolean> hook) {
|
||||||
|
if (pStack.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pSlot == -1) {
|
||||||
|
this.player.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresent(it -> {
|
||||||
|
try {
|
||||||
|
hook.setReturnValue(it.inventoryAddImpl(pStack));
|
||||||
|
} catch (Throwable throwable) {
|
||||||
|
CrashReport crashreport = CrashReport.forThrowable(throwable, "Adding item to inventory (Overdrive That Matters detour)");
|
||||||
|
CrashReportCategory crashreportcategory = crashreport.addCategory("Item being added");
|
||||||
|
crashreportcategory.setDetail("Registry Name", () -> String.valueOf(ForgeRegistries.ITEMS.getKey(pStack.getItem())));
|
||||||
|
crashreportcategory.setDetail("Item Class", () -> pStack.getItem().getClass().getName());
|
||||||
|
crashreportcategory.setDetail("Item ID", Item.getId(pStack.getItem()));
|
||||||
|
crashreportcategory.setDetail("Item data", pStack.getDamageValue());
|
||||||
|
crashreportcategory.setDetail("Item name", () -> pStack.getHoverName().getString());
|
||||||
|
throw new ReportedException(crashreport);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
package ru.dbotthepony.mc.otm.capability
|
package ru.dbotthepony.mc.otm.capability
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.nbt.ListTag
|
import net.minecraft.nbt.ListTag
|
||||||
|
import net.minecraft.nbt.NumericTag
|
||||||
import net.minecraft.nbt.StringTag
|
import net.minecraft.nbt.StringTag
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
@ -18,7 +20,9 @@ import net.minecraft.world.entity.boss.wither.WitherBoss
|
|||||||
import net.minecraft.world.entity.monster.Phantom
|
import net.minecraft.world.entity.monster.Phantom
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraft.world.item.ProjectileWeaponItem
|
import net.minecraft.world.item.ProjectileWeaponItem
|
||||||
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
||||||
import net.minecraft.world.level.Level
|
import net.minecraft.world.level.Level
|
||||||
@ -58,11 +62,15 @@ import ru.dbotthepony.mc.otm.core.collect.nonEmpty
|
|||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.minus
|
import ru.dbotthepony.mc.otm.core.math.minus
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
||||||
|
import ru.dbotthepony.mc.otm.core.nbt.getStringList
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
import ru.dbotthepony.mc.otm.core.util.IntValueCodec
|
import ru.dbotthepony.mc.otm.core.util.IntValueCodec
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.ItemStackValueCodec
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.ItemValueCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.Savetables
|
import ru.dbotthepony.mc.otm.core.util.Savetables
|
||||||
import ru.dbotthepony.mc.otm.core.util.UUIDValueCodec
|
import ru.dbotthepony.mc.otm.core.util.UUIDValueCodec
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.VarIntValueCodec
|
||||||
import ru.dbotthepony.mc.otm.menu.ExoPackInventoryMenu
|
import ru.dbotthepony.mc.otm.menu.ExoPackInventoryMenu
|
||||||
import ru.dbotthepony.mc.otm.network.*
|
import ru.dbotthepony.mc.otm.network.*
|
||||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||||
@ -108,6 +116,19 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
val level: Level get() = capability.ply.level
|
val level: Level get() = capability.ply.level
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event is fired on main event bus when [Inventory.add] was called and entire [ItemStack] can not be stored
|
||||||
|
* (both in [Inventory] and [MatteryPlayerCapability] exopack due to inventory filters or no free space).
|
||||||
|
*/
|
||||||
|
data class ItemStackLeftoverEvent(val stack: ItemStack, val capability: MatteryPlayerCapability) : Event() {
|
||||||
|
override fun isCancelable() = false
|
||||||
|
override fun hasResult() = false
|
||||||
|
override fun setResult(value: Result) {}
|
||||||
|
|
||||||
|
val player get() = capability.ply
|
||||||
|
val level: Level get() = capability.ply.level
|
||||||
|
}
|
||||||
|
|
||||||
private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) {
|
private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) {
|
||||||
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
|
||||||
super.setChanged(slot, new, old)
|
super.setChanged(slot, new, old)
|
||||||
@ -181,6 +202,16 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}, backingMap = this.exoPackSlotModifierMap)
|
}, backingMap = this.exoPackSlotModifierMap)
|
||||||
|
|
||||||
|
val regularSlotFilters = immutableList(Inventory.INVENTORY_SIZE) {
|
||||||
|
synchronizer.Field(null, ItemValueCodec.nullable)
|
||||||
|
}
|
||||||
|
|
||||||
|
val exoPackSlotFilters by synchronizer.Map(
|
||||||
|
keyCodec = VarIntValueCodec,
|
||||||
|
valueCodec = ItemValueCodec,
|
||||||
|
backingMap = Int2ObjectOpenHashMap()
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current slot count of Exopack
|
* Current slot count of Exopack
|
||||||
*
|
*
|
||||||
@ -291,15 +322,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
private var wasInLiquid = false
|
private var wasInLiquid = false
|
||||||
private var lastDimension = ResourceLocation("overworld")
|
private var lastDimension = ResourceLocation("overworld")
|
||||||
|
|
||||||
init {
|
|
||||||
savetables.int(::ticksIExist)
|
|
||||||
savetables.int(::iteration)
|
|
||||||
savetables.bool(::shouldSendIteration)
|
|
||||||
savetables.bool(::wasInLiquid)
|
|
||||||
savetables.vector(::lastOutsideLiquid)
|
|
||||||
savetables.location(::lastDimension)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whenever player should become an Android once transformation conditions are met (e.g. player dies or sleeps in bed)
|
* Whenever player should become an Android once transformation conditions are met (e.g. player dies or sleeps in bed)
|
||||||
*/
|
*/
|
||||||
@ -324,6 +346,26 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
*/
|
*/
|
||||||
val androidEnergy = AndroidPowerSource(ply, synchronizer, AndroidConfig.ANDROID_MAX_ENERGY, AndroidConfig.ANDROID_MAX_ENERGY)
|
val androidEnergy = AndroidPowerSource(ply, synchronizer, AndroidConfig.ANDROID_MAX_ENERGY, AndroidConfig.ANDROID_MAX_ENERGY)
|
||||||
|
|
||||||
|
init {
|
||||||
|
savetables.int(::ticksIExist)
|
||||||
|
savetables.int(::iteration)
|
||||||
|
|
||||||
|
savetables.bool(::shouldSendIteration)
|
||||||
|
savetables.bool(::wasInLiquid)
|
||||||
|
savetables.bool(::isAndroid)
|
||||||
|
savetables.bool(::willBecomeAndroid)
|
||||||
|
savetables.bool(::hasExoPack, "hasExoSuit")
|
||||||
|
savetables.bool(::displayExoPack, "displayExoSuit")
|
||||||
|
savetables.bool(::isExoPackCraftingUpgraded, "isExoSuitCraftingUpgraded")
|
||||||
|
|
||||||
|
savetables.vector(::lastOutsideLiquid)
|
||||||
|
savetables.location(::lastDimension)
|
||||||
|
|
||||||
|
savetables.stateful(::exoPackSlotModifier, "exoSuitSlotCountModifiers")
|
||||||
|
savetables.stateful(::exoPackContainer, "exoSuitContainer")
|
||||||
|
savetables.stateful(::androidEnergy)
|
||||||
|
}
|
||||||
|
|
||||||
fun invalidateNetworkState() {
|
fun invalidateNetworkState() {
|
||||||
synchronizer.invalidate()
|
synchronizer.invalidate()
|
||||||
publicSynchronizer.invalidate()
|
publicSynchronizer.invalidate()
|
||||||
@ -641,36 +683,36 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// exosuit
|
tag["features"] = ListTag().also {
|
||||||
tag["hasExoSuit"] = hasExoPack
|
|
||||||
tag["displayExoSuit"] = displayExoPack
|
|
||||||
tag["exoSuitContainer"] = exoPackContainer.serializeNBT()
|
|
||||||
tag["isExoSuitCraftingUpgraded"] = isExoPackCraftingUpgraded
|
|
||||||
tag["exoSuitSlotCountModifiers"] = exoPackSlotModifier.serializeNBT()
|
|
||||||
|
|
||||||
// android
|
|
||||||
tag["androidEnergy"] = androidEnergy.serializeNBT()
|
|
||||||
|
|
||||||
tag["isAndroid"] = isAndroid
|
|
||||||
tag["willBecomeAndroid"] = willBecomeAndroid
|
|
||||||
|
|
||||||
val featureList = ListTag()
|
|
||||||
val researchList = ListTag()
|
|
||||||
|
|
||||||
for (feature in featureMap.values) {
|
for (feature in featureMap.values) {
|
||||||
featureList.add(feature.serializeNBT().also {
|
it.add(feature.serializeNBT().also {
|
||||||
it["id"] = feature.type.registryName!!.toString()
|
it["id"] = feature.type.registryName!!.toString()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag["research"] = ListTag().also {
|
||||||
for ((type, instance) in research) {
|
for ((type, instance) in research) {
|
||||||
researchList.add(instance.serializeNBT().also {
|
it.add(instance.serializeNBT().also {
|
||||||
it["id"] = type.id.toString()
|
it["id"] = type.id.toString()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tag["features"] = featureList
|
tag["exoPackSlotFilters"] = ListTag().also {
|
||||||
tag["research"] = researchList
|
for ((slot, filter) in exoPackSlotFilters) {
|
||||||
|
it.add(CompoundTag().also {
|
||||||
|
it["slot"] = slot
|
||||||
|
it["filter"] = filter.registryName!!.toString()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag["regularSlotFilters"] = ListTag().also {
|
||||||
|
for (filter in regularSlotFilters) {
|
||||||
|
it.add(StringTag.valueOf(filter.value?.registryName?.toString() ?: ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
@ -678,6 +720,29 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
override fun deserializeNBT(tag: CompoundTag) {
|
override fun deserializeNBT(tag: CompoundTag) {
|
||||||
savetables.deserializeNBT(tag)
|
savetables.deserializeNBT(tag)
|
||||||
|
|
||||||
|
for (filter in regularSlotFilters) {
|
||||||
|
filter.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
exoPackSlotFilters.clear()
|
||||||
|
|
||||||
|
for (elem in tag.getCompoundList("exoPackSlotFilters")) {
|
||||||
|
val slot = (elem["slot"] as? NumericTag)?.asInt ?: continue
|
||||||
|
val filter = (elem["filter"] as? StringTag)?.asString ?: continue
|
||||||
|
|
||||||
|
if (slot >= 0) {
|
||||||
|
exoPackSlotFilters[slot] = ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(filter) ?: continue) ?: Items.AIR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val regularSlotFilters = tag.getStringList("regularSlotFilters")
|
||||||
|
|
||||||
|
for (i in 0 until regularSlotFilters.size.coerceAtMost(this.regularSlotFilters.size)) {
|
||||||
|
val path = regularSlotFilters[i].asString
|
||||||
|
if (path == "") continue
|
||||||
|
this.regularSlotFilters[i].value = ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(path) ?: continue) ?: Items.AIR
|
||||||
|
}
|
||||||
|
|
||||||
// iterations
|
// iterations
|
||||||
deathLog.clear()
|
deathLog.clear()
|
||||||
|
|
||||||
@ -689,20 +754,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// exosuit
|
|
||||||
hasExoPack = tag.getBoolean("hasExoSuit")
|
|
||||||
displayExoPack = tag.getBoolean("displayExoSuit")
|
|
||||||
tag.map("exoSuitSlotCountModifiers", exoPackSlotModifier::deserializeNBT)
|
|
||||||
|
|
||||||
exoPackContainer.deserializeNBT(tag["exoSuitContainer"])
|
|
||||||
isExoPackCraftingUpgraded = tag.getBoolean("isExoSuitCraftingUpgraded")
|
|
||||||
|
|
||||||
// android
|
|
||||||
isAndroid = tag.getBoolean("isAndroid")
|
|
||||||
willBecomeAndroid = tag.getBoolean("willBecomeAndroid")
|
|
||||||
|
|
||||||
tag.map("androidEnergy", androidEnergy::deserializeNBT)
|
|
||||||
|
|
||||||
featureMap.clear()
|
featureMap.clear()
|
||||||
research.clear()
|
research.clear()
|
||||||
|
|
||||||
@ -977,8 +1028,141 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
} else LazyOptional.empty()
|
} else LazyOptional.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This re-implement [Inventory.add] logic (original method is redirected to this)
|
||||||
|
*/
|
||||||
|
fun inventoryAddImpl(stack: ItemStack): Boolean {
|
||||||
|
val items = ply.inventory.items
|
||||||
|
val exoPackContainer = exoPackContainer
|
||||||
|
|
||||||
|
if (!stack.isStackable) {
|
||||||
|
for (i in items.indices) {
|
||||||
|
if (items[i].isEmpty && (regularSlotFilters[i].value === null || regularSlotFilters[i].value === stack.item)) {
|
||||||
|
items[i] = stack.copy()
|
||||||
|
items[i].popTime = 5
|
||||||
|
stack.count = 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0 until exoPackContainer.containerSize) {
|
||||||
|
if (exoPackContainer[i].isEmpty && (exoPackSlotFilters[i] === null || exoPackSlotFilters[i] === stack.item)) {
|
||||||
|
exoPackContainer[i] = stack.copy()
|
||||||
|
exoPackContainer[i].popTime = 5
|
||||||
|
stack.count = 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MinecraftForge.EVENT_BUS.post(ItemStackLeftoverEvent(stack, this))
|
||||||
|
|
||||||
|
if (ply.abilities.instabuild) {
|
||||||
|
stack.count = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return !stack.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
// двигаем в существующие слоты
|
||||||
|
items[ply.inventory.selected].also { stackStacks(it, stack) }
|
||||||
|
if (stack.isEmpty) return true
|
||||||
|
ply.inventory.offhand[0].also { stackStacks(it, stack) }
|
||||||
|
if (stack.isEmpty) return true
|
||||||
|
|
||||||
|
for (i in items.indices) {
|
||||||
|
if (stackStacks(items[i], stack) && stack.isEmpty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0 until exoPackContainer.containerSize) {
|
||||||
|
if (stackStacks(exoPackContainer[i], stack)) {
|
||||||
|
exoPackContainer.setChanged(i)
|
||||||
|
|
||||||
|
if (stack.isEmpty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// двигаем в пустые слоты
|
||||||
|
|
||||||
|
// двигаем в отфильтрованные слоты
|
||||||
|
for (i in items.indices) {
|
||||||
|
if (items[i].isEmpty && regularSlotFilters[i].value === stack.item) {
|
||||||
|
items[i] = stack.split(stack.count.coerceAtMost(stack.maxStackSize))
|
||||||
|
items[i].popTime = 5
|
||||||
|
|
||||||
|
if (stack.isEmpty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0 until exoPackContainer.containerSize) {
|
||||||
|
if (exoPackContainer[i].isEmpty && exoPackSlotFilters[i] === stack.item) {
|
||||||
|
exoPackContainer[i] = stack.split(stack.count.coerceAtMost(stack.maxStackSize))
|
||||||
|
exoPackContainer[i].popTime = 5
|
||||||
|
|
||||||
|
if (stack.isEmpty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// двигаем в обычные слоты
|
||||||
|
for (i in items.indices) {
|
||||||
|
if (items[i].isEmpty && regularSlotFilters[i].value === null) {
|
||||||
|
items[i] = stack.split(stack.count.coerceAtMost(stack.maxStackSize))
|
||||||
|
items[i].popTime = 5
|
||||||
|
|
||||||
|
if (stack.isEmpty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in 0 until exoPackContainer.containerSize) {
|
||||||
|
if (exoPackContainer[i].isEmpty && exoPackSlotFilters[i] === null) {
|
||||||
|
exoPackContainer[i] = stack.split(stack.count.coerceAtMost(stack.maxStackSize))
|
||||||
|
exoPackContainer[i].popTime = 5
|
||||||
|
|
||||||
|
if (stack.isEmpty) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MinecraftForge.EVENT_BUS.post(ItemStackLeftoverEvent(stack, this))
|
||||||
|
|
||||||
|
if (ply.abilities.instabuild) {
|
||||||
|
stack.count = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return !stack.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
companion object {
|
companion object {
|
||||||
|
private fun stackStacks(it: ItemStack, stack: ItemStack): Boolean {
|
||||||
|
if (
|
||||||
|
!it.isEmpty &&
|
||||||
|
it.maxStackSize > it.count &&
|
||||||
|
it.isStackable &&
|
||||||
|
ItemStack.isSameItemSameTags(it, stack)
|
||||||
|
) {
|
||||||
|
val new = (it.count + stack.count).coerceAtMost(it.maxStackSize)
|
||||||
|
val diff = new - it.count
|
||||||
|
it.count = new
|
||||||
|
stack.count -= diff
|
||||||
|
it.popTime = 5
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
WitherBoss.TARGETING_CONDITIONS.selector(WitherBoss.TARGETING_CONDITIONS.selector!!.and { it.matteryPlayer?.isAndroid != true })
|
WitherBoss.TARGETING_CONDITIONS.selector(WitherBoss.TARGETING_CONDITIONS.selector!!.and { it.matteryPlayer?.isAndroid != true })
|
||||||
WitherBoss.LIVING_ENTITY_SELECTOR = WitherBoss.LIVING_ENTITY_SELECTOR.and { it.matteryPlayer?.isAndroid != true }
|
WitherBoss.LIVING_ENTITY_SELECTOR = WitherBoss.LIVING_ENTITY_SELECTOR.and { it.matteryPlayer?.isAndroid != true }
|
||||||
|
@ -23,7 +23,7 @@ class AndroidPowerSource(
|
|||||||
synchronizer: FieldSynchronizer,
|
synchronizer: FieldSynchronizer,
|
||||||
initialCharge: Decimal,
|
initialCharge: Decimal,
|
||||||
maxCharge: Decimal
|
maxCharge: Decimal
|
||||||
) : IMatteryEnergyStorage, INBTSerializable<CompoundTag> {
|
) : IMatteryEnergyStorage, INBTSerializable<CompoundTag?> {
|
||||||
override val energyFlow: FlowDirection
|
override val energyFlow: FlowDirection
|
||||||
get() = FlowDirection.INPUT
|
get() = FlowDirection.INPUT
|
||||||
|
|
||||||
@ -46,7 +46,8 @@ class AndroidPowerSource(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserializeNBT(tag: CompoundTag) {
|
override fun deserializeNBT(tag: CompoundTag?) {
|
||||||
|
tag ?: return
|
||||||
battery = tag.getDecimal("battery")
|
battery = tag.getDecimal("battery")
|
||||||
maxBattery = tag.getDecimal("maxBattery")
|
maxBattery = tag.getDecimal("maxBattery")
|
||||||
item = tag.getItemStack("item")
|
item = tag.getItemStack("item")
|
||||||
|
@ -10,8 +10,8 @@ import ru.dbotthepony.mc.otm.client.render.sprite
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.*
|
import ru.dbotthepony.mc.otm.client.screen.panels.*
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeRectangleButtonPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.FilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.BackgroundPanel
|
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel
|
||||||
import ru.dbotthepony.mc.otm.client.setMousePos
|
import ru.dbotthepony.mc.otm.client.setMousePos
|
||||||
import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory
|
import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory
|
||||||
@ -48,10 +48,10 @@ class ExoPackInventoryScreen(menu: ExoPackInventoryMenu) : MatteryScreen<ExoPack
|
|||||||
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
||||||
val frame = FramePanel(this, width = 200f, height = FRAME_BASE_HEIGHT + inventoryRows * AbstractSlotPanel.SIZE, title = this.title)
|
val frame = FramePanel(this, width = 200f, height = FRAME_BASE_HEIGHT + inventoryRows * AbstractSlotPanel.SIZE, title = this.title)
|
||||||
|
|
||||||
val toolbeltLine = EditablePanel(this, frame, height = 18f)
|
val hotbarStrip = EditablePanel(this, frame, height = 18f)
|
||||||
toolbeltLine.dock = Dock.BOTTOM
|
hotbarStrip.dock = Dock.BOTTOM
|
||||||
|
|
||||||
toolbeltLine.setDockMargin(top = 3f)
|
hotbarStrip.setDockMargin(top = 3f)
|
||||||
|
|
||||||
scrollPanel = DiscreteScrollBarPanel(this, null, maxScroll = { integerDivisionDown(menu.playerCombinedInventorySlots.size, 9) },
|
scrollPanel = DiscreteScrollBarPanel(this, null, maxScroll = { integerDivisionDown(menu.playerCombinedInventorySlots.size, 9) },
|
||||||
scrollCallback = {
|
scrollCallback = {
|
||||||
@ -83,11 +83,12 @@ class ExoPackInventoryScreen(menu: ExoPackInventoryMenu) : MatteryScreen<ExoPack
|
|||||||
mainInventoryLine.dock = Dock.BOTTOM
|
mainInventoryLine.dock = Dock.BOTTOM
|
||||||
|
|
||||||
for (slot in menu.playerHotbarSlots) {
|
for (slot in menu.playerHotbarSlots) {
|
||||||
val panel = SlotPanel(this, toolbeltLine, slot)
|
FilteredSlotPanel.of(this, hotbarStrip, slot, filter = slot.filter!!).also {
|
||||||
panel.dock = Dock.LEFT
|
it.dock = Dock.LEFT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val offhand = SlotPanel(this, toolbeltLine, menu.offhandSlot)
|
val offhand = SlotPanel(this, hotbarStrip, menu.offhandSlot)
|
||||||
offhand.dock = Dock.RIGHT
|
offhand.dock = Dock.RIGHT
|
||||||
|
|
||||||
for (i in scrollPanel.scroll until scrollPanel.scroll + inventoryRows) {
|
for (i in scrollPanel.scroll until scrollPanel.scroll + inventoryRows) {
|
||||||
|
@ -11,25 +11,31 @@ import net.minecraft.client.renderer.entity.ItemRenderer
|
|||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.inventory.Slot
|
import net.minecraft.world.inventory.Slot
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraftforge.client.event.ContainerScreenEvent.Render.Background
|
import net.minecraftforge.client.event.ContainerScreenEvent.Render.Background
|
||||||
import net.minecraftforge.client.event.ContainerScreenEvent.Render.Foreground
|
import net.minecraftforge.client.event.ContainerScreenEvent.Render.Foreground
|
||||||
import net.minecraftforge.common.MinecraftForge
|
import net.minecraftforge.common.MinecraftForge
|
||||||
import org.lwjgl.opengl.GL11
|
import org.lwjgl.opengl.GL11
|
||||||
import org.lwjgl.opengl.GL13
|
import org.lwjgl.opengl.GL13
|
||||||
|
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||||
import ru.dbotthepony.mc.otm.config.ClientConfig
|
import ru.dbotthepony.mc.otm.config.ClientConfig
|
||||||
import ru.dbotthepony.mc.otm.client.moveMousePosScaled
|
import ru.dbotthepony.mc.otm.client.moveMousePosScaled
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.*
|
import ru.dbotthepony.mc.otm.client.screen.panels.*
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.FilteredSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.FoldableSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.FoldableSlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.HeightControls
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.HeightControls
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.ScrollBarConstants
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.ScrollBarConstants
|
||||||
import ru.dbotthepony.mc.otm.compat.cos.CosmeticToggleButton
|
import ru.dbotthepony.mc.otm.compat.cos.CosmeticToggleButton
|
||||||
|
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||||
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
|
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.PlayerSlot
|
import ru.dbotthepony.mc.otm.menu.PlayerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
|
||||||
|
import ru.dbotthepony.mc.otm.network.SetInventoryFilterPacket
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,7 +169,9 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
hotbarStrip.dock = Dock.BOTTOM
|
hotbarStrip.dock = Dock.BOTTOM
|
||||||
|
|
||||||
for (slot in menu.playerHotbarSlots) {
|
for (slot in menu.playerHotbarSlots) {
|
||||||
SlotPanel(this, hotbarStrip, slot).also { it.dock = Dock.LEFT }
|
FilteredSlotPanel.of(this, hotbarStrip, slot, filter = slot.filter!!).also {
|
||||||
|
it.dock = Dock.LEFT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val canvas = EditablePanel(this, inventoryFrame)
|
val canvas = EditablePanel(this, inventoryFrame)
|
||||||
@ -211,7 +219,9 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
hotbarStrip.dock = Dock.BOTTOM
|
hotbarStrip.dock = Dock.BOTTOM
|
||||||
|
|
||||||
for (slot in menu.playerHotbarSlots) {
|
for (slot in menu.playerHotbarSlots) {
|
||||||
SlotPanel(this, hotbarStrip, slot).also { it.dock = Dock.LEFT }
|
FilteredSlotPanel.of(this, hotbarStrip, slot, filter = slot.filter!!).also {
|
||||||
|
it.dock = Dock.LEFT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inventoryScrollbar.parent = slotListCanvas
|
inventoryScrollbar.parent = slotListCanvas
|
||||||
@ -250,13 +260,19 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i in 0 .. (8).coerceAtMost(menu.playerCombinedInventorySlots.size - offset - 1)) {
|
for (i in 0 .. (8).coerceAtMost(menu.playerCombinedInventorySlots.size - offset - 1)) {
|
||||||
val slot = object : SlotPanel<MatteryScreen<*>, Slot>(this@MatteryScreen, canvas, menu.playerCombinedInventorySlots[offset + i]) {
|
val slot = menu.playerCombinedInventorySlots[offset + i]
|
||||||
|
|
||||||
|
object : FilteredSlotPanel<MatteryScreen<*>, Slot>(this@MatteryScreen, canvas, slot) {
|
||||||
|
init {
|
||||||
|
dock = Dock.LEFT
|
||||||
|
}
|
||||||
|
|
||||||
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
|
override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
slot.dock = Dock.LEFT
|
override var slotFilter: Item? by slot.filter!!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return@Int2ObjectFunction canvas
|
return@Int2ObjectFunction canvas
|
||||||
|
@ -59,7 +59,7 @@ abstract class AbstractSlotPanel<out S : MatteryScreen<*>> @JvmOverloads constru
|
|||||||
|
|
||||||
if (!itemstack.isEmpty) {
|
if (!itemstack.isEmpty) {
|
||||||
// val font = RenderProperties.get(itemstack).getFont(itemstack)
|
// val font = RenderProperties.get(itemstack).getFont(itemstack)
|
||||||
val font = (itemstack.item.renderPropertiesInternal as? IClientItemExtensions)?.getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP)
|
val font = IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP)
|
||||||
|
|
||||||
// TODO: WHERE????????????
|
// TODO: WHERE????????????
|
||||||
// GuiUtils.preItemToolTip(itemstack);
|
// GuiUtils.preItemToolTip(itemstack);
|
||||||
@ -84,5 +84,6 @@ abstract class AbstractSlotPanel<out S : MatteryScreen<*>> @JvmOverloads constru
|
|||||||
val SLOT_HIGHLIGHT_DRAG = RGBAColor(200, 200, 200, 150)
|
val SLOT_HIGHLIGHT_DRAG = RGBAColor(200, 200, 200, 150)
|
||||||
const val SIZE = 18f
|
const val SIZE = 18f
|
||||||
val SLOT_BACKGROUND = WidgetLocation.MISC.sprite(0f, 0f, SIZE, SIZE)
|
val SLOT_BACKGROUND = WidgetLocation.MISC.sprite(0f, 0f, SIZE, SIZE)
|
||||||
|
val FILTERED_SLOT_BACKGROUND = WidgetLocation.MISC.sprite(46f, 0f, SIZE, SIZE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,113 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.client.screen.panels.slot
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack
|
||||||
|
import net.minecraft.world.inventory.Slot
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import net.minecraftforge.client.extensions.common.IClientItemExtensions
|
||||||
|
import ru.dbotthepony.mc.otm.client.isCtrlDown
|
||||||
|
import ru.dbotthepony.mc.otm.client.minecraft
|
||||||
|
import ru.dbotthepony.mc.otm.client.playGuiClickSound
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.MatterySprite
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.drawColor
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.drawRect
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||||
|
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||||
|
import ru.dbotthepony.mc.otm.core.math.RGBAColor
|
||||||
|
|
||||||
|
abstract class FilteredSlotPanel<out S : MatteryScreen<*>, out T : Slot>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
slot: T,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = SIZE,
|
||||||
|
height: Float = SIZE,
|
||||||
|
noItemIcon: MatterySprite? = null
|
||||||
|
) : SlotPanel<S, T>(screen, parent, slot, x, y, width, height, noItemIcon) {
|
||||||
|
abstract var slotFilter: Item?
|
||||||
|
|
||||||
|
override fun renderSlotBackground(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
super.renderSlotBackground(stack, mouseX, mouseY, partialTick)
|
||||||
|
|
||||||
|
if (slotFilter != null) {
|
||||||
|
if (slotFilter !== Items.AIR) {
|
||||||
|
val itemStack = ItemStack(slotFilter!!, 1)
|
||||||
|
|
||||||
|
screen.renderItemStack(absoluteX, absoluteY, itemStack, null)
|
||||||
|
clearDepth(stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
drawColor = SLOT_FILTER_COLOR
|
||||||
|
drawRect(stack, 0f, 0f, width, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
|
||||||
|
if (isHovered && slotFilter != null && slotFilter !== Items.AIR && itemStack.isEmpty) {
|
||||||
|
val itemstack = ItemStack(slotFilter!!, 1)
|
||||||
|
|
||||||
|
screen.renderComponentTooltip(
|
||||||
|
stack,
|
||||||
|
getItemStackTooltip(itemstack),
|
||||||
|
mouseX.toInt(),
|
||||||
|
mouseY.toInt(),
|
||||||
|
IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP) ?: screen.font,
|
||||||
|
itemstack
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.innerRenderTooltips(stack, mouseX, mouseY, partialTick)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isCtrlDown) {
|
||||||
|
if (slotFilter === null) {
|
||||||
|
if (screen.menu.carried.isEmpty) {
|
||||||
|
slotFilter = slot.item.item
|
||||||
|
} else {
|
||||||
|
slotFilter = screen.menu.carried.item
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
slotFilter = null
|
||||||
|
}
|
||||||
|
|
||||||
|
playGuiClickSound()
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return super.mouseClickedInner(x, y, button)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isCtrlDown) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseReleasedInner(x, y, button)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val SLOT_FILTER_COLOR = RGBAColor(85, 113, 216, 150)
|
||||||
|
|
||||||
|
fun <S : MatteryScreen<*>, T : Slot> of(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
slot: T,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
width: Float = SIZE,
|
||||||
|
height: Float = SIZE,
|
||||||
|
noItemIcon: MatterySprite? = null,
|
||||||
|
filter: GetterSetter<Item?>
|
||||||
|
): FilteredSlotPanel<S, T> {
|
||||||
|
return object : FilteredSlotPanel<S, T>(screen, parent, slot, x, y, width, height, noItemIcon) {
|
||||||
|
override var slotFilter: Item? by filter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ import com.google.gson.JsonObject
|
|||||||
import com.google.gson.JsonPrimitive
|
import com.google.gson.JsonPrimitive
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.nbt.NbtAccounter
|
||||||
import net.minecraft.network.FriendlyByteBuf
|
import net.minecraft.network.FriendlyByteBuf
|
||||||
import net.minecraft.network.chat.ComponentContents
|
import net.minecraft.network.chat.ComponentContents
|
||||||
import net.minecraft.network.chat.contents.TranslatableContents
|
import net.minecraft.network.chat.contents.TranslatableContents
|
||||||
@ -18,6 +19,7 @@ import net.minecraft.resources.ResourceLocation
|
|||||||
import net.minecraft.world.entity.Entity
|
import net.minecraft.world.entity.Entity
|
||||||
import net.minecraft.world.item.Item
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraft.world.item.crafting.Ingredient
|
import net.minecraft.world.item.crafting.Ingredient
|
||||||
import net.minecraft.world.level.BlockGetter
|
import net.minecraft.world.level.BlockGetter
|
||||||
import net.minecraft.world.level.block.state.BlockState
|
import net.minecraft.world.level.block.state.BlockState
|
||||||
@ -32,7 +34,11 @@ import net.minecraftforge.registries.ForgeRegistry
|
|||||||
import net.minecraftforge.registries.IForgeRegistry
|
import net.minecraftforge.registries.IForgeRegistry
|
||||||
import ru.dbotthepony.mc.otm.core.math.Vector
|
import ru.dbotthepony.mc.otm.core.math.Vector
|
||||||
import ru.dbotthepony.mc.otm.core.util.readInt
|
import ru.dbotthepony.mc.otm.core.util.readInt
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.readVarIntLE
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.writeInt
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.writeVarIntLE
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.io.OutputStream
|
||||||
import java.lang.ref.Reference
|
import java.lang.ref.Reference
|
||||||
import java.math.BigInteger
|
import java.math.BigInteger
|
||||||
import java.util.Arrays
|
import java.util.Arrays
|
||||||
@ -167,12 +173,16 @@ fun FriendlyByteBuf.writeItemType(value: Item) {
|
|||||||
writeInt(ForgeRegistries.ITEMS.getID(value))
|
writeInt(ForgeRegistries.ITEMS.getID(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FriendlyByteBuf.readItemType(): Item? {
|
fun OutputStream.writeItemType(value: Item) {
|
||||||
return ForgeRegistries.ITEMS.getValue(readInt())
|
writeVarIntLE(ForgeRegistries.ITEMS.getID(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun InputStream.readItemType(): Item? {
|
fun FriendlyByteBuf.readItemType(): Item {
|
||||||
return ForgeRegistries.ITEMS.getValue(readInt())
|
return ForgeRegistries.ITEMS.getValue(readInt()) ?: Items.AIR
|
||||||
|
}
|
||||||
|
|
||||||
|
fun InputStream.readItemType(sizeLimit: NbtAccounter? = null): Item {
|
||||||
|
return ForgeRegistries.ITEMS.getValue(readVarIntLE(sizeLimit)) ?: Items.AIR
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun <T : Comparable<T>> StateHolder<*, *>.get(property: Property<T>): T {
|
operator fun <T : Comparable<T>> StateHolder<*, *>.get(property: Property<T>): T {
|
||||||
|
@ -10,6 +10,8 @@ import net.minecraft.world.item.ItemStack
|
|||||||
import ru.dbotthepony.mc.otm.core.immutableMap
|
import ru.dbotthepony.mc.otm.core.immutableMap
|
||||||
import ru.dbotthepony.mc.otm.core.math.readDecimal
|
import ru.dbotthepony.mc.otm.core.math.readDecimal
|
||||||
import ru.dbotthepony.mc.otm.core.math.writeDecimal
|
import ru.dbotthepony.mc.otm.core.math.writeDecimal
|
||||||
|
import ru.dbotthepony.mc.otm.core.readItemType
|
||||||
|
import ru.dbotthepony.mc.otm.core.writeItemType
|
||||||
import java.io.DataInput
|
import java.io.DataInput
|
||||||
import java.io.DataInputStream
|
import java.io.DataInputStream
|
||||||
import java.io.DataOutput
|
import java.io.DataOutput
|
||||||
@ -60,6 +62,30 @@ class StreamCodec<V>(
|
|||||||
comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
|
comparator: ((a: V, b: V) -> Boolean) = { a, b -> a == b }
|
||||||
) : this({ stream, sizeLimit -> sizeLimit.accountBytes(payloadSize); reader.invoke(stream) }, writer, copier, comparator)
|
) : this({ stream, sizeLimit -> sizeLimit.accountBytes(payloadSize); reader.invoke(stream) }, writer, copier, comparator)
|
||||||
|
|
||||||
|
val nullable = object : IStreamCodec<V?> {
|
||||||
|
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V? {
|
||||||
|
sizeLimit.accountBytes(1L)
|
||||||
|
return if (stream.read() == 0) null else reader.invoke(stream, sizeLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(stream: DataOutputStream, value: V?) {
|
||||||
|
if (value === null) stream.write(0) else {
|
||||||
|
stream.write(1)
|
||||||
|
writer.invoke(stream, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copy(value: V?): V? {
|
||||||
|
return if (value === null) null else copier.invoke(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun compare(a: V?, b: V?): Boolean {
|
||||||
|
if (a === null && b === null) return true
|
||||||
|
if (a === null || b === null) return false
|
||||||
|
return comparator.invoke(a, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V {
|
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): V {
|
||||||
return reader.invoke(stream, sizeLimit)
|
return reader.invoke(stream, sizeLimit)
|
||||||
}
|
}
|
||||||
@ -86,6 +112,7 @@ val LongValueCodec = StreamCodec(DataInputStream::readLong, 8L, DataOutputStream
|
|||||||
val FloatValueCodec = StreamCodec(DataInputStream::readFloat, 4L, DataOutputStream::writeFloat)
|
val FloatValueCodec = StreamCodec(DataInputStream::readFloat, 4L, DataOutputStream::writeFloat)
|
||||||
val DoubleValueCodec = StreamCodec(DataInputStream::readDouble, 8L, DataOutputStream::writeDouble)
|
val DoubleValueCodec = StreamCodec(DataInputStream::readDouble, 8L, DataOutputStream::writeDouble)
|
||||||
val ItemStackValueCodec = StreamCodec(DataInputStream::readItem, DataOutputStream::writeItem, ItemStack::copy) { a, b -> a.equals(b, true) }
|
val ItemStackValueCodec = StreamCodec(DataInputStream::readItem, DataOutputStream::writeItem, ItemStack::copy) { a, b -> a.equals(b, true) }
|
||||||
|
val ItemValueCodec = StreamCodec(DataInputStream::readItemType, DataOutputStream::writeItemType)
|
||||||
val DecimalValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)
|
val DecimalValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)
|
||||||
val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
|
val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
|
||||||
val UUIDValueCodec = StreamCodec({ s, a -> a.accountBytes(8L); UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
|
val UUIDValueCodec = StreamCodec({ s, a -> a.accountBytes(8L); UUID(s.readLong(), s.readLong()) }, { s, v -> s.writeLong(v.mostSignificantBits); s.writeLong(v.leastSignificantBits) })
|
||||||
@ -331,7 +358,7 @@ fun OutputStream.writeBinaryString(input: String) {
|
|||||||
private data class IndexedStreamCodec<T>(
|
private data class IndexedStreamCodec<T>(
|
||||||
val condition: Predicate<Any?>,
|
val condition: Predicate<Any?>,
|
||||||
val id: Int,
|
val id: Int,
|
||||||
val codec: StreamCodec<T>
|
val codec: IStreamCodec<T>
|
||||||
) {
|
) {
|
||||||
fun read(stream: DataInputStream, sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): T {
|
fun read(stream: DataInputStream, sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256 KiB */)): T {
|
||||||
return codec.read(stream, sizeLimit)
|
return codec.read(stream, sizeLimit)
|
||||||
|
@ -14,6 +14,7 @@ import net.minecraft.world.Container
|
|||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.inventory.*
|
import net.minecraft.world.inventory.*
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasBindingCurse
|
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasBindingCurse
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity
|
import net.minecraft.world.level.block.entity.BlockEntity
|
||||||
@ -26,6 +27,7 @@ import ru.dbotthepony.mc.otm.compat.curios.curiosSlots
|
|||||||
import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot
|
import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot
|
||||||
import ru.dbotthepony.mc.otm.container.ItemFilter
|
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||||
import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot
|
import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot
|
||||||
|
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||||
import ru.dbotthepony.mc.otm.core.util.BigDecimalValueCodec
|
import ru.dbotthepony.mc.otm.core.util.BigDecimalValueCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.BinaryStringCodec
|
import ru.dbotthepony.mc.otm.core.util.BinaryStringCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec
|
import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec
|
||||||
@ -35,8 +37,10 @@ import ru.dbotthepony.mc.otm.core.util.VarIntValueCodec
|
|||||||
import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget
|
import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget
|
||||||
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
|
||||||
import ru.dbotthepony.mc.otm.network.MatteryPacket
|
import ru.dbotthepony.mc.otm.network.MatteryPacket
|
||||||
|
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
|
||||||
import ru.dbotthepony.mc.otm.network.MenuFieldPacket
|
import ru.dbotthepony.mc.otm.network.MenuFieldPacket
|
||||||
import ru.dbotthepony.mc.otm.network.MenuNetworkChannel
|
import ru.dbotthepony.mc.otm.network.MenuNetworkChannel
|
||||||
|
import ru.dbotthepony.mc.otm.network.SetInventoryFilterPacket
|
||||||
import ru.dbotthepony.mc.otm.network.enqueueWork
|
import ru.dbotthepony.mc.otm.network.enqueueWork
|
||||||
import ru.dbotthepony.mc.otm.network.packetHandled
|
import ru.dbotthepony.mc.otm.network.packetHandled
|
||||||
import ru.dbotthepony.mc.otm.network.sender
|
import ru.dbotthepony.mc.otm.network.sender
|
||||||
@ -70,12 +74,12 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
private val _matteryWidgets = ArrayList<AbstractWidget>()
|
private val _matteryWidgets = ArrayList<AbstractWidget>()
|
||||||
val matteryWidgets: List<AbstractWidget> = Collections.unmodifiableList(_matteryWidgets)
|
val matteryWidgets: List<AbstractWidget> = Collections.unmodifiableList(_matteryWidgets)
|
||||||
|
|
||||||
private val _playerInventorySlots = ArrayList<MatterySlot>()
|
private val _playerInventorySlots = ArrayList<InventorySlot>()
|
||||||
private val _playerInventorySlots2 = ArrayList<MatterySlot>()
|
private val _playerInventorySlots2 = ArrayList<InventorySlot>()
|
||||||
private val _playerHotbarSlots = ArrayList<MatterySlot>()
|
private val _playerHotbarSlots = ArrayList<InventorySlot>()
|
||||||
private val _playerMainSlots = ArrayList<MatterySlot>()
|
private val _playerMainSlots = ArrayList<InventorySlot>()
|
||||||
private val _playerExoSuitSlots = ArrayList<MatterySlot>()
|
private val _playerExoSuitSlots = ArrayList<InventorySlot>()
|
||||||
private val _playerCombinedInventorySlots = ArrayList<MatterySlot>()
|
private val _playerCombinedInventorySlots = ArrayList<InventorySlot>()
|
||||||
|
|
||||||
private val playerInputs = ArrayList<PlayerInput<*>>()
|
private val playerInputs = ArrayList<PlayerInput<*>>()
|
||||||
|
|
||||||
@ -155,32 +159,32 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
/**
|
/**
|
||||||
* inventory + exosuit + hotbar (in this order)
|
* inventory + exosuit + hotbar (in this order)
|
||||||
*/
|
*/
|
||||||
val playerInventorySlots: List<MatterySlot> = Collections.unmodifiableList(_playerInventorySlots)
|
val playerInventorySlots: List<InventorySlot> = Collections.unmodifiableList(_playerInventorySlots)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hotbar + inventory + exosuit (in this order)
|
* hotbar + inventory + exosuit (in this order)
|
||||||
*/
|
*/
|
||||||
val playerInventorySlots2: List<MatterySlot> = Collections.unmodifiableList(_playerInventorySlots2)
|
val playerInventorySlots2: List<InventorySlot> = Collections.unmodifiableList(_playerInventorySlots2)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hotbar only
|
* hotbar only
|
||||||
*/
|
*/
|
||||||
val playerHotbarSlots: List<MatterySlot> = Collections.unmodifiableList(_playerHotbarSlots)
|
val playerHotbarSlots: List<InventorySlot> = Collections.unmodifiableList(_playerHotbarSlots)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inventory only
|
* inventory only
|
||||||
*/
|
*/
|
||||||
val playerMainSlots: List<MatterySlot> = Collections.unmodifiableList(_playerMainSlots)
|
val playerMainSlots: List<InventorySlot> = Collections.unmodifiableList(_playerMainSlots)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* exosuit only
|
* exosuit only
|
||||||
*/
|
*/
|
||||||
val playerExoSuitSlots: List<MatterySlot> = Collections.unmodifiableList(_playerExoSuitSlots)
|
val playerExoSuitSlots: List<InventorySlot> = Collections.unmodifiableList(_playerExoSuitSlots)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inventory + exosuit (in this order)
|
* inventory + exosuit (in this order)
|
||||||
*/
|
*/
|
||||||
val playerCombinedInventorySlots: List<MatterySlot> = Collections.unmodifiableList(_playerCombinedInventorySlots)
|
val playerCombinedInventorySlots: List<InventorySlot> = Collections.unmodifiableList(_playerCombinedInventorySlots)
|
||||||
|
|
||||||
var autoCreateInventoryFrame = true
|
var autoCreateInventoryFrame = true
|
||||||
private set
|
private set
|
||||||
@ -250,6 +254,32 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
|
|
||||||
return super.isSameInventory(other)
|
return super.isSameInventory(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// фильтр существует только для автоматизации
|
||||||
|
// игрок всё равно может класть предмет вручную, даже если он не соответствует фильтру
|
||||||
|
internal val filter: GetterSetter<Item?>?
|
||||||
|
|
||||||
|
init {
|
||||||
|
val mattery = ply.matteryPlayer
|
||||||
|
|
||||||
|
if (mattery != null) {
|
||||||
|
if (container === inventory && slotIndex in mattery.regularSlotFilters.indices) {
|
||||||
|
filter = GetterSetter.of(
|
||||||
|
getter = { mattery.regularSlotFilters[slotIndex].value },
|
||||||
|
setter = { MatteryPlayerNetworkChannel.sendToServer(SetInventoryFilterPacket(SetInventoryFilterPacket.Type.INVENTORY, slotIndex, it)) }
|
||||||
|
)
|
||||||
|
} else if (container === mattery.exoPackContainer) {
|
||||||
|
filter = GetterSetter.of(
|
||||||
|
getter = { mattery.exoPackSlotFilters[slotIndex] },
|
||||||
|
setter = { MatteryPlayerNetworkChannel.sendToServer(SetInventoryFilterPacket(SetInventoryFilterPacket.Type.EXOPACK, slotIndex, it)) }
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
filter = null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filter = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open inner class EquipmentSlot(container: Container, index: Int, val type: net.minecraft.world.entity.EquipmentSlot, x: Int = 0, y: Int = 0) : InventorySlot(container, index, x, y) {
|
open inner class EquipmentSlot(container: Container, index: Int, val type: net.minecraft.world.entity.EquipmentSlot, x: Int = 0, y: Int = 0) : InventorySlot(container, index, x, y) {
|
||||||
@ -458,6 +488,18 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
val copy = slot.item.copy()
|
val copy = slot.item.copy()
|
||||||
var any = false
|
var any = false
|
||||||
|
|
||||||
|
if (target.any { it.any { it is InventorySlot && it.filter != null } }) {
|
||||||
|
for (collection in target) {
|
||||||
|
if (moveItemStackTo(slot, collection, onlyFiltered = true)) {
|
||||||
|
any = true
|
||||||
|
|
||||||
|
if (!slot.hasItem()) {
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (collection in target) {
|
for (collection in target) {
|
||||||
if (moveItemStackTo(slot, collection)) {
|
if (moveItemStackTo(slot, collection)) {
|
||||||
any = true
|
any = true
|
||||||
@ -506,25 +548,12 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun moveItemStackTo(
|
|
||||||
item: ItemStack,
|
|
||||||
slots: Collection<Slot>
|
|
||||||
): Boolean {
|
|
||||||
val remainder = moveItemStackToSlots(item, slots)
|
|
||||||
|
|
||||||
if (remainder.count == item.count) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
item.count = remainder.count
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
fun moveItemStackTo(
|
fun moveItemStackTo(
|
||||||
source: Slot,
|
source: Slot,
|
||||||
slots: Collection<Slot>
|
slots: Collection<Slot>,
|
||||||
|
onlyFiltered: Boolean = false
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val remainder = moveItemStackToSlots(source.item, slots)
|
val remainder = moveItemStackToSlots(source.item, slots, onlyFiltered = onlyFiltered)
|
||||||
|
|
||||||
if (remainder.count == source.item.count) {
|
if (remainder.count == source.item.count) {
|
||||||
return false
|
return false
|
||||||
@ -540,15 +569,25 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun moveItemStackToSlots(item: ItemStack, slots: Collection<Slot>, simulate: Boolean = false): ItemStack {
|
fun moveItemStackToSlots(item: ItemStack, slots: Collection<Slot>, simulate: Boolean = false, onlyFiltered: Boolean = false): ItemStack {
|
||||||
|
if (item.isEmpty) {
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
|
||||||
val copy = item.copy()
|
val copy = item.copy()
|
||||||
|
|
||||||
// first pass - stack with existing slots
|
// first pass - stack with existing slots
|
||||||
if (copy.isStackable) {
|
if (copy.isStackable) {
|
||||||
for (slot in slots) {
|
for (slot in slots) {
|
||||||
|
if (onlyFiltered && (slot !is InventorySlot || slot.filter == null || slot.filter.get() != item.item)) {
|
||||||
|
continue
|
||||||
|
} else if (!onlyFiltered && slot is InventorySlot && slot.filter != null && slot.filter.get() != null && slot.filter.get() != item.item) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
val limit = slot.getMaxStackSize(copy)
|
val limit = slot.getMaxStackSize(copy)
|
||||||
|
|
||||||
if (limit > slot.item.count && ItemStack.isSameItemSameTags(slot.item, copy) && slot.mayPlace(item)) {
|
if (limit > slot.item.count && slot.mayPlace(item) && ItemStack.isSameItemSameTags(slot.item, copy)) {
|
||||||
val newCount = (slot.item.count + copy.count).coerceAtMost(limit)
|
val newCount = (slot.item.count + copy.count).coerceAtMost(limit)
|
||||||
val diff = newCount - slot.item.count
|
val diff = newCount - slot.item.count
|
||||||
copy.count -= diff
|
copy.count -= diff
|
||||||
@ -567,6 +606,12 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
|
|
||||||
// second pass - drop stack into first free slot
|
// second pass - drop stack into first free slot
|
||||||
for (slot in slots) {
|
for (slot in slots) {
|
||||||
|
if (onlyFiltered && (slot !is InventorySlot || slot.filter == null || slot.filter.get() != item.item)) {
|
||||||
|
continue
|
||||||
|
} else if (!onlyFiltered && slot is InventorySlot && slot.filter != null && slot.filter.get() != null && slot.filter.get() != item.item) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
val limit = slot.getMaxStackSize(copy)
|
val limit = slot.getMaxStackSize(copy)
|
||||||
|
|
||||||
if (!slot.hasItem() && slot.mayPlace(item)) {
|
if (!slot.hasItem() && slot.mayPlace(item)) {
|
||||||
@ -597,9 +642,19 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
require(finalSlot < slots.size) { "Final slot $finalSlot is bigger than total size of array of ${slots.size}" }
|
require(finalSlot < slots.size) { "Final slot $finalSlot is bigger than total size of array of ${slots.size}" }
|
||||||
|
|
||||||
val slots = ArrayList<Slot>(finalSlot - initialSlot + 1)
|
val slots = ArrayList<Slot>(finalSlot - initialSlot + 1)
|
||||||
|
var filters = false
|
||||||
|
|
||||||
for (i in (if (inverse) finalSlot downTo initialSlot else initialSlot .. finalSlot)) {
|
for (i in (if (inverse) finalSlot downTo initialSlot else initialSlot .. finalSlot)) {
|
||||||
slots.add(slots[i])
|
val slot = slots[i]
|
||||||
|
slots.add(slot)
|
||||||
|
|
||||||
|
if (slot is InventorySlot && slot.filter != null) {
|
||||||
|
filters = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filters) {
|
||||||
|
return moveItemStackToSlots(moveItemStackToSlots(item, slots, simulate, onlyFiltered = true), slots, simulate, onlyFiltered = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return moveItemStackToSlots(item, slots, simulate)
|
return moveItemStackToSlots(item, slots, simulate)
|
||||||
|
@ -6,7 +6,9 @@ import net.minecraft.network.chat.Component
|
|||||||
import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket
|
import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket
|
||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.world.entity.player.Inventory
|
import net.minecraft.world.entity.player.Inventory
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT
|
import net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT
|
||||||
import net.minecraftforge.network.NetworkDirection.PLAY_TO_SERVER
|
import net.minecraftforge.network.NetworkDirection.PLAY_TO_SERVER
|
||||||
import net.minecraftforge.network.NetworkEvent
|
import net.minecraftforge.network.NetworkEvent
|
||||||
@ -27,6 +29,8 @@ import ru.dbotthepony.mc.otm.client.render.ShockwaveRenderer
|
|||||||
import ru.dbotthepony.mc.otm.container.get
|
import ru.dbotthepony.mc.otm.container.get
|
||||||
import ru.dbotthepony.mc.otm.container.set
|
import ru.dbotthepony.mc.otm.container.set
|
||||||
import ru.dbotthepony.mc.otm.core.math.Vector
|
import ru.dbotthepony.mc.otm.core.math.Vector
|
||||||
|
import ru.dbotthepony.mc.otm.core.readItemType
|
||||||
|
import ru.dbotthepony.mc.otm.core.writeItemType
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
|
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.ExoPackInventoryMenu
|
import ru.dbotthepony.mc.otm.menu.ExoPackInventoryMenu
|
||||||
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
import ru.dbotthepony.mc.otm.registry.AndroidFeatures
|
||||||
@ -510,8 +514,56 @@ object HideExosuitPacket : MatteryPacket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SetInventoryFilterPacket(val type: Type, val slot: Int, val item: Item?) : MatteryPacket {
|
||||||
|
enum class Type {
|
||||||
|
INVENTORY,
|
||||||
|
EXOPACK
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(buff: FriendlyByteBuf) {
|
||||||
|
buff.writeEnum(type)
|
||||||
|
buff.writeVarInt(slot)
|
||||||
|
|
||||||
|
if (item == null) {
|
||||||
|
buff.writeByte(0)
|
||||||
|
} else {
|
||||||
|
buff.writeByte(1)
|
||||||
|
buff.writeItemType(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun play(context: Supplier<NetworkEvent.Context>) {
|
||||||
|
context.packetHandled = true
|
||||||
|
val player = context.sender?.matteryPlayer ?: return
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
Type.INVENTORY -> {
|
||||||
|
if (slot in 0 until player.regularSlotFilters.size) {
|
||||||
|
player.regularSlotFilters[slot].value = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type.EXOPACK -> {
|
||||||
|
if (slot in 0 until player.exoPackSlotCount) {
|
||||||
|
if (item == null) {
|
||||||
|
player.exoPackSlotFilters.remove(slot)
|
||||||
|
} else {
|
||||||
|
player.exoPackSlotFilters[slot] = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun read(buff: FriendlyByteBuf): SetInventoryFilterPacket {
|
||||||
|
return SetInventoryFilterPacket(buff.readEnum(Type::class.java), buff.readVarInt(), if (buff.readByte() > 0) buff.readItemType() else null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
|
object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
|
||||||
version = "2",
|
version = "3",
|
||||||
name = "player"
|
name = "player"
|
||||||
) {
|
) {
|
||||||
fun register() {
|
fun register() {
|
||||||
@ -543,5 +595,7 @@ object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
|
|||||||
|
|
||||||
add(DisplayExosuitPacket::class, { DisplayExosuitPacket }, PLAY_TO_SERVER)
|
add(DisplayExosuitPacket::class, { DisplayExosuitPacket }, PLAY_TO_SERVER)
|
||||||
add(HideExosuitPacket::class, { HideExosuitPacket }, PLAY_TO_SERVER)
|
add(HideExosuitPacket::class, { HideExosuitPacket }, PLAY_TO_SERVER)
|
||||||
|
|
||||||
|
add(SetInventoryFilterPacket::class, SetInventoryFilterPacket.Companion::read, PLAY_TO_SERVER)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
public-f net.minecraft.client.gui.screens.Screen f_96539_ # title
|
public-f net.minecraft.client.gui.screens.Screen f_96539_ # title
|
||||||
public net.minecraft.server.MinecraftServer f_129744_ # storageSource
|
public net.minecraft.server.MinecraftServer f_129744_ # storageSource
|
||||||
|
|
||||||
|
public net.minecraft.world.entity.player.Inventory f_150070_ # SELECTION_SIZE
|
||||||
|
|
||||||
# for accessing and setting from MatteryScreen class
|
# for accessing and setting from MatteryScreen class
|
||||||
public net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_169600_
|
public net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_169600_
|
||||||
public net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_169605_
|
public net.minecraft.client.gui.screens.inventory.AbstractContainerScreen f_169605_
|
||||||
|
@ -533,46 +533,6 @@ function injectAtTail(path, instructions) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function injectInventoryInsertHook(
|
|
||||||
instructions,
|
|
||||||
determinedOffset,
|
|
||||||
hookName,
|
|
||||||
hookDesc,
|
|
||||||
pre
|
|
||||||
) {
|
|
||||||
var last = instructions.get(determinedOffset)
|
|
||||||
|
|
||||||
// print('Patching Inventory#add at instruction ' + determinedOffset + ' to add ' + hookName + hookDesc)
|
|
||||||
|
|
||||||
// loading this (Inventory) to stack
|
|
||||||
|
|
||||||
if (pre != undefined) {
|
|
||||||
instructions.insert(last, pre)
|
|
||||||
last = pre
|
|
||||||
}
|
|
||||||
|
|
||||||
var next = new VarInsnNode(opcodesRemapped.aload, 0)
|
|
||||||
instructions.insert(last, next)
|
|
||||||
|
|
||||||
last = next
|
|
||||||
// loading itemstack to stack
|
|
||||||
next = new VarInsnNode(opcodesRemapped.aload, 2)
|
|
||||||
|
|
||||||
instructions.insert(last, next)
|
|
||||||
|
|
||||||
last = next
|
|
||||||
// dispatching hook method
|
|
||||||
next = new MethodInsnNode(
|
|
||||||
opcodesRemapped.invokestatic,
|
|
||||||
'ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability',
|
|
||||||
hookName,
|
|
||||||
hookDesc,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
|
|
||||||
instructions.insert(last, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
function patchBlendFunc(node) {
|
function patchBlendFunc(node) {
|
||||||
var last = new MethodInsnNode(
|
var last = new MethodInsnNode(
|
||||||
opcodesRemapped.invokestatic,
|
opcodesRemapped.invokestatic,
|
||||||
@ -795,128 +755,6 @@ function initializeCoreMod() {
|
|||||||
return node
|
return node
|
||||||
}),
|
}),
|
||||||
|
|
||||||
'Inventory#add patch': {
|
|
||||||
'target': {
|
|
||||||
'type': 'METHOD',
|
|
||||||
'class': 'net.minecraft.world.entity.player.Inventory',
|
|
||||||
'methodName': ASMAPI.mapMethod('m_36040_'), // add
|
|
||||||
'methodDesc': '(ILnet/minecraft/world/item/ItemStack;)Z'
|
|
||||||
},
|
|
||||||
|
|
||||||
'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
|
|
||||||
|
|
||||||
// If item returned that it is damaged:
|
|
||||||
// 10: invokevirtual #97 // Method net/minecraft/world/item/ItemStack.isDamaged:()Z
|
|
||||||
// 13: ifeq 87
|
|
||||||
// 16: iload_1
|
|
||||||
// 17: iconst_m1
|
|
||||||
// 18: if_icmpne 26
|
|
||||||
// 21: aload_0
|
|
||||||
// 22: invokevirtual #86 // Method getFreeSlot:()I
|
|
||||||
// 25: istore_1
|
|
||||||
// <-- our target
|
|
||||||
// 26: iload_1
|
|
||||||
// 27: iflt 65
|
|
||||||
// 30: aload_0
|
|
||||||
// 31: getfield #19 // Field items:Lnet/minecraft/core/NonNullList;
|
|
||||||
// 34: iload_1
|
|
||||||
// 35: aload_2
|
|
||||||
|
|
||||||
var i
|
|
||||||
|
|
||||||
// 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++) {
|
|
||||||
var determinedOffset = test([
|
|
||||||
opcodesRemapped.invokevirtual,
|
|
||||||
opcodesRemapped.invokevirtual,
|
|
||||||
opcodesRemapped.aload,
|
|
||||||
opcodesRemapped.invokevirtual,
|
|
||||||
opcodesRemapped.ifne,
|
|
||||||
opcodesRemapped.aload,
|
|
||||||
opcodesRemapped.invokevirtual,
|
|
||||||
opcodesRemapped.iload,
|
|
||||||
opcodesRemapped.if_icmplt,
|
|
||||||
], node.instructions, i)
|
|
||||||
|
|
||||||
if (determinedOffset != -1) {
|
|
||||||
injectInventoryInsertHook(node.instructions, determinedOffset,
|
|
||||||
'inventoryAddItemHook',
|
|
||||||
'(Lnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/item/ItemStack;)V')
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// patch "damaged"
|
|
||||||
for (i = 0; i < node.instructions.size(); i++) {
|
|
||||||
var determinedOffset = test([
|
|
||||||
opcodesRemapped.invokevirtual,
|
|
||||||
opcodesRemapped.ifeq,
|
|
||||||
opcodesRemapped.iload,
|
|
||||||
opcodesRemapped.iconst_m1,
|
|
||||||
opcodesRemapped.if_icmpne,
|
|
||||||
opcodesRemapped.aload,
|
|
||||||
opcodesRemapped.invokevirtual,
|
|
||||||
opcodesRemapped.istore,
|
|
||||||
], node.instructions, i)
|
|
||||||
|
|
||||||
if (determinedOffset != -1) {
|
|
||||||
injectInventoryInsertHook(node.instructions, determinedOffset,
|
|
||||||
'inventoryAddDamagedItemHook',
|
|
||||||
'(ILnet/minecraft/world/entity/player/Inventory;Lnet/minecraft/world/item/ItemStack;)V',
|
|
||||||
new VarInsnNode(opcodesRemapped.iload, node.instructions.get(determinedOffset - 1)['var']))
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
'GameRenderer#render hook': {
|
'GameRenderer#render hook': {
|
||||||
'target': {
|
'target': {
|
||||||
'type': 'METHOD',
|
'type': 'METHOD',
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
"MixinPatchProjectileFinder",
|
"MixinPatchProjectileFinder",
|
||||||
"MixinLivingEntity",
|
"MixinLivingEntity",
|
||||||
"MixinAnvilBlock",
|
"MixinAnvilBlock",
|
||||||
|
"MixinInventory",
|
||||||
"MixinAbstractHurtingProjectile"
|
"MixinAbstractHurtingProjectile"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user