Storage bus insert/extract priorities configuration, operation mode, small refactorings

This commit is contained in:
DBotThePony 2023-08-12 01:08:42 +07:00
parent b3249cdcd7
commit f8c2be4d4c
Signed by: DBot
GPG Key ID: DCC23B5715498507
31 changed files with 638 additions and 265 deletions

View File

@ -709,6 +709,11 @@ private fun gui(provider: MatteryLanguageProvider) {
with(provider.english) { with(provider.english) {
gui("quicksearch", "Quick search...") gui("quicksearch", "Quick search...")
gui("insert_priority", "Insert priority")
gui("extract_priority", "Extract priority")
gui("increase", "Increase")
gui("decrease", "Decrease")
gui("color_picker", "Color Picker") gui("color_picker", "Color Picker")
gui("color.short.red", "R") gui("color.short.red", "R")

View File

@ -711,6 +711,11 @@ private fun gui(provider: MatteryLanguageProvider) {
with(provider.russian) { with(provider.russian) {
gui("quicksearch", "Быстрый поиск...") gui("quicksearch", "Быстрый поиск...")
gui("insert_priority", "Приоритет вставки")
gui("extract_priority", "Приоритет забора")
gui("increase", "Увеличить")
gui("decrease", "Уменьшить")
gui("color_picker", "Выбор цвета") gui("color_picker", "Выбор цвета")
gui("color.short.red", "К") gui("color.short.red", "К")

View File

@ -44,6 +44,7 @@ import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.isMekanismLoaded import ru.dbotthepony.mc.otm.capability.isMekanismLoaded
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
import ru.dbotthepony.mc.otm.compat.mekanism.Mekanism2MatteryEnergyWrapper import ru.dbotthepony.mc.otm.compat.mekanism.Mekanism2MatteryEnergyWrapper
import ru.dbotthepony.mc.otm.core.ISubscriptable
import ru.dbotthepony.mc.otm.core.collect.WeakHashSet import ru.dbotthepony.mc.otm.core.collect.WeakHashSet
import ru.dbotthepony.mc.otm.core.forValidRefs import ru.dbotthepony.mc.otm.core.forValidRefs
import ru.dbotthepony.mc.otm.core.get import ru.dbotthepony.mc.otm.core.get
@ -175,9 +176,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
} }
} }
interface SideListener<T> : Supplier<LazyOptional<T>> { interface SideListener<T> : Supplier<LazyOptional<T>>, ISubscriptable<LazyOptional<T>>
fun addListener(listener: Consumer<LazyOptional<T>>)
}
inner class Side(val side: RelativeSide) { inner class Side(val side: RelativeSide) {
init { init {
@ -194,17 +193,16 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
set(value) { set(value) {
if (value !== field) { if (value !== field) {
field = value field = value
listeners.accept(value)
for (tracker in listeners)
tracker.accept(value)
} }
} }
private val listeners = ArrayList<Consumer<LazyOptional<T>>>(0) private val listeners = ISubscriptable.Impl<LazyOptional<T>>()
override fun addListener(listener: Consumer<LazyOptional<T>>) { override fun addListener(listener: Consumer<LazyOptional<T>>): ISubscriptable.L {
listeners.add(listener) val l = listeners.addListener(listener)
listener.accept(value) listener.accept(value)
return l
} }
override fun get(): LazyOptional<T> { override fun get(): LazyOptional<T> {
@ -234,15 +232,16 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
private val mekanism: SubRef<IStrictEnergyHandler>? private val mekanism: SubRef<IStrictEnergyHandler>?
private var actualMekanism: LazyOptional<IEnergyStorage>? = null private var actualMekanism: LazyOptional<IEnergyStorage>? = null
private val listeners = ArrayList<Consumer<LazyOptional<IEnergyStorage>>>() private val listeners = ISubscriptable.Impl<LazyOptional<IEnergyStorage>>()
override fun addListener(listener: Consumer<LazyOptional<IEnergyStorage>>) { override fun addListener(listener: Consumer<LazyOptional<IEnergyStorage>>): ISubscriptable.L {
listeners.add(listener) val l = listeners.addListener(listener)
listener.accept(get()) listener.accept(get())
return l
} }
init { init {
regular.addListener { a -> listeners.forEach { it.accept(a) } } regular.addListener { listeners.accept(it) }
if (isMekanismLoaded) { if (isMekanismLoaded) {
mekanism = track(MatteryCapability.MEKANISM_ENERGY) as SubRef<IStrictEnergyHandler> mekanism = track(MatteryCapability.MEKANISM_ENERGY) as SubRef<IStrictEnergyHandler>
@ -256,7 +255,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
actualMekanism = null actualMekanism = null
} }
listeners.forEach { it.accept(get()) } listeners.accept(get())
} }
} else { } else {
mekanism = null mekanism = null

View File

@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.block.entity
import it.unimi.dsi.fastutil.booleans.BooleanConsumer import it.unimi.dsi.fastutil.booleans.BooleanConsumer
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.core.IBooleanSubscriptable
import ru.dbotthepony.mc.otm.core.ISubscriptable
import ru.dbotthepony.mc.otm.core.nbt.mapString import ru.dbotthepony.mc.otm.core.nbt.mapString
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
@ -11,15 +13,15 @@ interface IRedstoneControlled {
val redstoneControl: AbstractRedstoneControl val redstoneControl: AbstractRedstoneControl
} }
abstract class AbstractRedstoneControl : INBTSerializable<CompoundTag?> { abstract class AbstractRedstoneControl : INBTSerializable<CompoundTag?>, IBooleanSubscriptable {
abstract var redstoneSetting: RedstoneSetting abstract var redstoneSetting: RedstoneSetting
abstract var redstoneSignal: Int abstract var redstoneSignal: Int
protected val listeners = ArrayList<BooleanConsumer>() protected val listeners = IBooleanSubscriptable.Impl()
val isBlockedByRedstone: Boolean get() = !redstoneSetting.test(redstoneSignal) val isBlockedByRedstone: Boolean get() = !redstoneSetting.test(redstoneSignal)
fun addListener(callback: BooleanConsumer) { final override fun addListener(listener: BooleanConsumer): ISubscriptable.L {
listeners.add(callback) return listeners.addListener(listener)
} }
override fun serializeNBT(): CompoundTag { override fun serializeNBT(): CompoundTag {
@ -56,7 +58,7 @@ class RedstoneControl(private val valueChanges: (new: Boolean, old: Boolean) ->
if (state != old) { if (state != old) {
valueChanges.invoke(state, old) valueChanges.invoke(state, old)
listeners.forEach { it.accept(state) } listeners.accept(state)
} }
} }
@ -69,7 +71,7 @@ class RedstoneControl(private val valueChanges: (new: Boolean, old: Boolean) ->
if (state != old) { if (state != old) {
valueChanges.invoke(state, old) valueChanges.invoke(state, old)
listeners.forEach { it.accept(state) } listeners.accept(state)
} }
} }
} }
@ -89,7 +91,7 @@ class SynchronizedRedstoneControl(
if (state != old) { if (state != old) {
valueChanges.invoke(state, old) valueChanges.invoke(state, old)
listeners.forEach { it.accept(state) } listeners.accept(state)
} }
} }
}) })
@ -105,7 +107,7 @@ class SynchronizedRedstoneControl(
if (state != old) { if (state != old) {
valueChanges.invoke(state, old) valueChanges.invoke(state, old)
listeners.forEach { it.accept(state) } listeners.accept(state)
} }
} }
}).property }).property

View File

