Compare commits
9 Commits
95f19bc18f
...
d48dbf3ec9
Author | SHA1 | Date | |
---|---|---|---|
d48dbf3ec9 | |||
7f362a95a2 | |||
a84df28cf8 | |||
03c64425a9 | |||
d41d331e0f | |||
5b68a6c7ba | |||
d89d5b9672 | |||
ee4b12e687 | |||
9a5614de65 |
@ -987,6 +987,16 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
|
|||||||
|
|
||||||
private fun gui(provider: MatteryLanguageProvider) {
|
private fun gui(provider: MatteryLanguageProvider) {
|
||||||
with(provider.english) {
|
with(provider.english) {
|
||||||
|
gui("quickmove_from.restock", "Restock from storage")
|
||||||
|
gui("quickmove_from.restock_with_move", "Full restock from storage")
|
||||||
|
gui("quickmove_from.move", "Take all")
|
||||||
|
|
||||||
|
gui("quickmove_to.restock", "Restock to storage")
|
||||||
|
gui("quickmove_to.restock_with_move", "Full restock to storage")
|
||||||
|
gui("quickmove_to.move", "Deposit all")
|
||||||
|
|
||||||
|
gui("quickmove_hint", "Right click to show all variants")
|
||||||
|
|
||||||
gui("exopack.accept_wireless_charge", "Accept wireless charging")
|
gui("exopack.accept_wireless_charge", "Accept wireless charging")
|
||||||
gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging")
|
gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging")
|
||||||
|
|
||||||
|
@ -980,6 +980,16 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
|
|||||||
|
|
||||||
private fun gui(provider: MatteryLanguageProvider) {
|
private fun gui(provider: MatteryLanguageProvider) {
|
||||||
with(provider.russian) {
|
with(provider.russian) {
|
||||||
|
gui("quickmove_from.restock", "Быстрое пополнение из хранилища")
|
||||||
|
gui("quickmove_from.restock_with_move", "Быстрое перемещение из хранилища")
|
||||||
|
gui("quickmove_from.move", "Взять всё")
|
||||||
|
|
||||||
|
gui("quickmove_to.restock", "Быстрое пополнение в хранилище")
|
||||||
|
gui("quickmove_to.restock_with_move", "Быстрое перемещение в хранилище")
|
||||||
|
gui("quickmove_to.move", "Переместить всё")
|
||||||
|
|
||||||
|
gui("quickmove_hint", "Правый клик чтоб увидеть все варианты")
|
||||||
|
|
||||||
gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников")
|
gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников")
|
||||||
gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников")
|
gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников")
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.mixin;
|
|||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.GameRules;
|
||||||
import net.neoforged.neoforge.event.EventHooks;
|
import net.neoforged.neoforge.event.EventHooks;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@ -28,7 +29,7 @@ public class MixinLivingEntity {
|
|||||||
at = @At("HEAD"),
|
at = @At("HEAD"),
|
||||||
cancellable = true)
|
cancellable = true)
|
||||||
public void dropExperience(@Nullable Entity killer, CallbackInfo hook) {
|
public void dropExperience(@Nullable Entity killer, CallbackInfo hook) {
|
||||||
if (((Object) this) instanceof Player player && ServerConfig.INSTANCE.getDROP_EXPERIENCE_CAPSULES()) {
|
if (((Object) this) instanceof Player player && ServerConfig.INSTANCE.getDROP_EXPERIENCE_CAPSULES() && !player.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY)) {
|
||||||
hook.cancel();
|
hook.cancel();
|
||||||
|
|
||||||
var android = ((IMatteryPlayer) player).getOtmPlayer();
|
var android = ((IMatteryPlayer) player).getOtmPlayer();
|
||||||
|
@ -5,7 +5,7 @@ import ru.dbotthepony.mc.otm.client.render.sprites.MatteryAtlas
|
|||||||
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
import ru.dbotthepony.mc.otm.core.ResourceLocation
|
||||||
|
|
||||||
object WidgetLocation {
|
object WidgetLocation {
|
||||||
val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 72f)
|
val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 90f)
|
||||||
val WIDGET_18 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_18.png"), 72f, 72f)
|
val WIDGET_18 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_18.png"), 72f, 72f)
|
||||||
val WIDGET_15 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_15.png"), 60f, 60f)
|
val WIDGET_15 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_15.png"), 60f, 60f)
|
||||||
val WIDGET_8 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_8.png"), 64f, 32f)
|
val WIDGET_8 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_8.png"), 64f, 32f)
|
||||||
|
@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.core.immutableMap
|
|||||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||||
|
|
||||||
object Widgets18 {
|
object Widgets18 {
|
||||||
private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 4, columns = 5)
|
private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 5, columns = 5)
|
||||||
|
|
||||||
val SORT_DESCENDING = storageGrid.next()
|
val SORT_DESCENDING = storageGrid.next()
|
||||||
val SORT_ASCENDING = storageGrid.next()
|
val SORT_ASCENDING = storageGrid.next()
|
||||||
@ -24,6 +24,12 @@ object Widgets18 {
|
|||||||
val PLAY = storageGrid.next()
|
val PLAY = storageGrid.next()
|
||||||
val STOP = storageGrid.next()
|
val STOP = storageGrid.next()
|
||||||
val SORT_NOW = storageGrid.next()
|
val SORT_NOW = storageGrid.next()
|
||||||
|
val MOVE_EVERYTHING_TO_STORAGE = storageGrid.next()
|
||||||
|
val MOVE_EVERYTHING_FROM_STORAGE = storageGrid.next()
|
||||||
|
val RESTOCK_TO_STORAGE = storageGrid.next()
|
||||||
|
val RESTOCK_FROM_STORAGE = storageGrid.next()
|
||||||
|
val RESTOCK_WITH_MOVE_TO_STORAGE = storageGrid.next()
|
||||||
|
val RESTOCK_WITH_MOVE_FROM_STORAGE = storageGrid.next()
|
||||||
|
|
||||||
private val miscGrid = WidgetLocation.WIDGET_18.grid(4, 4)
|
private val miscGrid = WidgetLocation.WIDGET_18.grid(4, 4)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
||||||
|
|
||||||
class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Component) : MatteryScreen<CargoCrateMenu>(menu, inventory, title) {
|
class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Component) : MatteryScreen<CargoCrateMenu>(menu, inventory, title) {
|
||||||
@ -23,9 +24,16 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon
|
|||||||
UserFilteredSlotPanel(this, grid, slot)
|
UserFilteredSlotPanel(this, grid, slot)
|
||||||
|
|
||||||
val controls = DeviceControls(this, frame)
|
val controls = DeviceControls(this, frame)
|
||||||
|
|
||||||
controls.sortingButtons(menu.sort)
|
controls.sortingButtons(menu.sort)
|
||||||
|
|
||||||
|
val leftControls = DeviceControls(this, frame)
|
||||||
|
leftControls.dockOnLeft = true
|
||||||
|
leftControls.quickMoveButtons(menu.quickMoveFromStorage, QuickMoveInput.Mode.RESTOCK, true)
|
||||||
|
|
||||||
|
val leftInventoryControls = DeviceControls(this, inventoryFrame!!)
|
||||||
|
leftInventoryControls.dockOnLeft = true
|
||||||
|
leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, QuickMoveInput.Mode.RESTOCK_WITH_MOVE, false)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@ import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
|||||||
import ru.dbotthepony.mc.otm.core.util.ItemStackSorter
|
import ru.dbotthepony.mc.otm.core.util.ItemStackSorter
|
||||||
import ru.dbotthepony.mc.otm.core.util.getLevelFromXp
|
import ru.dbotthepony.mc.otm.core.util.getLevelFromXp
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.SortInput
|
import ru.dbotthepony.mc.otm.menu.SortInput
|
||||||
import ru.dbotthepony.mc.otm.menu.UpgradeSlots
|
import ru.dbotthepony.mc.otm.menu.UpgradeSlots
|
||||||
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
||||||
@ -385,13 +386,17 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P): P {
|
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P): P {
|
||||||
buttons.add(button)
|
if (button !in buttons) {
|
||||||
button.parent = this
|
buttons.add(button)
|
||||||
alignButtons()
|
button.parent = this
|
||||||
|
alignButtons()
|
||||||
|
}
|
||||||
|
|
||||||
return button
|
return button
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P, after: EditablePanel<*>): P {
|
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P, after: EditablePanel<*>): P {
|
||||||
|
buttons.remove(button)
|
||||||
val index = buttons.indexOf(after)
|
val index = buttons.indexOf(after)
|
||||||
if (index == -1) throw NoSuchElementException("Unknown panel to add button after: $after")
|
if (index == -1) throw NoSuchElementException("Unknown panel to add button after: $after")
|
||||||
buttons.add(index + 1, button)
|
buttons.add(index + 1, button)
|
||||||
@ -401,9 +406,12 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <P : EditablePanel<@UnsafeVariance S>> prependButton(button: P): P {
|
fun <P : EditablePanel<@UnsafeVariance S>> prependButton(button: P): P {
|
||||||
buttons.add(0, button)
|
if (button !in buttons) {
|
||||||
button.parent = this
|
buttons.add(0, button)
|
||||||
alignButtons()
|
button.parent = this
|
||||||
|
alignButtons()
|
||||||
|
}
|
||||||
|
|
||||||
return button
|
return button
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,9 +457,75 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private abstract inner class FoldableButtonPanel() : ButtonPanel<S>(screen, this@DeviceControls, width = 18f, height = 18f) {
|
||||||
|
init {
|
||||||
|
addButton(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var buttons: List<EditablePanel<S>>? = null
|
||||||
|
|
||||||
|
|
||||||
|
fun makeButtons() {
|
||||||
|
if (buttons == null) {
|
||||||
|
buttons = doMakeButtons().also {
|
||||||
|
it.forEach { addButton(it, this) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeButtons() {
|
||||||
|
if (buttons != null) {
|
||||||
|
buttons!!.forEach { it.remove() }
|
||||||
|
buttons = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun test(value: Int): Boolean {
|
||||||
|
return value == InputConstants.MOUSE_BUTTON_LEFT || hasExtraButtons && value == InputConstants.MOUSE_BUTTON_RIGHT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun switchButtons() {
|
||||||
|
if (buttons == null)
|
||||||
|
makeButtons()
|
||||||
|
else
|
||||||
|
removeButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract val hasExtraButtons: Boolean
|
||||||
|
protected abstract fun performAction()
|
||||||
|
protected abstract fun doMakeButtons(): List<EditablePanel<S>>
|
||||||
|
|
||||||
|
final override fun onClick(mouseButton: Int) {
|
||||||
|
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
|
performAction()
|
||||||
|
} else {
|
||||||
|
switchButtons()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun sortingButtons(input: SortInput, unfoldableSettings: Boolean = true) {
|
fun sortingButtons(input: SortInput, unfoldableSettings: Boolean = true) {
|
||||||
object : ButtonPanel<S>(screen, this@DeviceControls, width = 18f, height = 18f) {
|
object : FoldableButtonPanel() {
|
||||||
var buttons: List<EditablePanel<*>>? = null
|
override fun performAction() {
|
||||||
|
input.clientInput()
|
||||||
|
}
|
||||||
|
|
||||||
|
override var isDisabled: Boolean
|
||||||
|
get() { return !input.input.test(minecraft.player ?: return false) }
|
||||||
|
set(value) {}
|
||||||
|
|
||||||
|
override val hasExtraButtons: Boolean
|
||||||
|
get() = unfoldableSettings
|
||||||
|
|
||||||
|
override fun doMakeButtons(): List<EditablePanel<S>> {
|
||||||
|
return sortingButtons(Delegate.Of(input.settings::isAscending), Delegate.Of(input.settings::sorting), ItemStackSorter.DEFAULT) {
|
||||||
|
for (v in ItemStackSorter.entries) {
|
||||||
|
add(v, v.icon, v.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now"))
|
tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now"))
|
||||||
@ -459,50 +533,67 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
if (unfoldableSettings) {
|
if (unfoldableSettings) {
|
||||||
tooltips.add(TextComponent(""))
|
tooltips.add(TextComponent(""))
|
||||||
tooltips.add(TranslatableComponent("otm.gui.sorting.sort_settings").withStyle(ChatFormatting.GRAY))
|
tooltips.add(TranslatableComponent("otm.gui.sorting.sort_settings").withStyle(ChatFormatting.GRAY))
|
||||||
}
|
} else {
|
||||||
addButton(this)
|
|
||||||
|
|
||||||
if (!unfoldableSettings) {
|
|
||||||
makeButtons()
|
makeButtons()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val icon: IGUIRenderable
|
override val icon: IGUIRenderable
|
||||||
get() = Widgets18.SORT_NOW
|
get() = Widgets18.SORT_NOW
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun test(value: Int): Boolean {
|
fun quickMoveButtons(buttons: Map<QuickMoveInput.Mode, QuickMoveInput>, mainMode: QuickMoveInput.Mode, isFromStorage: Boolean, unfoldableSettings: Boolean = true) {
|
||||||
return value == InputConstants.MOUSE_BUTTON_LEFT || unfoldableSettings && value == InputConstants.MOUSE_BUTTON_RIGHT
|
object : FoldableButtonPanel() {
|
||||||
|
private val input = buttons[mainMode]!!
|
||||||
|
|
||||||
|
override fun performAction() {
|
||||||
|
input.clientInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
override var isDisabled: Boolean
|
override var isDisabled: Boolean
|
||||||
get() { return !input.input.test(minecraft.player ?: return false) }
|
get() { return !input.input.test(minecraft.player ?: return false) }
|
||||||
set(value) {}
|
set(value) {}
|
||||||
|
|
||||||
private fun makeButtons() {
|
override val hasExtraButtons: Boolean
|
||||||
buttons = sortingButtons(Delegate.Of(input.settings::isAscending), Delegate.Of(input.settings::sorting), ItemStackSorter.DEFAULT) {
|
get() = unfoldableSettings
|
||||||
for (v in ItemStackSorter.entries) {
|
|
||||||
add(v, v.icon, v.title)
|
override fun doMakeButtons(): List<EditablePanel<S>> {
|
||||||
|
return buttons.entries
|
||||||
|
.stream()
|
||||||
|
.filter { (m, _) -> m != input.mode }
|
||||||
|
.map { (m, b) ->
|
||||||
|
square18(
|
||||||
|
screen,
|
||||||
|
this,
|
||||||
|
icon = if (isFromStorage) m.iconFromStorage else m.iconToStorage,
|
||||||
|
onPress = { b.clientInput() }
|
||||||
|
).also {
|
||||||
|
if (isFromStorage)
|
||||||
|
it.tooltips.add(m.textFromStorage)
|
||||||
|
else
|
||||||
|
it.tooltips.add(m.textToStorage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
.toList()
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
buttons!!.forEach { removeButton(it) }
|
|
||||||
buttons!!.forEach { addButton(it as EditablePanel<S>, this) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick(mouseButton: Int) {
|
init {
|
||||||
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
if (isFromStorage)
|
||||||
input.clientInput()
|
tooltips.add(input.mode.textFromStorage)
|
||||||
|
else
|
||||||
|
tooltips.add(input.mode.textToStorage)
|
||||||
|
|
||||||
|
if (unfoldableSettings) {
|
||||||
|
tooltips.add(TextComponent(""))
|
||||||
|
tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY))
|
||||||
} else {
|
} else {
|
||||||
if (buttons == null) {
|
makeButtons()
|
||||||
makeButtons()
|
|
||||||
} else {
|
|
||||||
buttons!!.forEach { it.remove() }
|
|
||||||
buttons = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val icon: IGUIRenderable
|
||||||
|
get() = if (isFromStorage) input.mode.iconFromStorage else input.mode.iconToStorage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import net.minecraft.world.entity.player.Player
|
|||||||
import net.minecraft.world.inventory.MenuType
|
import net.minecraft.world.inventory.MenuType
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.SortInput
|
import ru.dbotthepony.mc.otm.menu.SortInput
|
||||||
|
|
||||||
abstract class AbstractVanillaChestMenu(
|
abstract class AbstractVanillaChestMenu(
|
||||||
@ -18,6 +19,8 @@ abstract class AbstractVanillaChestMenu(
|
|||||||
abstract val columns: Int
|
abstract val columns: Int
|
||||||
|
|
||||||
abstract val containerSlots: List<MatteryMenuSlot>
|
abstract val containerSlots: List<MatteryMenuSlot>
|
||||||
|
abstract val quickMoveToStorage: Map<QuickMoveInput.Mode, QuickMoveInput>
|
||||||
|
abstract val quickMoveFromStorage: Map<QuickMoveInput.Mode, QuickMoveInput>
|
||||||
val sort = SortInput(this, container, playerSortSettings)
|
val sort = SortInput(this, container, playerSortSettings)
|
||||||
|
|
||||||
override fun stillValid(player: Player): Boolean {
|
override fun stillValid(player: Player): Boolean {
|
||||||
|
@ -6,6 +6,7 @@ import net.minecraft.world.entity.player.Inventory
|
|||||||
import net.minecraft.world.inventory.MenuType
|
import net.minecraft.world.inventory.MenuType
|
||||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.makeSlots
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
|
|
||||||
class MatteryChestMenu(
|
class MatteryChestMenu(
|
||||||
@ -22,6 +23,9 @@ class MatteryChestMenu(
|
|||||||
addInventorySlots()
|
addInventorySlots()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots)
|
||||||
|
override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
|
@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Inventory
|
|||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.makeSlots
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
|
|
||||||
class MatteryShulkerBoxMenu(
|
class MatteryShulkerBoxMenu(
|
||||||
@ -24,6 +25,9 @@ class MatteryShulkerBoxMenu(
|
|||||||
addInventorySlots()
|
addInventorySlots()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots)
|
||||||
|
override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots)
|
||||||
|
|
||||||
class Slot(container: Container, slot: Int) : MatteryMenuSlot(container, slot) {
|
class Slot(container: Container, slot: Int) : MatteryMenuSlot(container, slot) {
|
||||||
override fun mayPlace(stack: ItemStack): Boolean {
|
override fun mayPlace(stack: ItemStack): Boolean {
|
||||||
return super.mayPlace(stack) && stack.item.canFitInsideContainerItems()
|
return super.mayPlace(stack) && stack.item.canFitInsideContainerItems()
|
||||||
|
@ -10,6 +10,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
|||||||
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.SlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
|
|
||||||
class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, title: Component) : MatteryScreen<AbstractVanillaChestMenu>(menu, inventory, title) {
|
class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, title: Component) : MatteryScreen<AbstractVanillaChestMenu>(menu, inventory, title) {
|
||||||
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
||||||
@ -28,6 +29,14 @@ class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, t
|
|||||||
val controls = DeviceControls(this, frame)
|
val controls = DeviceControls(this, frame)
|
||||||
controls.sortingButtons(menu.sort)
|
controls.sortingButtons(menu.sort)
|
||||||
|
|
||||||
|
val leftControls = DeviceControls(this, frame)
|
||||||
|
leftControls.dockOnLeft = true
|
||||||
|
leftControls.quickMoveButtons(menu.quickMoveFromStorage, QuickMoveInput.Mode.RESTOCK, true)
|
||||||
|
|
||||||
|
val leftInventoryControls = DeviceControls(this, inventoryFrame!!)
|
||||||
|
leftInventoryControls.dockOnLeft = true
|
||||||
|
leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, QuickMoveInput.Mode.RESTOCK_WITH_MOVE, false)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,17 @@ package ru.dbotthepony.mc.otm.core.util
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.HashCommon
|
import it.unimi.dsi.fastutil.HashCommon
|
||||||
import net.minecraft.core.component.DataComponentMap
|
import net.minecraft.core.component.DataComponentMap
|
||||||
|
import net.minecraft.core.component.DataComponentPatch
|
||||||
|
import net.minecraft.core.component.PatchedDataComponentMap
|
||||||
|
import net.minecraft.core.registries.BuiltInRegistries
|
||||||
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 ru.dbotthepony.mc.otm.core.getHolder
|
||||||
|
|
||||||
class ItemStackKey(val item: Item, val components: DataComponentMap) {
|
class ItemStackKey(val item: Item, val components: DataComponentPatch) {
|
||||||
// make copy of original itemstack because there is no copy() method on DataComponentMap, which is returned by ItemStack#getComponents
|
// make copy of original itemstack because there is no copy() method on DataComponentMap, which is returned by ItemStack#getComponents
|
||||||
constructor(itemStack: ItemStack) : this(itemStack.item, itemStack.copy().components)
|
constructor(itemStack: ItemStack) : this(itemStack.item, itemStack.copy().componentsPatch)
|
||||||
|
constructor(item: Item) : this(item, DataComponentPatch.EMPTY)
|
||||||
|
|
||||||
private var hashComputed = false
|
private var hashComputed = false
|
||||||
private var hash = 0
|
private var hash = 0
|
||||||
@ -25,6 +30,10 @@ class ItemStackKey(val item: Item, val components: DataComponentMap) {
|
|||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun asItemStack(count: Int = 1): ItemStack {
|
||||||
|
return ItemStack(BuiltInRegistries.ITEM.getHolder(item)!!, count, components)
|
||||||
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "ItemStackKey[$item, $components]"
|
return "ItemStackKey[$item, $components]"
|
||||||
}
|
}
|
||||||
@ -33,3 +42,12 @@ class ItemStackKey(val item: Item, val components: DataComponentMap) {
|
|||||||
fun ItemStack.asKey(): ItemStackKey {
|
fun ItemStack.asKey(): ItemStackKey {
|
||||||
return ItemStackKey(this)
|
return ItemStackKey(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ItemStack.asKeyOrNull(): ItemStackKey? {
|
||||||
|
if (isEmpty) return null
|
||||||
|
return ItemStackKey(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Item.asKey(): ItemStackKey {
|
||||||
|
return ItemStackKey(this)
|
||||||
|
}
|
||||||
|
@ -177,7 +177,7 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO
|
|||||||
|
|
||||||
if (!player.level().isClientSide) {
|
if (!player.level().isClientSide) {
|
||||||
for (slot in craftingGrid.slotIterator()) {
|
for (slot in craftingGrid.slotIterator()) {
|
||||||
val leftover = moveItemStackToSlots(slot.item, playerInventorySlots)
|
val leftover = QuickMoveInput.moveItemStackToSlots(slot.item, playerInventorySlots)
|
||||||
|
|
||||||
if (!leftover.isEmpty) {
|
if (!leftover.isEmpty) {
|
||||||
player.drop(leftover, true)
|
player.drop(leftover, true)
|
||||||
@ -205,11 +205,11 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO
|
|||||||
|
|
||||||
if (slotIndex == craftingResultSlot.index) {
|
if (slotIndex == craftingResultSlot.index) {
|
||||||
val item = craftingResultSlot.item
|
val item = craftingResultSlot.item
|
||||||
val leftover = moveItemStackToSlots(item, playerInventorySlots, simulate = true)
|
val leftover = QuickMoveInput.moveItemStackToSlots(item, playerInventorySlots, simulate = true)
|
||||||
|
|
||||||
if (leftover.isEmpty) {
|
if (leftover.isEmpty) {
|
||||||
val copy = item.copy()
|
val copy = item.copy()
|
||||||
moveItemStackToSlots(item, playerInventorySlots, simulate = false)
|
QuickMoveInput.moveItemStackToSlots(item, playerInventorySlots, simulate = false)
|
||||||
item.count = 0
|
item.count = 0
|
||||||
craftingResultSlot.onTake(ply, copy)
|
craftingResultSlot.onTake(ply, copy)
|
||||||
return copy
|
return copy
|
||||||
|
@ -452,25 +452,10 @@ abstract class MatteryMenu(
|
|||||||
val copy = slot.item.copy()
|
val copy = slot.item.copy()
|
||||||
var any = false
|
var any = false
|
||||||
|
|
||||||
if (target.any { it.any { it.containerSlotOrNull() is IFilteredContainerSlot } }) {
|
|
||||||
for (collection in target) {
|
|
||||||
if (moveItemStackTo(ply, slot, collection, onlyFiltered = true)) {
|
|
||||||
any = true
|
|
||||||
|
|
||||||
if (!slot.hasItem()) {
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (collection in target) {
|
for (collection in target) {
|
||||||
if (moveItemStackTo(ply, slot, collection)) {
|
if (QuickMoveInput.moveItemStackTo(ply, slot, collection)) {
|
||||||
any = true
|
any = true
|
||||||
|
if (!slot.hasItem()) return copy
|
||||||
if (!slot.hasItem()) {
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,7 +471,7 @@ abstract class MatteryMenu(
|
|||||||
return stack
|
return stack
|
||||||
}
|
}
|
||||||
|
|
||||||
return moveItemStackToSlots(stack, _playerInventorySlots, simulate = simulate)
|
return QuickMoveInput.moveItemStackToSlots(stack, _playerInventorySlots, simulate = simulate)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun canTakeItemForPickAll(itemStack: ItemStack, slot: Slot): Boolean {
|
override fun canTakeItemForPickAll(itemStack: ItemStack, slot: Slot): Boolean {
|
||||||
@ -521,22 +506,12 @@ abstract class MatteryMenu(
|
|||||||
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)) {
|
||||||
val slot = slots[i]
|
slots.add(this.slots[i])
|
||||||
slots.add(slot)
|
|
||||||
|
|
||||||
if (slot.containerSlotOrNull() is IFilteredContainerSlot) {
|
|
||||||
filters = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filters) {
|
return QuickMoveInput.moveItemStackToSlots(item, slots, simulate)
|
||||||
return moveItemStackToSlots(moveItemStackToSlots(item, slots, simulate, onlyFiltered = true), slots, simulate, onlyFiltered = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return moveItemStackToSlots(item, slots, simulate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var armorSlots: ImmutableList<PlayerSlot<EquipmentMenuSlot, Slot>>? = null
|
private var armorSlots: ImmutableList<PlayerSlot<EquipmentMenuSlot, Slot>>? = null
|
||||||
@ -613,96 +588,5 @@ abstract class MatteryMenu(
|
|||||||
InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS,
|
InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS,
|
||||||
InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE,
|
InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE,
|
||||||
InventoryMenu.EMPTY_ARMOR_SLOT_HELMET)
|
InventoryMenu.EMPTY_ARMOR_SLOT_HELMET)
|
||||||
|
|
||||||
fun moveItemStackTo(
|
|
||||||
player: Player,
|
|
||||||
source: Slot,
|
|
||||||
slots: Collection<Slot>,
|
|
||||||
onlyFiltered: Boolean = false
|
|
||||||
): Boolean {
|
|
||||||
val remainder = moveItemStackToSlots(source.item, slots, onlyFiltered = onlyFiltered)
|
|
||||||
|
|
||||||
if (remainder.count == source.item.count) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val copy = source.item.copy()
|
|
||||||
|
|
||||||
if (remainder.isEmpty) {
|
|
||||||
source.setByPlayer(ItemStack.EMPTY)
|
|
||||||
source.onTake(player, copy)
|
|
||||||
} else {
|
|
||||||
copy.count = source.item.count - remainder.count
|
|
||||||
source.item.count = remainder.count
|
|
||||||
source.onTake(player, copy)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun moveItemStackToSlots(item: ItemStack, slots: Collection<Slot>, simulate: Boolean = false, onlyFiltered: Boolean = false): ItemStack {
|
|
||||||
if (item.isEmpty) {
|
|
||||||
return ItemStack.EMPTY
|
|
||||||
}
|
|
||||||
|
|
||||||
val copy = item.copy()
|
|
||||||
|
|
||||||
// first pass - stack with existing slots
|
|
||||||
if (copy.isStackable) {
|
|
||||||
for (slot in slots) {
|
|
||||||
if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) {
|
|
||||||
continue
|
|
||||||
} else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val limit = slot.getMaxStackSize(copy)
|
|
||||||
|
|
||||||
if (limit > slot.item.count && slot.mayPlace(item) && ItemStack.isSameItemSameComponents(slot.item, copy)) {
|
|
||||||
val newCount = (slot.item.count + copy.count).coerceAtMost(limit)
|
|
||||||
val diff = newCount - slot.item.count
|
|
||||||
copy.count -= diff
|
|
||||||
|
|
||||||
if (!simulate) {
|
|
||||||
slot.item.count += diff
|
|
||||||
slot.setChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copy.isEmpty) {
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// second pass - drop stack into first free slot
|
|
||||||
for (slot in slots) {
|
|
||||||
if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) {
|
|
||||||
continue
|
|
||||||
} else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val limit = slot.getMaxStackSize(copy)
|
|
||||||
|
|
||||||
if (!slot.hasItem() && slot.mayPlace(item)) {
|
|
||||||
val newCount = copy.count.coerceAtMost(limit)
|
|
||||||
|
|
||||||
if (!simulate) {
|
|
||||||
slot.setByPlayer(copy.copy().also { it.count = newCount })
|
|
||||||
slot.setChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
copy.count -= newCount
|
|
||||||
|
|
||||||
if (copy.isEmpty) {
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return copy
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
228
src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt
Normal file
228
src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.menu
|
||||||
|
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.world.entity.player.Player
|
||||||
|
import net.minecraft.world.inventory.Slot
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||||
|
import ru.dbotthepony.mc.otm.client.render.sprites.AbstractMatterySprite
|
||||||
|
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot
|
||||||
|
import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull
|
||||||
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.ItemStackKey
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.asKey
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.asKeyOrNull
|
||||||
|
|
||||||
|
class QuickMoveInput(private val menu: MatteryMenu, val from: Collection<Slot>, val to: Collection<Slot>, val mode: Mode) {
|
||||||
|
enum class Mode(val iconFromStorage: AbstractMatterySprite, val iconToStorage: AbstractMatterySprite) {
|
||||||
|
RESTOCK(
|
||||||
|
Widgets18.RESTOCK_FROM_STORAGE,
|
||||||
|
Widgets18.RESTOCK_TO_STORAGE
|
||||||
|
) {
|
||||||
|
override fun move(from: Collection<Slot>, to: Collection<Slot>, player: Player) {
|
||||||
|
val (_, itemsFrom) = computeSlotLists(from, true)
|
||||||
|
val (_, itemsTo) = computeSlotLists(to, false)
|
||||||
|
|
||||||
|
val intersect = if (itemsFrom.size < itemsTo.size) itemsFrom.keys.filter { it in itemsTo.keys } else itemsTo.keys.filter { it in itemsFrom.keys }
|
||||||
|
|
||||||
|
for (key in intersect) {
|
||||||
|
val slotsTo = itemsTo[key]!!
|
||||||
|
itemsFrom[key]!!.forEach { moveItemStackTo(player, it, slotsTo) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
RESTOCK_WITH_MOVE(
|
||||||
|
Widgets18.RESTOCK_WITH_MOVE_FROM_STORAGE,
|
||||||
|
Widgets18.RESTOCK_WITH_MOVE_TO_STORAGE
|
||||||
|
) {
|
||||||
|
override fun move(from: Collection<Slot>, to: Collection<Slot>, player: Player) {
|
||||||
|
val (_, itemsFrom) = computeSlotLists(from, true)
|
||||||
|
val (emptyTo, itemsTo) = computeSlotLists(to, false)
|
||||||
|
|
||||||
|
val intersect = if (itemsFrom.size < itemsTo.size) itemsFrom.keys.filter { it in itemsTo.keys } else itemsTo.keys.filter { it in itemsFrom.keys }
|
||||||
|
|
||||||
|
for (key in intersect) {
|
||||||
|
val slotsTo = prioritySortSlots(itemsTo[key]!!, key.asItemStack())
|
||||||
|
val slotsFrom = itemsFrom[key]!!
|
||||||
|
slotsFrom.removeIf { moveItemStackTo(player, it, slotsTo, sort = false); it.item.isEmpty }
|
||||||
|
var moveAny = false
|
||||||
|
slotsFrom.forEach { moveAny = moveItemStackTo(player, it, emptyTo, sort = false) || moveAny }
|
||||||
|
if (moveAny) emptyTo.removeIf { it.item.isNotEmpty }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
MOVE(
|
||||||
|
Widgets18.MOVE_EVERYTHING_FROM_STORAGE,
|
||||||
|
Widgets18.MOVE_EVERYTHING_TO_STORAGE
|
||||||
|
) {
|
||||||
|
override fun move(from: Collection<Slot>, to: Collection<Slot>, player: Player) {
|
||||||
|
val toSorted = prioritySortSlots(to)
|
||||||
|
|
||||||
|
from.forEach {
|
||||||
|
val slot = it.containerSlotOrNull()
|
||||||
|
|
||||||
|
if (slot !is IFilteredContainerSlot || !slot.hasFilter)
|
||||||
|
moveItemStackTo(player, it, toSorted, sort = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract fun move(from: Collection<Slot>, to: Collection<Slot>, player: Player)
|
||||||
|
|
||||||
|
val textFromStorage: Component get() {
|
||||||
|
return TranslatableComponent("otm.gui.quickmove_from.${name.lowercase()}")
|
||||||
|
}
|
||||||
|
|
||||||
|
val textToStorage: Component get() {
|
||||||
|
return TranslatableComponent("otm.gui.quickmove_to.${name.lowercase()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val input = menu.oneWayInput(handler = ::handle)
|
||||||
|
|
||||||
|
fun clientInput() {
|
||||||
|
input.accept(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handle() {
|
||||||
|
mode.move(from, to, menu.player)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun create(menu: MatteryMenu, from: Collection<Slot>, to: Collection<Slot>): Map<Mode, QuickMoveInput> {
|
||||||
|
return Mode.entries.associateWith { QuickMoveInput(menu, from, to, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun computeSlotLists(slots: Collection<Slot>, skipFilteredSlots: Boolean): Pair<MutableList<Slot>, MutableMap<ItemStackKey, MutableList<Slot>>> {
|
||||||
|
val emptySlots = ArrayList<Slot>()
|
||||||
|
val filledSlots = HashMap<ItemStackKey, MutableList<Slot>>()
|
||||||
|
|
||||||
|
for (slot in slots) {
|
||||||
|
val underlyingSlot = slot.containerSlotOrNull()
|
||||||
|
|
||||||
|
if (underlyingSlot is IFilteredContainerSlot && (underlyingSlot.filter == Items.AIR || underlyingSlot.filter != null && skipFilteredSlots))
|
||||||
|
continue
|
||||||
|
|
||||||
|
val key = slot.item.asKeyOrNull() ?: (underlyingSlot as? IFilteredContainerSlot)?.filter?.asKey()
|
||||||
|
|
||||||
|
if (key == null) {
|
||||||
|
emptySlots.add(slot)
|
||||||
|
} else {
|
||||||
|
filledSlots.computeIfAbsent(key) { ArrayList() }.add(slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return emptySlots to filledSlots
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveItemStackTo(
|
||||||
|
player: Player,
|
||||||
|
source: Slot,
|
||||||
|
slots: Collection<Slot>,
|
||||||
|
sort: Boolean = true
|
||||||
|
): Boolean {
|
||||||
|
if (!source.mayPickup(player) || source.item.isEmpty || slots.isEmpty())
|
||||||
|
return false
|
||||||
|
|
||||||
|
val remainder = moveItemStackToSlots(source.item, slots, sort = sort)
|
||||||
|
|
||||||
|
if (remainder.count == source.item.count)
|
||||||
|
return false
|
||||||
|
|
||||||
|
val copy = source.item.copy()
|
||||||
|
|
||||||
|
if (remainder.isEmpty) {
|
||||||
|
source.setByPlayer(ItemStack.EMPTY)
|
||||||
|
source.onTake(player, copy)
|
||||||
|
} else {
|
||||||
|
copy.count = source.item.count - remainder.count
|
||||||
|
source.item.count = remainder.count
|
||||||
|
source.onTake(player, copy)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prioritySortSlots(slots: Collection<Slot>, filterItem: ItemStack? = null): MutableList<Slot> {
|
||||||
|
val sortedSlots = ArrayList(slots)
|
||||||
|
|
||||||
|
sortedSlots.removeIf {
|
||||||
|
val slot = it.containerSlotOrNull()
|
||||||
|
it.isOverCapacity || filterItem != null && !it.mayPlace(filterItem) || slot is IFilteredContainerSlot && slot.isForbiddenForAutomation
|
||||||
|
}
|
||||||
|
|
||||||
|
sortedSlots.sortWith { a, b ->
|
||||||
|
val hasItemA = a.item.isNotEmpty
|
||||||
|
val hasItemB = b.item.isNotEmpty
|
||||||
|
|
||||||
|
if (hasItemA && hasItemB)
|
||||||
|
return@sortWith 0
|
||||||
|
else if (hasItemA)
|
||||||
|
return@sortWith -1
|
||||||
|
else if (hasItemB)
|
||||||
|
return@sortWith 1
|
||||||
|
|
||||||
|
val slotA = a.containerSlotOrNull()
|
||||||
|
val slotB = b.containerSlotOrNull()
|
||||||
|
|
||||||
|
val hasFilterA = slotA is IFilteredContainerSlot && slotA.hasFilter
|
||||||
|
val hasFilterB = slotB is IFilteredContainerSlot && slotB.hasFilter
|
||||||
|
|
||||||
|
if (hasFilterA && hasFilterB || !hasFilterA && !hasFilterB)
|
||||||
|
return@sortWith 0
|
||||||
|
else if (hasFilterA)
|
||||||
|
return@sortWith -1
|
||||||
|
else
|
||||||
|
return@sortWith 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedSlots
|
||||||
|
}
|
||||||
|
|
||||||
|
fun moveItemStackToSlots(item: ItemStack, slots: Collection<Slot>, simulate: Boolean = false, sort: Boolean = true): ItemStack {
|
||||||
|
if (item.isEmpty)
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
else if (slots.isEmpty())
|
||||||
|
return item.copy()
|
||||||
|
|
||||||
|
val sortedSlots = if (sort) prioritySortSlots(slots, item) else slots
|
||||||
|
val copy = item.copy()
|
||||||
|
|
||||||
|
for (slot in sortedSlots) {
|
||||||
|
val limit = slot.getMaxStackSize(copy)
|
||||||
|
|
||||||
|
if (!slot.hasItem()) {
|
||||||
|
val newCount = copy.count.coerceAtMost(limit)
|
||||||
|
|
||||||
|
if (!simulate) {
|
||||||
|
slot.setByPlayer(copy.copy().also { it.count = newCount })
|
||||||
|
// slot.setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
copy.shrink(newCount)
|
||||||
|
|
||||||
|
if (copy.isEmpty)
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
} else if (limit > slot.item.count && ItemStack.isSameItemSameComponents(slot.item, copy)) {
|
||||||
|
val newCount = (slot.item.count + copy.count).coerceAtMost(limit)
|
||||||
|
val diff = newCount - slot.item.count
|
||||||
|
copy.count -= diff
|
||||||
|
|
||||||
|
if (!simulate) {
|
||||||
|
slot.item.count += diff
|
||||||
|
slot.setChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (copy.isEmpty)
|
||||||
|
return ItemStack.EMPTY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return copy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
|||||||
import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull
|
import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull
|
||||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
|
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
|
||||||
import ru.dbotthepony.mc.otm.core.immutableList
|
import ru.dbotthepony.mc.otm.core.immutableList
|
||||||
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
||||||
import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput
|
import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput
|
||||||
@ -242,6 +243,10 @@ fun MatteryMenu.addFilterControls(slots: KMutableProperty0<ItemFilter>?, amount:
|
|||||||
return addFilterControls(slots?.let { Delegate.Of(it) }, amount)
|
return addFilterControls(slots?.let { Delegate.Of(it) }, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val Slot.isOverCapacity: Boolean get() {
|
||||||
|
return item.isNotEmpty && getMaxStackSize(item) <= item.count
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [openState] **is clientside only**, attempting to use it on server will result
|
* [openState] **is clientside only**, attempting to use it on server will result
|
||||||
* in classloading exceptions.
|
* in classloading exceptions.
|
||||||
|
@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Player
|
|||||||
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
||||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.SortInput
|
import ru.dbotthepony.mc.otm.menu.SortInput
|
||||||
import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot
|
import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot
|
||||||
import ru.dbotthepony.mc.otm.menu.makeSlots
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
@ -20,6 +21,8 @@ class CargoCrateMenu(
|
|||||||
private val trackedPlayerOpen = !inventory.player.isSpectator
|
private val trackedPlayerOpen = !inventory.player.isSpectator
|
||||||
|
|
||||||
val sort = SortInput(this, actualContainer, playerSortSettings)
|
val sort = SortInput(this, actualContainer, playerSortSettings)
|
||||||
|
val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, storageSlots)
|
||||||
|
val quickMoveFromStorage = QuickMoveInput.create(this, storageSlots, playerInventorySlots)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (trackedPlayerOpen) {
|
if (trackedPlayerOpen) {
|
||||||
|
@ -17,6 +17,7 @@ import ru.dbotthepony.mc.otm.core.collect.reduce
|
|||||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.QuickMoveInput
|
||||||
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewProvider
|
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewProvider
|
||||||
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView
|
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView
|
||||||
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
||||||
@ -137,9 +138,9 @@ class ItemMonitorMenu(
|
|||||||
|
|
||||||
if (settings.resultTarget == ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM) {
|
if (settings.resultTarget == ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM) {
|
||||||
remaining = view.insertStack(ItemStorageStack(itemStack), simulate).toItemStack()
|
remaining = view.insertStack(ItemStorageStack(itemStack), simulate).toItemStack()
|
||||||
remaining = moveItemStackToSlots(remaining, playerInventorySlots, simulate)
|
remaining = QuickMoveInput.moveItemStackToSlots(remaining, playerInventorySlots, simulate)
|
||||||
} else {
|
} else {
|
||||||
remaining = moveItemStackToSlots(itemStack, playerInventorySlots, simulate)
|
remaining = QuickMoveInput.moveItemStackToSlots(itemStack, playerInventorySlots, simulate)
|
||||||
remaining = view.insertStack(ItemStorageStack(remaining), simulate).toItemStack()
|
remaining = view.insertStack(ItemStorageStack(remaining), simulate).toItemStack()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,7 +185,7 @@ class ItemMonitorMenu(
|
|||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
|
|
||||||
remainder = moveItemStackToSlots(remainder, playerInventorySlots)
|
remainder = QuickMoveInput.moveItemStackToSlots(remainder, playerInventorySlots)
|
||||||
|
|
||||||
slots[slotIndex].set(remainder)
|
slots[slotIndex].set(remainder)
|
||||||
return if (remainder.count != item.count) item else ItemStack.EMPTY
|
return if (remainder.count != item.count) item else ItemStack.EMPTY
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user