Wireless android charger and misc fixes

This commit is contained in:
DBotThePony 2023-06-27 19:14:10 +07:00
parent 0ec8f3709a
commit e3bc9e226f
Signed by: DBot
GPG Key ID: DCC23B5715498507
27 changed files with 402 additions and 87 deletions

View File

@ -226,6 +226,7 @@ private fun misc(provider: MatteryLanguageProvider) {
misc("item.power.last_tick", "Last tick: %s")
misc("item.power.storage", "Stored energy: %s / %s")
misc("item.power.storage0", "Stored energy: %s")
misc("item.power.throughput", "Max I/O: %s / %s")
misc("item.power.throughput_mono", "Max I/O: %s")
misc("item.power.infinity", "∞ MtJ")
@ -362,6 +363,7 @@ private fun death(provider: MatteryLanguageProvider) {
private fun blocks(provider: MatteryLanguageProvider) {
with(provider.english) {
add(MBlocks.ANDROID_STATION, "Android Station")
add(MBlocks.ANDROID_CHARGER, "Wireless Android Charger")
add(MBlocks.BATTERY_BANK, "Battery Bank")
add(MBlocks.MATTER_DECOMPOSER, "Matter Decomposer")
add(MBlocks.MATTER_CAPACITOR_BANK, "Matter Capacitor Bank")

View File

@ -367,6 +367,7 @@ private fun death(provider: MatteryLanguageProvider) {
private fun blocks(provider: MatteryLanguageProvider) {
with(provider.russian) {
add(MBlocks.ANDROID_STATION, "Станция андроидов")
add(MBlocks.ANDROID_CHARGER, "Беспроводной зарядник андроидов")
add(MBlocks.BATTERY_BANK, "Банк аккумуляторов")
add(MBlocks.MATTER_DECOMPOSER, "Декомпозитор материи")
add(MBlocks.MATTER_CAPACITOR_BANK, "Банк накопителей материи")

View File

@ -137,6 +137,7 @@ fun addLootTables(lootTables: LootTables) {
lootTables.tile(MBlocks.HOLO_SIGN, "isLocked")
lootTables.tile(MBlocks.STORAGE_CABLE)
lootTables.tile(MBlocks.ANDROID_STATION)
lootTables.tile(MBlocks.ANDROID_CHARGER)
lootTables.tile(MBlocks.BATTERY_BANK)
lootTables.tile(MBlocks.DRIVE_VIEWER)

View File

@ -180,6 +180,7 @@ fun addTags(tagsProvider: TagsProvider) {
MBlocks.ESSENCE_STORAGE,
MBlocks.MATTER_RECONSTRUCTOR,
MBlocks.FLUID_TANK,
MBlocks.ANDROID_CHARGER,
), Tiers.IRON)
tagsProvider.requiresPickaxe(MBlocks.TRITANIUM_ANVIL, Tiers.IRON)

View File

@ -32,7 +32,6 @@ import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.core.nbt.getJson
import ru.dbotthepony.mc.otm.core.nbt.putJson
import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.util.ITickable
import ru.dbotthepony.mc.otm.once
@ -235,27 +234,51 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
}
inner class ConfigurableEnergy<T : IMatteryEnergyStorage>(
val capability: T,
val energy: T,
val possibleModes: FlowDirection = capability.energyFlow,
val modesFront: FlowDirection = energy.energyFlow,
val modesBack: FlowDirection = energy.energyFlow,
val modesLeft: FlowDirection = energy.energyFlow,
val modesRight: FlowDirection = energy.energyFlow,
val modesTop: FlowDirection = energy.energyFlow,
val modesBottom: FlowDirection = energy.energyFlow,
val frontDefault: FlowDirection = possibleModes,
val backDefault: FlowDirection = possibleModes,
val leftDefault: FlowDirection = possibleModes,
val rightDefault: FlowDirection = possibleModes,
val topDefault: FlowDirection = possibleModes,
val bottomDefault: FlowDirection = possibleModes,
val frontDefault: FlowDirection = modesFront,
val backDefault: FlowDirection = modesBack,
val leftDefault: FlowDirection = modesLeft,
val rightDefault: FlowDirection = modesRight,
val topDefault: FlowDirection = modesTop,
val bottomDefault: FlowDirection = modesBottom,
) {
constructor(
energy: T,
possibleModes: FlowDirection,
frontDefault: FlowDirection = possibleModes,
backDefault: FlowDirection = possibleModes,
leftDefault: FlowDirection = possibleModes,
rightDefault: FlowDirection = possibleModes,
topDefault: FlowDirection = possibleModes,
bottomDefault: FlowDirection = possibleModes,
) : this(
energy,
modesFront = possibleModes, frontDefault = frontDefault,
modesBack = possibleModes, backDefault = backDefault,
modesLeft = possibleModes, leftDefault = leftDefault,
modesRight = possibleModes, rightDefault = rightDefault,
modesTop = possibleModes, topDefault = topDefault,
modesBottom = possibleModes, bottomDefault = bottomDefault,
)
init {
exposeEnergySideless(capability)
exposeEnergySideless(energy)
}
val front = Piece(RelativeSide.FRONT).also { it.energyFlow = frontDefault }
val back = Piece(RelativeSide.BACK).also { it.energyFlow = backDefault }
val left = Piece(RelativeSide.LEFT).also { it.energyFlow = leftDefault }
val right = Piece(RelativeSide.RIGHT).also { it.energyFlow = rightDefault }
val top = Piece(RelativeSide.TOP).also { it.energyFlow = topDefault }
val bottom = Piece(RelativeSide.BOTTOM).also { it.energyFlow = bottomDefault }
val front = Piece(RelativeSide.FRONT, modesFront).also { it.energyFlow = frontDefault }
val back = Piece(RelativeSide.BACK, modesBack).also { it.energyFlow = backDefault }
val left = Piece(RelativeSide.LEFT, modesLeft).also { it.energyFlow = leftDefault }
val right = Piece(RelativeSide.RIGHT, modesRight).also { it.energyFlow = rightDefault }
val top = Piece(RelativeSide.TOP, modesTop).also { it.energyFlow = topDefault }
val bottom = Piece(RelativeSide.BOTTOM, modesBottom).also { it.energyFlow = bottomDefault }
val pieces = immutableMap {
put(RelativeSide.FRONT, front)
@ -275,15 +298,15 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
put(RelativeSide.BOTTOM, bottomDefault)
}
inner class Piece(val side: RelativeSide) : IMatteryEnergyStorage, ITickable {
inner class Piece(val side: RelativeSide, val possibleModes: FlowDirection) : IMatteryEnergyStorage, ITickable {
private val capControllers = exposeEnergy(side, this@Piece)
private val neighbour by sides[side]!!.track(ForgeCapabilities.ENERGY)
override var batteryLevel: Decimal by capability::batteryLevel
override val maxBatteryLevel: Decimal by capability::maxBatteryLevel
override val missingPower: Decimal by capability::missingPower
override var batteryLevel: Decimal by energy::batteryLevel
override val maxBatteryLevel: Decimal by energy::maxBatteryLevel
override val missingPower: Decimal by energy::missingPower
override val canSetBatteryLevel: Boolean by capability::canSetBatteryLevel
override val canSetBatteryLevel: Boolean by energy::canSetBatteryLevel
// var automatePull by synchronizer.bool().property
var automatePull = false
@ -299,33 +322,33 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
}
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return capability.extractEnergy(howMuch, simulate)
return energy.extractEnergy(howMuch, simulate)
}
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
return capability.receiveEnergy(howMuch, simulate)
return energy.receiveEnergy(howMuch, simulate)
}
override fun extractEnergyChecked(howMuch: Decimal, simulate: Boolean): Decimal {
if (energyFlow.output)
return capability.extractEnergyChecked(howMuch, simulate)
return energy.extractEnergyChecked(howMuch, simulate)
return Decimal.ZERO
}
override fun receiveEnergyChecked(howMuch: Decimal, simulate: Boolean): Decimal {
if (energyFlow.input)
return capability.receiveEnergyChecked(howMuch, simulate)
return energy.receiveEnergyChecked(howMuch, simulate)
return Decimal.ZERO
}
override fun drainBattery(): Boolean {
return capability.drainBattery()
return energy.drainBattery()
}
override fun fillBattery(): Boolean {
return capability.fillBattery()
return energy.fillBattery()
}
override fun tick() {
@ -334,11 +357,11 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
neighbour.ifPresentK {
if (energyFlow.input && automatePull) {
moveEnergy(source = it, destination = capability, simulate = false)
moveEnergy(source = it, destination = energy, simulate = false)
}
if (energyFlow.output && automatePush) {
moveEnergy(source = capability, destination = it, simulate = false)
moveEnergy(source = energy, destination = it, simulate = false)
}
}
}

View File

@ -32,7 +32,7 @@ abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229
super.tick()
val energy = matteryEnergy
if (energy == null || !batteryContainer.any { !it.isEmpty })
if (energy == null || batteryContainer.isEmpty)
return
var demand = energy.receiveEnergy(energy.missingPower, true)

View File

@ -0,0 +1,52 @@
package ru.dbotthepony.mc.otm.block.entity.tech
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.Vec3
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matteryPlayer
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid
import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_CHARGER, blockPos, blockState) {
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? {
return AndroidChargerMenu(containerID, inventory, this)
}
val energyConfig = ConfigurableEnergy(ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.ANDROID_CHARGER)), modesTop = FlowDirection.NONE)
init {
savetables.stateful(energyConfig::energy, ENERGY_KEY)
}
override fun tick() {
super.tick()
val level = level ?: return
var available = energyConfig.energy.extractEnergy(energyConfig.energy.batteryLevel, true)
if (!available.isPositive) return
val ents = level.getEntitiesInEllipsoid(blockPos.center, Vec3(MachinesConfig.AndroidCharger.RADIUS_WIDTH, MachinesConfig.AndroidCharger.RADIUS_HEIGHT, MachinesConfig.AndroidCharger.RADIUS_WIDTH)) { it is Player }
ents.sort()
for ((ent) in ents) {
val ply = ent.matteryPlayer ?: continue
if (ply.isAndroid) {
val received = ply.androidEnergy.receiveEnergyChecked(available, false)
available -= received
energyConfig.energy.extractEnergy(received, false)
if (!available.isPositive) return
}
}
}
}

View File

@ -181,7 +181,7 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte
init {
energyConfig.front.automatePush = true
savetables.stateful(Supplier { energyConfig.capability.savedata }, "energyUsageHistory")
savetables.stateful(Supplier { energyConfig.energy.savedata }, "energyUsageHistory")
}
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {

View File

@ -62,6 +62,7 @@ class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte
})
val energyConfig = ConfigurableEnergy(energy, possibleModes = FlowDirection.BI_DIRECTIONAL)
val itemConfig = ConfigurableItemHandler(
input = charge.handler(HandlerFilter.OnlyIn.and(HandlerFilter.Chargeable)),
output = discharge.handler(HandlerFilter.OnlyOut.and(HandlerFilter.Dischargeable))

View File

@ -0,0 +1,135 @@
package ru.dbotthepony.mc.otm.block.tech
import net.minecraft.core.BlockPos
import net.minecraft.network.chat.Component
import net.minecraft.util.StringRepresentable
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.TooltipFlag
import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.BlockGetter
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.material.PushReaction
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerBlockEntity
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.core.get
import ru.dbotthepony.mc.otm.core.gracefulBlockBreak
import ru.dbotthepony.mc.otm.core.math.plus
import ru.dbotthepony.mc.otm.oncePre
class AndroidChargerBlock : RotatableMatteryBlock(Properties.of().destroyTime(2.5f).explosionResistance(40f).pushReaction(PushReaction.BLOCK).requiresCorrectToolForDrops()), EntityBlock {
enum class Type : StringRepresentable {
BASE,
MIDDLE,
TOP;
override fun getSerializedName(): String {
return name.lowercase()
}
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
super.createBlockStateDefinition(builder)
builder.add(PART)
}
init {
registerDefaultState(defaultBlockState().setValue(PART, Type.BASE))
}
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
val level = context.level
if (level.isOutsideBuildHeight(context.clickedPos + BlockPos(0, 0, 2))) return null
for (i in 1 .. 2) {
val pos = context.clickedPos + BlockPos(0, 0, i)
if (!level.getBlockState(pos).canBeReplaced(context)) return null
}
return super.getStateForPlacement(context)
}
override fun setPlacedBy(level: Level, blockPos: BlockPos, blockState: BlockState, entity: LivingEntity?, itemStack: ItemStack) {
super.setPlacedBy(level, blockPos, blockState, entity, itemStack)
if (blockState[PART] == Type.BASE) {
level.setBlock(blockPos.above(), blockState.setValue(PART, Type.MIDDLE), UPDATE_ALL)
level.setBlock(blockPos.above().above(), blockState.setValue(PART, Type.TOP), UPDATE_ALL)
}
}
override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity? {
if (p_153216_[PART] != Type.BASE) return null
return AndroidChargerBlockEntity(p_153215_, p_153216_)
}
override fun <T : BlockEntity?> getTicker(p_153212_: Level, blockState: BlockState, p_153214_: BlockEntityType<T>): BlockEntityTicker<T>? {
if (p_153212_.isClientSide || blockState[PART] != Type.BASE) return null
return BlockEntityTicker { _, _, _, t -> if (t is AndroidChargerBlockEntity) t.tick() }
}
override fun getDestroyProgress(p_60466_: BlockState, p_60467_: Player, p_60468_: BlockGetter, p_60469_: BlockPos): Float {
// запрет на ломание не нижнего блока игроком
if (p_60466_[PART] != Type.BASE) return 0f
return super.getDestroyProgress(p_60466_, p_60467_, p_60468_, p_60469_)
}
override fun neighborChanged(state: BlockState, level: Level, pos: BlockPos, neighbour: Block, neighbourPos: BlockPos, movedByPiston: Boolean) {
super.neighborChanged(state, level, pos, neighbour, neighbourPos, movedByPiston)
level.oncePre {
if (level.getBlockState(pos) == state) {
when (state[PART]!!) {
Type.BASE -> {
val a = level.getBlockState(pos.above())
val b = level.getBlockState(pos.above().above())
if (a.block != this || b.block != this || a[PART] != Type.MIDDLE || b[PART] != Type.TOP) {
level.gracefulBlockBreak(pos, state)
}
}
Type.MIDDLE -> {
val a = level.getBlockState(pos.below())
val b = level.getBlockState(pos.above())
if (a.block != this || b.block != this || a[PART] != Type.BASE || b[PART] != Type.TOP) {
level.setBlock(pos, Blocks.AIR.defaultBlockState(), UPDATE_ALL)
}
}
Type.TOP -> {
val a = level.getBlockState(pos.below())
val b = level.getBlockState(pos.below().below())
if (a.block != this || b.block != this || a[PART] != Type.MIDDLE || b[PART] != Type.BASE) {
level.setBlock(pos, Blocks.AIR.defaultBlockState(), UPDATE_ALL)
}
}
}
}
}
}
override fun appendHoverText(p_49816_: ItemStack, p_49817_: BlockGetter?, p_49818_: MutableList<Component>, p_49819_: TooltipFlag) {
super.appendHoverText(p_49816_, p_49817_, p_49818_, p_49819_)
WorkerEnergyStorage.appendHoverText(p_49816_, p_49817_, p_49818_, p_49819_)
MatteryPoweredBlockEntity.appendHoverText(p_49816_, p_49817_, p_49818_, p_49819_)
}
companion object {
val PART: EnumProperty<Type> = EnumProperty.create("part", Type::class.java)
}
}

View File

@ -166,7 +166,7 @@ sealed class BlockEnergyStorageImpl(
const val MAX_INPUT_KEY = "max_input"
const val MAX_OUTPUT_KEY = "max_output"
fun makeConfigEntry(builder: ForgeConfigSpec.Builder, name: String? = null, capacity: Decimal = DEFAULT_MAX_CAPACITY, throughput: Decimal = DEFAULT_MAX_IO): ConciseBalanceValues {
fun makeConfigEntry(builder: ForgeConfigSpec.Builder, name: String? = null, capacity: Decimal = DEFAULT_MAX_CAPACITY, throughput: Decimal = DEFAULT_MAX_IO, configurator: ForgeConfigSpec.Builder.() -> Unit = {}): ConciseBalanceValues {
if (name != null)
builder.push(name)
@ -175,6 +175,8 @@ sealed class BlockEnergyStorageImpl(
override val throughput: Decimal by builder.defineDecimal("throughput", throughput, Decimal.ONE)
}
configurator.invoke(builder)
if (name != null)
builder.pop()
@ -226,7 +228,7 @@ open class WorkerEnergyStorage(
val tag = (itemStack.tag?.get(BlockItem.BLOCK_ENTITY_TAG) as? CompoundTag)?.get(MatteryBlockEntity.ENERGY_KEY) as? CompoundTag ?: return
val cap = WorkerEnergyStorage({}, DEFAULT_MAX_CAPACITY)
cap.deserializeNBT(tag)
batteryLevel(cap, tooltips)
batteryLevel(cap, tooltips, false)
}
fun appendHoverText(itemStack: ItemStack, blockGetter: BlockGetter?, tooltips: MutableList<Component>, flag: TooltipFlag) {

View File

@ -23,13 +23,20 @@ internal fun batteryLevel(it: IEnergyStorage, tooltips: MutableList<Component>)
).withStyle(ChatFormatting.GRAY))
}
internal fun batteryLevel(it: IMatteryEnergyStorage, tooltips: MutableList<Component>) {
tooltips.add(
TranslatableComponent(
"otm.item.power.storage",
it.batteryLevel.formatPower(formatAsReadable = ShiftPressedCond),
it.maxBatteryLevel.formatPower(formatAsReadable = ShiftPressedCond)
).withStyle(ChatFormatting.GRAY))
internal fun batteryLevel(it: IMatteryEnergyStorage, tooltips: MutableList<Component>, displayMaxLevel: Boolean = true) {
if (displayMaxLevel)
tooltips.add(
TranslatableComponent(
"otm.item.power.storage",
it.batteryLevel.formatPower(formatAsReadable = ShiftPressedCond),
it.maxBatteryLevel.formatPower(formatAsReadable = ShiftPressedCond)
).withStyle(ChatFormatting.GRAY))
else
tooltips.add(
TranslatableComponent(
"otm.item.power.storage0",
it.batteryLevel.formatPower(formatAsReadable = ShiftPressedCond)
).withStyle(ChatFormatting.GRAY))
if (it is IEnergyStorageImpl) {
when (it.energyFlow) {

View File

@ -128,6 +128,12 @@ private fun <S : MatteryScreen<*>> makeEnergyModeButton(screen: S, parent: Frame
button.finish()
if (input.possibleModes == FlowDirection.NONE) {
button.visible = false
}
button.predicate = Predicate { input.possibleModes.isSupertype(it) }
return button
}
@ -224,12 +230,12 @@ private fun <S : MatteryScreen<*>> makeEnergyConfigPanel(
}
}
val front = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.FRONT]!!, RelativeSide.FRONT).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
val back = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.BACK]!!, RelativeSide.BACK).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
val left = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.LEFT]!!, RelativeSide.LEFT).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
val right = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.RIGHT]!!, RelativeSide.RIGHT).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
val top = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.TOP]!!, RelativeSide.TOP).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
val bottom = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.BOTTOM]!!, RelativeSide.BOTTOM).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
val front = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.FRONT]!!, RelativeSide.FRONT)
val back = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.BACK]!!, RelativeSide.BACK)
val left = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.LEFT]!!, RelativeSide.LEFT)
val right = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.RIGHT]!!, RelativeSide.RIGHT)
val top = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.TOP]!!, RelativeSide.TOP)
val bottom = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.BOTTOM]!!, RelativeSide.BOTTOM)
moveButtons(front, back, left, right, top, bottom)
screen.addPanel(frame)