@ -18,7 +18,9 @@ import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.block.CableBlock import ru.dbotthepony.mc.otm.block.CableBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.storage.AbstractStorageImportExport.Companion.FILTER_KEY import ru.dbotthepony.mc.otm.block.entity.storage.AbstractStorageImportExport.Companion.FILTER_KEY
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.ItemFilter
@ -45,20 +47,14 @@ private class TrackedTuple(override var stack: ItemStorageStack, override val id
} }
} }
private fun Long.clamp(): Int {
if (this > Int.MAX_VALUE) {
return Int.MAX_VALUE
}
return this.toInt()
}
class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_BUS, blockPos, blockState) { class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_BUS, blockPos, blockState) {
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return StorageBusMenu(containerID, inventory, this) return StorageBusMenu(containerID, inventory, this)
} }
val energy = WorkerEnergyStorage(this::setChangedLight, MachinesConfig.STORAGE_INTERFACES) val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.STORAGE_INTERFACES))
val energyConfig = ConfigurableEnergy(energy, modesFront = FlowDirection.NONE)
val cell: StorageNode = object : StorageNode(energy) { val cell: StorageNode = object : StorageNode(energy) {
override fun onNeighbour(link: Link) { override fun onNeighbour(link: Link) {
if (link is DirectionLink) { if (link is DirectionLink) {
@ -93,8 +89,13 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
setChangedLight() setChangedLight()
} }
var mode: FlowDirection = FlowDirection.BI_DIRECTIONAL
set(value) {
field = value
setChangedLight()
}
init { init {
exposeEnergyGlobally(energy)
savetable(::energy, ENERGY_KEY) savetable(::energy, ENERGY_KEY)
savetables.int(::insertPriority) savetables.int(::insertPriority)
savetables.int(::extractPriority) savetables.int(::extractPriority)
@ -103,11 +104,21 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
side(RelativeSide.FRONT).track(ForgeCapabilities.ITEM_HANDLER).addListener { side(RelativeSide.FRONT).track(ForgeCapabilities.ITEM_HANDLER).addListener {
component?.let(cell::removeStorageComponent) component?.let(cell::removeStorageComponent)
component = if (it.isPresent) { component = if (it.isPresent) {
ItemHandlerComponent(it.orThrow()).also(cell::addStorageComponent) ItemHandlerComponent(it.orThrow()).also { if (!redstoneControl.isBlockedByRedstone) cell.addStorageComponent(it) }
} else { } else {
null null
} }
} }
redstoneControl.addListener {
val component = component ?: return@addListener
if (it) {
cell.removeStorageComponent(component)
} else {
cell.addStorageComponent(component)
}
}
} }
val filter = ItemFilter(MAX_FILTERS) { _, _, _ -> val filter = ItemFilter(MAX_FILTERS) { _, _, _ ->
@ -359,7 +370,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
} }
override fun insertStack(stack: ItemStorageStack, simulate: Boolean): ItemStorageStack { override fun insertStack(stack: ItemStorageStack, simulate: Boolean): ItemStorageStack {
if (redstoneControl.isBlockedByRedstone || energy.batteryLevel.isZero || !filter.match(stack.toItemStack())) if (redstoneControl.isBlockedByRedstone || energy.batteryLevel.isZero || !filter.match(stack.toItemStack()) || !mode.input)
return stack return stack
val required = StorageStack.ITEMS.energyPerInsert(stack) val required = StorageStack.ITEMS.energyPerInsert(stack)
@ -390,7 +401,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
} }
override fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): ItemStorageStack { override fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): ItemStorageStack {
if (redstoneControl.isBlockedByRedstone || !amount.isPositive || !energy.batteryLevel.isPositive) if (redstoneControl.isBlockedByRedstone || !amount.isPositive || !energy.batteryLevel.isPositive || !mode.output)
return ItemStorageStack.EMPTY return ItemStorageStack.EMPTY
var total = BigInteger.ZERO var total = BigInteger.ZERO

View File

@ -21,7 +21,8 @@ import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.UpgradeContainer
import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.container.balance
import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.findAny import ru.dbotthepony.mc.otm.core.collect.find
import ru.dbotthepony.mc.otm.core.collect.maybe
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
import ru.dbotthepony.mc.otm.menu.tech.TwinPlatePressMenu import ru.dbotthepony.mc.otm.menu.tech.TwinPlatePressMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
@ -92,8 +93,7 @@ class PlatePressBlockEntity(
.values .values
.iterator() .iterator()
.filter { it.matches(inputContainer, id) } .filter { it.matches(inputContainer, id) }
.findAny() .maybe() ?: return JobContainer.noItem()
.orElse(null) ?: return JobContainer.noItem()
val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems) val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems)

View File

@ -64,7 +64,7 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio
}.build() }.build()
} }
val translation: Component val title: Component
get() = TranslatableComponent(translationKey) get() = TranslatableComponent(translationKey)
/** /**
@ -105,6 +105,9 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio
} }
companion object { companion object {
@JvmField
val WITHOUT_NONE: ImmutableSet<FlowDirection> = ImmutableSet.of(INPUT, OUTPUT, BI_DIRECTIONAL)
@JvmStatic @JvmStatic
fun of(input: Boolean, output: Boolean): FlowDirection { fun of(input: Boolean, output: Boolean): FlowDirection {
if (input && output) { if (input && output) {

View File

@ -30,6 +30,10 @@ enum class GravityRounding {
return base - subtraction return base - subtraction
} }
} }
override fun round(base: Float): Float {
return base
}
}, },
/** /**
@ -39,6 +43,10 @@ enum class GravityRounding {
override fun round(base: Float, subtraction: Float): Float { override fun round(base: Float, subtraction: Float): Float {
return (base - subtraction).roundToInt().toFloat() return (base - subtraction).roundToInt().toFloat()
} }
override fun round(base: Float): Float {
return base.roundToInt().toFloat()
}
}, },
/** /**
@ -48,9 +56,14 @@ enum class GravityRounding {
override fun round(base: Float, subtraction: Float): Float { override fun round(base: Float, subtraction: Float): Float {
return base - subtraction return base - subtraction
} }
override fun round(base: Float): Float {
return base
}
}; };
abstract fun round(base: Float, subtraction: Float): Float abstract fun round(base: Float, subtraction: Float): Float
abstract fun round(base: Float): Float
} }
interface IXGravity { interface IXGravity {
@ -60,6 +73,8 @@ interface IXGravity {
fun x(x: Float, width: FloatSupplier): Float = x(x, width, 1f) fun x(x: Float, width: FloatSupplier): Float = x(x, width, 1f)
fun x(x: Float, width: Float): Float = x(x, width, 1f) fun x(x: Float, width: Float): Float = x(x, width, 1f)
fun repositionX(outer: Float, inner: Float, rounding: GravityRounding = GravityRounding.YES): Float
fun x(x: Float, font: Font, text: Component): Float = x(x, font, text, 1f) fun x(x: Float, font: Font, text: Component): Float = x(x, font, text, 1f)
fun x(x: Float, font: Font, text: Component, scale: Float = 1f, rounding: GravityRounding = GravityRounding.DEFAULT): Float fun x(x: Float, font: Font, text: Component, scale: Float = 1f, rounding: GravityRounding = GravityRounding.DEFAULT): Float
@ -80,6 +95,8 @@ interface IYGravity {
fun y(y: Float, height: Float, scale: Float = 1f, rounding: GravityRounding = GravityRounding.DEFAULT): Float fun y(y: Float, height: Float, scale: Float = 1f, rounding: GravityRounding = GravityRounding.DEFAULT): Float
fun y(y: Float, height: Float): Float = y(y, height, 1f) fun y(y: Float, height: Float): Float = y(y, height, 1f)
fun repositionY(outer: Float, inner: Float, rounding: GravityRounding = GravityRounding.YES): Float
fun y(y: Float, height: Int, scale: Float = 1f): Float { fun y(y: Float, height: Int, scale: Float = 1f): Float {
return y(y, height.toFloat(), scale).roundToInt().toFloat() return y(y, height.toFloat(), scale).roundToInt().toFloat()
} }
@ -106,6 +123,10 @@ enum class XGravity : IXGravity {
override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float { override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float {
return x return x
} }
override fun repositionX(outer: Float, inner: Float, rounding: GravityRounding): Float {
return 0f
}
}, },
CENTER { CENTER {
override fun x(x: Float, width: FloatSupplier, scale: Float, rounding: GravityRounding): Float { override fun x(x: Float, width: FloatSupplier, scale: Float, rounding: GravityRounding): Float {
@ -127,6 +148,13 @@ enum class XGravity : IXGravity {
override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float { override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float {
return rounding.round(x, font.width(text) / 2f * scale) return rounding.round(x, font.width(text) / 2f * scale)
} }
override fun repositionX(outer: Float, inner: Float, rounding: GravityRounding): Float {
if (outer <= inner)
return 0f
else
return rounding.round((outer - inner) / 2f, 0f)
}
}, },
RIGHT { RIGHT {
override fun x(x: Float, width: FloatSupplier, scale: Float, rounding: GravityRounding): Float { override fun x(x: Float, width: FloatSupplier, scale: Float, rounding: GravityRounding): Float {
@ -148,6 +176,13 @@ enum class XGravity : IXGravity {
override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float { override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float {
return rounding.round(x, font.width(text) * scale) return rounding.round(x, font.width(text) * scale)
} }
override fun repositionX(outer: Float, inner: Float, rounding: GravityRounding): Float {
if (outer <= inner)
return 0f
else
return rounding.round(outer - inner, 0f)
}
}; };
} }
@ -160,6 +195,10 @@ enum class YGravity : IYGravity {
override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float { override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float {
return y return y
} }
override fun repositionY(outer: Float, inner: Float, rounding: GravityRounding): Float {
return 0f
}
}, },
CENTER { CENTER {
@ -170,6 +209,13 @@ enum class YGravity : IYGravity {
override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float { override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float {
return rounding.round(y, height / 2f * scale) return rounding.round(y, height / 2f * scale)
} }
override fun repositionY(outer: Float, inner: Float, rounding: GravityRounding): Float {
if (outer <= inner)
return 0f
else
return rounding.round((outer - inner) / 2f, 0f)
}
}, },
BOTTOM { BOTTOM {
@ -180,6 +226,13 @@ enum class YGravity : IYGravity {
override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float { override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float {
return rounding.round(y, height * scale) return rounding.round(y, height * scale)
} }
override fun repositionY(outer: Float, inner: Float, rounding: GravityRounding): Float {
if (outer <= inner)
return 0f
else
return rounding.round(outer - inner, 0f)
}
}; };
} }

View File

@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.client.render.sprites.MatteryAtlas
object WidgetLocation { object WidgetLocation {
val LARGE_BUTTON = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/large_button.png"), 72f, 18f) val LARGE_BUTTON = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/large_button.png"), 72f, 18f)
val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 36f) val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 54f)
val MISC_18 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/misc18.png"), 72f, 72f) val MISC_18 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/misc18.png"), 72f, 72f)
val SLOT_BACKGROUNDS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/slot_backgrounds.png"), 72f, 72f) val SLOT_BACKGROUNDS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/slot_backgrounds.png"), 72f, 72f)

View File

@ -37,7 +37,7 @@ object Widgets18 {
val BUTTON_DISABLED_STRETCHABLE = makeButton(buttonGrids) val BUTTON_DISABLED_STRETCHABLE = makeButton(buttonGrids)
val BUTTON_DISABLED = buttonGrids.next() val BUTTON_DISABLED = buttonGrids.next()
private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 2, columns = 5) private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 3, columns = 5)
val ARROW_DOWN = storageGrid.next() val ARROW_DOWN = storageGrid.next()
val ARROW_UP = storageGrid.next() val ARROW_UP = storageGrid.next()
val SORT_DEFAULT = storageGrid.next() val SORT_DEFAULT = storageGrid.next()
@ -47,6 +47,9 @@ object Widgets18 {
val SORT_ID = storageGrid.next() val SORT_ID = storageGrid.next()
val SORT_MATTER_VALUE = storageGrid.next() val SORT_MATTER_VALUE = storageGrid.next()
val SORT_MATTER_COMPLEXITY = storageGrid.next() val SORT_MATTER_COMPLEXITY = storageGrid.next()
val ONLY_STORE = storageGrid.next()
val ONLY_EXTRACT = storageGrid.next()
val STORE_EXTRACT = storageGrid.next()
private val miscGrid = WidgetLocation.MISC_18.grid(4, 4) private val miscGrid = WidgetLocation.MISC_18.grid(4, 4)

View File

@ -19,6 +19,7 @@ import net.minecraftforge.common.MinecraftForge
import org.lwjgl.opengl.GL11 import org.lwjgl.opengl.GL11
import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.client.moveMousePosScaled import ru.dbotthepony.mc.otm.client.moveMousePosScaled
import ru.dbotthepony.mc.otm.client.render.WidgetLocation
import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.render.Widgets18
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.*
@ -31,14 +32,23 @@ 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.client.screen.widget.HorizontalPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.HorizontalPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PatternGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.config.ClientConfig import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.core.TranslatableComponent 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.integerDivisionDown import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import java.util.* import java.util.*
import kotlin.collections.ArrayDeque import kotlin.collections.ArrayDeque
import kotlin.collections.List import kotlin.collections.List
@ -374,6 +384,59 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
return true return true
} }
protected fun makeBars(
parent: EditablePanel<*>,
energy: LevelGaugeWidget? = null,
profiledEnergy: ProfiledLevelGaugeWidget<*>? = null,
matter: LevelGaugeWidget? = null,
profiledMatter: ProfiledLevelGaugeWidget<*>? = null,
patterns: LevelGaugeWidget? = null,
batterySlot: MatterySlot? = null,
) {
var bars = 0
if (energy != null) bars++
if (profiledEnergy != null) bars++
if (matter != null) bars++
if (patterns != null) bars++
if (profiledMatter != null) bars++
val canvas = EditablePanel(this, parent, width = AbstractSlotPanel.SIZE.coerceAtLeast(9f * bars))
canvas.dock = Dock.LEFT
canvas.childrenOrder = -1000
val gauges = EditablePanel(this, canvas, height = WidgetLocation.VERTICAL_GAUGES.height)
gauges.dock = Dock.TOP
if (profiledEnergy != null) {
if (bars == 1) {
WideProfiledPowerGaugePanel(this, gauges, profiledEnergy).dock = Dock.TOP
} else {
ProfiledPowerGaugePanel(this, gauges, profiledEnergy).dock = Dock.LEFT
}
} else if (energy != null) {
if (bars == 1) {
WidePowerGaugePanel(this, gauges, energy).dock = Dock.TOP
} else {
PowerGaugePanel(this, gauges, energy).dock = Dock.LEFT
}
}
if (matter != null) {
MatterGaugePanel(this, gauges, matter).dock = Dock.LEFT
}
if (patterns != null) {
PatternGaugePanel(this, gauges, patterns).dock = Dock.LEFT
}
if (batterySlot != null) {
BatterySlotPanel(this, canvas, batterySlot).also {
it.dock = Dock.BOTTOM
it.dockResize = DockResizeMode.NONE
}
}
}
/** /**
* Safely to be overriden. By default, creates well-known dimensions window * Safely to be overriden. By default, creates well-known dimensions window
* *

View File

@ -580,7 +580,7 @@ open class ColorPickerPanel<out S : Screen>(
} }
} }
override fun acceptsCharacter(codepoint: Char, mods: Int): Boolean { override fun acceptsCharacter(codepoint: Char, mods: Int, index: Int): Boolean {
return RGBAColor.isHexCharacter(codepoint) return RGBAColor.isHexCharacter(codepoint)
} }
} }

View File

@ -33,6 +33,8 @@ data class ScreenPos(val x: Float, val y: Float)
data class DockProperty(val left: Float = 0f, val top: Float = 0f, val right: Float = 0f, val bottom: Float = 0f) { data class DockProperty(val left: Float = 0f, val top: Float = 0f, val right: Float = 0f, val bottom: Float = 0f) {
val isEmpty get() = left == 0f && right == 0f && top == 0f && bottom == 0f val isEmpty get() = left == 0f && right == 0f && top == 0f && bottom == 0f
val horizontal get() = left + right
val vertical get() = top + bottom
companion object { companion object {
val EMPTY = DockProperty() val EMPTY = DockProperty()
@ -73,7 +75,6 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
height: Float = 10f, height: Float = 10f,
) : Comparable<EditablePanel<*>> { ) : Comparable<EditablePanel<*>> {
// layout engine does not support navigation using keyboard // layout engine does not support navigation using keyboard
// fuck off
val listener: GuiEventListener = object : GuiEventListener { val listener: GuiEventListener = object : GuiEventListener {
override fun setFocused(p_265728_: Boolean) { override fun setFocused(p_265728_: Boolean) {
if (p_265728_) { if (p_265728_) {
@ -138,6 +139,9 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
} }
} }
/**
* Bigger values means lesser priority while docking
*/
var childrenOrder = 0 var childrenOrder = 0
set(value) { set(value) {
if (field != value) { if (field != value) {
@ -235,17 +239,21 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
} }
/** /**
* Width to be utilized in docking code. * Width of this panel as considered by docking code, updated inside [performLayout]
* *
* Can only differ from [width] if [dockResize] is not [DockResizeMode.ALL] and not [DockResizeMode.WIDTH] * If panel is not docked ([dock] is [Dock.NONE]), this value equals to [width] plus [DockProperty.horizontal] of [dockMargin]
*
* If panel is docked, this value will be equal to [width], if [dockResize] allows resizing [width], or could-have value, if [dockResize] doesn't
*/ */
var dockedWidth: Float = 0f var dockedWidth: Float = 0f
private set private set
/** /**
* Height to be utilized in docking code. * Height of this panel as considered by docking code, updated inside [performLayout]
* *
* Can only differ from [height] if [dockResize] is not [DockResizeMode.ALL] and not [DockResizeMode.HEIGHT] * If panel is not docked ([dock] is [Dock.NONE]), this value equals to [height] plus [DockProperty.vertical] of [dockMargin]
*
* If panel is docked, this value will be equal to [height], if [dockResize] allows resizing [height], or could-have value, if [dockResize] doesn't
*/ */
var dockedHeight: Float = 0f var dockedHeight: Float = 0f
private set private set
@ -362,6 +370,38 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
} }
} }
var dockPaddingLeft: Float
get() = dockPadding.left
set(value) {
if (value != dockPadding.left) {
dockPadding = dockPadding.copy(left = value)
}
}
var dockPaddingRight: Float
get() = dockPadding.right
set(value) {
if (value != dockPadding.right) {
dockPadding = dockPadding.copy(right = value)
}
}
var dockPaddingTop: Float
get() = dockPadding.top
set(value) {
if (value != dockPadding.top) {
dockPadding = dockPadding.copy(top = value)
}
}
var dockPaddingBottom: Float
get() = dockPadding.bottom
set(value) {
if (value != dockPadding.bottom) {
dockPadding = dockPadding.copy(bottom = value)
}
}
var acceptMouseInput = true var acceptMouseInput = true
var acceptKeyboardInput = true var acceptKeyboardInput = true
var grabMouseInput = false var grabMouseInput = false
@ -1060,7 +1100,11 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
for (child in visibleChildrenInternal) { for (child in visibleChildrenInternal) {
when (child.dock) { when (child.dock) {
Dock.NONE -> {} Dock.NONE -> {
child.dockedWidth = child.width + child.dockMargin.horizontal
child.dockedHeight = child.height + child.dockMargin.vertical
}
Dock.FILL -> {} Dock.FILL -> {}
Dock.LEFT -> { Dock.LEFT -> {
@ -1192,8 +1236,8 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
* *
* Performs layout if required * Performs layout if required
*/ */
open fun sizeToContents() { open fun sizeToContents(performLayout: Boolean = true) {
if (layoutInvalidated) { if (layoutInvalidated && performLayout) {
performLayout() performLayout()
} }
@ -1398,8 +1442,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
} }
fun getChildren(index: Int): EditablePanel<*>? { fun getChildren(index: Int): EditablePanel<*>? {
if (index < 0 || index >= childrenInternal.size) return null return childrenInternal.getOrNull(index)
return childrenInternal[index]
} }
fun isGrabbingMouseInput(): Boolean { fun isGrabbingMouseInput(): Boolean {

View File

@ -61,8 +61,8 @@ open class Label<out S : Screen> @JvmOverloads constructor(
} }
} }
override fun sizeToContents() { override fun sizeToContents(performLayout: Boolean) {
super.sizeToContents() super.sizeToContents(performLayout)
val w = font.width(text) val w = font.width(text)
val h = font.lineHeight + 2 val h = font.lineHeight + 2

View File

@ -56,8 +56,8 @@ open class ButtonPanel<out S : Screen>(
graphics.draw(font, label, width / 2f, height / 2f, color = textColor, gravity = RenderGravity.CENTER_CENTER) graphics.draw(font, label, width / 2f, height / 2f, color = textColor, gravity = RenderGravity.CENTER_CENTER)
} }
override fun sizeToContents() { override fun sizeToContents(performLayout: Boolean) {
super.sizeToContents() super.sizeToContents(performLayout)
height = height.coerceAtLeast(HEIGHT).coerceAtLeast(font.lineHeight.toFloat() + 2f) height = height.coerceAtLeast(HEIGHT).coerceAtLeast(font.lineHeight.toFloat() + 2f)
width = width.coerceAtLeast(HEIGHT).coerceAtLeast(font.width(label) + 4f) width = width.coerceAtLeast(HEIGHT).coerceAtLeast(font.width(label) + 4f)

View File

@ -4,12 +4,13 @@ import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.menu.input.AbstractPlayerInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.AbstractPlayerInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback
import ru.dbotthepony.mc.otm.milliTime import ru.dbotthepony.mc.otm.milliTime
open class NetworkedStringInputPanel<out S : Screen>( open class NetworkedStringInputPanel<out S : Screen>(
screen: S, screen: S,
parent: EditablePanel<*>?, parent: EditablePanel<*>?,
val backend: AbstractPlayerInputWithFeedback<String>, val backend: IPlayerInputWithFeedback<String>,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
width: Float = 60f, width: Float = 60f,
@ -29,7 +30,7 @@ open class NetworkedStringInputPanel<out S : Screen>(
private var lastChanges = 0L private var lastChanges = 0L
override fun onTextChanged(old: String, new: String) { override fun onTextChanged(new: String, old: String) {
lastChanges = milliTime + 1000L lastChanges = milliTime + 1000L
backend.accept(new) backend.accept(new)
} }
@ -38,7 +39,7 @@ open class NetworkedStringInputPanel<out S : Screen>(
super.tickInner() super.tickInner()
if (milliTime >= lastChanges) { if (milliTime >= lastChanges) {
text = backend.value text = backend.get()
} }
} }
} }

View File

@ -0,0 +1,215 @@
package ru.dbotthepony.mc.otm.client.screen.panels.input
import com.mojang.blaze3d.platform.InputConstants
import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.render.Widgets
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.RectangleButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.HeightControls
import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.math.Decimal
abstract class NumberInputPanel<out S : Screen, N : Number>(
screen: S,
parent: EditablePanel<*>,
val prop: GetterSetter<N>,
x: Float = 0f,
y: Float = 0f,
width: Float = WIDTH,
height: Float = HeightControls.BUTTON_HEIGHT * 2f,
var min: N? = null,
var max: N? = null,
) : EditablePanel<S>(screen, parent, x, y, width, height) {
abstract fun toNumber(input: String): N?
abstract fun increase(input: N): N
abstract fun decrease(input: N): N
abstract val isFractional: Boolean
fun clamp(value: N): N {
val min = min
val max = max
if (min != null && (value as Comparable<N>) < min) return min
if (max != null && (value as Comparable<N>) > max) return max
return value
}
fun increase() {
prop.accept(clamp(increase(prop.get())))
}
fun decrease() {
prop.accept(clamp(decrease(prop.get())))
}
val textInput = object : TextInputPanel<S>(screen, this@NumberInputPanel) {
init {
allowNumbersAndSign()
dock = Dock.FILL
text = prop.get().toString()
}
override fun acceptsCharacter(codepoint: Char, mods: Int, index: Int): Boolean {
if (!isFractional && codepoint == '.') return false
return super.acceptsCharacter(codepoint, mods, index)
}
override fun tickInner() {
super.tickInner()
if (!hasHierarchicalFocus()) {
text = prop.get().toString()
}
}
override fun onTextChanged(new: String, old: String) {
if (hasHierarchicalFocus()) {
val i = toNumber(new)
if (i != null) prop.accept(i)
}
}
}
val controls = EditablePanel(screen, this, width = HeightControls.BUTTON_WIDTH, height = HeightControls.BUTTON_HEIGHT)
val increaseControl = Control(true)
val decreaseControl = Control(false)
init {
increaseControl.childrenOrder = 1
decreaseControl.childrenOrder = 2
textInput.dockRight = 2f
}
init {
controls.dock = Dock.RIGHT
}
inner class Control(val isIncrease: Boolean) : RectangleButtonPanel<S>(screen, controls, width = HeightControls.BUTTON_WIDTH, height = HeightControls.BUTTON_HEIGHT) {
override val PRESSED = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_PRESSED else Widgets.ARROW_UP_BUTTON_PRESSED
override val HOVERED = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_HOVERED else Widgets.ARROW_UP_BUTTON_HOVERED
override val IDLE = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_IDLE else Widgets.ARROW_UP_BUTTON_IDLE
override val DISABLED = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_DISABLED else Widgets.ARROW_UP_BUTTON_DISABLED
init {
dock = Dock.TOP
if (isIncrease)
tooltips.add(TranslatableComponent("otm.gui.increase"))
else
tooltips.add(TranslatableComponent("otm.gui.decrease"))
}
override fun test(value: Int): Boolean {
return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT
}
override fun onClick(mouseButton: Int) {
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
if (isIncrease) {
increase()
} else {
decrease()
}
} else if (mouseButton == InputConstants.MOUSE_BUTTON_RIGHT) {
if (isIncrease) {
decrease()
} else {
increase()
}
}
}
}
companion object {
const val WIDTH = 50f
}
}
abstract class LNumberInputPanel<out S : Screen, N : Number>(
screen: S,
parent: EditablePanel<*>,
prop: GetterSetter<N>,
x: Float = 0f,
y: Float = 0f,
width: Float = WIDTH,
height: Float = HeightControls.BUTTON_HEIGHT * 2f,
min: N? = null,
max: N? = null,
val toNumber: (String) -> N?,
val increase: (N) -> N,
val decrease: (N) -> N,
final override val isFractional: Boolean
) : NumberInputPanel<S, N>(screen, parent, prop, x, y, width, height, min, max) {
final override fun toNumber(input: String): N? {
return toNumber.invoke(input)
}
final override fun increase(input: N): N {
return increase.invoke(input)
}
final override fun decrease(input: N): N {
return decrease.invoke(input)
}
}
open class IntInputPanel<out S : Screen>(
screen: S,
parent: EditablePanel<*>,
prop: GetterSetter<Int>,
x: Float = 0f,
y: Float = 0f,
width: Float = WIDTH,
height: Float = HeightControls.BUTTON_HEIGHT * 2f,
var step: Int = 1,
min: Int? = null,
max: Int? = null,
) : NumberInputPanel<S, Int>(screen, parent, prop, x, y, width, height, min, max) {
final override fun toNumber(input: String): Int? {
return input.toIntOrNull()
}
final override fun increase(input: Int): Int {
return input + step
}
final override fun decrease(input: Int): Int {
return input - step
}
final override val isFractional: Boolean
get() = false
}
open class DecimalInputPanel<out S : Screen>(
screen: S,
parent: EditablePanel<*>,
prop: GetterSetter<Decimal>,
x: Float = 0f,
y: Float = 0f,
width: Float = WIDTH,
height: Float = HeightControls.BUTTON_HEIGHT * 2f,
var step: Decimal = Decimal.ONE,
min: Decimal? = null,
max: Decimal? = null,
) : NumberInputPanel<S, Decimal>(screen, parent, prop, x, y, width, height, min, max) {
final override fun toNumber(input: String): Decimal? {
return try {
Decimal(input)
} catch (err: NumberFormatException) {
null
}
}
final override fun increase(input: Decimal): Decimal {
return input + step
}
final override fun decrease(input: Decimal): Decimal {
return input - step
}
final override val isFractional: Boolean
get() = true
}

View File

@ -27,7 +27,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.addAll import ru.dbotthepony.mc.otm.core.addAll
import ru.dbotthepony.mc.otm.core.collect.mapToInt import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.reduce import ru.dbotthepony.mc.otm.core.collect.reduce
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.milliTime import ru.dbotthepony.mc.otm.milliTime
@ -904,7 +904,7 @@ open class TextInputPanel<out S : Screen>(
pushbackSnapshot() pushbackSnapshot()
if (multiLine) { if (multiLine) {
var index = cursorRow + (0 until cursorLine).iterator().mapToInt { this[it]?.length ?: 0 }.reduce(0, Int::plus) var index = cursorRow + (0 until cursorLine).iterator().map { this[it]?.length ?: 0 }.reduce(0, Int::plus)
val insert = minecraft.keyboardHandler.clipboard.replace("\t", " ").filter { acceptsCharacter(it, 0, index++) }.split(NEWLINES).toMutableList() val insert = minecraft.keyboardHandler.clipboard.replace("\t", " ").filter { acceptsCharacter(it, 0, index++) }.split(NEWLINES).toMutableList()
val actualLastSize = insert.lastOrNull()?.length ?: 0 val actualLastSize = insert.lastOrNull()?.length ?: 0
val line = this[cursorLine] val line = this[cursorLine]
@ -944,7 +944,7 @@ open class TextInputPanel<out S : Screen>(
cursorRow = actualLastSize cursorRow = actualLastSize
} }
} else { } else {
var index = cursorRow + (0 until cursorLine).iterator().mapToInt { this[it]?.length ?: 0 }.reduce(0, Int::plus) var index = cursorRow + (0 until cursorLine).iterator().map { this[it]?.length ?: 0 }.reduce(0, Int::plus)
val insert = minecraft.keyboardHandler.clipboard.replace("\t", " ").replace(NEWLINES, "").filter { acceptsCharacter(it, 0, index++) } val insert = minecraft.keyboardHandler.clipboard.replace("\t", " ").replace(NEWLINES, "").filter { acceptsCharacter(it, 0, index++) }
val line = this[cursorLine] val line = this[cursorLine]
@ -1462,7 +1462,7 @@ open class TextInputPanel<out S : Screen>(
} }
private val NUMBERS = CharOpenHashSet().also { private val NUMBERS = CharOpenHashSet().also {
for (char in "0123456789-+") for (char in "0123456789.")
it.add(char) it.add(char)
} }

View File

@ -1,8 +1,12 @@
package ru.dbotthepony.mc.otm.client.screen.panels.util package ru.dbotthepony.mc.otm.client.screen.panels.util
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.render.RenderGravity
import ru.dbotthepony.mc.otm.client.screen.panels.Dock import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.maybe
open class GridPanel<out S : Screen>( open class GridPanel<out S : Screen>(
screen: S, screen: S,
@ -26,37 +30,54 @@ open class GridPanel<out S : Screen>(
invalidateLayout() invalidateLayout()
} }
var gravity: RenderGravity = RenderGravity.CENTER_CENTER
set(value) {
field = value
invalidateLayout()
}
override fun performLayout() { override fun performLayout() {
var currentX = 0f super.performLayout()
var currentY = 0f var children = visibleChildren.iterator().filter { it.dock == Dock.NONE }
var lineY = 0f
var index = 0 var totalWidth = 0f
var totalHeight = 0f
for (row in 0 until rows) { for (row in 0 until rows) {
var column = 0 var maxHeight = 0f
var width = 0f
while (column < columns) { for (column in 0 until columns) {
val child = getChildren(index) ?: break val child = children.maybe() ?: break
width += child.dockedWidth
if (child.visible && child.dock === Dock.NONE) { maxHeight = maxHeight.coerceAtLeast(child.dockedHeight)
lineY = lineY.coerceAtLeast(child.height + child.dockMargin.top + child.dockMargin.bottom)
child.setPos(currentX + child.dockMargin.left, currentY + child.dockMargin.top)
currentX += child.width + child.dockMargin.left + child.dockMargin.right
} else {
column--
} }
index++ totalWidth = totalWidth.coerceAtLeast(width)
column++ totalHeight += maxHeight
} }
currentY += lineY val alignX = gravity.repositionX(width, totalWidth)
currentX = 0f val alignY = gravity.repositionY(height, totalHeight)
lineY = 0f children = visibleChildren.iterator().filter { it.dock == Dock.NONE }
getChildren(index) ?: break totalWidth = 0f
totalHeight = 0f
for (row in 0 until rows) {
var maxHeight = 0f
var width = 0f
for (column in 0 until columns) {
val child = children.maybe() ?: break
child.x = alignX + width
child.y = alignY + totalHeight
width += child.dockedWidth
maxHeight = maxHeight.coerceAtLeast(child.dockedHeight)
} }
super.performLayout() totalWidth = totalWidth.coerceAtLeast(width)
totalHeight += maxHeight
}
} }
} }

View File

@ -46,7 +46,7 @@ open class HeightControls<out S : Screen>(
decrease.isDisabled = !value.canDecrease decrease.isDisabled = !value.canDecrease
} }
open inner class Control(val isIncrease: Boolean) : RectangleButtonPanel<S>(screen, this@HeightControls, width = BUTTON_WIDTH, height = BUTTON_HEIGHT) { inner class Control(val isIncrease: Boolean) : RectangleButtonPanel<S>(screen, this@HeightControls, width = BUTTON_WIDTH, height = BUTTON_HEIGHT) {
override val PRESSED: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_PRESSED else Widgets.ARROW_UP_BUTTON_PRESSED override val PRESSED: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_PRESSED else Widgets.ARROW_UP_BUTTON_PRESSED
override val HOVERED: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_HOVERED else Widgets.ARROW_UP_BUTTON_HOVERED override val HOVERED: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_HOVERED else Widgets.ARROW_UP_BUTTON_HOVERED
override val IDLE: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_IDLE else Widgets.ARROW_UP_BUTTON_IDLE override val IDLE: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_IDLE else Widgets.ARROW_UP_BUTTON_IDLE
@ -57,10 +57,14 @@ open class HeightControls<out S : Screen>(
dockBottom = 2f dockBottom = 2f
} }
override fun onClick(clickButton: Int) { override fun test(value: Int): Boolean {
if (clickButton == InputConstants.MOUSE_BUTTON_LEFT) { return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT
}
override fun onClick(mouseButton: Int) {
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
this@HeightControls.onClick(isIncrease) this@HeightControls.onClick(isIncrease)
} else if (clickButton == InputConstants.MOUSE_BUTTON_RIGHT) { } else if (mouseButton == InputConstants.MOUSE_BUTTON_RIGHT) {
this@HeightControls.onClick(!isIncrease) this@HeightControls.onClick(!isIncrease)
} }
} }

View File

@ -13,13 +13,13 @@ class HorizontalStripPanel<out S : Screen>(
width: Float = 0f, width: Float = 0f,
height: Float = 0f, height: Float = 0f,
) : EditablePanel<S>(screen, parent, x, y, width, height) { ) : EditablePanel<S>(screen, parent, x, y, width, height) {
override fun sizeToContents() { override fun sizeToContents(performLayout: Boolean) {
var w = 0f var w = 0f
var h = 0f var h = 0f
for (child in children) { for (child in visibleChildren) {
if (child.dock == Dock.NONE) { if (child.dock == Dock.NONE) {
w += child.width + child.dockMargin.left + child.dockMargin.right w += child.width + child.dockMargin.horizontal
h = h.coerceAtLeast(child.height) h = h.coerceAtLeast(child.height)
} }
} }
@ -33,19 +33,19 @@ class HorizontalStripPanel<out S : Screen>(
var w = 0f var w = 0f
for (child in children) { for (child in visibleChildren) {
if (child.dock == Dock.NONE) { if (child.dock == Dock.NONE) {
w += child.width + child.dockMargin.left + child.dockMargin.right w += child.width + child.dockMargin.horizontal
} }
} }
w = width / 2f - w / 2f w = width / 2f - w / 2f
for (child in children) { for (child in visibleChildren) {
if (child.dock == Dock.NONE) { if (child.dock == Dock.NONE) {
child.y = (height / 2f - child.height / 2f).roundToInt().toFloat() child.y = (height / 2f - child.height / 2f).roundToInt().toFloat()
child.x = (w + child.dockMargin.left).roundToInt().toFloat() child.x = (w + child.dockMargin.left).roundToInt().toFloat()
w += child.dockMargin.left + child.width + child.dockMargin.right w += child.dockMargin.horizontal + child.width
} }
} }
} }

View File

@ -2,57 +2,64 @@ package ru.dbotthepony.mc.otm.client.screen.storage
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 ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.panels.*
import ru.dbotthepony.mc.otm.client.screen.panels.button.CheckBoxLabelInputPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.CheckBoxLabelInputPanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeEnumRectangleButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.input.IntInputPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.FilterSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.FilterSlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
import ru.dbotthepony.mc.otm.menu.storage.StorageBusMenu import ru.dbotthepony.mc.otm.menu.storage.StorageBusMenu
class StorageBusScreen(menu: StorageBusMenu, inventory: Inventory, title: Component) : class StorageBusScreen(menu: StorageBusMenu, inventory: Inventory, title: Component) :
MatteryScreen<StorageBusMenu>(menu, inventory, title) { MatteryScreen<StorageBusMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> { override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
val frame = super.makeMainFrame()!! val frame = FramePanel(this, 150f, 126f, title)
WidePowerGaugePanel(this, frame, menu.energyWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT) makeBars(frame, profiledEnergy = menu.profiledEnergy, batterySlot = menu.batterySlot)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) val right = EditablePanel(this, frame, width = AbstractSlotPanel.SIZE * 6f)
right.dock = Dock.RIGHT
val grid = GridPanel(this, right, columns = 6, rows = 3, height = AbstractSlotPanel.SIZE * 3f)
grid.dock = Dock.TOP
grid.dockBottom = 2f
for (row in 0 .. 2) { for (slot in menu.busFilterSlots)
for (column in 0 .. 5) { FilterSlotPanel(this, grid, slot)
FilterSlotPanel(this, frame, menu.busFilterSlots[row + column * 3], 55f + 18f * column, 17f + 18f * row)
} IntInputPanel(this, right, menu.insertPriority).also {
it.dock = Dock.BOTTOM
it.dockBottom = 2f
it.tooltips.add(TranslatableComponent("otm.gui.insert_priority"))
it.childrenOrder = -1
} }
CheckBoxLabelInputPanel(this, frame, menu.busFilterState, TranslatableComponent("otm.gui.filter.is_whitelist"), 59f, 78f, width = 170f) IntInputPanel(this, right, menu.extractPriority).also {
it.dock = Dock.BOTTOM
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig) it.dockBottom = 2f
it.tooltips.add(TranslatableComponent("otm.gui.extract_priority"))
/*object : TextInputPanel<StorageBusScreen>(this@StorageBusScreen, frame) { it.childrenOrder = -2
init {
allowNumbersAndSign()
dock = Dock.BOTTOM
} }
override fun tickInner() { CheckBoxLabelInputPanel(this, right, menu.busFilterState, TranslatableComponent("otm.gui.filter.is_whitelist")).also {
super.tickInner() it.dock = Dock.BOTTOM
it.childrenOrder = -3
if (!hasHierarchicalFocus()) {
text = menu.insertPriority.value.toString()
}
} }
override fun onTextChanged(new: String, old: String) { val controls = DeviceControls(this, frame, redstoneConfig = menu.redstoneConfig)
if (hasHierarchicalFocus()) { val mode = LargeEnumRectangleButtonPanel(this, frame, prop = menu.mode, defaultValue = FlowDirection.BI_DIRECTIONAL, enum = FlowDirection::class.java)
val i = new.toIntOrNull()
if (i != null) menu.insertPriority.accept(i) mode.add(FlowDirection.INPUT, Widgets18.ONLY_STORE, FlowDirection.INPUT.title)
} mode.add(FlowDirection.OUTPUT, Widgets18.ONLY_EXTRACT, FlowDirection.OUTPUT.title)
} mode.add(FlowDirection.BI_DIRECTIONAL, Widgets18.STORE_EXTRACT, FlowDirection.BI_DIRECTIONAL.title)
}*/ mode.finish()
controls.addButton(mode)
return frame return frame
} }

View File

@ -5,13 +5,8 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.UpgradeType
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
import ru.dbotthepony.mc.otm.config.VerboseEnergyBalanceValues import ru.dbotthepony.mc.otm.config.VerboseEnergyBalanceValues
import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.mapToDouble
import ru.dbotthepony.mc.otm.core.collect.mapToInt
import ru.dbotthepony.mc.otm.core.collect.reduce import ru.dbotthepony.mc.otm.core.collect.reduce
import ru.dbotthepony.mc.otm.core.collect.sum
import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import kotlin.math.pow import kotlin.math.pow
@ -28,9 +23,9 @@ open class UpgradeContainer(slotCount: Int, open val allowedUpgrades: Set<Upgrad
} }
override val speedBonus: Double override val speedBonus: Double
get() = iterator().mapToDouble { it.getCapability(MatteryCapability.UPGRADE).map { it.speedBonus }.orElse(0.0) * it.count }.sum() get() = iterator().map { it.getCapability(MatteryCapability.UPGRADE).map { it.speedBonus }.orElse(0.0) * it.count }.reduce(0.0) { a, b -> a + b }
override val processingItems: Int override val processingItems: Int
get() = iterator().mapToInt { it.getCapability(MatteryCapability.UPGRADE).map { it.processingItems }.orElse(0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } get() = iterator().map { it.getCapability(MatteryCapability.UPGRADE).map { it.processingItems }.orElse(0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b }
override val energyStorageFlat: Decimal override val energyStorageFlat: Decimal
get() = decimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus) get() = decimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus)
override val energyStorage: Decimal override val energyStorage: Decimal
@ -42,7 +37,7 @@ open class UpgradeContainer(slotCount: Int, open val allowedUpgrades: Set<Upgrad
override val energyConsumed: Decimal override val energyConsumed: Decimal
get() = decimals(IMatteryUpgrade::energyConsumed, Decimal::plus) get() = decimals(IMatteryUpgrade::energyConsumed, Decimal::plus)
override val failureMultiplier: Double override val failureMultiplier: Double
get() = iterator().mapToDouble { it.getCapability(MatteryCapability.UPGRADE).map { it.failureMultiplier }.orElse(1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } get() = iterator().map { it.getCapability(MatteryCapability.UPGRADE).map { it.failureMultiplier }.orElse(1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b }
override val energyThroughputFlat: Decimal override val energyThroughputFlat: Decimal
get() = decimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus) get() = decimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus)
override val energyThroughput: Decimal override val energyThroughput: Decimal

View File

@ -0,0 +1,5 @@
package ru.dbotthepony.mc.otm.core
interface ByteSupplier {
fun getAsByte(): Byte
}

View File

@ -0,0 +1,5 @@
package ru.dbotthepony.mc.otm.core
interface ShortSupplier {
fun getAsShort(): Short
}

View File

@ -21,7 +21,7 @@ import java.util.stream.Collector
* *
* Resulting [Iterator] is [MutableIterator] if [parent] is * Resulting [Iterator] is [MutableIterator] if [parent] is
*/ */
class FilteredIterator<T>(private val parent: Iterator<T>, private val predicate: Predicate<in T>) : MutableIterator<T> { class FilteringIterator<T>(private val parent: Iterator<T>, private val predicate: Predicate<in T>) : MutableIterator<T> {
private var foundValue: Any? = Companion private var foundValue: Any? = Companion
override fun hasNext(): Boolean { override fun hasNext(): Boolean {
@ -124,18 +124,6 @@ class FlatMappingIterator<T, R>(private val parent: Iterator<T>, private val map
} }
} }
fun <T> concatIterators(): MutableIterator<T> {
return ObjectIterators.EMPTY_ITERATOR as MutableIterator<T>
}
fun <T> concatIterators(a: Iterator<T>): MutableIterator<T> {
return a as MutableIterator<T>
}
fun <T> concatIterators(vararg iterators: Iterator<T>): MutableIterator<T> {
return iterators.iterator().flatMap { it }
}
/** /**
* Limits amount of values returned by [parent] iterator to return at most [limit] values * Limits amount of values returned by [parent] iterator to return at most [limit] values
* *
@ -201,12 +189,24 @@ class SkippingIterator<T>(private val parent: Iterator<T>, skip: Long) : Mutable
} }
} }
fun <T> concatIterators(): MutableIterator<T> {
return ObjectIterators.EMPTY_ITERATOR as MutableIterator<T>
}
fun <T> concatIterators(a: Iterator<T>): MutableIterator<T> {
return a as MutableIterator<T>
}
fun <T> concatIterators(vararg iterators: Iterator<T>): MutableIterator<T> {
return iterators.iterator().flatMap { it }
}
/** /**
* Filters elements of [this] iterator * Filters elements of [this] iterator
* *
* Resulting [Iterator] is [MutableIterator] if [this] is * Resulting [Iterator] is [MutableIterator] if [this] is
*/ */
fun <T> Iterator<T>.filter(condition: Predicate<in T>) = FilteredIterator(this, condition) fun <T> Iterator<T>.filter(condition: Predicate<in T>) = FilteringIterator(this, condition)
/** /**
* Maps elements of [this] iterator from values of [T] to [R] using function [mapper] * Maps elements of [this] iterator from values of [T] to [R] using function [mapper]
@ -236,92 +236,16 @@ fun <T, R> Iterator<T>.flatMap(mapper: (T) -> Iterator<R>) = FlatMappingIterator
*/ */
fun <T, R> Iterator<T>.flatMap(mapper: java.util.function.Function<T, Iterator<R>>) = FlatMappingIterator(this, mapper::apply) fun <T, R> Iterator<T>.flatMap(mapper: java.util.function.Function<T, Iterator<R>>) = FlatMappingIterator(this, mapper::apply)
fun interface O2DFunction<T> {
fun apply(value: T): Double
}
fun interface O2IFunction<T> {
fun apply(value: T): Int
}
fun <T> Iterator<T>.mapToDouble(mapper: O2DFunction<T>): it.unimi.dsi.fastutil.doubles.DoubleIterator {
return object : it.unimi.dsi.fastutil.doubles.DoubleIterator {
override fun hasNext(): Boolean {
return this@mapToDouble.hasNext()
}
override fun remove() {
(this@mapToDouble as MutableIterator).remove()
}
override fun nextDouble(): Double {
return mapper.apply(this@mapToDouble.next())
}
}
}
fun <T> Iterator<T>.mapToInt(mapper: O2IFunction<T>): it.unimi.dsi.fastutil.ints.IntIterator {
return object : it.unimi.dsi.fastutil.ints.IntIterator {
override fun hasNext(): Boolean {
return this@mapToInt.hasNext()
}
override fun remove() {
(this@mapToInt as MutableIterator).remove()
}
override fun nextInt(): Int {
return mapper.apply(this@mapToInt.next())
}
}
}
fun it.unimi.dsi.fastutil.doubles.DoubleIterator.sum(): Double {
var value = 0.0
while (hasNext()) value += nextDouble()
return value
}
fun it.unimi.dsi.fastutil.ints.IntIterator.sum(): Int {
var value = 0
while (hasNext()) value += nextInt()
return value
}
fun interface DD2DFunction {
fun apply(a: Double, b: Double): Double
}
fun interface II2IFunction {
fun apply(a: Int, b: Int): Int
}
fun it.unimi.dsi.fastutil.doubles.DoubleIterator.reduce(identity: Double, reducer: DD2DFunction): Double {
var result = identity
while (hasNext()) result = reducer.apply(result, nextDouble())
return result
}
fun it.unimi.dsi.fastutil.ints.IntIterator.reduce(identity: Int, reducer: II2IFunction): Int {
var result = identity
while (hasNext()) result = reducer.apply(result, nextInt())
return result
}
fun <T> Iterator<T>.reduce(identity: T, reducer: (T, T) -> T): T { fun <T> Iterator<T>.reduce(identity: T, reducer: (T, T) -> T): T {
var result = identity var result = identity
for (value in this) result = reducer.invoke(result, value)
for (value in this) {
result = reducer.invoke(result, value)
}
return result return result
} }
fun <T> Iterator<T>.reduce(identity: T, reducer: BinaryOperator<T>): T = reduce(identity, reducer::apply) fun <T> Iterator<T>.reduce(identity: T, reducer: BinaryOperator<T>): T = reduce(identity, reducer::apply)
fun <T> Iterator<T?>.filterNotNull(): Iterator<T> = filter { it != null } as Iterator<T> fun <T> Iterator<T?>.filterNotNull(): Iterator<T> = filter { it != null } as Iterator<T>
fun <T> Iterator<T>.anyMatch(predicate: Predicate<in T>): Boolean { fun <T> Iterator<T>.any(predicate: Predicate<in T>): Boolean {
for (value in this) { for (value in this) {
if (predicate.test(value)) { if (predicate.test(value)) {
return true return true
@ -331,7 +255,7 @@ fun <T> Iterator<T>.anyMatch(predicate: Predicate<in T>): Boolean {
return false return false
} }
fun <T> Iterator<T>.allMatch(predicate: Predicate<in T>): Boolean { fun <T> Iterator<T>.all(predicate: Predicate<in T>): Boolean {
for (value in this) { for (value in this) {
if (!predicate.test(value)) { if (!predicate.test(value)) {
return false return false
@ -341,7 +265,7 @@ fun <T> Iterator<T>.allMatch(predicate: Predicate<in T>): Boolean {
return true return true
} }
fun <T> Iterator<T>.noneMatch(predicate: Predicate<in T>): Boolean { fun <T> Iterator<T>.none(predicate: Predicate<in T>): Boolean {
for (value in this) { for (value in this) {
if (predicate.test(value)) { if (predicate.test(value)) {
return false return false
@ -368,7 +292,7 @@ fun <T> Iterator<T>.toList(): MutableList<T> {
return result return result
} }
fun <T : Any> Iterator<T>.findFirst(): Optional<T> { fun <T : Any> Iterator<T>.find(): Optional<T> {
if (hasNext()) { if (hasNext()) {
return Optional.of(next()) return Optional.of(next())
} }
@ -376,7 +300,6 @@ fun <T : Any> Iterator<T>.findFirst(): Optional<T> {
return Optional.empty<T>() return Optional.empty<T>()
} }
fun <T : Any> Iterator<T>.findAny() = findFirst()
fun <T> Iterator<T>.limit(limit: Long) = LimitingIterator(this, limit) fun <T> Iterator<T>.limit(limit: Long) = LimitingIterator(this, limit)
fun <T> Iterator<T>.skip(skip: Long) = if (skip == 0L) this else SkippingIterator(this, skip) fun <T> Iterator<T>.skip(skip: Long) = if (skip == 0L) this else SkippingIterator(this, skip)
@ -418,8 +341,8 @@ fun <T : Any> Iterator<T>.max(comparator: Comparator<T>): Optional<T> {
return Optional.of(max) return Optional.of(max)
} }
fun <T> Iterator<T>.peek(peeker: (T) -> Unit): Iterator<T> { fun <T> Iterator<T>.peek(peeker: (T) -> Unit): MutableIterator<T> {
return object : Iterator<T> { return object : MutableIterator<T> {
override fun hasNext(): Boolean { override fun hasNext(): Boolean {
return this@peek.hasNext() return this@peek.hasNext()
} }
@ -427,5 +350,16 @@ fun <T> Iterator<T>.peek(peeker: (T) -> Unit): Iterator<T> {
override fun next(): T { override fun next(): T {
return this@peek.next().also(peeker) return this@peek.next().also(peeker)
} }
override fun remove() {
(this@peek as MutableIterator<T>).remove()
}
} }
} }
fun <T> Iterator<T>.maybe(): T? {
return if (hasNext())
next()
else
null
}

View File

@ -5,40 +5,40 @@ import ru.dbotthepony.mc.otm.core.util.EnumValueCodec
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
import kotlin.reflect.KMutableProperty0 import kotlin.reflect.KMutableProperty0
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu) = EnumInputWithFeedback(menu, E::class.java) inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, state: KMutableProperty0<E>?) = EnumInputWithFeedback(menu, E::class.java, state) inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, state: KMutableProperty0<E>?, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, state, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, state: GetterSetter<E>) = EnumInputWithFeedback(menu, E::class.java, state) inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, state: GetterSetter<E>?, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, state, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean) = EnumInputWithFeedback(menu, E::class.java, allowSpectators) inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: KMutableProperty0<E>?) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state) inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: KMutableProperty0<E>?, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state, allowedValues = allowedValues)
inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: GetterSetter<E>) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state) inline fun <reified E : Enum<E>> EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: GetterSetter<E>?, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state, allowedValues = allowedValues)
class EnumInputWithFeedback<E : Enum<E>>(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean = false) : AbstractPlayerInputWithFeedback<E>() { class EnumInputWithFeedback<E : Enum<E>>(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean = false, val allowedValues: Set<E>? = null) : AbstractPlayerInputWithFeedback<E>() {
val codec = EnumValueCodec(clazz) val codec = EnumValueCodec(clazz)
private val default = codec.values.first() private val default = codec.values.first()
override val input = menu.PlayerInput(codec, allowSpectators) { consumer?.invoke(it) } override val input = menu.PlayerInput(codec, allowSpectators) { if (allowedValues == null || it in allowedValues) consumer?.invoke(it) }
override val field = menu.mSynchronizer.ComputedField(getter = { supplier?.invoke() ?: default }, codec) override val field = menu.mSynchronizer.ComputedField(getter = { supplier?.invoke() ?: default }, codec)
constructor(menu: MatteryMenu, clazz: Class<E>, state: KMutableProperty0<E>?) : this(menu, clazz) { constructor(menu: MatteryMenu, clazz: Class<E>, state: KMutableProperty0<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowedValues = allowedValues) {
if (state != null) { if (state != null) {
with(state) with(state)
} }
} }
constructor(menu: MatteryMenu, clazz: Class<E>, state: GetterSetter<E>?) : this(menu, clazz) { constructor(menu: MatteryMenu, clazz: Class<E>, state: GetterSetter<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowedValues = allowedValues) {
if (state != null) { if (state != null) {
with(state) with(state)
} }
} }
constructor(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean, state: KMutableProperty0<E>?) : this(menu, clazz, allowSpectators) { constructor(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean, state: KMutableProperty0<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowSpectators, allowedValues = allowedValues) {
if (state != null) { if (state != null) {
with(state) with(state)
} }
} }
constructor(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean, state: GetterSetter<E>?) : this(menu, clazz, allowSpectators) { constructor(menu: MatteryMenu, clazz: Class<E>, allowSpectators: Boolean, state: GetterSetter<E>?, allowedValues: Set<E>? = null) : this(menu, clazz, allowSpectators, allowedValues = allowedValues) {
if (state != null) { if (state != null) {
with(state) with(state)
} }

View File

@ -10,7 +10,7 @@ import ru.dbotthepony.mc.otm.block.entity.storage.IItemMonitorPlayerSettings
import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorBlockEntity import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorBlockEntity
import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorPlayerSettings import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorPlayerSettings
import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.get
import ru.dbotthepony.mc.otm.core.collect.mapToInt import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.reduce 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
@ -206,7 +206,7 @@ class ItemMonitorMenu(
return ItemStack.EMPTY return ItemStack.EMPTY
} }
} else { } else {
if (crafted > 0 && crafted >= tile.craftingGrid.iterator().mapToInt { it.maxStackSize }.reduce(Int.MAX_VALUE, Int::coerceAtMost)) { if (crafted > 0 && crafted >= tile.craftingGrid.iterator().map { it.maxStackSize }.reduce(Int.MAX_VALUE, Int::coerceAtMost)) {
return ItemStack.EMPTY return ItemStack.EMPTY
} }
} }

View File

@ -2,33 +2,32 @@ package ru.dbotthepony.mc.otm.menu.storage
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.IntInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.IntInputWithFeedback
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class StorageBusMenu @JvmOverloads constructor( class StorageBusMenu(
containerId: Int, containerId: Int,
inventory: Inventory, inventory: Inventory,
tile: StorageBusBlockEntity? = null tile: StorageBusBlockEntity? = null
) : MatteryPoweredMenu(MMenus.STORAGE_BUS, containerId, inventory, tile) { ) : MatteryPoweredMenu(MMenus.STORAGE_BUS, containerId, inventory, tile) {
val busFilterSlots: List<ItemFilterNetworkSlot> val busFilterSlots: List<ItemFilterNetworkSlot>
val busFilterState: BooleanInputWithFeedback val busFilterState = BooleanInputWithFeedback(this, tile?.let { it.filter::isWhitelist })
val insertPriority: IntInputWithFeedback val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority })
val extractPriority: IntInputWithFeedback val extractPriority = IntInputWithFeedback(this, tile?.let { it::extractPriority })
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
val mode = EnumInputWithFeedback(this, tile?.let { it::mode }, FlowDirection.WITHOUT_NONE)
init { init {
if (tile != null) { if (tile != null) {
busFilterSlots = addFilterSlots(tile.filter) busFilterSlots = addFilterSlots(tile.filter)
busFilterState = BooleanInputWithFeedback(this, tile.filter::isWhitelist)
insertPriority = IntInputWithFeedback(this, tile::insertPriority)
extractPriority = IntInputWithFeedback(this, tile::extractPriority)
} else { } else {
busFilterSlots = addFilterSlots(StorageBusBlockEntity.MAX_FILTERS) busFilterSlots = addFilterSlots(StorageBusBlockEntity.MAX_FILTERS)
busFilterState = BooleanInputWithFeedback(this)
insertPriority = IntInputWithFeedback(this)
extractPriority = IntInputWithFeedback(this)
} }
addStorageSlot(batterySlot) addStorageSlot(batterySlot)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 847 B

After

Width:  |  Height:  |  Size: 981 B