Compare commits

...

3 Commits

21 changed files with 386 additions and 147 deletions

View File

@ -853,6 +853,24 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) {
with(provider.english) {
gui("black_hole_generator.help0", "Generates energy using angular momentum of Singularities")
gui("black_hole_generator.help1", "The stronger gravity Singularity has, the more power is generated!")
gui("black_hole_generator.help2", "Using Spacetime Normalizers will reduce gravitation strength of Singularity, which will reduce power output.")
gui("black_hole_generator.help3", "This machine is the only 'safe' way of disposing Singularities, by draining them dry by continuously injecting antimatter until Singularity lose all its mass")
gui("black_hole_generator.injection_rate.mode", "Injection rate")
gui("black_hole_generator.injection_rate.desc", "Amount of MtU injected each tick, from either injectors (or both)")
gui("black_hole_generator.target_mass.mode", "Target mass")
gui("black_hole_generator.sustain.mode", "Sustain")
gui("black_hole_generator.sustain.desc", "Keep Singularity's mass at target level, injecting matter or antimatter when necessary")
gui("black_hole_generator.matter_only.mode", "Inject matter only")
gui("black_hole_generator.matter_only.desc", "Only inject matter into singularity. Way less power generated, but mass of Singularity will increase over time, as well as power output")
gui("black_hole_generator.antimatter_only.mode", "Inject antimatter only")
gui("black_hole_generator.antimatter_only.desc", "Only inject antimatter into singularity. Way more power generated, but mass of Singularity will decrease over time, as well as power output")
gui("draw_multiblock_guide", "Draw building guide")
gui("ago", "%s ago")

View File

@ -857,6 +857,23 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) {
with(provider.russian) {
gui("black_hole_generator.help0", "Генерирует электричество используя угловое ускорение сингулярностей")
gui("black_hole_generator.help1", "Чем сильнее гравитационное поле сингулярности, тем больше генерация!")
gui("black_hole_generator.help2", "Использование стабилизаторов пространства-времени ослабляет гравитационное поле, снижая генерацию")
gui("black_hole_generator.help3", "Данный генератор единственный способ 'безопасно' избавиться от сингулярности, полностью лишив её накопленной массы в режиме подпитки антиматерией")
gui("black_hole_generator.injection_rate.mode", "Скорость подпитки")
gui("black_hole_generator.target_mass.mode", "Целевая масса")
gui("black_hole_generator.sustain.mode", "Поддерживать массу")
gui("black_hole_generator.sustain.desc", "Поддерживать массу сингулярности на заданном значении, подпитывая материей или антиматерией по мере необходимости")
gui("black_hole_generator.matter_only.mode", "Подпитка материей")
gui("black_hole_generator.matter_only.desc", "Подпитывать только материей, существенно снизив генерацию энергии, но увеличивая массу сингулярности, а так же дальнейшую выработку энергии")
gui("black_hole_generator.antimatter_only.mode", "Подпитка антиматерией")
gui("black_hole_generator.antimatter_only.desc", "Подпитывать только антиматерией, существенно увеличив генерацию энергии, но уменьшая массу сингулярности, а так же дальнейшую выработку энергии")
gui("draw_multiblock_guide", "Отображать помощника постройки")
gui("ago", "%s тому назад")

View File

@ -44,7 +44,6 @@ import ru.dbotthepony.mc.otm.config.ClientConfig;
import ru.dbotthepony.mc.otm.config.ExopackConfig;
import ru.dbotthepony.mc.otm.config.ItemsConfig;
import ru.dbotthepony.mc.otm.config.MachinesConfig;
import ru.dbotthepony.mc.otm.config.ServerCompatConfig;
import ru.dbotthepony.mc.otm.config.ServerConfig;
import ru.dbotthepony.mc.otm.config.ToolsConfig;
import ru.dbotthepony.mc.otm.data.DecimalProvider;
@ -170,7 +169,6 @@ public final class OverdriveThatMatters {
ClientConfig.INSTANCE.register(container);
ServerConfig.INSTANCE.register(container);
CablesConfig.INSTANCE.register(container);
ServerCompatConfig.INSTANCE.register(container);
AndroidConfig.INSTANCE.register(container);
ExopackConfig.INSTANCE.register(container);
ItemsConfig.INSTANCE.register(container);

View File

@ -49,7 +49,7 @@ import kotlin.math.roundToInt
import kotlin.math.sqrt
class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryBlockEntity(MBlockEntities.BLACK_HOLE, p_155229_, p_155230_) {
var mass by syncher.decimal(BASELINE_MASS, setter = setter@{ field, mass ->
var mass by syncher.decimal(ServerConfig.Blackhole.BASELINE_MASS, setter = setter@{ field, mass ->
if (level !is ServerLevel) {
field.accept(mass)
return@setter
@ -118,7 +118,7 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery
else -> massForDiv /= 16384
}
gravitationStrength = sqrt(massForDiv.div(BASELINE_MASS).toDouble()).coerceIn(0.2, 40.0)
gravitationStrength = sqrt(massForDiv.div(ServerConfig.Blackhole.BASELINE_MASS).toDouble()).coerceIn(0.2, 40.0)
affectedBounds = BoundingBox(
(-30 * gravitationStrength).toInt(),
(-30 * gravitationStrength).toInt(),
@ -141,7 +141,7 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery
override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) {
super.loadAdditional(nbt, registry)
mass = nbt.map("mass", Decimal::deserializeNBT) ?: BASELINE_MASS
mass = nbt.map("mass", Decimal::deserializeNBT) ?: ServerConfig.Blackhole.BASELINE_MASS
spinDirection = nbt.getBoolean("spin_direction")
}
@ -307,7 +307,6 @@ class BlackHoleBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mattery
companion object {
const val ITERATIONS = 30_000
val BASELINE_MASS = Decimal(50_000)
val HAWKING_MASS_LOSE_STEP = Decimal(-100)
}
}

View File

@ -1,9 +1,12 @@
package ru.dbotthepony.mc.otm.block.entity.blackhole
import com.mojang.serialization.Codec
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import it.unimi.dsi.fastutil.objects.ObjectIterators
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.util.StringRepresentable
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
@ -22,10 +25,13 @@ import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.receiveEnergy
import ru.dbotthepony.mc.otm.capability.matter.CombinedProfiledMatterStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.config.ServerConfig
import ru.dbotthepony.mc.otm.core.RandomSource2Generator
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.multiblock.ShapedMultiblock
import ru.dbotthepony.mc.otm.core.getBlockStateNow
import ru.dbotthepony.mc.otm.core.getValue
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.plus
@ -38,6 +44,7 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MBlockTags
import ru.dbotthepony.mc.otm.registry.MBlocks
import java.io.Closeable
import kotlin.math.min
class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.BLACK_HOLE_GENERATOR, blockPos, blockState) {
var multiblock: ShapedMultiblock? = null
@ -74,10 +81,38 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
{ level?.random?.let { RandomSource2Generator(it) } }
)
enum class Mode(val label: Component, val tooltip: Component) {
TARGET_MASS(TranslatableComponent("otm.gui.black_hole_generator.sustain.mode"), TranslatableComponent("otm.gui.black_hole_generator.sustain.desc")),
MATTER_ONLY(TranslatableComponent("otm.gui.black_hole_generator.matter_only.mode"), TranslatableComponent("otm.gui.black_hole_generator.matter_only.desc")),
ANTIMATTER_ONLY(TranslatableComponent("otm.gui.black_hole_generator.antimatter_only.mode"), TranslatableComponent("otm.gui.black_hole_generator.antimatter_only.desc"));
}
var mode = Mode.TARGET_MASS
set(value) {
field = value
markDirtyFast()
}
var injectionRate = Decimal.ONE_TENTH
set(value) {
field = maxOf(Decimal.ONE_TENTH, value)
markDirtyFast()
}
var targetMass = ServerConfig.Blackhole.BASELINE_MASS
set(value) {
field = maxOf(Decimal.ONE, value)
markDirtyFast()
}
init {
exposeSideless(MatteryCapability.MATTER_BLOCK, matter)
exposeSideless(MatteryCapability.BLOCK_ENERGY, energy)
exposeSideless(Capabilities.EnergyStorage.BLOCK, energy)
savetables.enum(::mode, map = Mode::valueOf)
savetables.decimal(::injectionRate)
savetables.decimal(::targetMass)
}
private fun findBlackHoleRange(): Int {
@ -109,6 +144,9 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
energy.tick()
matter.tick()
if (redstoneControl.isBlockedByRedstone)
return
val level = level!!
if (lastRange == -1) {
@ -123,14 +161,48 @@ class BlackHoleGeneratorBlockEntity(blockPos: BlockPos, blockState: BlockState)
} else {
val blackHole = multiblock.blockEntities(BLACK_HOLE).first()
if (matter.extractMatter(MachinesConfig.BlackHoleGenerator.MATTER_RATE, true) != MachinesConfig.BlackHoleGenerator.MATTER_RATE) return
val energyToStore = blackHole.mass / MachinesConfig.BlackHoleGenerator.MASS_DIVISOR
if (energy.receiveEnergy(energyToStore, true) != energyToStore) return
val matterExtracted = matter.extractMatter(if (mode == Mode.TARGET_MASS && blackHole.mass != targetMass) minOf(injectionRate, (blackHole.mass - targetMass).absoluteValue) else injectionRate, true)
if (!matterExtracted.isPositive) return
matter.extractMatter(MachinesConfig.BlackHoleGenerator.MATTER_RATE, false)
energy.receiveEnergy(energyToStore, false)
val targetEnergy = when (mode) {
Mode.TARGET_MASS -> {
if (targetMass > blackHole.mass) {
MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_FEED * matterExtracted * blackHole.gravitationStrength
} else if (targetMass < blackHole.mass) {
MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_DRAIN * matterExtracted * blackHole.gravitationStrength
} else {
MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_SUSTAIN * matterExtracted * blackHole.gravitationStrength
}
}
blackHole.mass += MachinesConfig.BlackHoleGenerator.MASS_FEEDING_RATIO * MachinesConfig.BlackHoleGenerator.MATTER_RATE
Mode.MATTER_ONLY -> MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_FEED * matterExtracted
Mode.ANTIMATTER_ONLY -> MachinesConfig.BlackHoleGenerator.GENERATION_RATIO_DRAIN * matterExtracted
}
val energyInserted = energy.receiveEnergy(targetEnergy, true)
if (!energyInserted.isPositive) return
val actualMatterRatio = energyInserted / targetEnergy * matterExtracted
matter.extractMatter(actualMatterRatio, false)
energy.receiveEnergy(energyInserted, false)
when (mode) {
Mode.TARGET_MASS -> {
if (targetMass > blackHole.mass) {
blackHole.mass += actualMatterRatio * MachinesConfig.BlackHoleGenerator.FEEDING_EFFICIENCY
} else if (targetMass < blackHole.mass) {
blackHole.mass -= actualMatterRatio * MachinesConfig.BlackHoleGenerator.DRAINING_EFFICIENCY
}
}
Mode.MATTER_ONLY -> {
blackHole.mass += actualMatterRatio * MachinesConfig.BlackHoleGenerator.FEEDING_EFFICIENCY
}
Mode.ANTIMATTER_ONLY -> {
blackHole.mass -= actualMatterRatio * MachinesConfig.BlackHoleGenerator.DRAINING_EFFICIENCY
}
}
}
}
}

View File

@ -16,4 +16,11 @@ object Widgets15 {
val BUTTON_PRESSED = misc15.next()
val BUTTON_DISABLED_STRETCHABLE = misc15.makeButton(2f)
val BUTTON_DISABLED = misc15.next()
val RADIO_IDLE = misc15.next()
val RADIO_HOVERED = misc15.next()
val RADIO_PRESSED = misc15.next()
val RADIO_DISABLED = misc15.next()
val RADIO_ICON = misc15.next()
val RADIO_ICON_DISABLED = misc15.next()
}

View File

@ -7,9 +7,9 @@ import ru.dbotthepony.mc.otm.client.render.RenderGravity
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.kommons.math.RGBAColor
open class Label<out S : Screen> @JvmOverloads constructor(
open class Label<out S : Screen>(
screen: S,
parent: EditablePanel<*>?,
parent: EditablePanel<*>? = null,
x: Float = 0f,
y: Float = 0f,
width: Float = 100f,

View File

@ -23,10 +23,8 @@ abstract class BooleanButtonPanel<out S : Screen>(
y: Float = 0f,
width: Float,
height: Float,
val isChecked: Delegate<Boolean>,
) : ButtonPanel<S>(screen, parent, x, y, width, height) {
protected abstract fun onChange(newValue: Boolean)
abstract var isChecked: Boolean
abstract val tooltipActive: Component?
abstract val tooltipInactive: Component?
abstract val iconActive: IGUIRenderable?
@ -36,17 +34,25 @@ abstract class BooleanButtonPanel<out S : Screen>(
open val iconDisabledInactive: IGUIRenderable?
get() = iconInactive
override var isDisabled: Boolean
get() {
if (isChecked is IPlayerInputWithFeedback<Boolean>) {
return !isChecked.test(minecraft.player!!)
} else {
return super.isDisabled
}
}
set(value) { super.isDisabled = value }
override val icon: IGUIRenderable?
get() = if (isChecked) {
get() = if (isChecked.get()) {
if (isDisabled) iconDisabledActive else iconActive
} else {
if (isDisabled) iconDisabledInactive else iconInactive
}
override fun onClick(mouseButton: Int) {
val newValue = !isChecked
isChecked = newValue
onChange(newValue)
isChecked.accept(!isChecked.get())
}
override fun innerRenderTooltips(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
@ -65,14 +71,14 @@ abstract class BooleanButtonPanel<out S : Screen>(
}
if (tooltipActive != null) {
if (isChecked)
if (isChecked.get())
tooltips.add(TranslatableComponent("otm.gui.tooltip.enum.active", tooltipActive.copy().withStyle(ChatFormatting.WHITE)))
else
tooltips.add(tooltipActive.copy().withStyle(ChatFormatting.GRAY))
}
if (tooltipInactive != null) {
if (isChecked)
if (isChecked.get())
tooltips.add(tooltipInactive.copy().withStyle(ChatFormatting.GRAY))
else
tooltips.add(TranslatableComponent("otm.gui.tooltip.enum.active", tooltipInactive.copy().withStyle(ChatFormatting.WHITE)))
@ -85,13 +91,41 @@ abstract class BooleanButtonPanel<out S : Screen>(
return super.innerRenderTooltips(graphics, mouseX, mouseY, partialTick)
}
open class Checkbox<out S : Screen>(
open class Radio<out S : Screen>(
screen: S,
parent: EditablePanel<*>?,
parent: EditablePanel<*>? = null,
x: Float = 0f,
y: Float = 0f,
val prop: Delegate<Boolean>,
) : BooleanButtonPanel<S>(screen, parent, x, y, 15f, 15f) {
prop: Delegate<Boolean>,
) : BooleanButtonPanel<S>(screen, parent, x, y, 15f, 15f, prop) {
override val disabledSprite: IGUIRenderable
get() = Widgets15.RADIO_DISABLED
override val pressedSprite: IGUIRenderable
get() = Widgets15.RADIO_PRESSED
override val hoveredSprite: IGUIRenderable
get() = Widgets15.RADIO_HOVERED
override val idleSprite: IGUIRenderable
get() = Widgets15.RADIO_IDLE
override var tooltipActive: Component? = null
override var tooltipInactive: Component? = null
override val iconActive: IGUIRenderable?
get() = Widgets15.RADIO_ICON
override val iconInactive: IGUIRenderable?
get() = null
override val iconDisabledActive: IGUIRenderable?
get() = Widgets15.RADIO_ICON_DISABLED
override val iconSpaceReservation: SpaceReservation
get() = SpaceReservation.ICON_ONLY
}
open class Checkbox<out S : Screen>(
screen: S,
parent: EditablePanel<*>? = null,
x: Float = 0f,
y: Float = 0f,
prop: Delegate<Boolean>,
) : BooleanButtonPanel<S>(screen, parent, x, y, 15f, 15f, prop) {
constructor(
screen: S,
parent: EditablePanel<*>?,
@ -119,33 +153,13 @@ abstract class BooleanButtonPanel<out S : Screen>(
prop: Delegate<Boolean>,
) : this(screen, parent, 0f, 0f, prop)
override fun onChange(newValue: Boolean) {
// do nothing
}
var displayUncheckedIcon = true
override var label: Component? = null
override var isChecked: Boolean
get() = prop.get()
set(value) { prop.accept(value) }
override var labelColor: RGBAColor = RGBAColor.WHITE
override val iconWinding: UVWindingOrder
get() = UVWindingOrder.NORMAL
override var iconOnLeft: Boolean = true
override val iconSpaceReservation: SpaceReservation = SpaceReservation.ICON_AND_TEXT
override var isDisabled: Boolean
get() {
if (prop is IPlayerInputWithFeedback<Boolean>) {
return !prop.test(minecraft.player!!)
} else {
return super.isDisabled
}
}
set(value) { super.isDisabled = value }
override var tooltipActive: Component? = null
override val tooltipInactive: Component? = null
override val iconActive: IGUIRenderable
@ -161,41 +175,23 @@ abstract class BooleanButtonPanel<out S : Screen>(
open class Simple<out S : Screen>(
screen: S,
parent: EditablePanel<*>?,
parent: EditablePanel<*>? = null,
x: Float = 0f,
y: Float = 0f,
width: Float,
height: Float,
val prop: Delegate<Boolean>,
prop: Delegate<Boolean>,
override var iconActive: IGUIRenderable? = null,
override var iconInactive: IGUIRenderable? = null,
val onChange: ((newValue: Boolean) -> Unit)? = null,
override var tooltipActive: Component? = null,
override var tooltipInactive: Component? = null,
) : BooleanButtonPanel<S>(screen, parent, x, y, width, height) {
override fun onChange(newValue: Boolean) {
// do nothing
}
) : BooleanButtonPanel<S>(screen, parent, x, y, width, height, prop) {
override var label: Component? = null
override var isChecked: Boolean
get() = prop.get()
set(value) { prop.accept(value) }
override var labelColor: RGBAColor = RGBAColor.WHITE
override var iconWinding: UVWindingOrder = UVWindingOrder.NORMAL
override var iconOnLeft: Boolean = true
override val iconSpaceReservation: SpaceReservation = SpaceReservation.DEFAULT
override var isDisabled: Boolean
get() {
if (prop is IPlayerInputWithFeedback<Boolean>) {
return !prop.test(minecraft.player!!)
} else {
return super.isDisabled
}
}
set(value) { super.isDisabled = value }
}
companion object {
@ -209,11 +205,10 @@ abstract class BooleanButtonPanel<out S : Screen>(
prop: Delegate<Boolean>,
iconActive: IGUIRenderable? = null,
iconInactive: IGUIRenderable? = null,
onChange: ((newValue: Boolean) -> Unit)? = null,
tooltipActive: Component? = null,
tooltipInactive: Component? = null,
): Simple<S> {
return Simple(screen, parent, x, y, 18f, 18f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive)
return Simple(screen, parent, x, y, 18f, 18f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
}
fun <S : Screen> square15(
@ -224,11 +219,10 @@ abstract class BooleanButtonPanel<out S : Screen>(
prop: Delegate<Boolean>,
iconActive: IGUIRenderable? = null,
iconInactive: IGUIRenderable? = null,
onChange: ((newValue: Boolean) -> Unit)? = null,
tooltipActive: Component? = null,
tooltipInactive: Component? = null,
): Simple<S> {
return Simple(screen, parent, x, y, 15f, 15f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive)
return Simple(screen, parent, x, y, 15f, 15f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
}
fun <S : Screen> square8(
@ -239,11 +233,10 @@ abstract class BooleanButtonPanel<out S : Screen>(
prop: Delegate<Boolean>,
iconActive: IGUIRenderable? = null,
iconInactive: IGUIRenderable? = null,
onChange: ((newValue: Boolean) -> Unit)? = null,
tooltipActive: Component? = null,
tooltipInactive: Component? = null,
): Simple<S> {
return Simple(screen, parent, x, y, 8f, 8f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive)
return Simple(screen, parent, x, y, 8f, 8f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
}
fun <S : Screen> square18(
@ -252,11 +245,10 @@ abstract class BooleanButtonPanel<out S : Screen>(
prop: Delegate<Boolean>,
iconActive: IGUIRenderable? = null,
iconInactive: IGUIRenderable? = null,
onChange: ((newValue: Boolean) -> Unit)? = null,
tooltipActive: Component? = null,
tooltipInactive: Component? = null,
): Simple<S> {
return Simple(screen, parent, 0f, 0f, 18f, 18f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive)
return Simple(screen, parent, 0f, 0f, 18f, 18f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
}
fun <S : Screen> square15(
@ -265,11 +257,10 @@ abstract class BooleanButtonPanel<out S : Screen>(
prop: Delegate<Boolean>,
iconActive: IGUIRenderable? = null,
iconInactive: IGUIRenderable? = null,
onChange: ((newValue: Boolean) -> Unit)? = null,
tooltipActive: Component? = null,
tooltipInactive: Component? = null,
): Simple<S> {
return Simple(screen, parent, 0f, 0f, 15f, 15f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive)
return Simple(screen, parent, 0f, 0f, 15f, 15f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
}
fun <S : Screen> square8(
@ -278,11 +269,10 @@ abstract class BooleanButtonPanel<out S : Screen>(
prop: Delegate<Boolean>,
iconActive: IGUIRenderable? = null,
iconInactive: IGUIRenderable? = null,
onChange: ((newValue: Boolean) -> Unit)? = null,
tooltipActive: Component? = null,
tooltipInactive: Component? = null,
): Simple<S> {
return Simple(screen, parent, 0f, 0f, 8f, 8f, prop, iconActive, iconInactive, onChange, tooltipActive, tooltipInactive)
return Simple(screen, parent, 0f, 0f, 8f, 8f, prop, iconActive, iconInactive, tooltipActive, tooltipInactive)
}
}
}

View File

@ -18,7 +18,7 @@ abstract class NumberInputPanel<out S : Screen, N : Number>(
x: Float = 0f,
y: Float = 0f,
width: Float = WIDTH,
height: Float = HeightControls.BUTTON_HEIGHT * 2f,
height: Float = HeightControls.BUTTON_HEIGHT * 2f + 1f,
var min: N? = null,
var max: N? = null,
) : EditablePanel<S>(screen, parent, x, y, width, height) {
@ -92,12 +92,13 @@ abstract class NumberInputPanel<out S : Screen, N : Number>(
override val disabledSprite get() = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_DISABLED else Widgets.ARROW_UP_BUTTON_DISABLED
init {
dock = Dock.TOP
if (isIncrease)
if (isIncrease) {
tooltips.add(TranslatableComponent("otm.gui.increase"))
else
dock = Dock.TOP
} else {
tooltips.add(TranslatableComponent("otm.gui.decrease"))
dock = Dock.BOTTOM
}
}
override fun test(value: Int): Boolean {
@ -133,7 +134,7 @@ abstract class LNumberInputPanel<out S : Screen, N : Number>(
x: Float = 0f,
y: Float = 0f,
width: Float = WIDTH,
height: Float = HeightControls.BUTTON_HEIGHT * 2f,
height: Float = HeightControls.BUTTON_HEIGHT * 2f + 1f,
min: N? = null,
max: N? = null,
val toNumber: (String) -> N?,
@ -189,7 +190,7 @@ open class DecimalInputPanel<out S : Screen>(
x: Float = 0f,
y: Float = 0f,
width: Float = WIDTH,
height: Float = HeightControls.BUTTON_HEIGHT * 2f,
height: Float = HeightControls.BUTTON_HEIGHT * 2f + 1f,
var step: Decimal = Decimal.ONE,
min: Decimal? = null,
max: Decimal? = null,

View File

@ -41,7 +41,7 @@ open class TextInputPanel<out S : Screen>(
x: Float = 0f,
y: Float = 0f,
width: Float = 60f,
height: Float = 11f,
height: Float = 15f,
) : EditablePanel<S>(screen, parent, x, y, width, height) {
private data class TextSelection(val cursor: Int, val shift: Int) {
val isLeft get() = shift < 0
@ -159,7 +159,7 @@ open class TextInputPanel<out S : Screen>(
init {
scissor = true
dockPadding = DockProperty(2f, 2f, 2f, 2f)
dockPadding = DockProperty(3f, 3f, 3f, 3f)
}
private var oldText = ArrayList<String>()

View File

@ -0,0 +1,41 @@
package ru.dbotthepony.mc.otm.client.screen.panels.util
import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty
import ru.dbotthepony.mc.otm.client.screen.panels.DockResizeMode
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import kotlin.math.max
fun <B : EditablePanel<S>, L : EditablePanel<S>, S : Screen> makeButtonLabel(
screen: S,
parent: EditablePanel<*>?,
button: B,
label: L,
x: Float = 0f,
y: Float = 0f,
): Triple<B, L, EditablePanel<S>> {
val canvas = EditablePanel(screen, parent, x, y)
with(canvas) {
width = button.width + label.width + 2f
height = max(button.height, label.height)
button.parent = this
label.parent = this
button.childrenOrder = 0
label.childrenOrder = 1
button.dockMargin = DockProperty.EMPTY
label.dockMargin = DockProperty(left = 2f)
label.dock = Dock.FILL
label.dockResize = DockResizeMode.WIDTH
button.dock = Dock.LEFT
button.dockResize = DockResizeMode.NONE
}
return Triple(button, label, canvas)
}

View File

@ -2,32 +2,84 @@ package ru.dbotthepony.mc.otm.client.screen.tech
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleGeneratorBlockEntity
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
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.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.Label
import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.input.DecimalInputPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.makeButtonLabel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.menu.tech.BlackHoleGeneratorMenu
class BlackHoleGeneratorScreen(menu: BlackHoleGeneratorMenu, inventory: Inventory, title: Component) : MatteryScreen<BlackHoleGeneratorMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
val frame = FramePanel.padded(this, 200f, 60f, title)
val frame = FramePanel.padded(this, 240f, 130f, title)
frame.behaveAsWindow()
frame.onClose { onClose() }
frame.makeHelpButton().also {
it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help0"))
it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help1"))
it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help2"))
it.tooltips.add(TextComponent(""))
it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help3"))
}
val energy = ProfiledPowerGaugePanel(this, frame, menu.energy)
val matter = ProfiledMatterGaugePanel(this, frame, menu.matter)
matter.dockLeft = 1f
matter.dockLeft = 2f
energy.dock = Dock.LEFT
matter.dock = Dock.LEFT
matter.dockRight = 4f
matter.dockRight = 5f
val drawGuide = BooleanButtonPanel.Checkbox(this, frame, menu.drawBuildingGuide, TranslatableComponent("otm.gui.draw_multiblock_guide"))
drawGuide.dock = Dock.TOP
drawGuide.dockBottom = 2f
Label(this, frame, text = TranslatableComponent("otm.gui.black_hole_generator.injection_rate.mode")).also {
it.dock = Dock.TOP
it.dockTop = 2f
}
val injectionRate = DecimalInputPanel(this, frame, menu.injectionRate, min = Decimal.ONE_TENTH, step = Decimal.ONE_TENTH)
injectionRate.dock = Dock.TOP
injectionRate.dockTop = 1f
Label(this, frame, text = TranslatableComponent("otm.gui.black_hole_generator.target_mass.mode")).also {
it.dock = Dock.TOP
it.dockTop = 2f
}
val targetMass = DecimalInputPanel(this, frame, menu.targetMass, min = Decimal.ONE, step = Decimal(1000))
targetMass.dock = Dock.TOP
targetMass.dockTop = 1f
targetMass.dockBottom = 4f
for (mode in BlackHoleGeneratorBlockEntity.Mode.entries) {
val (radio, label, canvas) = makeButtonLabel(
this,
frame,
BooleanButtonPanel.Radio(this, prop = menu.mode.map({ it == mode }, { if (it) mode else BlackHoleGeneratorBlockEntity.Mode.TARGET_MASS })),
Label(this, text = mode.label)
)
label.tooltips.add(mode.tooltip)
radio.tooltips.add(mode.tooltip)
canvas.tooltips.add(mode.tooltip)
canvas.dock = Dock.TOP
canvas.dockTop = 2f
}
DeviceControls(this, frame, redstoneConfig = menu.redstoneConfig)
return frame
}

View File

@ -155,3 +155,17 @@ open class ProfiledMatterGaugePanel<out S : Screen>(
}
}
}
/**
* Shortcut to [ProfiledMatterGaugePanel] with doubled width
*/
@Suppress("FunctionName")
fun <S : Screen> WideProfiledMatterGaugePanel(
screen: S,
parent: EditablePanel<*>? = null,
widget: IProfiledLevelGaugeWidget,
x: Float = 0f,
y: Float = 0f,
width: Float = 18f,
height: Float = 48f
) = ProfiledMatterGaugePanel(screen, parent, widget, x, y, width, height)

View File

@ -201,21 +201,38 @@ object MachinesConfig : AbstractConfig("machines") {
val MATTER_HATCH by builder
.comment("Internal buffer of matter hatch")
.defineDecimal("MATTER_HATCH", Decimal(200), Decimal.ONE)
.defineDecimal("MATTER_HATCH", Decimal(4_000), Decimal.ONE)
object BlackHoleGenerator {
init {
builder.push("BLACK_HOLE_GENERATOR")
}
val MATTER_RATE: Decimal
get() = Decimal("0.25")
val GENERATION_RATIO_SUSTAIN: Decimal by builder
.comment("Baseline energy generation when Singularity has gravitation strength of 1")
.comment("and inject rate of 1 MtU, in 'target mass' generation mode, *when* target mass is achieved.")
.defineDecimal("GENERATION_RATIO_SUSTAIN", Decimal(8_000))
val MASS_DIVISOR: Decimal
get() = Decimal.TEN
val GENERATION_RATIO_FEED: Decimal by builder
.comment("Baseline energy generation when Singularity has gravitation strength of 1")
.comment("and inject rate of 1 MtU, in 'inject mater only' generation mode.")
.defineDecimal("GENERATION_RATIO_FEED", Decimal(4_000))
val MASS_FEEDING_RATIO: Decimal
get() = Decimal("0.1")
val GENERATION_RATIO_DRAIN: Decimal by builder
.comment("Baseline energy generation when Singularity has gravitation strength of 1")
.comment("and inject rate of 1 MtU, in 'inject antimatter only' generation mode.")
.defineDecimal("GENERATION_RATIO_DRAIN", Decimal(25_000))
val FEEDING_EFFICIENCY: Decimal by builder
.comment("Efficiency at increasing mass of Singularity when injecting mass,")
.comment("when generator is working in either 'inject only' or 'target mass' modes when")
.comment("Singularity mass is lesser than required. 0.6 means 60% of injected mass")
.comment("increases Singularity mass.")
.defineDecimal("FEEDING_EFFICIENCY", Decimal("0.6"), Decimal.ZERO, Decimal.ONE)
val DRAINING_EFFICIENCY: Decimal by builder
.comment("Same as FEEDING_EFFICIENCY, but for 'draining' Singularity mass (inject antimatter only)")
.defineDecimal("DRAINING_EFFICIENCY", Decimal("1.0"), Decimal.ZERO, Decimal.ONE)
init {
builder.pop()

View File

@ -1,40 +0,0 @@
package ru.dbotthepony.mc.otm.config
object ServerCompatConfig : AbstractConfig("compat-server") {
object AdAstra {
init {
builder.push("AD_ASTRA")
}
val ANDROIDS_DO_NOT_NEED_OXYGEN: Boolean by builder
.comment("Android do not need oxygen in space")
.define("ANDROIDS_DO_NOT_NEED_OXYGEN", true)
val WHATS_UP_WITH_TEMPERATURE: Boolean by builder
.comment("Disables temperature mechanics on planets without atmosphere.")
.comment("I attended physics classes in middle school, and this kills me.")
.define("WHATS_UP_WITH_TEMPERATURE", true)
val ANDROID_COSMIC_RAYS: Boolean by builder
.comment("Androids without spacesuit will get damaged over time by cosmic radiation")
.comment("on planets without atmosphere.")
.define("ANDROID_COSMIC_RAYS", true)
val ANDROID_COSMIC_RAYS_CHANCE: Double by builder
.comment("Chance in percent android will be damaged this tick per missing piece of spacesuit")
.comment("Max chance in tick of damage is this value multiplied by 4 (spacesuit is completely missing)")
.defineInRange("ANDROID_COSMIC_RAYS_CHANCE", 0.015, 0.0, 1.0)
val TRITANIUM_ARMOR_PROTECTS_AGAINST_COSMIC_RAYS: Boolean by builder
.comment("Should androids get 3/4th protection from cosmic rays per piece of tritanium armor")
.define("TRITANIUM_ARMOR_PROTECTS_AGAINST_COSMIC_RAYS", true)
init {
builder.pop()
}
}
init {
AdAstra
}
}

View File

@ -1,5 +1,9 @@
package ru.dbotthepony.mc.otm.config
import ru.dbotthepony.kommons.util.getValue
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.defineDecimal
object ServerConfig : AbstractConfig("misc") {
val LABORATORY_LAMP_LIGHT_LENGTH: Int by builder.comment("In blocks").defineInRange("LABORATORY_LAMP_LIGHT_LENGTH", 6, 1, 128)
val INFINITE_EXOSUIT_UPGRADES: Boolean by builder.comment("Allows to apply the same upgrade over and over again.", "Obviously completely breaks balance.").define("INFINITE_EXOSUIT_UPGRADES", false)
@ -23,11 +27,21 @@ object ServerConfig : AbstractConfig("misc") {
init {
builder.pop()
builder.push("BLACKHOLES")
Blackhole
}
object Blackhole {
init {
builder.push("BLACK_HOLE")
}
val BASELINE_MASS by builder
.comment("Mass of Singularity to be considered 'baseline' in regard to all calculations")
.comment("(such as gravitational strength), including the initial mass of Singularity.")
.comment("Changing this value mid-game can result in unwanted side effects,")
.comment("and lowering this value after generating world may result in unforeseen consequences far worse than resonance cascade.")
.defineDecimal("BASELINE_MASS", Decimal(500_000), Decimal.ONE)
val PLAYER_DAMAGE_SCALE: Double by builder
.comment("Percentage of damage received by players from Event Horizon of Singularities")
.defineInRange("PLAYER_DAMAGE_SCALE", 0.25, 0.0, Float.MAX_VALUE.toDouble())
@ -53,13 +67,13 @@ object ServerConfig : AbstractConfig("misc") {
.defineInRange("BOSS_FORCE_MULTIPLIER", 0.4, 0.0, Float.MAX_VALUE.toDouble())
val DESTROY_BLOCKS: Boolean by builder
.comment("Whenever singularities should destroy blocks")
.comment("Whenever singularities should destroy blocks.")
.comment("Keep in mind that mobs behind blocks can cause serious server lag")
.comment("when trying to reach singularity")
.comment("when trying to reach singularity due to considerable pressure on physics engine solver.")
.define("DESTROY_BLOCKS", true)
}
init {
builder.pop()
init {
builder.pop()
}
}
}

View File

@ -0,0 +1,33 @@
package ru.dbotthepony.mc.otm.menu.input
import ru.dbotthepony.kommons.util.Delegate
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.data.DecimalCodec
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import java.util.function.Supplier
import kotlin.reflect.KMutableProperty0
class DecimalInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean = false) : AbstractPlayerInputWithFeedback<Decimal>() {
override val input = menu.decimalInput(allowSpectators) { consumer?.invoke(it) }
override val field = menu.mSynchronizer.computed(Supplier { supplier?.invoke() ?: Decimal.ZERO }, DecimalCodec.NETWORK)
constructor(menu: MatteryMenu, allowSpectators: Boolean, state: KMutableProperty0<Decimal>?) : this(menu, allowSpectators) {
if (state != null)
with(state)
}
constructor(menu: MatteryMenu, allowSpectators: Boolean, state: Delegate<Decimal>?) : this(menu, allowSpectators) {
if (state != null)
with(state)
}
constructor(menu: MatteryMenu, state: KMutableProperty0<Decimal>?) : this(menu) {
if (state != null)
with(state)
}
constructor(menu: MatteryMenu, state: Delegate<Decimal>?) : this(menu) {
if (state != null)
with(state)
}
}

View File

@ -4,6 +4,8 @@ import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleGeneratorBlockEntity
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.DecimalInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
import ru.dbotthepony.mc.otm.menu.widget.CombinedProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus
@ -15,4 +17,8 @@ class BlackHoleGeneratorMenu(
val drawBuildingGuide = BooleanInputWithFeedback(this, tile?.let { it::drawBuildingGuide })
val energy = CombinedProfiledLevelGaugeWidget(this, tile?.energy)
val matter = CombinedProfiledLevelGaugeWidget(this, tile?.matter)
val injectionRate = DecimalInputWithFeedback(this, tile?.let { it::injectionRate })
val targetMass = DecimalInputWithFeedback(this, tile?.let { it::targetMass })
val mode = EnumInputWithFeedback(this, tile?.let { it::mode })
val redstoneConfig = EnumInputWithFeedback(this, tile?.let { it.redstoneControl::redstoneSetting })
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 800 B

After

Width:  |  Height:  |  Size: 964 B