View File

@ -0,0 +1,47 @@
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.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.button.makeDeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.SpritePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu
class AndroidChargerScreen(menu: AndroidChargerMenu, inventory: Inventory, title: Component) : MatteryScreen<AndroidChargerMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
val frame = super.makeMainFrame()!!
frame.height = 42f
frame.width -= 20f
val strip = EditablePanel(this, frame, height = AbstractSlotPanel.SIZE)
strip.dock = Dock.BOTTOM
BatterySlotPanel(this, strip, menu.batterySlot).also {
it.dock = Dock.LEFT
it.dockRight = 2f
}
SpritePanel(this, strip, ProgressGaugePanel.GAUGE_BACKGROUND).also {
it.dock = Dock.LEFT
it.dockRight = 2f
it.dockTop = 2f
}
TallHorizontalProfiledPowerGaugePanel(this, strip, menu.profiledEnergy).also {
it.dock = Dock.LEFT
it.dockRight = 2f
}
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig)
return frame
}
}

View File

@ -1,6 +1,5 @@
package ru.dbotthepony.mc.otm.client.screen.tech
import com.mojang.blaze3d.vertex.PoseStack
import net.minecraft.client.gui.GuiGraphics
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
@ -14,9 +13,9 @@ import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.PlayerEquipmentPanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.makeCuriosPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.SpritePanel
import ru.dbotthepony.mc.otm.client.screen.widget.HorizontalPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalPowerGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel
import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu
@ -40,17 +39,10 @@ class EnergyServoScreen(menu: EnergyServoMenu, inventory: Inventory, title: Comp
it.dockRight = 2f
}
object : EditablePanel<EnergyServoScreen>(this@EnergyServoScreen, strip) {
init {
dock = Dock.LEFT
dockRight = 2f
dockTop = 2f
width = ProgressGaugePanel.GAUGE_BACKGROUND.width
}
override fun innerRender(graphics: GuiGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {
ProgressGaugePanel.GAUGE_BACKGROUND.render(graphics)
}
SpritePanel(this, strip, ProgressGaugePanel.GAUGE_BACKGROUND).also {
it.dock = Dock.LEFT
it.dockRight = 2f
it.dockTop = 2f
}
TallHorizontalProfiledPowerGaugePanel(this, strip, menu.powerGauge).also {

View File

@ -30,4 +30,16 @@ object MachinesConfig : AbstractConfig("machines") {
val ITEM_MONITOR = BlockEnergyStorageImpl.makeConfigEntry(builder, MNames.ITEM_MONITOR)
val DRIVE_VIEWER = BlockEnergyStorageImpl.makeConfigEntry(builder, MNames.DRIVE_VIEWER)
val DRIVE_RACK = BlockEnergyStorageImpl.makeConfigEntry(builder, MNames.DRIVE_RACK, capacity = Decimal(80_000))
object AndroidCharger {
val RADIUS_WIDTH: Double by builder
.comment("Effective charger range on horizontal plane")
.defineInRange("RADIUS_WIDTH", 16.0, 1.0, Double.MAX_VALUE)
val RADIUS_HEIGHT: Double by builder
.comment("Effective charger range on vertical plane")
.defineInRange("RADIUS_HEIGHT", 4.0, 1.0, Double.MAX_VALUE)
}
val ANDROID_CHARGER = BlockEnergyStorageImpl.makeConfigEntry(builder, MNames.ANDROID_CHARGER, capacity = Decimal(400_000), throughput = Decimal(8192)) { AndroidCharger }
}

View File

@ -360,11 +360,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
}
override fun isEmpty(): Boolean {
for (stack in slots)
if (!stack.isEmpty)
return false
return true
return slots.all { it.isEmpty }
}
operator fun get(slot: Int) = getItem(slot)

View File

@ -9,10 +9,16 @@ import java.util.LinkedList
import java.util.function.Predicate
import kotlin.math.pow
data class EntityDistance<T : Entity>(val entity: T, val distance: Double) : Comparable<EntityDistance<*>> {
override fun compareTo(other: EntityDistance<*>): Int {
return distance.compareTo(other.distance)
}
}
/**
* Pair of entity and distance fraction to center of ellipsoid
*/
fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, except: Entity?, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, except: Entity?, predicate: Predicate<in Entity>): MutableList<EntityDistance<Entity>> {
val entities = getEntities(except, AABB(
pos.x - dimensions.x,
pos.y - dimensions.y,
@ -23,7 +29,7 @@ fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, except: Entity
pos.z + dimensions.z,
), predicate)
val result = LinkedList<Pair<Entity, Double>>()
val result = ArrayList<EntityDistance<Entity>>()
for (it in entities) {
val a = (it.position - pos).let { vec ->
@ -41,7 +47,7 @@ fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, except: Entity
val min = a.coerceAtMost(b)
if (min <= 1.0) {
result.add(it to min)
result.add(EntityDistance(it, min))
}
}
@ -51,7 +57,7 @@ fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, except: Entity
/**
* Pair of entity and distance fraction to center of ellipsoid
*/
fun <T : Entity> Level.getEntitiesInEllipsoid(type: Class<out T>, pos: Vector, dimensions: Vector, predicate: Predicate<in Entity>): List<Pair<T, Double>> {
fun <T : Entity> Level.getEntitiesInEllipsoid(type: Class<out T>, pos: Vector, dimensions: Vector, predicate: Predicate<in Entity>): MutableList<EntityDistance<T>> {
val entities = getEntitiesOfClass(type, AABB(
pos.x - dimensions.x,
pos.y - dimensions.y,
@ -62,7 +68,7 @@ fun <T : Entity> Level.getEntitiesInEllipsoid(type: Class<out T>, pos: Vector, d
pos.z + dimensions.z,
), predicate)
val result = LinkedList<Pair<T, Double>>()
val result = ArrayList<EntityDistance<T>>()
for (it in entities) {
val a = (it.position - pos).let { vec ->
@ -80,7 +86,7 @@ fun <T : Entity> Level.getEntitiesInEllipsoid(type: Class<out T>, pos: Vector, d
val min = a.coerceAtMost(b)
if (min <= 1.0) {
result.add(it to min)
result.add(EntityDistance(it, min))
}
}
@ -90,27 +96,27 @@ fun <T : Entity> Level.getEntitiesInEllipsoid(type: Class<out T>, pos: Vector, d
/**
* Pair of entity and distance fraction to center of ellipsoid
*/
fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
fun Level.getEntitiesInEllipsoid(pos: Vector, dimensions: Vector, predicate: Predicate<in Entity>): MutableList<EntityDistance<Entity>> {
return getEntitiesInEllipsoid(pos, dimensions, null, predicate)
}
/**
* Pair of entity and distance fraction to center of ellipsoid
*/
fun Level.getEntitiesInSphere(pos: Vector, radius: Double, except: Entity?, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
fun Level.getEntitiesInSphere(pos: Vector, radius: Double, except: Entity?, predicate: Predicate<in Entity>): MutableList<EntityDistance<Entity>> {
return getEntitiesInEllipsoid(pos, Vector(radius, radius, radius), except, predicate)
}
/**
* Pair of entity and distance fraction to center of ellipsoid
*/
fun Level.getEntitiesInSphere(pos: Vector, radius: Double, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
fun Level.getEntitiesInSphere(pos: Vector, radius: Double, predicate: Predicate<in Entity>): MutableList<EntityDistance<Entity>> {
return getEntitiesInEllipsoid(pos, Vector(radius, radius, radius), null, predicate)
}
/**
* Pair of entity and distance fraction to center of ellipsoid
*/
fun Level.getEntitiesInSphere(type: Class<out Entity>, pos: Vector, radius: Double, predicate: Predicate<in Entity>): List<Pair<Entity, Double>> {
fun <T : Entity> Level.getEntitiesInSphere(type: Class<out T>, pos: Vector, radius: Double, predicate: Predicate<in Entity>): MutableList<EntityDistance<T>> {
return getEntitiesInEllipsoid(type, pos, Vector(radius, radius, radius), predicate)
}

View File

@ -10,14 +10,14 @@ import ru.dbotthepony.mc.otm.menu.MatteryMenu
* [allowPull] and [allowPush] controls whenever player is allowed to change these options
*/
class EnergyConfigPlayerInput(val menu: MatteryMenu, config: MatteryDeviceBlockEntity.ConfigurableEnergy<*>? = null, val allowPull: Boolean = false, val allowPush: Boolean = false) {
var possibleModes by menu.mSynchronizer.enum(FlowDirection::class.java)
private set
inner class Piece(val side: RelativeSide) {
val pull = BooleanInputWithFeedback(menu)
val push = BooleanInputWithFeedback(menu)
val input = EnumInputWithFeedback<FlowDirection>(menu)
var possibleModes by menu.mSynchronizer.enum(FlowDirection::class.java)
private set
var default by menu.mSynchronizer.enum(FlowDirection.NONE)
init {
@ -25,20 +25,19 @@ class EnergyConfigPlayerInput(val menu: MatteryMenu, config: MatteryDeviceBlockE
push.filter { allowPush && possibleModes.isSupertype(FlowDirection.OUTPUT) }
}
fun with(config: MatteryDeviceBlockEntity.ConfigurableEnergy<*>.Piece, parent: MatteryDeviceBlockEntity.ConfigurableEnergy<*>) {
fun with(config: MatteryDeviceBlockEntity.ConfigurableEnergy<*>.Piece) {
possibleModes = config.possibleModes
pull.with(config::automatePull)
push.with(config::automatePush)
input.withSupplier { config.energyFlow }.withConsumer { if (parent.possibleModes.isSupertype(it)) config.energyFlow = it }
input.withSupplier { config.energyFlow }.withConsumer { if (possibleModes.isSupertype(it)) config.energyFlow = it }
}
}
val pieces = immutableMap { for (side in RelativeSide.values()) put(side, Piece(side)) }
fun with(config: MatteryDeviceBlockEntity.ConfigurableEnergy<*>) {
possibleModes = config.possibleModes
for ((side, v) in config.pieces) {
pieces[side]!!.with(v, config)
pieces[side]!!.with(v)
pieces[side]!!.default = config.defaults[side]!!
}
}

View File

@ -6,7 +6,7 @@ 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: 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)
class EnumInputWithFeedback<E : Enum<E>>(menu: MatteryMenu, clazz: Class<E>) : AbstractPlayerInputWithFeedback<E>() {
@ -16,8 +16,10 @@ class EnumInputWithFeedback<E : Enum<E>>(menu: MatteryMenu, clazz: Class<E>) : A
override val input = menu.PlayerInput(codec, false) { consumer?.invoke(it) }
override val value by menu.mSynchronizer.ComputedField(getter = { supplier?.invoke() ?: default }, codec)
constructor(menu: MatteryMenu, clazz: Class<E>, state: KMutableProperty0<E>) : this(menu, clazz) {
with(state)
constructor(menu: MatteryMenu, clazz: Class<E>, state: KMutableProperty0<E>?) : this(menu, clazz) {
if (state != null) {
with(state)
}
}
constructor(menu: MatteryMenu, clazz: Class<E>, state: GetterSetter<E>) : this(menu, clazz) {

View File

@ -0,0 +1,21 @@
package ru.dbotthepony.mc.otm.menu.tech
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerBlockEntity
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus
class AndroidChargerMenu(
p_38852_: Int,
inventory: Inventory,
tile: AndroidChargerBlockEntity? = null
) : MatteryPoweredMenu(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile) {
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy, energyWidget)
init {
addInventorySlots()
}
}

View File

@ -21,7 +21,7 @@ class BatteryBankMenu @JvmOverloads constructor(
inventory: Inventory,
tile: BatteryBankBlockEntity? = null,
) : MatteryMenu(MMenus.BATTERY_BANK, p_38852_, inventory, tile) {
val powerLevel = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.capability)
val powerLevel = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy)
val storageSlots: List<MatterySlot>
val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java)
val energyConfig = EnergyConfigPlayerInput(this, allowPull = false, allowPush = true)

View File

@ -55,6 +55,7 @@ object MBlockEntities {
val ESSENCE_STORAGE: BlockEntityType<EssenceStorageBlockEntity> by registry.register(MNames.ESSENCE_STORAGE) { BlockEntityType.Builder.of(::EssenceStorageBlockEntity, MBlocks.ESSENCE_STORAGE).build(null) }
val MATTER_RECONSTRUCTOR: BlockEntityType<MatterReconstructorBlockEntity> by registry.register(MNames.MATTER_RECONSTRUCTOR) { BlockEntityType.Builder.of(::MatterReconstructorBlockEntity, MBlocks.MATTER_RECONSTRUCTOR).build(null) }
val FLUID_TANK: BlockEntityType<FluidTankBlockEntity> by registry.register(MNames.FLUID_TANK) { BlockEntityType.Builder.of(::FluidTankBlockEntity, MBlocks.FLUID_TANK).build(null) }
val ANDROID_CHARGER: BlockEntityType<AndroidChargerBlockEntity> by registry.register(MNames.ANDROID_CHARGER) { BlockEntityType.Builder.of(::AndroidChargerBlockEntity, MBlocks.ANDROID_CHARGER).build(null) }
val STORAGE_BUS: BlockEntityType<StorageBusBlockEntity> by registry.register(MNames.STORAGE_BUS) { BlockEntityType.Builder.of(::StorageBusBlockEntity, MBlocks.STORAGE_BUS).build(null) }
val STORAGE_IMPORTER: BlockEntityType<StorageImporterBlockEntity> by registry.register(MNames.STORAGE_IMPORTER) { BlockEntityType.Builder.of(::StorageImporterBlockEntity, MBlocks.STORAGE_IMPORTER).build(null) }

View File

@ -58,6 +58,7 @@ import ru.dbotthepony.mc.otm.block.storage.StorageBusBlock
import ru.dbotthepony.mc.otm.block.storage.StorageExporterBlock
import ru.dbotthepony.mc.otm.block.storage.StorageImporterBlock
import ru.dbotthepony.mc.otm.block.storage.StoragePowerSupplierBlock
import ru.dbotthepony.mc.otm.block.tech.AndroidChargerBlock
import ru.dbotthepony.mc.otm.block.tech.CobblerBlock
import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock
import ru.dbotthepony.mc.otm.core.TranslatableComponent
@ -71,6 +72,7 @@ object MBlocks {
}
val ANDROID_STATION: Block by registry.register(MNames.ANDROID_STATION) { AndroidStationBlock() }
val ANDROID_CHARGER: Block by registry.register(MNames.ANDROID_CHARGER) { AndroidChargerBlock() }
val BATTERY_BANK: Block by registry.register(MNames.BATTERY_BANK) { BatteryBankBlock() }
val MATTER_DECOMPOSER: Block by registry.register(MNames.MATTER_DECOMPOSER) { MatterDecomposerBlock() }
val MATTER_CAPACITOR_BANK: Block by registry.register(MNames.MATTER_CAPACITOR_BANK) { MatterCapacitorBankBlock() }

View File

@ -44,6 +44,7 @@ object MItems {
}
val ANDROID_STATION: BlockItem by registry.register(MNames.ANDROID_STATION) { BlockItem(MBlocks.ANDROID_STATION, DEFAULT_PROPERTIES) }
val ANDROID_CHARGER: BlockItem by registry.register(MNames.ANDROID_CHARGER) { BlockItem(MBlocks.ANDROID_CHARGER, DEFAULT_PROPERTIES) }
val BATTERY_BANK: BlockItem by registry.register(MNames.BATTERY_BANK) { BlockItem(MBlocks.BATTERY_BANK, DEFAULT_PROPERTIES) }
val MATTER_DECOMPOSER: BlockItem by registry.register(MNames.MATTER_DECOMPOSER) { BlockItem(MBlocks.MATTER_DECOMPOSER, DEFAULT_PROPERTIES) }
val MATTER_CAPACITOR_BANK: BlockItem by registry.register(MNames.MATTER_CAPACITOR_BANK) { BlockItem(MBlocks.MATTER_CAPACITOR_BANK, DEFAULT_PROPERTIES) }
@ -134,7 +135,7 @@ object MItems {
}
val MACHINES = SupplierList(
::ANDROID_STATION, ::BATTERY_BANK, ::MATTER_DECOMPOSER, ::MATTER_CAPACITOR_BANK, ::MATTER_CABLE, ::PATTERN_STORAGE,
::ANDROID_STATION, ::ANDROID_CHARGER, ::BATTERY_BANK, ::MATTER_DECOMPOSER, ::MATTER_CAPACITOR_BANK, ::MATTER_CABLE, ::PATTERN_STORAGE,
::MATTER_SCANNER, ::MATTER_PANEL, ::MATTER_REPLICATOR, ::MATTER_BOTTLER, ::ENERGY_COUNTER, ::CHEMICAL_GENERATOR,
::PLATE_PRESS, ::TWIN_PLATE_PRESS, ::MATTER_RECYCLER,
// ::STORAGE_BUS, ::STORAGE_IMPORTER, ::STORAGE_EXPORTER, ::DRIVE_VIEWER,

View File

@ -28,6 +28,7 @@ import ru.dbotthepony.mc.otm.client.screen.storage.StorageBusScreen
import ru.dbotthepony.mc.otm.client.screen.storage.StorageExporterScreen
import ru.dbotthepony.mc.otm.client.screen.storage.StorageImporterScreen
import ru.dbotthepony.mc.otm.client.screen.storage.StoragePowerSupplierScreen
import ru.dbotthepony.mc.otm.client.screen.tech.AndroidChargerScreen
import ru.dbotthepony.mc.otm.client.screen.tech.AndroidStationScreen
import ru.dbotthepony.mc.otm.client.screen.tech.BatteryBankScreen
import ru.dbotthepony.mc.otm.client.screen.tech.ChemicalGeneratorScreen
@ -57,6 +58,7 @@ import ru.dbotthepony.mc.otm.menu.storage.StorageBusMenu
import ru.dbotthepony.mc.otm.menu.storage.StorageExporterMenu
import ru.dbotthepony.mc.otm.menu.storage.StorageImporterMenu
import ru.dbotthepony.mc.otm.menu.storage.StoragePowerSupplierMenu
import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu
import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu
import ru.dbotthepony.mc.otm.menu.tech.BatteryBankMenu
import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu
@ -71,6 +73,7 @@ object MMenus {
private val registry = DeferredRegister.create(ForgeRegistries.MENU_TYPES, OverdriveThatMatters.MOD_ID)
val ANDROID_STATION: MenuType<AndroidStationMenu> by registry.register(MNames.ANDROID_STATION) { MenuType(::AndroidStationMenu, FeatureFlags.VANILLA_SET) }
val ANDROID_CHARGER: MenuType<AndroidChargerMenu> by registry.register(MNames.ANDROID_CHARGER) { MenuType(::AndroidChargerMenu, FeatureFlags.VANILLA_SET) }
val BATTERY_BANK: MenuType<BatteryBankMenu> by registry.register(MNames.BATTERY_BANK) { MenuType(::BatteryBankMenu, FeatureFlags.VANILLA_SET) }
val MATTER_DECOMPOSER: MenuType<MatterDecomposerMenu> by registry.register(MNames.MATTER_DECOMPOSER) { MenuType(::MatterDecomposerMenu, FeatureFlags.VANILLA_SET) }
val MATTER_CAPACITOR_BANK: MenuType<MatterCapacitorBankMenu> by registry.register(MNames.MATTER_CAPACITOR_BANK) { MenuType(::MatterCapacitorBankMenu, FeatureFlags.VANILLA_SET) }
@ -110,6 +113,7 @@ object MMenus {
private fun registerClient(event: FMLClientSetupEvent) {
event.enqueueWork {
MenuScreens.register(ANDROID_STATION, ::AndroidStationScreen)
MenuScreens.register(ANDROID_CHARGER, ::AndroidChargerScreen)
MenuScreens.register(BATTERY_BANK, ::BatteryBankScreen)
MenuScreens.register(MATTER_DECOMPOSER, ::MatterDecomposerScreen)
MenuScreens.register(MATTER_CAPACITOR_BANK, ::MatterCapacitorBankScreen)

View File

@ -12,6 +12,7 @@ object MNames {
const val ENGINE = "engine"
const val HOLO_SIGN = "holo_sign"
const val FLUID_TANK = "fluid_tank"
const val ANDROID_CHARGER = "android_charger"
// blocks
const val ANDROID_STATION = "android_station"