Storage bus insert/extract priorities configuration, operation mode, small refactorings
This commit is contained in:
parent
b3249cdcd7
commit
f8c2be4d4c
@ -709,6 +709,11 @@ private fun gui(provider: MatteryLanguageProvider) {
|
||||
with(provider.english) {
|
||||
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.short.red", "R")
|
||||
|
@ -711,6 +711,11 @@ private fun gui(provider: MatteryLanguageProvider) {
|
||||
with(provider.russian) {
|
||||
gui("quicksearch", "Быстрый поиск...")
|
||||
|
||||
gui("insert_priority", "Приоритет вставки")
|
||||
gui("extract_priority", "Приоритет забора")
|
||||
gui("increase", "Увеличить")
|
||||
gui("decrease", "Уменьшить")
|
||||
|
||||
gui("color_picker", "Выбор цвета")
|
||||
|
||||
gui("color.short.red", "К")
|
||||
|
@ -44,6 +44,7 @@ import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.isMekanismLoaded
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper
|
||||
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.forValidRefs
|
||||
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>> {
|
||||
fun addListener(listener: Consumer<LazyOptional<T>>)
|
||||
}
|
||||
interface SideListener<T> : Supplier<LazyOptional<T>>, ISubscriptable<LazyOptional<T>>
|
||||
|
||||
inner class Side(val side: RelativeSide) {
|
||||
init {
|
||||
@ -194,17 +193,16 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
set(value) {
|
||||
if (value !== field) {
|
||||
field = value
|
||||
|
||||
for (tracker in listeners)
|
||||
tracker.accept(value)
|
||||
listeners.accept(value)
|
||||
}
|
||||
}
|
||||
|
||||
private val listeners = ArrayList<Consumer<LazyOptional<T>>>(0)
|
||||
private val listeners = ISubscriptable.Impl<LazyOptional<T>>()
|
||||
|
||||
override fun addListener(listener: Consumer<LazyOptional<T>>) {
|
||||
listeners.add(listener)
|
||||
override fun addListener(listener: Consumer<LazyOptional<T>>): ISubscriptable.L {
|
||||
val l = listeners.addListener(listener)
|
||||
listener.accept(value)
|
||||
return l
|
||||
}
|
||||
|
||||
override fun get(): LazyOptional<T> {
|
||||
@ -234,15 +232,16 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
private val mekanism: SubRef<IStrictEnergyHandler>?
|
||||
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>>) {
|
||||
listeners.add(listener)
|
||||
override fun addListener(listener: Consumer<LazyOptional<IEnergyStorage>>): ISubscriptable.L {
|
||||
val l = listeners.addListener(listener)
|
||||
listener.accept(get())
|
||||
return l
|
||||
}
|
||||
|
||||
init {
|
||||
regular.addListener { a -> listeners.forEach { it.accept(a) } }
|
||||
regular.addListener { listeners.accept(it) }
|
||||
|
||||
if (isMekanismLoaded) {
|
||||
mekanism = track(MatteryCapability.MEKANISM_ENERGY) as SubRef<IStrictEnergyHandler>
|
||||
@ -256,7 +255,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
actualMekanism = null
|
||||
}
|
||||
|
||||
listeners.forEach { it.accept(get()) }
|
||||
listeners.accept(get())
|
||||
}
|
||||
} else {
|
||||
mekanism = null
|
||||
|
@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.block.entity
|
||||
import it.unimi.dsi.fastutil.booleans.BooleanConsumer
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
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.set
|
||||
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
|
||||
@ -11,15 +13,15 @@ interface IRedstoneControlled {
|
||||
val redstoneControl: AbstractRedstoneControl
|
||||
}
|
||||
|
||||
abstract class AbstractRedstoneControl : INBTSerializable<CompoundTag?> {
|
||||
abstract class AbstractRedstoneControl : INBTSerializable<CompoundTag?>, IBooleanSubscriptable {
|
||||
abstract var redstoneSetting: RedstoneSetting
|
||||
abstract var redstoneSignal: Int
|
||||
protected val listeners = ArrayList<BooleanConsumer>()
|
||||
protected val listeners = IBooleanSubscriptable.Impl()
|
||||
|
||||
val isBlockedByRedstone: Boolean get() = !redstoneSetting.test(redstoneSignal)
|
||||
|
||||
fun addListener(callback: BooleanConsumer) {
|
||||
listeners.add(callback)
|
||||
final override fun addListener(listener: BooleanConsumer): ISubscriptable.L {
|
||||
return listeners.addListener(listener)
|
||||
}
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
@ -56,7 +58,7 @@ class RedstoneControl(private val valueChanges: (new: Boolean, old: Boolean) ->
|
||||
|
||||
if (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) {
|
||||
valueChanges.invoke(state, old)
|
||||
listeners.forEach { it.accept(state) }
|
||||
listeners.accept(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -89,7 +91,7 @@ class SynchronizedRedstoneControl(
|
||||
|
||||
if (state != old) {
|
||||
valueChanges.invoke(state, old)
|
||||
listeners.forEach { it.accept(state) }
|
||||
listeners.accept(state)
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -105,7 +107,7 @@ class SynchronizedRedstoneControl(
|
||||
|
||||
if (state != old) {
|
||||
valueChanges.invoke(state, old)
|
||||
listeners.forEach { it.accept(state) }
|
||||
listeners.accept(state)
|
||||
}
|
||||
}
|
||||
}).property
|
||||
|
@ -18,7 +18,9 @@ import ru.dbotthepony.mc.otm.*
|
||||
import ru.dbotthepony.mc.otm.block.CableBlock
|
||||
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.capability.FlowDirection
|
||||
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.config.MachinesConfig
|
||||
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) {
|
||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||
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) {
|
||||
override fun onNeighbour(link: Link) {
|
||||
if (link is DirectionLink) {
|
||||
@ -93,8 +89,13 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
|
||||
setChangedLight()
|
||||
}
|
||||
|
||||
var mode: FlowDirection = FlowDirection.BI_DIRECTIONAL
|
||||
set(value) {
|
||||
field = value
|
||||
setChangedLight()
|
||||
}
|
||||
|
||||
init {
|
||||
exposeEnergyGlobally(energy)
|
||||
savetable(::energy, ENERGY_KEY)
|
||||
savetables.int(::insertPriority)
|
||||
savetables.int(::extractPriority)
|
||||
@ -103,11 +104,21 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
|
||||
side(RelativeSide.FRONT).track(ForgeCapabilities.ITEM_HANDLER).addListener {
|
||||
component?.let(cell::removeStorageComponent)
|
||||
component = if (it.isPresent) {
|
||||
ItemHandlerComponent(it.orThrow()).also(cell::addStorageComponent)
|
||||
ItemHandlerComponent(it.orThrow()).also { if (!redstoneControl.isBlockedByRedstone) cell.addStorageComponent(it) }
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
redstoneControl.addListener {
|
||||
val component = component ?: return@addListener
|
||||
|
||||
if (it) {
|
||||
cell.removeStorageComponent(component)
|
||||
} else {
|
||||
cell.addStorageComponent(component)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val filter = ItemFilter(MAX_FILTERS) { _, _, _ ->
|
||||
@ -359,7 +370,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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 {
|
||||
if (redstoneControl.isBlockedByRedstone || !amount.isPositive || !energy.batteryLevel.isPositive)
|
||||
if (redstoneControl.isBlockedByRedstone || !amount.isPositive || !energy.batteryLevel.isPositive || !mode.output)
|
||||
return ItemStorageStack.EMPTY
|
||||
|
||||
var total = BigInteger.ZERO
|
||||
|
@ -21,7 +21,8 @@ import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||
import ru.dbotthepony.mc.otm.container.balance
|
||||
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.TwinPlatePressMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
@ -92,8 +93,7 @@ class PlatePressBlockEntity(
|
||||
.values
|
||||
.iterator()
|
||||
.filter { it.matches(inputContainer, id) }
|
||||
.findAny()
|
||||
.orElse(null) ?: return JobContainer.noItem()
|
||||
.maybe() ?: return JobContainer.noItem()
|
||||
|
||||
val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems)
|
||||
|
||||
|
@ -64,7 +64,7 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio
|
||||
}.build()
|
||||
}
|
||||
|
||||
val translation: Component
|
||||
val title: Component
|
||||
get() = TranslatableComponent(translationKey)
|
||||
|
||||
/**
|
||||
@ -105,6 +105,9 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val WITHOUT_NONE: ImmutableSet<FlowDirection> = ImmutableSet.of(INPUT, OUTPUT, BI_DIRECTIONAL)
|
||||
|
||||
@JvmStatic
|
||||
fun of(input: Boolean, output: Boolean): FlowDirection {
|
||||
if (input && output) {
|
||||
|
@ -30,6 +30,10 @@ enum class GravityRounding {
|
||||
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 {
|
||||
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 {
|
||||
return base - subtraction
|
||||
}
|
||||
|
||||
override fun round(base: Float): Float {
|
||||
return base
|
||||
}
|
||||
};
|
||||
|
||||
abstract fun round(base: Float, subtraction: Float): Float
|
||||
abstract fun round(base: Float): Float
|
||||
}
|
||||
|
||||
interface IXGravity {
|
||||
@ -60,6 +73,8 @@ interface IXGravity {
|
||||
fun x(x: Float, width: FloatSupplier): 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, 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): 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 {
|
||||
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 {
|
||||
return x
|
||||
}
|
||||
|
||||
override fun repositionX(outer: Float, inner: Float, rounding: GravityRounding): Float {
|
||||
return 0f
|
||||
}
|
||||
},
|
||||
CENTER {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return y
|
||||
}
|
||||
|
||||
override fun repositionY(outer: Float, inner: Float, rounding: GravityRounding): Float {
|
||||
return 0f
|
||||
}
|
||||
},
|
||||
|
||||
CENTER {
|
||||
@ -170,6 +209,13 @@ enum class YGravity : IYGravity {
|
||||
override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float {
|
||||
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 {
|
||||
@ -180,6 +226,13 @@ enum class YGravity : IYGravity {
|
||||
override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float {
|
||||
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)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.client.render.sprites.MatteryAtlas
|
||||
|
||||
object WidgetLocation {
|
||||
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 SLOT_BACKGROUNDS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/slot_backgrounds.png"), 72f, 72f)
|
||||
|
||||
|
@ -37,7 +37,7 @@ object Widgets18 {
|
||||
val BUTTON_DISABLED_STRETCHABLE = makeButton(buttonGrids)
|
||||
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_UP = storageGrid.next()
|
||||
val SORT_DEFAULT = storageGrid.next()
|
||||
@ -47,6 +47,9 @@ object Widgets18 {
|
||||
val SORT_ID = storageGrid.next()
|
||||
val SORT_MATTER_VALUE = 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)
|
||||
|
||||
|
@ -19,6 +19,7 @@ import net.minecraftforge.common.MinecraftForge
|
||||
import org.lwjgl.opengl.GL11
|
||||
import ru.dbotthepony.mc.otm.capability.matteryPlayer
|
||||
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.translation
|
||||
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.ScrollBarConstants
|
||||
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.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.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.math.component1
|
||||
import ru.dbotthepony.mc.otm.core.math.component2
|
||||
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
|
||||
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 kotlin.collections.ArrayDeque
|
||||
import kotlin.collections.List
|
||||
@ -374,6 +384,59 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
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
|
||||
*
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
val isEmpty get() = left == 0f && right == 0f && top == 0f && bottom == 0f
|
||||
val horizontal get() = left + right
|
||||
val vertical get() = top + bottom
|
||||
|
||||
companion object {
|
||||
val EMPTY = DockProperty()
|
||||
@ -73,7 +75,6 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
|
||||
height: Float = 10f,
|
||||
) : Comparable<EditablePanel<*>> {
|
||||
// layout engine does not support navigation using keyboard
|
||||
// fuck off
|
||||
val listener: GuiEventListener = object : GuiEventListener {
|
||||
override fun setFocused(p_265728_: Boolean) {
|
||||
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
|
||||
set(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
|
||||
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
|
||||
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 acceptKeyboardInput = true
|
||||
var grabMouseInput = false
|
||||
@ -1060,7 +1100,11 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
|
||||
|
||||
for (child in visibleChildrenInternal) {
|
||||
when (child.dock) {
|
||||
Dock.NONE -> {}
|
||||
Dock.NONE -> {
|
||||
child.dockedWidth = child.width + child.dockMargin.horizontal
|
||||
child.dockedHeight = child.height + child.dockMargin.vertical
|
||||
}
|
||||
|
||||
Dock.FILL -> {}
|
||||
|
||||
Dock.LEFT -> {
|
||||
@ -1192,8 +1236,8 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
|
||||
*
|
||||
* Performs layout if required
|
||||
*/
|
||||
open fun sizeToContents() {
|
||||
if (layoutInvalidated) {
|
||||
open fun sizeToContents(performLayout: Boolean = true) {
|
||||
if (layoutInvalidated && performLayout) {
|
||||
performLayout()
|
||||
}
|
||||
|
||||
@ -1398,8 +1442,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun getChildren(index: Int): EditablePanel<*>? {
|
||||
if (index < 0 || index >= childrenInternal.size) return null
|
||||
return childrenInternal[index]
|
||||
return childrenInternal.getOrNull(index)
|
||||
}
|
||||
|
||||
fun isGrabbingMouseInput(): Boolean {
|
||||
|
@ -61,8 +61,8 @@ open class Label<out S : Screen> @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun sizeToContents() {
|
||||
super.sizeToContents()
|
||||
override fun sizeToContents(performLayout: Boolean) {
|
||||
super.sizeToContents(performLayout)
|
||||
|
||||
val w = font.width(text)
|
||||
val h = font.lineHeight + 2
|
||||
|
@ -56,8 +56,8 @@ open class ButtonPanel<out S : Screen>(
|
||||
graphics.draw(font, label, width / 2f, height / 2f, color = textColor, gravity = RenderGravity.CENTER_CENTER)
|
||||
}
|
||||
|
||||
override fun sizeToContents() {
|
||||
super.sizeToContents()
|
||||
override fun sizeToContents(performLayout: Boolean) {
|
||||
super.sizeToContents(performLayout)
|
||||
|
||||
height = height.coerceAtLeast(HEIGHT).coerceAtLeast(font.lineHeight.toFloat() + 2f)
|
||||
width = width.coerceAtLeast(HEIGHT).coerceAtLeast(font.width(label) + 4f)
|
||||
|
@ -4,12 +4,13 @@ import net.minecraft.client.gui.screens.Screen
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.menu.input.AbstractPlayerInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.milliTime
|
||||
|
||||
open class NetworkedStringInputPanel<out S : Screen>(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>?,
|
||||
val backend: AbstractPlayerInputWithFeedback<String>,
|
||||
val backend: IPlayerInputWithFeedback<String>,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
width: Float = 60f,
|
||||
@ -29,7 +30,7 @@ open class NetworkedStringInputPanel<out S : Screen>(
|
||||
|
||||
private var lastChanges = 0L
|
||||
|
||||
override fun onTextChanged(old: String, new: String) {
|
||||
override fun onTextChanged(new: String, old: String) {
|
||||
lastChanges = milliTime + 1000L
|
||||
backend.accept(new)
|
||||
}
|
||||
@ -38,7 +39,7 @@ open class NetworkedStringInputPanel<out S : Screen>(
|
||||
super.tickInner()
|
||||
|
||||
if (milliTime >= lastChanges) {
|
||||
text = backend.value
|
||||
text = backend.get()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
@ -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.core.TextComponent
|
||||
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.math.RGBAColor
|
||||
import ru.dbotthepony.mc.otm.milliTime
|
||||
@ -904,7 +904,7 @@ open class TextInputPanel<out S : Screen>(
|
||||
pushbackSnapshot()
|
||||
|
||||
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 actualLastSize = insert.lastOrNull()?.length ?: 0
|
||||
val line = this[cursorLine]
|
||||
@ -944,7 +944,7 @@ open class TextInputPanel<out S : Screen>(
|
||||
cursorRow = actualLastSize
|
||||
}
|
||||
} 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 line = this[cursorLine]
|
||||
|
||||
@ -1462,7 +1462,7 @@ open class TextInputPanel<out S : Screen>(
|
||||
}
|
||||
|
||||
private val NUMBERS = CharOpenHashSet().also {
|
||||
for (char in "0123456789-+")
|
||||
for (char in "0123456789.")
|
||||
it.add(char)
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,12 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen.panels.util
|
||||
|
||||
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.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>(
|
||||
screen: S,
|
||||
@ -26,37 +30,54 @@ open class GridPanel<out S : Screen>(
|
||||
invalidateLayout()
|
||||
}
|
||||
|
||||
override fun performLayout() {
|
||||
var currentX = 0f
|
||||
var currentY = 0f
|
||||
var lineY = 0f
|
||||
var index = 0
|
||||
|
||||
for (row in 0 until rows) {
|
||||
var column = 0
|
||||
|
||||
while (column < columns) {
|
||||
val child = getChildren(index) ?: break
|
||||
|
||||
if (child.visible && child.dock === Dock.NONE) {
|
||||
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++
|
||||
column++
|
||||
}
|
||||
|
||||
currentY += lineY
|
||||
currentX = 0f
|
||||
lineY = 0f
|
||||
|
||||
getChildren(index) ?: break
|
||||
var gravity: RenderGravity = RenderGravity.CENTER_CENTER
|
||||
set(value) {
|
||||
field = value
|
||||
invalidateLayout()
|
||||
}
|
||||
|
||||
override fun performLayout() {
|
||||
super.performLayout()
|
||||
var children = visibleChildren.iterator().filter { it.dock == Dock.NONE }
|
||||
|
||||
var totalWidth = 0f
|
||||
var 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
|
||||
width += child.dockedWidth
|
||||
maxHeight = maxHeight.coerceAtLeast(child.dockedHeight)
|
||||
}
|
||||
|
||||
totalWidth = totalWidth.coerceAtLeast(width)
|
||||
totalHeight += maxHeight
|
||||
}
|
||||
|
||||
val alignX = gravity.repositionX(width, totalWidth)
|
||||
val alignY = gravity.repositionY(height, totalHeight)
|
||||
children = visibleChildren.iterator().filter { it.dock == Dock.NONE }
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
totalWidth = totalWidth.coerceAtLeast(width)
|
||||
totalHeight += maxHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ open class HeightControls<out S : Screen>(
|
||||
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 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
|
||||
@ -57,10 +57,14 @@ open class HeightControls<out S : Screen>(
|
||||
dockBottom = 2f
|
||||
}
|
||||
|
||||
override fun onClick(clickButton: Int) {
|
||||
if (clickButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||
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) {
|
||||
this@HeightControls.onClick(isIncrease)
|
||||
} else if (clickButton == InputConstants.MOUSE_BUTTON_RIGHT) {
|
||||
} else if (mouseButton == InputConstants.MOUSE_BUTTON_RIGHT) {
|
||||
this@HeightControls.onClick(!isIncrease)
|
||||
}
|
||||
}
|
||||
|
@ -13,13 +13,13 @@ class HorizontalStripPanel<out S : Screen>(
|
||||
width: Float = 0f,
|
||||
height: Float = 0f,
|
||||
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||
override fun sizeToContents() {
|
||||
override fun sizeToContents(performLayout: Boolean) {
|
||||
var w = 0f
|
||||
var h = 0f
|
||||
|
||||
for (child in children) {
|
||||
for (child in visibleChildren) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -33,19 +33,19 @@ class HorizontalStripPanel<out S : Screen>(
|
||||
|
||||
var w = 0f
|
||||
|
||||
for (child in children) {
|
||||
for (child in visibleChildren) {
|
||||
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
|
||||
|
||||
for (child in children) {
|
||||
for (child in visibleChildren) {
|
||||
if (child.dock == Dock.NONE) {
|
||||
child.y = (height / 2f - child.height / 2f).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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,57 +2,64 @@ package ru.dbotthepony.mc.otm.client.screen.storage
|
||||
|
||||
import net.minecraft.network.chat.Component
|
||||
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.core.TranslatableComponent
|
||||
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.makeDeviceControls
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeEnumRectangleButtonPanel
|
||||
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.widget.WidePowerGaugePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
|
||||
|
||||
import ru.dbotthepony.mc.otm.menu.storage.StorageBusMenu
|
||||
|
||||
class StorageBusScreen(menu: StorageBusMenu, inventory: Inventory, title: Component) :
|
||||
MatteryScreen<StorageBusMenu>(menu, inventory, title) {
|
||||
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)
|
||||
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
|
||||
makeBars(frame, profiledEnergy = menu.profiledEnergy, batterySlot = menu.batterySlot)
|
||||
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 (column in 0 .. 5) {
|
||||
FilterSlotPanel(this, frame, menu.busFilterSlots[row + column * 3], 55f + 18f * column, 17f + 18f * row)
|
||||
}
|
||||
for (slot in menu.busFilterSlots)
|
||||
FilterSlotPanel(this, grid, slot)
|
||||
|
||||
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
|
||||
it.dockBottom = 2f
|
||||
it.tooltips.add(TranslatableComponent("otm.gui.extract_priority"))
|
||||
it.childrenOrder = -2
|
||||
}
|
||||
|
||||
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig)
|
||||
CheckBoxLabelInputPanel(this, right, menu.busFilterState, TranslatableComponent("otm.gui.filter.is_whitelist")).also {
|
||||
it.dock = Dock.BOTTOM
|
||||
it.childrenOrder = -3
|
||||
}
|
||||
|
||||
/*object : TextInputPanel<StorageBusScreen>(this@StorageBusScreen, frame) {
|
||||
init {
|
||||
allowNumbersAndSign()
|
||||
dock = Dock.BOTTOM
|
||||
}
|
||||
val controls = DeviceControls(this, frame, redstoneConfig = menu.redstoneConfig)
|
||||
val mode = LargeEnumRectangleButtonPanel(this, frame, prop = menu.mode, defaultValue = FlowDirection.BI_DIRECTIONAL, enum = FlowDirection::class.java)
|
||||
|
||||
override fun tickInner() {
|
||||
super.tickInner()
|
||||
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()
|
||||
|
||||
if (!hasHierarchicalFocus()) {
|
||||
text = menu.insertPriority.value.toString()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTextChanged(new: String, old: String) {
|
||||
if (hasHierarchicalFocus()) {
|
||||
val i = new.toIntOrNull()
|
||||
if (i != null) menu.insertPriority.accept(i)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
controls.addButton(mode)
|
||||
|
||||
return frame
|
||||
}
|
||||
|
@ -5,13 +5,8 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability
|
||||
import ru.dbotthepony.mc.otm.capability.UpgradeType
|
||||
import ru.dbotthepony.mc.otm.config.EnergyBalanceValues
|
||||
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.mapToDouble
|
||||
import ru.dbotthepony.mc.otm.core.collect.mapToInt
|
||||
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 kotlin.math.pow
|
||||
|
||||
@ -28,9 +23,9 @@ open class UpgradeContainer(slotCount: Int, open val allowedUpgrades: Set<Upgrad
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
get() = decimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus)
|
||||
override val energyStorage: Decimal
|
||||
@ -42,7 +37,7 @@ open class UpgradeContainer(slotCount: Int, open val allowedUpgrades: Set<Upgrad
|
||||
override val energyConsumed: Decimal
|
||||
get() = decimals(IMatteryUpgrade::energyConsumed, Decimal::plus)
|
||||
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
|
||||
get() = decimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus)
|
||||
override val energyThroughput: Decimal
|
||||
|
@ -0,0 +1,5 @@
|
||||
package ru.dbotthepony.mc.otm.core
|
||||
|
||||
interface ByteSupplier {
|
||||
fun getAsByte(): Byte
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package ru.dbotthepony.mc.otm.core
|
||||
|
||||
interface ShortSupplier {
|
||||
fun getAsShort(): Short
|
||||
}
|
@ -21,7 +21,7 @@ import java.util.stream.Collector
|
||||
*
|
||||
* 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
|
||||
|
||||
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
|
||||
*
|
||||
@ -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
|
||||
*
|
||||
* 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]
|
||||
@ -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 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 {
|
||||
var result = identity
|
||||
|
||||
for (value in this) {
|
||||
result = reducer.invoke(result, value)
|
||||
}
|
||||
|
||||
for (value in this) result = reducer.invoke(result, value)
|
||||
return result
|
||||
}
|
||||
|
||||
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>.anyMatch(predicate: Predicate<in T>): Boolean {
|
||||
fun <T> Iterator<T>.any(predicate: Predicate<in T>): Boolean {
|
||||
for (value in this) {
|
||||
if (predicate.test(value)) {
|
||||
return true
|
||||
@ -331,7 +255,7 @@ fun <T> Iterator<T>.anyMatch(predicate: Predicate<in T>): Boolean {
|
||||
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) {
|
||||
if (!predicate.test(value)) {
|
||||
return false
|
||||
@ -341,7 +265,7 @@ fun <T> Iterator<T>.allMatch(predicate: Predicate<in T>): Boolean {
|
||||
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) {
|
||||
if (predicate.test(value)) {
|
||||
return false
|
||||
@ -368,7 +292,7 @@ fun <T> Iterator<T>.toList(): MutableList<T> {
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T : Any> Iterator<T>.findFirst(): Optional<T> {
|
||||
fun <T : Any> Iterator<T>.find(): Optional<T> {
|
||||
if (hasNext()) {
|
||||
return Optional.of(next())
|
||||
}
|
||||
@ -376,7 +300,6 @@ fun <T : Any> Iterator<T>.findFirst(): Optional<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>.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)
|
||||
}
|
||||
|
||||
fun <T> Iterator<T>.peek(peeker: (T) -> Unit): Iterator<T> {
|
||||
return object : Iterator<T> {
|
||||
fun <T> Iterator<T>.peek(peeker: (T) -> Unit): MutableIterator<T> {
|
||||
return object : MutableIterator<T> {
|
||||
override fun hasNext(): Boolean {
|
||||
return this@peek.hasNext()
|
||||
}
|
||||
@ -427,5 +350,16 @@ fun <T> Iterator<T>.peek(peeker: (T) -> Unit): Iterator<T> {
|
||||
override fun next(): T {
|
||||
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
|
||||
}
|
@ -5,40 +5,40 @@ import ru.dbotthepony.mc.otm.core.util.EnumValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
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, state: KMutableProperty0<E>?) = EnumInputWithFeedback(menu, E::class.java, state)
|
||||
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, allowedValues: Set<E>? = null) = EnumInputWithFeedback(menu, E::class.java, allowedValues = allowedValues)
|
||||
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>?, 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, state: KMutableProperty0<E>?) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state)
|
||||
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, 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>?, 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>?, 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)
|
||||
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)
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
with(state)
|
||||
}
|
||||
|
@ -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.ItemMonitorPlayerSettings
|
||||
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.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
|
||||
@ -206,7 +206,7 @@ class ItemMonitorMenu(
|
||||
return ItemStack.EMPTY
|
||||
}
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
@ -2,33 +2,32 @@ package ru.dbotthepony.mc.otm.menu.storage
|
||||
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
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.menu.MatteryPoweredMenu
|
||||
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.widget.ProfiledLevelGaugeWidget
|
||||
import ru.dbotthepony.mc.otm.registry.MMenus
|
||||
|
||||
class StorageBusMenu @JvmOverloads constructor(
|
||||
class StorageBusMenu(
|
||||
containerId: Int,
|
||||
inventory: Inventory,
|
||||
tile: StorageBusBlockEntity? = null
|
||||
) : MatteryPoweredMenu(MMenus.STORAGE_BUS, containerId, inventory, tile) {
|
||||
val busFilterSlots: List<ItemFilterNetworkSlot>
|
||||
val busFilterState: BooleanInputWithFeedback
|
||||
val insertPriority: IntInputWithFeedback
|
||||
val extractPriority: IntInputWithFeedback
|
||||
val busFilterState = BooleanInputWithFeedback(this, tile?.let { it.filter::isWhitelist })
|
||||
val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority })
|
||||
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 {
|
||||
if (tile != null) {
|
||||
busFilterSlots = addFilterSlots(tile.filter)
|
||||
busFilterState = BooleanInputWithFeedback(this, tile.filter::isWhitelist)
|
||||
insertPriority = IntInputWithFeedback(this, tile::insertPriority)
|
||||
extractPriority = IntInputWithFeedback(this, tile::extractPriority)
|
||||
} else {
|
||||
busFilterSlots = addFilterSlots(StorageBusBlockEntity.MAX_FILTERS)
|
||||
busFilterState = BooleanInputWithFeedback(this)
|
||||
insertPriority = IntInputWithFeedback(this)
|
||||
extractPriority = IntInputWithFeedback(this)
|
||||
}
|
||||
|
||||
addStorageSlot(batterySlot)
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 847 B After Width: | Height: | Size: 981 B |
Binary file not shown.
Loading…
Reference in New Issue
Block a user