Exopack arbitrary inventory slots charging
This commit is contained in:
parent
344364520d
commit
37f4b77994
@ -118,6 +118,7 @@ private fun sounds(provider: MatteryLanguageProvider) {
|
|||||||
private fun misc(provider: MatteryLanguageProvider) {
|
private fun misc(provider: MatteryLanguageProvider) {
|
||||||
with(provider.english) {
|
with(provider.english) {
|
||||||
gui("help.slot_filters", "Hold CTRL to setup slot filters")
|
gui("help.slot_filters", "Hold CTRL to setup slot filters")
|
||||||
|
gui("help.slot_charging", "Hold ALT to switch slot charging")
|
||||||
|
|
||||||
misc("needs_no_power", "Requires no power to operate")
|
misc("needs_no_power", "Requires no power to operate")
|
||||||
|
|
||||||
|
@ -126,6 +126,7 @@ private fun sounds(provider: MatteryLanguageProvider) {
|
|||||||
private fun misc(provider: MatteryLanguageProvider) {
|
private fun misc(provider: MatteryLanguageProvider) {
|
||||||
with(provider.russian) {
|
with(provider.russian) {
|
||||||
gui("help.slot_filters", "Удерживайте CTRL для настройки фильтрации слотов")
|
gui("help.slot_filters", "Удерживайте CTRL для настройки фильтрации слотов")
|
||||||
|
gui("help.slot_charging", "Удерживайте ALT для переключения зарядки слотов")
|
||||||
|
|
||||||
misc("needs_no_power", "Не требует энергии для работы")
|
misc("needs_no_power", "Не требует энергии для работы")
|
||||||
|
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package ru.dbotthepony.mc.otm.capability
|
package ru.dbotthepony.mc.otm.capability
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||||
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.commands.Commands
|
import net.minecraft.commands.Commands
|
||||||
import net.minecraft.commands.arguments.EntityArgument
|
import net.minecraft.commands.arguments.EntityArgument
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
|
import net.minecraft.nbt.ByteTag
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
|
import net.minecraft.nbt.IntTag
|
||||||
import net.minecraft.nbt.ListTag
|
import net.minecraft.nbt.ListTag
|
||||||
import net.minecraft.nbt.StringTag
|
import net.minecraft.nbt.StringTag
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
@ -72,6 +75,7 @@ import ru.dbotthepony.mc.otm.client.minecraft
|
|||||||
import ru.dbotthepony.mc.otm.config.AndroidConfig
|
import ru.dbotthepony.mc.otm.config.AndroidConfig
|
||||||
import ru.dbotthepony.mc.otm.config.ExopackConfig
|
import ru.dbotthepony.mc.otm.config.ExopackConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||||
|
import ru.dbotthepony.mc.otm.container.get
|
||||||
import ru.dbotthepony.mc.otm.container.iterator
|
import ru.dbotthepony.mc.otm.container.iterator
|
||||||
import ru.dbotthepony.mc.otm.container.stream
|
import ru.dbotthepony.mc.otm.container.stream
|
||||||
import ru.dbotthepony.mc.otm.container.vanishCursedItems
|
import ru.dbotthepony.mc.otm.container.vanishCursedItems
|
||||||
@ -80,14 +84,18 @@ import ru.dbotthepony.mc.otm.core.collect.UUIDIntModifiersMap
|
|||||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||||
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.getByteList
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
|
||||||
|
import ru.dbotthepony.mc.otm.core.nbt.getIntList
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.getStringList
|
import ru.dbotthepony.mc.otm.core.nbt.getStringList
|
||||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.IntValueCodec
|
import ru.dbotthepony.mc.otm.core.util.IntValueCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.ItemValueCodec
|
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.TickList
|
import ru.dbotthepony.mc.otm.core.util.TickList
|
||||||
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.network.synchronizer.FieldSynchronizer
|
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
|
||||||
@ -224,6 +232,27 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
synchronizer.Field(null, ItemValueCodec.nullable)
|
synchronizer.Field(null, ItemValueCodec.nullable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val regularSlotChargeFlag = immutableList(Inventory.INVENTORY_SIZE + 4) {
|
||||||
|
synchronizer.bool()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun slotChargeToDefault() {
|
||||||
|
// броня
|
||||||
|
regularSlotChargeFlag[36].boolean = true
|
||||||
|
regularSlotChargeFlag[37].boolean = true
|
||||||
|
regularSlotChargeFlag[38].boolean = true
|
||||||
|
regularSlotChargeFlag[39].boolean = true
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
slotChargeToDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
val exoPackSlotsChargeFlag by synchronizer.Set(
|
||||||
|
codec = VarIntValueCodec,
|
||||||
|
backingSet = IntAVLTreeSet(),
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exopack container, which actually store items inside Exopack
|
* Exopack container, which actually store items inside Exopack
|
||||||
*/
|
*/
|
||||||
@ -808,6 +837,18 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tag["regularSlotChargeFlag"] = ListTag().also {
|
||||||
|
for (flag in regularSlotChargeFlag) {
|
||||||
|
it.add(ByteTag.valueOf(flag.boolean))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tag["exoPackSlotsChargeFlag"] = ListTag().also {
|
||||||
|
for (value in exoPackSlotsChargeFlag) {
|
||||||
|
it.add(IntTag.valueOf(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return tag
|
return tag
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -818,6 +859,14 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
filter.value = null
|
filter.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (flag in regularSlotChargeFlag) {
|
||||||
|
flag.boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
|
exoPackSlotsChargeFlag.clear()
|
||||||
|
|
||||||
|
slotChargeToDefault()
|
||||||
|
|
||||||
val regularSlotFilters = tag.getStringList("regularSlotFilters")
|
val regularSlotFilters = tag.getStringList("regularSlotFilters")
|
||||||
|
|
||||||
for (i in 0 until regularSlotFilters.size.coerceAtMost(this.regularSlotFilters.size)) {
|
for (i in 0 until regularSlotFilters.size.coerceAtMost(this.regularSlotFilters.size)) {
|
||||||
@ -826,6 +875,16 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
this.regularSlotFilters[i].value = ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(path) ?: continue) ?: Items.AIR
|
this.regularSlotFilters[i].value = ForgeRegistries.ITEMS.getValue(ResourceLocation.tryParse(path) ?: continue) ?: Items.AIR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val regularSlotChargeFlag = tag.getByteList("regularSlotChargeFlag")
|
||||||
|
|
||||||
|
for (i in 0 until regularSlotChargeFlag.size.coerceAtMost(this.regularSlotChargeFlag.size)) {
|
||||||
|
this.regularSlotChargeFlag[i].boolean = regularSlotChargeFlag[i].asInt > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
for (v in tag.getIntList("exoPackSlotsChargeFlag")) {
|
||||||
|
this.exoPackSlotsChargeFlag.add(v.asInt)
|
||||||
|
}
|
||||||
|
|
||||||
// iterations
|
// iterations
|
||||||
deathLog.clear()
|
deathLog.clear()
|
||||||
|
|
||||||
@ -965,9 +1024,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
if (isExoPackSmeltingInstalled)
|
if (isExoPackSmeltingInstalled)
|
||||||
smelters.forEach { it.think() }
|
smelters.forEach { it.think() }
|
||||||
|
|
||||||
if (!exoPackChargeSlots.isEmpty && exoPackEnergy.batteryLevel.isPositive) {
|
if (exoPackEnergy.batteryLevel.isPositive) {
|
||||||
var available = exoPackEnergy.extractEnergy(exoPackEnergy.batteryLevel, true)
|
var available = exoPackEnergy.extractEnergy(exoPackEnergy.batteryLevel, true)
|
||||||
|
|
||||||
|
if (!exoPackChargeSlots.isEmpty) {
|
||||||
for (item in exoPackChargeSlots) {
|
for (item in exoPackChargeSlots) {
|
||||||
if (item.isNotEmpty) {
|
if (item.isNotEmpty) {
|
||||||
item.energy?.let {
|
item.energy?.let {
|
||||||
@ -978,6 +1038,39 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (available.isPositive) {
|
||||||
|
for ((i, flag) in regularSlotChargeFlag.withIndex()) {
|
||||||
|
if (flag.boolean) {
|
||||||
|
val item = ply.inventory[i]
|
||||||
|
|
||||||
|
if (item.isNotEmpty) {
|
||||||
|
item.energy?.let {
|
||||||
|
available -= exoPackEnergy.extractEnergy(it.receiveEnergy(available, false), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!available.isPositive) break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (available.isPositive) {
|
||||||
|
for (slot in exoPackSlotsChargeFlag) {
|
||||||
|
if (slot in 0 until exoPackContainer.containerSize) {
|
||||||
|
val item = exoPackContainer[slot]
|
||||||
|
|
||||||
|
if (item.isNotEmpty) {
|
||||||
|
item.energy?.let {
|
||||||
|
available -= exoPackEnergy.extractEnergy(it.receiveEnergy(available, false), false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!available.isPositive) break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ fun Window.isKeyDown(key: Int) = InputConstants.isKeyDown(window, key)
|
|||||||
|
|
||||||
val Window.isShiftDown get() = isKeyDown(InputConstants.KEY_LSHIFT) || isKeyDown(InputConstants.KEY_RSHIFT)
|
val Window.isShiftDown get() = isKeyDown(InputConstants.KEY_LSHIFT) || isKeyDown(InputConstants.KEY_RSHIFT)
|
||||||
val Window.isCtrlDown get() = isKeyDown(InputConstants.KEY_RCONTROL) || isKeyDown(InputConstants.KEY_LCONTROL)
|
val Window.isCtrlDown get() = isKeyDown(InputConstants.KEY_RCONTROL) || isKeyDown(InputConstants.KEY_LCONTROL)
|
||||||
|
val Window.isAltDown get() = isKeyDown(InputConstants.KEY_RALT) || isKeyDown(InputConstants.KEY_LALT)
|
||||||
|
|
||||||
object ShiftPressedCond : BooleanSupplier {
|
object ShiftPressedCond : BooleanSupplier {
|
||||||
override fun getAsBoolean(): Boolean {
|
override fun getAsBoolean(): Boolean {
|
||||||
|
@ -13,7 +13,7 @@ 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.BatterySlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.InventorySlotPanel
|
||||||
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.BackgroundPanel
|
||||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel
|
||||||
@ -55,7 +55,7 @@ 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)
|
||||||
|
|
||||||
frame.makeHelpButton().addSlotFiltersHelp()
|
frame.makeHelpButton().addSlotFiltersHelp().tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))
|
||||||
|
|
||||||
val hotbarStrip = EditablePanel(this, frame, height = 18f)
|
val hotbarStrip = EditablePanel(this, frame, height = 18f)
|
||||||
hotbarStrip.dock = Dock.BOTTOM
|
hotbarStrip.dock = Dock.BOTTOM
|
||||||
@ -92,7 +92,7 @@ class ExoPackInventoryScreen(menu: ExoPackInventoryMenu) : MatteryScreen<ExoPack
|
|||||||
mainInventoryLine.dock = Dock.BOTTOM
|
mainInventoryLine.dock = Dock.BOTTOM
|
||||||
|
|
||||||
for (slot in menu.playerHotbarSlots) {
|
for (slot in menu.playerHotbarSlots) {
|
||||||
UserFilteredSlotPanel.of(this, hotbarStrip, slot).also {
|
InventorySlotPanel(this, hotbarStrip, slot).also {
|
||||||
it.dock = Dock.LEFT
|
it.dock = Dock.LEFT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,42 @@
|
|||||||
package ru.dbotthepony.mc.otm.client.screen
|
package ru.dbotthepony.mc.otm.client.screen
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem
|
import com.mojang.blaze3d.systems.RenderSystem
|
||||||
import com.mojang.blaze3d.vertex.PoseStack
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
|
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||||
import net.minecraft.ChatFormatting
|
import net.minecraft.ChatFormatting
|
||||||
import net.minecraft.client.gui.Font
|
import net.minecraft.client.gui.Font
|
||||||
import net.minecraft.client.gui.GuiGraphics
|
import net.minecraft.client.gui.GuiGraphics
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen
|
||||||
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.Item
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraftforge.client.ForgeHooksClient
|
|
||||||
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 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.render.clearDepth
|
|
||||||
import ru.dbotthepony.mc.otm.client.render.translation
|
import ru.dbotthepony.mc.otm.client.render.translation
|
||||||
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.UserFilteredSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.InventorySlotPanel
|
||||||
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.config.ClientConfig
|
||||||
|
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||||
import ru.dbotthepony.mc.otm.core.math.component1
|
import ru.dbotthepony.mc.otm.core.math.component1
|
||||||
import ru.dbotthepony.mc.otm.core.math.component2
|
import ru.dbotthepony.mc.otm.core.math.component2
|
||||||
import ru.dbotthepony.mc.otm.core.math.component3
|
|
||||||
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 java.util.Collections
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayDeque
|
||||||
|
import kotlin.collections.List
|
||||||
|
import kotlin.collections.MutableSet
|
||||||
|
import kotlin.collections.indices
|
||||||
|
import kotlin.collections.isNotEmpty
|
||||||
|
import kotlin.collections.withIndex
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class encapsulate most of logic for handling EditablePanel and it's children.
|
* This class encapsulate most of logic for handling EditablePanel and it's children.
|
||||||
@ -151,12 +152,13 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
if (menu.playerInventorySlots.isNotEmpty() && menu.autoCreateInventoryFrame) {
|
if (menu.playerInventorySlots.isNotEmpty() && menu.autoCreateInventoryFrame) {
|
||||||
if (menu.playerExoSuitSlots.isEmpty()) {
|
if (menu.playerExoSuitSlots.isEmpty()) {
|
||||||
inventoryFrame = FramePanel<MatteryScreen<*>>(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH, INVENTORY_FRAME_HEIGHT, inventory.displayName).also(this::addPanel)
|
inventoryFrame = FramePanel<MatteryScreen<*>>(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH, INVENTORY_FRAME_HEIGHT, inventory.displayName).also(this::addPanel)
|
||||||
|
inventoryFrame!!.makeHelpButton().addSlotFiltersHelp().tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))
|
||||||
|
|
||||||
val hotbarStrip = EditablePanel(this, inventoryFrame, height = AbstractSlotPanel.SIZE)
|
val hotbarStrip = EditablePanel(this, inventoryFrame, height = AbstractSlotPanel.SIZE)
|
||||||
hotbarStrip.dock = Dock.BOTTOM
|
hotbarStrip.dock = Dock.BOTTOM
|
||||||
|
|
||||||
for (slot in menu.playerHotbarSlots) {
|
for (slot in menu.playerHotbarSlots) {
|
||||||
UserFilteredSlotPanel.of(this, hotbarStrip, slot).also {
|
InventorySlotPanel(this, hotbarStrip, slot).also {
|
||||||
it.dock = Dock.LEFT
|
it.dock = Dock.LEFT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,6 +176,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inventoryFrame = FramePanel<MatteryScreen<*>>(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH_EXTENDED, BASE_INVENTORY_FRAME_HEIGHT + AbstractSlotPanel.SIZE * inventoryRows, inventory.displayName).also(this::addPanel)
|
inventoryFrame = FramePanel<MatteryScreen<*>>(this, null, 0f, 0f, INVENTORY_FRAME_WIDTH_EXTENDED, BASE_INVENTORY_FRAME_HEIGHT + AbstractSlotPanel.SIZE * inventoryRows, inventory.displayName).also(this::addPanel)
|
||||||
|
inventoryFrame!!.makeHelpButton().addSlotFiltersHelp().tooltips.add(TranslatableComponent("otm.gui.help.slot_charging"))
|
||||||
|
|
||||||
inventoryScrollbar = DiscreteScrollBarPanel(this, inventoryFrame, { integerDivisionDown(menu.playerCombinedInventorySlots.size, 9) }, {
|
inventoryScrollbar = DiscreteScrollBarPanel(this, inventoryFrame, { integerDivisionDown(menu.playerCombinedInventorySlots.size, 9) }, {
|
||||||
_, old, new ->
|
_, old, new ->
|
||||||
@ -206,7 +209,7 @@ 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) {
|
||||||
UserFilteredSlotPanel.of(this, hotbarStrip, slot).also {
|
InventorySlotPanel(this, hotbarStrip, slot).also {
|
||||||
it.dock = Dock.LEFT
|
it.dock = Dock.LEFT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -249,7 +252,7 @@ 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 = menu.playerCombinedInventorySlots[offset + i]
|
val slot = menu.playerCombinedInventorySlots[offset + i]
|
||||||
|
|
||||||
object : UserFilteredSlotPanel<MatteryScreen<*>, Slot>(this@MatteryScreen, canvas, slot) {
|
object : InventorySlotPanel<MatteryScreen<*>, MatteryMenu.InventorySlot>(this@MatteryScreen, canvas, slot) {
|
||||||
init {
|
init {
|
||||||
dock = Dock.LEFT
|
dock = Dock.LEFT
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import ru.dbotthepony.mc.otm.client.minecraft
|
|||||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
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.FoldableSlotPanel
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.FoldableSlotPanel
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.slot.InventorySlotPanel
|
||||||
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.BackgroundPanel
|
||||||
import ru.dbotthepony.mc.otm.compat.cos.CosmeticToggleButton
|
import ru.dbotthepony.mc.otm.compat.cos.CosmeticToggleButton
|
||||||
@ -64,10 +65,10 @@ open class PlayerEquipmentPanel<S : MatteryScreen<*>>(
|
|||||||
|
|
||||||
for ((slot, cosmeticSlot) in armorSlots) {
|
for ((slot, cosmeticSlot) in armorSlots) {
|
||||||
if (cosmeticSlot == null) {
|
if (cosmeticSlot == null) {
|
||||||
SlotPanel(screen, armorSlotsStrip, slot).dock = Dock.TOP
|
InventorySlotPanel(screen, armorSlotsStrip, slot).dock = Dock.TOP
|
||||||
} else {
|
} else {
|
||||||
FoldableSlotPanel(screen, armorSlotsStrip,
|
FoldableSlotPanel(screen, armorSlotsStrip,
|
||||||
SlotPanel(screen, null, slot).also { CosmeticToggleButton(screen, it, slot.type) },
|
InventorySlotPanel(screen, null, slot).also { CosmeticToggleButton(screen, it, slot.type) },
|
||||||
listOf(SlotPanel(screen, null, cosmeticSlot))).dock = Dock.TOP
|
listOf(SlotPanel(screen, null, cosmeticSlot))).dock = Dock.TOP
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.client.screen.panels.slot
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.InputConstants
|
||||||
|
import net.minecraft.client.gui.GuiGraphics
|
||||||
|
import net.minecraft.world.item.Item
|
||||||
|
import ru.dbotthepony.mc.otm.client.isAltDown
|
||||||
|
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.Widgets18
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||||
|
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||||
|
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||||
|
|
||||||
|
open class InventorySlotPanel<out S : MatteryScreen<*>, out T : MatteryMenu.InventorySlot>(
|
||||||
|
screen: S,
|
||||||
|
parent: EditablePanel<*>?,
|
||||||
|
slot: T,
|
||||||
|
x: Float = 0f,
|
||||||
|
y: Float = 0f,
|
||||||
|
noItemIcon: MatterySprite? = null
|
||||||
|
) : UserFilteredSlotPanel<S, T>(screen, parent, slot, x, y, SIZE, SIZE, noItemIcon) {
|
||||||
|
override var slotFilter: Item?
|
||||||
|
get() = slot.filter?.get()
|
||||||
|
set(value) { slot.filter?.accept(value) }
|
||||||
|
|
||||||
|
override fun renderSlotBackground(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||||
|
super.renderSlotBackground(graphics, mouseX, mouseY, partialTick)
|
||||||
|
|
||||||
|
if (slot.chargeFlag?.get() == true) {
|
||||||
|
Widgets18.BATTERY_SLOT_BACKGROUND.render(graphics, 0f, 0f, width, height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||||
|
if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isAltDown) {
|
||||||
|
val chargeFlag = slot.chargeFlag
|
||||||
|
|
||||||
|
if (chargeFlag == null) {
|
||||||
|
return super.mouseClickedInner(x, y, button)
|
||||||
|
} else {
|
||||||
|
chargeFlag.accept(!chargeFlag.get())
|
||||||
|
playGuiClickSound()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.mouseClickedInner(x, y, button)
|
||||||
|
}
|
||||||
|
}
|
@ -262,20 +262,40 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
|||||||
return super.isSameInventory(other)
|
return super.isSameInventory(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var chargeFlag: GetterSetter<Boolean>? = null
|
||||||
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val mattery = ply.matteryPlayer
|
val mattery = ply.matteryPlayer
|
||||||
|
|
||||||
if (mattery != null) {
|
if (mattery != null) {
|
||||||
if (container === inventory && slotIndex in mattery.regularSlotFilters.indices) {
|
if (container === inventory) {
|
||||||
|
if (slotIndex in mattery.regularSlotFilters.indices)
|
||||||
filter = GetterSetter.of(
|
filter = GetterSetter.of(
|
||||||
getter = { mattery.regularSlotFilters[slotIndex].value },
|
getter = { mattery.regularSlotFilters[slotIndex].value },
|
||||||
setter = { MatteryPlayerNetworkChannel.sendToServer(SetInventoryFilterPacket(SetInventoryFilterPacket.Type.INVENTORY, slotIndex, it)) }
|
setter = { MatteryPlayerNetworkChannel.sendToServer(SetInventoryFilterPacket(SetInventoryFilterPacket.Type.INVENTORY, slotIndex, it)) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (slotIndex in mattery.regularSlotChargeFlag.indices) {
|
||||||
|
val input = booleanInput(true) { mattery.regularSlotChargeFlag[slotIndex].boolean = it }
|
||||||
|
|
||||||
|
chargeFlag = GetterSetter.of(
|
||||||
|
getter = { mattery.regularSlotChargeFlag[slotIndex].boolean },
|
||||||
|
setter = input::input
|
||||||
|
)
|
||||||
|
}
|
||||||
} else if (container === mattery.exoPackContainer) {
|
} else if (container === mattery.exoPackContainer) {
|
||||||
filter = GetterSetter.of(
|
filter = GetterSetter.of(
|
||||||
getter = { mattery.exoPackContainer.getSlotFilter(slotIndex) },
|
getter = { mattery.exoPackContainer.getSlotFilter(slotIndex) },
|
||||||
setter = { MatteryPlayerNetworkChannel.sendToServer(SetInventoryFilterPacket(SetInventoryFilterPacket.Type.EXOPACK, slotIndex, it)) }
|
setter = { MatteryPlayerNetworkChannel.sendToServer(SetInventoryFilterPacket(SetInventoryFilterPacket.Type.EXOPACK, slotIndex, it)) }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val input = booleanInput(true) { if (it) mattery.exoPackSlotsChargeFlag.add(slotIndex) else mattery.exoPackSlotsChargeFlag.remove(slotIndex) }
|
||||||
|
|
||||||
|
chargeFlag = GetterSetter.of(
|
||||||
|
getter = { slotIndex in mattery.exoPackSlotsChargeFlag },
|
||||||
|
setter = input::input
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
filter = null
|
filter = null
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package ru.dbotthepony.mc.otm.network.synchronizer
|
package ru.dbotthepony.mc.otm.network.synchronizer
|
||||||
|
|
||||||
enum class MapAction {
|
enum class ChangesetAction {
|
||||||
CLEAR, ADD, REMOVE
|
CLEAR, ADD, REMOVE
|
||||||
}
|
}
|
@ -349,6 +349,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
|
|
||||||
// use LinkedList because it is ensured memory is freed on LinkedList#clear
|
// use LinkedList because it is ensured memory is freed on LinkedList#clear
|
||||||
private val mapBacklogs = Reference2ObjectOpenHashMap<Map<*, *>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
|
private val mapBacklogs = Reference2ObjectOpenHashMap<Map<*, *>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
|
||||||
|
private val setBacklogs = Reference2ObjectOpenHashMap<Set<*>, LinkedList<Pair<Any?, (DataOutputStream) -> Unit>>>()
|
||||||
|
|
||||||
var unused: Boolean = false
|
var unused: Boolean = false
|
||||||
private set
|
private set
|
||||||
@ -401,6 +402,24 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun <K, V> removeMapBacklog(map: Map<K, V>) {
|
||||||
|
mapBacklogs.remove(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <V> getSetBacklog(set: Set<V>): LinkedList<Pair<Any?, (DataOutputStream) -> Unit>> {
|
||||||
|
if (unused) {
|
||||||
|
return LinkedList()
|
||||||
|
}
|
||||||
|
|
||||||
|
return setBacklogs.computeIfAbsent(set, Reference2ObjectFunction {
|
||||||
|
LinkedList()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <V> removeSetBacklog(set: Set<V>) {
|
||||||
|
setBacklogs.remove(set)
|
||||||
|
}
|
||||||
|
|
||||||
fun collectNetworkPayload(): FastByteArrayOutputStream? {
|
fun collectNetworkPayload(): FastByteArrayOutputStream? {
|
||||||
if (unused || dirtyFields.isEmpty()) {
|
if (unused || dirtyFields.isEmpty()) {
|
||||||
return null
|
return null
|
||||||
@ -1527,6 +1546,246 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inner class Set<E>(
|
||||||
|
private val codec: IStreamCodec<E>,
|
||||||
|
private val backingSet: MutableSet<E>,
|
||||||
|
private val callback: ((changes: Collection<SetChangeset<E>>) -> Unit)? = null,
|
||||||
|
) : AbstractField<MutableSet<E>>() {
|
||||||
|
private var isRemote = false
|
||||||
|
private var isDirty = false
|
||||||
|
|
||||||
|
private fun pushBacklog(element: E, action: (DataOutputStream) -> Unit) {
|
||||||
|
check(!isRemote) { "Field marked as remote" }
|
||||||
|
|
||||||
|
val pair = element to action
|
||||||
|
|
||||||
|
forEachEndpoint {
|
||||||
|
val list = it.getSetBacklog(this)
|
||||||
|
val iterator = list.listIterator()
|
||||||
|
|
||||||
|
for (value in iterator) {
|
||||||
|
if (value.first == element) {
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list.addLast(pair)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun observe(): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove() {
|
||||||
|
if (!isRemoved) {
|
||||||
|
forEachEndpoint { it.removeSetBacklog(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
super.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun markDirty() {
|
||||||
|
check(!isRemoved) { "Field was removed" }
|
||||||
|
notifyEndpoints(this)
|
||||||
|
isDirty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun markDirty(endpoint: Endpoint) {
|
||||||
|
super.markDirty(endpoint)
|
||||||
|
|
||||||
|
endpoint.getSetBacklog(this).let {
|
||||||
|
it.clear()
|
||||||
|
it.add(null to ClearBacklogEntry)
|
||||||
|
|
||||||
|
for (value in backingSet) {
|
||||||
|
it.add(value to { it.write(ChangesetAction.ADD.ordinal + 1); codec.write(it, value) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val value: MutableSet<E> = object : MutableSet<E> {
|
||||||
|
override fun add(element: E): Boolean {
|
||||||
|
if (backingSet.add(element)) {
|
||||||
|
if (!isRemote) {
|
||||||
|
markDirty()
|
||||||
|
|
||||||
|
pushBacklog(element) {
|
||||||
|
it.write(ChangesetAction.ADD.ordinal + 1)
|
||||||
|
codec.write(it, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addAll(elements: Collection<E>): Boolean {
|
||||||
|
var any = false
|
||||||
|
elements.forEach { any = add(it) || any }
|
||||||
|
return any
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clear() {
|
||||||
|
if (backingSet.isNotEmpty()) {
|
||||||
|
backingSet.clear()
|
||||||
|
|
||||||
|
if (!isRemote) {
|
||||||
|
markDirty()
|
||||||
|
|
||||||
|
forEachEndpoint {
|
||||||
|
it.getSetBacklog(this@Set).let {
|
||||||
|
it.clear()
|
||||||
|
it.add(null to ClearBacklogEntry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun iterator(): MutableIterator<E> {
|
||||||
|
return object : MutableIterator<E> {
|
||||||
|
private val parent = backingSet.iterator()
|
||||||
|
private var lastElement: Any? = Mark
|
||||||
|
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return parent.hasNext()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun next(): E {
|
||||||
|
return parent.next().also { lastElement = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove() {
|
||||||
|
parent.remove()
|
||||||
|
val lastElement = lastElement
|
||||||
|
|
||||||
|
if (lastElement !== Mark) {
|
||||||
|
this.lastElement = Mark
|
||||||
|
|
||||||
|
if (!isRemote) {
|
||||||
|
markDirty()
|
||||||
|
|
||||||
|
pushBacklog(lastElement as E) {
|
||||||
|
it.write(ChangesetAction.REMOVE.ordinal + 1)
|
||||||
|
codec.write(it, lastElement as E)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun remove(element: E): Boolean {
|
||||||
|
if (backingSet.remove(element)) {
|
||||||
|
if (!isRemote) {
|
||||||
|
markDirty()
|
||||||
|
|
||||||
|
pushBacklog(element) {
|
||||||
|
it.write(ChangesetAction.REMOVE.ordinal + 1)
|
||||||
|
codec.write(it, element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeAll(elements: Collection<E>): Boolean {
|
||||||
|
var any = false
|
||||||
|
elements.forEach { any = remove(it) || any }
|
||||||
|
return any
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun retainAll(elements: Collection<E>): Boolean {
|
||||||
|
var any = false
|
||||||
|
|
||||||
|
val iterator = iterator()
|
||||||
|
|
||||||
|
for (value in iterator) {
|
||||||
|
if (value !in elements) {
|
||||||
|
any = true
|
||||||
|
iterator.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return any
|
||||||
|
}
|
||||||
|
|
||||||
|
override val size: Int
|
||||||
|
get() = backingSet.size
|
||||||
|
|
||||||
|
override fun contains(element: E): Boolean {
|
||||||
|
return element in backingSet
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun containsAll(elements: Collection<E>): Boolean {
|
||||||
|
return backingSet.containsAll(elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isEmpty(): Boolean {
|
||||||
|
return backingSet.isEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(stream: DataOutputStream, endpoint: Endpoint) {
|
||||||
|
val list = endpoint.getSetBacklog(this)
|
||||||
|
|
||||||
|
for (value in list) {
|
||||||
|
value.second.invoke(stream)
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.write(0)
|
||||||
|
list.clear()
|
||||||
|
isDirty = false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun read(stream: DataInputStream) {
|
||||||
|
if (!isRemote) {
|
||||||
|
isRemote = true
|
||||||
|
forEachEndpoint { it.removeSetBacklog(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
isDirty = false
|
||||||
|
|
||||||
|
var action = stream.read()
|
||||||
|
val changeset = LinkedList<SetChangeset<E>>()
|
||||||
|
|
||||||
|
while (action != 0) {
|
||||||
|
if ((action - 1) !in ChangesetActionList.indices) {
|
||||||
|
throw IllegalArgumentException("Unknown changeset action with index ${action - 1}")
|
||||||
|
}
|
||||||
|
|
||||||
|
when (ChangesetActionList[action - 1]) {
|
||||||
|
ChangesetAction.CLEAR -> {
|
||||||
|
changeset.add(SetChangeset(ChangesetAction.CLEAR, null))
|
||||||
|
backingSet.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangesetAction.ADD -> {
|
||||||
|
val read = codec.read(stream)
|
||||||
|
changeset.add(SetChangeset(ChangesetAction.ADD, read))
|
||||||
|
backingSet.add(read)
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangesetAction.REMOVE -> {
|
||||||
|
val read = codec.read(stream)
|
||||||
|
changeset.add(SetChangeset(ChangesetAction.REMOVE, read))
|
||||||
|
backingSet.remove(read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action = stream.read()
|
||||||
|
}
|
||||||
|
|
||||||
|
callback?.invoke(changeset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inner class Map<K, V>(
|
inner class Map<K, V>(
|
||||||
private val keyCodec: IStreamCodec<K>,
|
private val keyCodec: IStreamCodec<K>,
|
||||||
private val valueCodec: IStreamCodec<V>,
|
private val valueCodec: IStreamCodec<V>,
|
||||||
@ -1545,17 +1804,19 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun pushBacklog(key: Any?, value: (DataOutputStream) -> Unit) {
|
private fun pushBacklog(key: Any?, value: (DataOutputStream) -> Unit) {
|
||||||
|
val pair = key to value
|
||||||
|
|
||||||
forEachEndpoint {
|
forEachEndpoint {
|
||||||
val list = it.getMapBacklog(this)
|
val list = it.getMapBacklog(this)
|
||||||
val iterator = list.listIterator()
|
val iterator = list.listIterator()
|
||||||
|
|
||||||
for (pair in iterator) {
|
for (e in iterator) {
|
||||||
if (pair.first == key) {
|
if (e.first == key) {
|
||||||
iterator.remove()
|
iterator.remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list.addLast(key to value)
|
list.addLast(pair)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1582,7 +1843,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
val valueCopy = valueCodec.copy(value)
|
val valueCopy = valueCodec.copy(value)
|
||||||
|
|
||||||
pushBacklog(key) {
|
pushBacklog(key) {
|
||||||
it.write(MapAction.ADD.ordinal + 1)
|
it.write(ChangesetAction.ADD.ordinal + 1)
|
||||||
keyCodec.write(it, key)
|
keyCodec.write(it, key)
|
||||||
valueCodec.write(it, valueCopy)
|
valueCodec.write(it, valueCopy)
|
||||||
}
|
}
|
||||||
@ -1631,7 +1892,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
val valueCopy = valueCodec.copy(value)
|
val valueCopy = valueCodec.copy(value)
|
||||||
|
|
||||||
val action = { it: DataOutputStream ->
|
val action = { it: DataOutputStream ->
|
||||||
it.write(MapAction.ADD.ordinal + 1)
|
it.write(ChangesetAction.ADD.ordinal + 1)
|
||||||
keyCodec.write(it, key)
|
keyCodec.write(it, key)
|
||||||
valueCodec.write(it, valueCopy)
|
valueCodec.write(it, valueCopy)
|
||||||
}
|
}
|
||||||
@ -1660,7 +1921,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
val valueCopy = valueCodec.copy(value)
|
val valueCopy = valueCodec.copy(value)
|
||||||
|
|
||||||
backlog.add(key to {
|
backlog.add(key to {
|
||||||
it.write(MapAction.ADD.ordinal + 1)
|
it.write(ChangesetAction.ADD.ordinal + 1)
|
||||||
keyCodec.write(it, key)
|
keyCodec.write(it, key)
|
||||||
valueCodec.write(it, valueCopy)
|
valueCodec.write(it, valueCopy)
|
||||||
})
|
})
|
||||||
@ -1707,7 +1968,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
|
|
||||||
pushBacklog(key) {
|
pushBacklog(key) {
|
||||||
@Suppress("BlockingMethodInNonBlockingContext") // false positive
|
@Suppress("BlockingMethodInNonBlockingContext") // false positive
|
||||||
it.write(MapAction.ADD.ordinal + 1)
|
it.write(ChangesetAction.ADD.ordinal + 1)
|
||||||
keyCodec.write(it, key)
|
keyCodec.write(it, key)
|
||||||
valueCodec.write(it, valueCopy)
|
valueCodec.write(it, valueCopy)
|
||||||
}
|
}
|
||||||
@ -1735,7 +1996,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
|
|
||||||
pushBacklog(key) {
|
pushBacklog(key) {
|
||||||
@Suppress("BlockingMethodInNonBlockingContext") // false positive
|
@Suppress("BlockingMethodInNonBlockingContext") // false positive
|
||||||
it.write(MapAction.REMOVE.ordinal + 1)
|
it.write(ChangesetAction.REMOVE.ordinal + 1)
|
||||||
keyCodec.write(it, keyCopy)
|
keyCodec.write(it, keyCopy)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1767,7 +2028,7 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
override fun read(stream: DataInputStream) {
|
override fun read(stream: DataInputStream) {
|
||||||
if (!isRemote) {
|
if (!isRemote) {
|
||||||
isRemote = true
|
isRemote = true
|
||||||
clearBacklog()
|
forEachEndpoint { it.removeMapBacklog(this) }
|
||||||
observingBackingMap?.clear()
|
observingBackingMap?.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1777,27 +2038,27 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
var readAction = stream.read() - 1
|
var readAction = stream.read() - 1
|
||||||
|
|
||||||
while (readAction != -1) {
|
while (readAction != -1) {
|
||||||
if (readAction >= MapActionList.size) {
|
if (readAction >= ChangesetActionList.size) {
|
||||||
throw IndexOutOfBoundsException("Unknown map action with ID $readAction")
|
throw IndexOutOfBoundsException("Unknown map action with ID $readAction")
|
||||||
}
|
}
|
||||||
|
|
||||||
when (MapActionList[readAction]) {
|
when (ChangesetActionList[readAction]) {
|
||||||
MapAction.CLEAR -> {
|
ChangesetAction.CLEAR -> {
|
||||||
backingMap.clear()
|
backingMap.clear()
|
||||||
changeset.add(ClearMapChangeset)
|
changeset.add(ClearMapChangeset)
|
||||||
}
|
}
|
||||||
|
|
||||||
MapAction.ADD -> {
|
ChangesetAction.ADD -> {
|
||||||
val key = keyCodec.read(stream)
|
val key = keyCodec.read(stream)
|
||||||
val value = valueCodec.read(stream)
|
val value = valueCodec.read(stream)
|
||||||
backingMap[key] = value
|
backingMap[key] = value
|
||||||
changeset.add(MapChangeset(MapAction.ADD, key, value))
|
changeset.add(MapChangeset(ChangesetAction.ADD, key, value))
|
||||||
}
|
}
|
||||||
|
|
||||||
MapAction.REMOVE -> {
|
ChangesetAction.REMOVE -> {
|
||||||
val key = keyCodec.read(stream)
|
val key = keyCodec.read(stream)
|
||||||
backingMap.remove(key)
|
backingMap.remove(key)
|
||||||
changeset.add(MapChangeset(MapAction.REMOVE, key, null))
|
changeset.add(MapChangeset(ChangesetAction.REMOVE, key, null))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1860,9 +2121,11 @@ class FieldSynchronizer(private val callback: Runnable, private val alwaysCallCa
|
|||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object Mark
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val ClearBacklogEntry = { stream: DataOutputStream -> stream.write(MapAction.CLEAR.ordinal + 1) }
|
private val ClearBacklogEntry = { stream: DataOutputStream -> stream.write(ChangesetAction.CLEAR.ordinal + 1) }
|
||||||
private val MapActionList = MapAction.values()
|
private val ChangesetActionList = ChangesetAction.values()
|
||||||
private val ClearMapChangeset = MapChangeset(MapAction.CLEAR, null, null)
|
private val ClearMapChangeset = MapChangeset(ChangesetAction.CLEAR, null, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
package ru.dbotthepony.mc.otm.network.synchronizer
|
package ru.dbotthepony.mc.otm.network.synchronizer
|
||||||
|
|
||||||
data class MapChangeset<out K, out V>(
|
data class MapChangeset<out K, out V>(
|
||||||
val action: MapAction,
|
val action: ChangesetAction,
|
||||||
val key: K?,
|
val key: K?,
|
||||||
val value: V?
|
val value: V?
|
||||||
) {
|
) {
|
||||||
inline fun map(add: (K, V) -> Unit, remove: (K) -> Unit) {
|
inline fun map(add: (K, V) -> Unit, remove: (K) -> Unit) {
|
||||||
when (action) {
|
when (action) {
|
||||||
MapAction.ADD -> add.invoke(key!!, value!!)
|
ChangesetAction.ADD -> add.invoke(key!!, value!!)
|
||||||
MapAction.REMOVE -> remove.invoke(key!!)
|
ChangesetAction.REMOVE -> remove.invoke(key!!)
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun map(add: (K, V) -> Unit, remove: (K) -> Unit, clear: () -> Unit) {
|
inline fun map(add: (K, V) -> Unit, remove: (K) -> Unit, clear: () -> Unit) {
|
||||||
when (action) {
|
when (action) {
|
||||||
MapAction.CLEAR -> clear.invoke()
|
ChangesetAction.CLEAR -> clear.invoke()
|
||||||
MapAction.ADD -> add.invoke(key!!, value!!)
|
ChangesetAction.ADD -> add.invoke(key!!, value!!)
|
||||||
MapAction.REMOVE -> remove.invoke(key!!)
|
ChangesetAction.REMOVE -> remove.invoke(key!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.network.synchronizer
|
||||||
|
|
||||||
|
data class SetChangeset<out V>(
|
||||||
|
val action: ChangesetAction,
|
||||||
|
val value: V?
|
||||||
|
) {
|
||||||
|
inline fun map(add: (V) -> Unit, remove: (V) -> Unit) {
|
||||||
|
when (action) {
|
||||||
|
ChangesetAction.ADD -> add.invoke(value!!)
|
||||||
|
ChangesetAction.REMOVE -> remove.invoke(value!!)
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun map(add: (V) -> Unit, remove: (V) -> Unit, clear: () -> Unit) {
|
||||||
|
when (action) {
|
||||||
|
ChangesetAction.CLEAR -> clear.invoke()
|
||||||
|
ChangesetAction.ADD -> add.invoke(value!!)
|
||||||
|
ChangesetAction.REMOVE -> remove.invoke(value!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user