Updated energy counter, move energy API to kotlin

This commit is contained in:
DBotThePony 2022-01-03 21:06:21 +07:00
parent bb17f93a91
commit 6c029b98b7
Signed by: DBot
GPG Key ID: DCC23B5715498507
14 changed files with 578 additions and 724 deletions

View File

@ -4,6 +4,7 @@ import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.core.Vec3i import net.minecraft.core.Vec3i
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import java.util.function.Consumer import java.util.function.Consumer
@ -47,7 +48,7 @@ inline fun CompoundTag.ifHas(s: String, type: Byte, consumer: (Tag) -> Unit) {
} }
} }
inline fun <T : Tag> CompoundTag.ifHas(s: String, type: Class<T>, consumer: (T) -> Unit) { inline fun <reified T : Tag> CompoundTag.ifHas(s: String, type: Class<T>, consumer: (T) -> Unit) {
val tag = get(s) val tag = get(s)
if (tag != null && tag::class.java == type) { if (tag != null && tag::class.java == type) {

View File

@ -1,74 +1,75 @@
package ru.dbotthepony.mc.otm.block; package ru.dbotthepony.mc.otm.block
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos
import net.minecraft.core.BlockPos; import net.minecraft.core.Direction
import net.minecraft.core.Direction; import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.Level
import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker
import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.level.block.state.properties.EnumProperty; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.entity.BlockEntityEnergyCounter
import ru.dbotthepony.mc.otm.block.entity.BlockEntityEnergyCounter;
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMatterBottler;
import javax.annotation.Nullable; class BlockEnergyCounter : BlockMattery(), EntityBlock {
import javax.annotation.ParametersAreNonnullByDefault; override fun newBlockEntity(blockPos: BlockPos, blockState: BlockState): BlockEntity {
return BlockEntityEnergyCounter(blockPos, blockState)
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
public class BlockEnergyCounter extends BlockMattery implements EntityBlock {
public static final EnumProperty<Direction> INPUT_DIRECTION = EnumProperty.create("input", Direction.class);
public static final EnumProperty<Direction> IF_DIRECTION = EnumProperty.create("if", Direction.class);
@Nullable
@Override
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new BlockEntityEnergyCounter(blockPos, blockState);
} }
@Nullable override fun <T : BlockEntity?> getTicker(
@Override level: Level,
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level p_153212_, BlockState p_153213_, BlockEntityType<T> p_153214_) { blockState: BlockState,
return p_153212_.isClientSide || p_153214_ != Registry.BlockEntities.ENERGY_COUNTER ? null : BlockEntityEnergyCounter::tick; blockEntityType: BlockEntityType<T>
): BlockEntityTicker<T>? {
if (level.isClientSide || blockEntityType !== Registry.BlockEntities.ENERGY_COUNTER)
return null
return BlockEntityTicker { _, _, _, tile -> if (tile is BlockEntityEnergyCounter) tile.tick() }
} }
@Nullable override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
@Override val inputDir =
public BlockState getStateForPlacement(BlockPlaceContext context) { if (context.player != null && context.player!!.isCrouching) context.clickedFace.opposite else context.clickedFace
final var input_direction = context.getPlayer() != null && context.getPlayer().isCrouching() ? context.getClickedFace().getOpposite() : context.getClickedFace();
final var opposite = input_direction.getOpposite();
Direction dir = null; val opposite = inputDir.opposite
var dir: Direction? = null
for (var _dir : context.getNearestLookingDirections()) { for (_dir in context.nearestLookingDirections) {
if (_dir != input_direction && _dir != opposite) { if (_dir != inputDir && _dir != opposite) {
dir = _dir.getOpposite(); dir = _dir.opposite
break; break
} }
} }
assert dir != null; return defaultBlockState().setValue(INPUT_DIRECTION, inputDir).setValue(IF_DIRECTION, dir!!)
return defaultBlockState().setValue(INPUT_DIRECTION, input_direction).setValue(IF_DIRECTION, dir);
} }
@Override override fun createBlockStateDefinition(p_49915_: StateDefinition.Builder<Block, BlockState>) {
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> p_49915_) { super.createBlockStateDefinition(p_49915_)
super.createBlockStateDefinition(p_49915_); p_49915_.add(INPUT_DIRECTION, IF_DIRECTION)
p_49915_.add(INPUT_DIRECTION, IF_DIRECTION);
} }
@Override override fun neighborChanged(
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block sender, BlockPos sender_pos, boolean flag) { state: BlockState,
super.neighborChanged(state, level, pos, sender, sender_pos, flag); level: Level,
pos: BlockPos,
sender: Block,
sender_pos: BlockPos,
flag: Boolean
) {
super.neighborChanged(state, level, pos, sender, sender_pos, flag)
if (!level.isClientSide && level.getBlockEntity(pos) instanceof BlockEntityEnergyCounter tile) { if (!level.isClientSide) {
tile.checkSurroundings(level); (level.getBlockEntity(pos) as? BlockEntityEnergyCounter)?.checkSurroundings(level)
} }
} }
companion object {
@JvmField val INPUT_DIRECTION: EnumProperty<Direction> = EnumProperty.create("input", Direction::class.java)
@JvmField val IF_DIRECTION: EnumProperty<Direction> = EnumProperty.create("if", Direction::class.java)
}
} }

View File

@ -188,7 +188,7 @@ class BlockEntityBatteryBank(p_155229_: BlockPos, p_155230_: BlockState) : Block
return distributeEnergy(true, howMuch, simulate) return distributeEnergy(true, howMuch, simulate)
} }
override fun getBatteryLevel(): Fraction { override val batteryLevel: Fraction get() {
var result = Fraction.ZERO var result = Fraction.ZERO
for (i in 0 until container.containerSize) { for (i in 0 until container.containerSize) {
@ -208,7 +208,7 @@ class BlockEntityBatteryBank(p_155229_: BlockPos, p_155230_: BlockState) : Block
return result return result
} }
override fun getMaxBatteryLevel(): Fraction { override val maxBatteryLevel: Fraction get() {
var result = Fraction.ZERO var result = Fraction.ZERO
for (i in 0 until container.containerSize) { for (i in 0 until container.containerSize) {

View File

@ -29,10 +29,11 @@ import ru.dbotthepony.mc.otm.menu.ChemicalGeneratorMenu
import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.receiveEnergy import ru.dbotthepony.mc.otm.capability.receiveEnergy
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEntityMattery(Registry.BlockEntities.CHEMICAL_GENERATOR, pos, state), IMatteryEnergyStorage { class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEntityMattery(Registry.BlockEntities.CHEMICAL_GENERATOR, pos, state) {
override fun getDefaultDisplayName(): Component { override fun getDefaultDisplayName(): Component {
return NAME return NAME
} }
@ -42,13 +43,14 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
} }
private var valid = true private var valid = true
private var resolver = LazyOptional.of {this} private var resolver = LazyOptional.of {energy}
@JvmField val energy = MatteryMachineEnergyStorage(this::setChangedLight, MatteryMachineEnergyStorage.MachineType.GENERATOR, MAX_ENERGY, THROUGHPUT)
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> { override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (valid && (cap == MatteryCapability.ENERGY || cap == CapabilityEnergy.ENERGY) && side != blockState.getValue(BlockMatteryRotatable.FACING)) if (valid && (cap === MatteryCapability.ENERGY || cap === CapabilityEnergy.ENERGY) && side !== blockState.getValue(BlockMatteryRotatable.FACING))
return resolver.cast() return resolver.cast()
if (valid && cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) if (valid && cap === CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return itemHandler.get().cast() return itemHandler.get().cast()
return super.getCapability(cap, side) return super.getCapability(cap, side)
@ -65,7 +67,7 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
super.reviveCaps() super.reviveCaps()
itemHandler.revive() itemHandler.revive()
valid = true valid = true
resolver = LazyOptional.of {this} resolver = LazyOptional.of {energy}
} }
override fun setLevel(level: Level) { override fun setLevel(level: Level) {
@ -87,7 +89,7 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
override fun saveAdditional(nbt: CompoundTag) { override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt) super.saveAdditional(nbt)
nbt["energy"] = power.serializeNBT() nbt["energy"] = energy.serializeNBT()
nbt["slots"] = container.serializeNBT() nbt["slots"] = container.serializeNBT()
nbt["working_ticks"] = workingTicks nbt["working_ticks"] = workingTicks
nbt["working_ticks_total"] = workingTicksTotal nbt["working_ticks_total"] = workingTicksTotal
@ -96,8 +98,8 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
override fun load(nbt: CompoundTag) { override fun load(nbt: CompoundTag) {
super.load(nbt) super.load(nbt)
nbt.ifHas("energy") { nbt.ifHas("energy", CompoundTag::class.java) {
power = Fraction.deserializeNBT(it) energy.deserializeNBT(it)
} }
nbt.ifHas("slots") { nbt.ifHas("slots") {
@ -169,44 +171,6 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
} }
} }
private var power = Fraction.ZERO
override fun extractEnergyOuter(howMuch: Fraction, simulate: Boolean): Fraction {
return extractEnergyInner(howMuch, simulate)
}
override fun extractEnergyInner(howMuch: Fraction, simulate: Boolean): Fraction {
val extracted = howMuch.min(THROUGHPUT, power)
if (!simulate && !extracted.isZero()) {
power -= extracted
check = true
setChangedLight()
}
return extracted
}
override fun receiveEnergyOuter(howMuch: Fraction, simulate: Boolean): Fraction {
return Fraction.ZERO
}
override fun receiveEnergyInner(howMuch: Fraction, simulate: Boolean): Fraction {
val new = (howMuch + power).min(MAX_ENERGY)
val diff = new - power
if (!simulate) {
power = new
setChangedLight()
}
return diff
}
override fun getBatteryLevel(): Fraction = power
override fun getMaxBatteryLevel(): Fraction = MAX_ENERGY
override fun canExtract(): Boolean = true
var workingTicks = 0 var workingTicks = 0
private set private set
@ -218,19 +182,19 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
private fun workWithPower(it: IEnergyStorage) { private fun workWithPower(it: IEnergyStorage) {
if (it is IMatteryEnergyStorage) { if (it is IMatteryEnergyStorage) {
val demand = it.missingPower val demand = it.missingPower
val extracted = extractEnergyInner(demand, true) val extracted = energy.extractEnergyInner(demand, true)
val received = it.receiveEnergyOuter(extracted, false) val received = it.receiveEnergyOuter(extracted, false)
if (!received.isZero()) { if (!received.isZero()) {
extractEnergyInner(received, false) energy.extractEnergyInner(received, false)
} }
} else { } else {
val demand = it.receiveEnergy(THROUGHPUT_INT, true) val demand = it.receiveEnergy(THROUGHPUT_INT, true)
val extracted = extractEnergyInner(demand, true) val extracted = energy.extractEnergyInner(demand, true)
val received = it.receiveEnergy(extracted, false) val received = it.receiveEnergy(extracted, false)
if (received != 0) { if (received != 0) {
extractEnergyInner(received, false) energy.extractEnergyInner(received, false)
} }
} }
} }
@ -238,7 +202,7 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
fun tick() { fun tick() {
if (workingTicks > 0 && !isBlockedByRedstone) { if (workingTicks > 0 && !isBlockedByRedstone) {
workingTicks-- workingTicks--
receiveEnergyInner(GENERATION_SPEED, false) energy.receiveEnergyInner(GENERATION_SPEED, false)
if (workingTicks == 0) { if (workingTicks == 0) {
workingTicksTotal = 0 workingTicksTotal = 0
@ -256,7 +220,7 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
if (!container.getItem(0).isEmpty) { if (!container.getItem(0).isEmpty) {
val ticks = ForgeHooks.getBurnTime(container.getItem(0), null) val ticks = ForgeHooks.getBurnTime(container.getItem(0), null)
if (ticks >= 4 && (batteryLevel < Fraction.ONE || GENERATION_SPEED * (ticks / 4) + batteryLevel <= maxBatteryLevel)) { if (ticks >= 4 && (energy.batteryLevel < Fraction.ONE || GENERATION_SPEED * (ticks / 4) + energy.batteryLevel <= energy.maxBatteryLevel)) {
workingTicksTotal = ticks / 4 workingTicksTotal = ticks / 4
workingTicks = ticks / 4 workingTicks = ticks / 4
container.getItem(0).shrink(1) container.getItem(0).shrink(1)
@ -266,13 +230,13 @@ class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEnti
check = false check = false
} }
if (power.isZero()) return if (energy.batteryLevel.isZero()) return
val item = container.getItem(1) val item = container.getItem(1)
if (!item.isEmpty) { if (!item.isEmpty) {
item.getCapability(CapabilityEnergy.ENERGY).ifPresent(this::workWithPower) item.getCapability(CapabilityEnergy.ENERGY).ifPresent(this::workWithPower)
if (power.isZero()) return if (energy.batteryLevel.isZero()) return
} }
for (consumer in consumers) { for (consumer in consumers) {

View File

@ -1,410 +1,349 @@
package ru.dbotthepony.mc.otm.block.entity; package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos
import net.minecraft.core.BlockPos; import net.minecraft.core.Direction
import net.minecraft.core.Direction; import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.*; import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component; import net.minecraft.nbt.IntTag
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.nbt.ListTag
import net.minecraft.server.level.ServerLevel; import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory; import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.world.entity.player.Player; import net.minecraft.server.level.ServerLevel
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.level.Level; import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.Level
import net.minecraftforge.common.capabilities.Capability; import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.energy.CapabilityEnergy; import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.IEnergyStorage; import net.minecraftforge.energy.CapabilityEnergy
import org.apache.logging.log4j.LogManager; import net.minecraftforge.energy.IEnergyStorage
import org.apache.logging.log4j.Logger; import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.OverdriveThatMatters; import ru.dbotthepony.mc.otm.block.BlockEnergyCounter
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.block.BlockEnergyCounter; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage; import ru.dbotthepony.mc.otm.capability.extractEnergy
import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.capability.receiveEnergy
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.menu.EnergyCounterMenu; import ru.dbotthepony.mc.otm.menu.EnergyCounterMenu
import java.lang.ref.WeakReference
import javax.annotation.Nonnull; class BlockEntityEnergyCounter(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntityMattery(Registry.BlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) {
import javax.annotation.Nullable; var passed = Fraction.ZERO
import javax.annotation.ParametersAreNonnullByDefault; private set
import java.lang.ref.WeakReference;
import java.util.Arrays;
@MethodsReturnNonnullByDefault private val history = Array(10 * 20) { Fraction.ZERO }
@ParametersAreNonnullByDefault private var historyTick = 0
public class BlockEntityEnergyCounter extends BlockEntityMattery {
protected Fraction passed = Fraction.ZERO;
protected final Fraction[] history = new Fraction[10 * 20];
protected int history_tick = 0;
public static <T extends BlockEntity> void tick(Level level, BlockPos blockPos, BlockState blockState, T t) { fun size() = history.size
if (t instanceof BlockEntityEnergyCounter tile) { operator fun get(i: Int) = history[i]
tile.history_tick = (tile.history_tick + 1) % tile.history.length; val lastTick: Fraction get() = history[historyTick]
tile.history[tile.history_tick] = Fraction.ZERO;
} fun getHistory(ticks: Int): Array<Fraction> {
require(!(ticks < 1 || ticks >= history.size)) { "Invalid history length provided" }
val history = Array(ticks) { Fraction.ZERO }
for (i in 0 until ticks) {
var index = (historyTick - i) % this.history.size
if (index < 0) index += this.history.size
history[i] = this.history[index]
} }
public Fraction[] getHistory(int ticks) { return history
if (ticks < 1 || ticks >= history.length) {
throw new IllegalArgumentException("Invalid history length provided");
} }
final var history = new Fraction[ticks]; fun calcAverage(ticks: Int): Fraction {
return sumHistory(ticks) / ticks
for (int i = 0; i < ticks; i++) {
int index = (history_tick - i) % this.history.length;
if (index < 0)
index += this.history.length;
history[i] = this.history[index];
} }
return history; fun sumHistory(ticks: Int): Fraction {
require(!(ticks < 1 || ticks >= history.size)) { "Invalid history length provided" }
var value = Fraction.ZERO
for (i in 0 until ticks) {
var index = (historyTick - i) % history.size
if (index < 0) index += history.size
value += history[index]
} }
public Fraction calcAverage(int ticks) { return value
return sumHistory(ticks).div(ticks);
} }
public Fraction sumHistory(int ticks) { override fun saveAdditional(nbt: CompoundTag) {
if (ticks < 1 || ticks >= history.length) { super.saveAdditional(nbt)
throw new IllegalArgumentException("Invalid history length provided"); nbt["passed"] = passed.serializeNBT()
val list = ListTag()
nbt["history"] = list
nbt["history_tick"] = historyTick
for (num in history)
list.add(num.serializeNBT())
} }
var value = Fraction.ZERO; override fun load(nbt: CompoundTag) {
super.load(nbt)
for (int i = 0; i < ticks; i++) { nbt.ifHas(("passed")) {
int index = (history_tick - i) % this.history.length; passed = Fraction.deserializeNBT(it)
if (index < 0)
index += this.history.length;
value = value.plus(history[index]);
} }
return value; nbt.ifHas(("history_tick"), IntTag::class.java) {
historyTick = it.asInt
} }
public Fraction getPassed() { nbt.ifHas("history", ListTag::class.java) {
return passed; for (i in it.indices) {
} val bytes = it[i] as? ByteArrayTag
history[i] = if (bytes != null) Fraction.deserializeNBT(bytes) else Fraction.ZERO
public BlockEntityEnergyCounter(BlockPos p_155229_, BlockState p_155230_) {
super(Registry.BlockEntities.ENERGY_COUNTER, p_155229_, p_155230_);
Arrays.fill(history, Fraction.ZERO);
}
@Override
public void saveAdditional(CompoundTag nbt) {
super.saveAdditional(nbt);
nbt.put("passed", passed.serializeNBT());
var list = new ListTag();
nbt.put("history", list);
nbt.putInt("history_tick", history_tick);
for (var num : history)
list.add(StringTag.valueOf(num.toString()));
}
private static final Logger LOGGER = LogManager.getLogger();
@Override
public void load(CompoundTag nbt) {
super.load(nbt);
if (nbt.contains("passed"))
passed = Fraction.deserializeNBT(nbt.get("passed"));
if (nbt.get("history_tick") instanceof IntTag tag)
history_tick = tag.getAsInt();
// TODO: старый формат данных, удалить на релизе
var list = nbt.getList("history", Tag.TAG_STRING);
for (int i = 0; i < list.size(); i++) {
try {
history[i] = Fraction.fromString(list.getString(i));
} catch(Throwable err) {
LOGGER.error(err);
}
}
// новый формат данных
list = nbt.getList("history", Tag.TAG_BYTE_ARRAY);
for (int i = 0; i < list.size(); i++) {
try {
history[i] = Fraction.fromString(list.getString(i));
} catch(Throwable err) {
LOGGER.error(err);
} }
} }
} }
private static final TranslatableComponent NAME = new TranslatableComponent("block.overdrive_that_matters.energy_counter"); override fun getDefaultDisplayName(): Component {
return NAME
@Override
protected Component getDefaultDisplayName() {
return NAME;
} }
@Nullable override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
@Override return EnergyCounterMenu(containerID, inventory, this)
public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply) {
return new EnergyCounterMenu(containerID, inventory, this);
} }
public final EnergyCounterCap input = new EnergyCounterCap(true); private val energyInput = EnergyCounterCap(true)
public final EnergyCounterCap output = new EnergyCounterCap(false); private val energyOutput = EnergyCounterCap(false)
protected LazyOptional<IMatteryEnergyStorage> input_cap_mte = LazyOptional.empty(); private var inputCapability = LazyOptional.empty<IEnergyStorage>()
protected LazyOptional<IEnergyStorage> input_cap_fe = LazyOptional.empty(); private var outputCapability = LazyOptional.empty<IEnergyStorage>()
protected LazyOptional<IMatteryEnergyStorage> output_cap_mte = LazyOptional.empty();
protected LazyOptional<IEnergyStorage> output_cap_fe = LazyOptional.empty();
@Override override fun setLevel(p_155231_: Level) {
public void setLevel(Level p_155231_) { super.setLevel(p_155231_)
super.setLevel(p_155231_);
if (p_155231_ instanceof ServerLevel level) { val level = level
OverdriveThatMatters.tickOnceSelf(level, this::checkSurroundings); if (level is ServerLevel) {
OverdriveThatMatters.tickOnce(level) { checkSurroundings(level) }
} }
} }
public class EnergyCounterCap implements IMatteryEnergyStorage { private inner class EnergyCounterCap(val is_input: Boolean) : IMatteryEnergyStorage {
public final boolean is_input; override fun extractEnergyOuter(howMuch: Fraction, simulate: Boolean): Fraction {
return extractEnergyInner(howMuch, simulate)
public EnergyCounterCap(boolean is_input) {
this.is_input = is_input;
} }
private EnergyCounterCap opposite() { override fun extractEnergyInner(howMuch: Fraction, simulate: Boolean): Fraction {
return is_input ? output : input;
}
@Override
public Fraction extractEnergyOuter(Fraction howMuch, boolean simulate) {
return extractEnergyInner(howMuch, simulate);
}
@Override
public Fraction extractEnergyInner(Fraction howMuch, boolean simulate) {
if (is_input) if (is_input)
return Fraction.ZERO; return Fraction.ZERO
if (input_cap_mte.isPresent()) { if (inputCapability.isPresent) {
final var value = input_cap_mte.resolve().get().extractEnergyOuter(howMuch, simulate); val it = inputCapability.resolve().get()
val diff: Fraction
if (it is IMatteryEnergyStorage) {
diff = it.extractEnergyOuter(howMuch, simulate)
} else {
diff = Fraction(it.extractEnergy(howMuch, simulate))
}
if (!simulate) { if (!simulate) {
passed = passed.plus(value); passed += diff
history[history_tick] = history[history_tick].plus(value); history[historyTick] += diff
setChangedLight();
} }
return value; return diff
} }
if (input_cap_fe.isPresent()) { return Fraction.ZERO
final var value = MatteryCapability.drainFE(input_cap_fe.resolve().get(), howMuch, simulate);
if (!simulate) {
passed = passed.plus(value);
history[history_tick] = history[history_tick].plus(value);
setChangedLight();
} }
return value; override fun receiveEnergyOuter(howMuch: Fraction, simulate: Boolean): Fraction {
return receiveEnergyInner(howMuch, simulate)
} }
return Fraction.ZERO; override fun receiveEnergyInner(howMuch: Fraction, simulate: Boolean): Fraction {
}
@Override
public Fraction receiveEnergyOuter(Fraction howMuch, boolean simulate) {
return receiveEnergyInner(howMuch, simulate);
}
@Override
public Fraction receiveEnergyInner(Fraction howMuch, boolean simulate) {
if (!is_input) if (!is_input)
return Fraction.ZERO; return Fraction.ZERO
if (output_cap_mte.isPresent()) { if (outputCapability.isPresent) {
final var value = output_cap_mte.resolve().get().receiveEnergyOuter(howMuch, simulate); val it = outputCapability.resolve().get()
val diff: Fraction
if (it is IMatteryEnergyStorage) {
diff = it.receiveEnergyOuter(howMuch, simulate)
} else {
diff = Fraction(it.receiveEnergy(howMuch, simulate))
}
if (!simulate) { if (!simulate) {
passed = passed.plus(value); passed += diff
history[history_tick] = history[history_tick].plus(value); history[historyTick] += diff
setChangedLight();
} }
return value; return diff
} }
if (output_cap_fe.isPresent()) { return Fraction.ZERO
final var value = MatteryCapability.floodFE(output_cap_fe.resolve().get(), howMuch, simulate);
if (!simulate) {
passed = passed.plus(value);
history[history_tick] = history[history_tick].plus(value);
setChangedLight();
} }
return value; override val batteryLevel: Fraction
} get() {
return Fraction.ZERO;
}
@Override
public Fraction getBatteryLevel() {
if (is_input) { if (is_input) {
if (output_cap_mte.isPresent()) { if (outputCapability.isPresent) {
return output_cap_mte.resolve().get().getBatteryLevel(); val it = outputCapability.resolve().get()
if (it is IMatteryEnergyStorage) {
return it.batteryLevel
} }
if (output_cap_fe.isPresent()) { return Fraction(it.energyStored)
return new Fraction(output_cap_fe.resolve().get().getEnergyStored());
} }
} else { } else {
if (input_cap_mte.isPresent()) { if (inputCapability.isPresent) {
return input_cap_mte.resolve().get().getBatteryLevel(); val it = inputCapability.resolve().get()
if (it is IMatteryEnergyStorage) {
return it.batteryLevel
} }
if (input_cap_fe.isPresent()) { return Fraction(it.energyStored)
return new Fraction(input_cap_fe.resolve().get().getEnergyStored());
} }
} }
return Fraction.ZERO; return Fraction.ZERO
} }
@Override override val maxBatteryLevel: Fraction
public Fraction getMaxBatteryLevel() { get() {
if (is_input) { if (is_input) {
if (output_cap_mte.isPresent()) { if (outputCapability.isPresent) {
return output_cap_mte.resolve().get().getMaxBatteryLevel(); val it = outputCapability.resolve().get()
if (it is IMatteryEnergyStorage) {
return it.maxBatteryLevel
} }
if (output_cap_fe.isPresent()) { return Fraction(it.maxEnergyStored)
return new Fraction(output_cap_fe.resolve().get().getMaxEnergyStored());
} }
} else { } else {
if (input_cap_mte.isPresent()) { if (inputCapability.isPresent) {
return input_cap_mte.resolve().get().getMaxBatteryLevel(); val it = inputCapability.resolve().get()
if (it is IMatteryEnergyStorage) {
return it.maxBatteryLevel
} }
if (input_cap_fe.isPresent()) { return Fraction(it.maxEnergyStored)
return new Fraction(input_cap_fe.resolve().get().getMaxEnergyStored());
} }
} }
return Fraction.ZERO; return Fraction.ZERO
} }
@Override override fun canExtract() = !is_input
public boolean canExtract() { override fun canReceive() = is_input
return !is_input;
} }
@Override private var resolverInput = LazyOptional.of<IMatteryEnergyStorage> { energyInput }
public boolean canReceive() { private var resolverOutput = LazyOptional.of<IMatteryEnergyStorage> { energyOutput }
return is_input; private var valid = true
}
override fun invalidateCaps() {
super.invalidateCaps()
valid = false
resolverInput.invalidate()
resolverOutput.invalidate()
} }
protected LazyOptional<IMatteryEnergyStorage> input_resolver = LazyOptional.of(() -> input); override fun reviveCaps() {
protected LazyOptional<IMatteryEnergyStorage> output_resolver = LazyOptional.of(() -> output); super.reviveCaps()
valid = true
@Override resolverInput = LazyOptional.of { energyInput }
public void invalidateCaps() { resolverOutput = LazyOptional.of { energyOutput }
super.invalidateCaps();
input_resolver.invalidate();
output_resolver.invalidate();
} }
@Override @Suppress("deprecation")
public void reviveCaps() { override fun setBlockState(new: BlockState) {
super.reviveCaps(); val old = blockState
input_resolver = LazyOptional.of(() -> input); super.setBlockState(new)
output_resolver = LazyOptional.of(() -> output);
}
@Override if (new !== old && new.getValue(BlockEnergyCounter.INPUT_DIRECTION) != old.getValue(BlockEnergyCounter.INPUT_DIRECTION)) {
@SuppressWarnings("deprecation") resolverInput.invalidate()
public void setBlockState(BlockState p_155251_) { resolverOutput.invalidate()
final var old = getBlockState(); resolverInput = LazyOptional.of { energyInput }
resolverOutput = LazyOptional.of { energyOutput }
super.setBlockState(p_155251_);
if (p_155251_ != old && p_155251_.getValue(BlockEnergyCounter.INPUT_DIRECTION) != old.getValue(BlockEnergyCounter.INPUT_DIRECTION)) {
input_resolver.invalidate();
output_resolver.invalidate();
input_resolver = LazyOptional.of(() -> input);
output_resolver = LazyOptional.of(() -> output);
if (level != null) if (level != null)
checkSurroundings(level); checkSurroundings(level)
} }
} }
private <T> LazyOptional<T> getAndBind(Level level, LazyOptional<T> old, Capability<T> cap, Direction side) { private fun getAndBind(
final var ent = level.getBlockEntity(getBlockPos().offset(side.getNormal())); level: Level,
old: LazyOptional<IEnergyStorage>,
side: Direction
): LazyOptional<IEnergyStorage> {
val ent = level.getBlockEntity(blockPos.offset(side.normal)) ?: return LazyOptional.empty()
val resolve = ent.getCapability(CapabilityEnergy.ENERGY, side.opposite)
if (ent == null) if (resolve !== old) {
return LazyOptional.empty(); val weak = WeakReference(this)
final var resolve = ent.getCapability(cap, side.getOpposite()); resolve.addListener {
val get = weak.get()
if (resolve != old) { if (get?.level != null) {
final var weak = new WeakReference<>(this); get.checkSurroundings(get.level)
resolve.addListener((l) -> {
final var get = weak.get();
if (get != null && get.level != null) {
get.checkSurroundings(get.level);
}
});
return resolve;
}
return old;
}
public void checkSurroundings(Level level) {
if (isRemoved() || !(level instanceof ServerLevel))
return;
input_cap_mte = getAndBind(level, input_cap_mte, MatteryCapability.ENERGY, getBlockState().getValue(BlockEnergyCounter.INPUT_DIRECTION));
input_cap_fe = getAndBind(level, input_cap_fe, CapabilityEnergy.ENERGY, getBlockState().getValue(BlockEnergyCounter.INPUT_DIRECTION));
output_cap_mte = getAndBind(level, output_cap_mte, MatteryCapability.ENERGY, getBlockState().getValue(BlockEnergyCounter.INPUT_DIRECTION).getOpposite());
output_cap_fe = getAndBind(level, output_cap_fe, CapabilityEnergy.ENERGY, getBlockState().getValue(BlockEnergyCounter.INPUT_DIRECTION).getOpposite());
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
if (side == null || isRemoved())
return super.getCapability(cap, side);
if (side == getBlockState().getValue(BlockEnergyCounter.INPUT_DIRECTION)) {
if (cap == MatteryCapability.ENERGY || cap == CapabilityEnergy.ENERGY) {
return input_resolver.cast();
}
} else if (side == getBlockState().getValue(BlockEnergyCounter.INPUT_DIRECTION).getOpposite()) {
if (cap == MatteryCapability.ENERGY || cap == CapabilityEnergy.ENERGY) {
return output_resolver.cast();
} }
} }
return super.getCapability(cap, side); return resolve
}
return old
}
fun checkSurroundings(level: Level?) {
if (isRemoved || level !is ServerLevel) return
inputCapability = getAndBind(
level,
inputCapability,
blockState.getValue(BlockEnergyCounter.INPUT_DIRECTION)
)
outputCapability = getAndBind(
level,
outputCapability,
-blockState.getValue(BlockEnergyCounter.INPUT_DIRECTION)
)
}
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
if (side == null || isRemoved)
return super.getCapability(cap, side)
if (valid) {
if (side == blockState.getValue(BlockEnergyCounter.INPUT_DIRECTION)) {
if (cap === MatteryCapability.ENERGY || cap === CapabilityEnergy.ENERGY) {
return resolverInput.cast()
}
} else if (side == blockState.getValue(BlockEnergyCounter.INPUT_DIRECTION).opposite) {
if (cap === MatteryCapability.ENERGY || cap === CapabilityEnergy.ENERGY) {
return resolverOutput.cast()
}
}
}
return super.getCapability(cap, side)
}
fun tick() {
historyTick = (historyTick + 1) % history.size
history[historyTick] = Fraction.ZERO
}
companion object {
private val NAME = TranslatableComponent("block.overdrive_that_matters.energy_counter")
} }
} }

View File

@ -1,123 +1,104 @@
package ru.dbotthepony.mc.otm.capability; package ru.dbotthepony.mc.otm.capability
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraftforge.energy.IEnergyStorage
import net.minecraftforge.energy.IEnergyStorage; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.core.Fraction;
import javax.annotation.ParametersAreNonnullByDefault;
// IEnergyStorage for direct compat with Forge Energy // IEnergyStorage for direct compat with Forge Energy
@MethodsReturnNonnullByDefault interface IMatteryEnergyStorage : IEnergyStorage {
@ParametersAreNonnullByDefault
@SuppressWarnings("unused")
public interface IMatteryEnergyStorage extends IEnergyStorage {
// such as cables. This is something that would work only with energy storage // such as cables. This is something that would work only with energy storage
Fraction extractEnergyOuter(Fraction howMuch, boolean simulate); fun extractEnergyOuter(howMuch: Fraction, simulate: Boolean): Fraction
// for internal needs, e.g. for work // for internal needs, e.g. for work
// CAN also be used by something that does evil // CAN also be used by something that does evil
// e.g. sucking out energy anomaly should use this // e.g. sucking out energy anomaly should use this
Fraction extractEnergyInner(Fraction howMuch, boolean simulate); fun extractEnergyInner(howMuch: Fraction, simulate: Boolean): Fraction
// energy is received from outside, e.g. cables // energy is received from outside, e.g. cables
Fraction receiveEnergyOuter(Fraction howMuch, boolean simulate); fun receiveEnergyOuter(howMuch: Fraction, simulate: Boolean): Fraction
// energy is received from inside, e.g. generator generates power // energy is received from inside, e.g. generator generates power
Fraction receiveEnergyInner(Fraction howMuch, boolean simulate); fun receiveEnergyInner(howMuch: Fraction, simulate: Boolean): Fraction
default Fraction extractEnergyOuter(long howMuch, boolean simulate) { fun extractEnergyOuter(howMuch: Long, simulate: Boolean): Fraction {
return extractEnergyOuter(new Fraction(howMuch), simulate); return extractEnergyOuter(Fraction(howMuch), simulate)
} }
default Fraction extractEnergyOuter(int howMuch, boolean simulate) { fun extractEnergyOuter(howMuch: Int, simulate: Boolean): Fraction {
return extractEnergyOuter(new Fraction(howMuch), simulate); return extractEnergyOuter(Fraction(howMuch), simulate)
} }
default Fraction receiveEnergyOuter(long howMuch, boolean simulate) { fun receiveEnergyOuter(howMuch: Long, simulate: Boolean): Fraction {
return receiveEnergyOuter(new Fraction(howMuch), simulate); return receiveEnergyOuter(Fraction(howMuch), simulate)
} }
default Fraction receiveEnergyOuter(int howMuch, boolean simulate) { fun receiveEnergyOuter(howMuch: Int, simulate: Boolean): Fraction {
return receiveEnergyOuter(new Fraction(howMuch), simulate); return receiveEnergyOuter(Fraction(howMuch), simulate)
} }
default Fraction extractEnergyInner(long howMuch, boolean simulate) { fun extractEnergyInner(howMuch: Long, simulate: Boolean): Fraction {
return extractEnergyInner(new Fraction(howMuch), simulate); return extractEnergyInner(Fraction(howMuch), simulate)
} }
default Fraction extractEnergyInner(int howMuch, boolean simulate) { fun extractEnergyInner(howMuch: Int, simulate: Boolean): Fraction {
return extractEnergyInner(new Fraction(howMuch), simulate); return extractEnergyInner(Fraction(howMuch), simulate)
} }
default Fraction receiveEnergyInner(long howMuch, boolean simulate) { fun receiveEnergyInner(howMuch: Long, simulate: Boolean): Fraction {
return receiveEnergyInner(new Fraction(howMuch), simulate); return receiveEnergyInner(Fraction(howMuch), simulate)
} }
default Fraction receiveEnergyInner(int howMuch, boolean simulate) { fun receiveEnergyInner(howMuch: Int, simulate: Boolean): Fraction {
return receiveEnergyInner(new Fraction(howMuch), simulate); return receiveEnergyInner(Fraction(howMuch), simulate)
} }
Fraction getBatteryLevel(); val batteryLevel: Fraction
val maxBatteryLevel: Fraction
val missingPower: Fraction
get() = maxBatteryLevel - batteryLevel
Fraction getMaxBatteryLevel(); override fun receiveEnergy(maxReceive: Int, simulate: Boolean): Int {
val received = receiveEnergyOuter(maxReceive, true).toInt()
default Fraction getMissingPower() {
return getMaxBatteryLevel().minus(getBatteryLevel());
}
@Override
default int receiveEnergy(int maxReceive, boolean simulate) {
int received = receiveEnergyOuter(maxReceive, true).toInt();
if (received == 0) {
// Receiving only a fraction // Receiving only a fraction
return 0; if (received == 0)
return 0
return receiveEnergyOuter(Fraction(received), simulate).toInt()
} }
return receiveEnergyOuter(new Fraction(received), simulate).toInt(); override fun extractEnergy(maxReceive: Int, simulate: Boolean): Int {
} val extracted = extractEnergyOuter(maxReceive, true).toInt()
@Override
default int extractEnergy(int maxReceive, boolean simulate) {
int extracted = extractEnergyOuter(maxReceive, true).toInt();
if (extracted == 0) {
// Extracting only a fraction // Extracting only a fraction
return 0; if (extracted == 0)
return 0
return extractEnergyOuter(Fraction(extracted), simulate).toInt()
} }
return extractEnergyOuter(new Fraction(extracted), simulate).toInt(); override fun getEnergyStored(): Int {
val level = batteryLevel
if (level < MatteryCapability.INT_MAX_VALUE)
return level.toInt()
return Int.MAX_VALUE
} }
@Override override fun getMaxEnergyStored(): Int {
default int getEnergyStored() { val level = maxBatteryLevel
Fraction level = getBatteryLevel();
if (level.compareTo(MatteryCapability.INT_MAX_VALUE) < 0) { if (level < MatteryCapability.INT_MAX_VALUE)
return level.toInt(); return level.toInt()
return Int.MAX_VALUE
} }
return Integer.MAX_VALUE; override fun canExtract(): Boolean {
return extractEnergyOuter(Fraction.ONE, true) > Fraction.ZERO
} }
@Override override fun canReceive(): Boolean {
default int getMaxEnergyStored() { return receiveEnergyOuter(Fraction.ONE, true) > Fraction.ZERO
Fraction level = getMaxBatteryLevel();
if (level.compareTo(MatteryCapability.INT_MAX_VALUE) < 0) {
return level.toInt();
}
return Integer.MAX_VALUE;
}
@Override
default boolean canExtract() {
return extractEnergyOuter(Fraction.ONE, true).compareTo(Fraction.ZERO) > 0;
}
@Override
default boolean canReceive() {
return receiveEnergyOuter(Fraction.ONE, true).compareTo(Fraction.ZERO) > 0;
} }
} }

View File

@ -1,144 +1,103 @@
package ru.dbotthepony.mc.otm.capability; package ru.dbotthepony.mc.otm.capability
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.common.util.INBTSerializable; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.core.Fraction.Companion.deserializeNBT
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
import javax.annotation.Nonnull; open class MatteryMachineEnergyStorage @JvmOverloads constructor(
import javax.annotation.ParametersAreNonnullByDefault; protected val listener: () -> Unit,
import java.math.BigDecimal; val type: MachineType,
override var maxBatteryLevel: Fraction = DEFAULT_MAX_CAPACITY,
protected var maxInput: Fraction = DEFAULT_MAX_RECEIVE,
protected var maxOutput: Fraction = maxInput
) : IMatteryEnergyStorage, INBTSerializable<CompoundTag> {
@JvmOverloads
constructor(
listener: BlockEntity,
type: MachineType,
maxBatteryLevel: Fraction = DEFAULT_MAX_CAPACITY,
maxInput: Fraction = DEFAULT_MAX_RECEIVE,
maxOutput: Fraction = maxInput) : this({listener.setChanged()}, type, maxBatteryLevel, maxInput, maxOutput)
@MethodsReturnNonnullByDefault enum class MachineType {
@ParametersAreNonnullByDefault WORKER, GENERATOR, CAPACITOR
public class MatteryMachineEnergyStorage implements IMatteryEnergyStorage, INBTSerializable<CompoundTag> {
public enum MachineType {
WORKER,
GENERATOR,
CAPACITOR,
} }
public static final Fraction DEFAULT_MAX_RECEIVE = new Fraction(200); override var batteryLevel = Fraction.ZERO
public static final Fraction DEFAULT_MAX_EXTRACT = new Fraction(200); protected set
public static final Fraction DEFAULT_MAX_CAPACITY = new Fraction(60000);
protected Fraction energy_stored = Fraction.ZERO; override fun extractEnergyOuter(howMuch: Fraction, simulate: Boolean): Fraction {
protected Fraction energy_stored_max; if (type == MachineType.WORKER)
protected Fraction max_input; return Fraction.ZERO
protected Fraction max_output;
protected final MachineType machine_type;
protected final BlockEntity listener;
public MatteryMachineEnergyStorage(BlockEntity listener, MachineType type, Fraction capacity) { return extractEnergyInner(howMuch, simulate)
this(listener, type, capacity, DEFAULT_MAX_RECEIVE, DEFAULT_MAX_EXTRACT);
} }
public MatteryMachineEnergyStorage(BlockEntity listener, MachineType type) { override fun extractEnergyInner(howMuch: Fraction, simulate: Boolean): Fraction {
this(listener, type, DEFAULT_MAX_CAPACITY); val new = batteryLevel.minus(howMuch.min(maxOutput)).moreThanZero()
val diff = batteryLevel.minus(new)
if (!simulate && batteryLevel != new) {
batteryLevel = new
listener()
} }
public MatteryMachineEnergyStorage(BlockEntity listener, MachineType type, Fraction capacity, Fraction maxReceive, Fraction maxExtract) { return diff
this.listener = listener;
energy_stored_max = capacity;
max_input = maxReceive;
max_output = maxExtract;
machine_type = type;
} }
@Nonnull override fun receiveEnergyOuter(howMuch: Fraction, simulate: Boolean): Fraction {
@Override if (type == MachineType.GENERATOR)
public Fraction extractEnergyOuter(Fraction howMuch, boolean simulate) { return Fraction.ZERO
if (machine_type == MachineType.WORKER) {
return Fraction.ZERO; return receiveEnergyInner(howMuch, simulate)
} }
return extractEnergyInner(howMuch, simulate); override fun receiveEnergyInner(howMuch: Fraction, simulate: Boolean): Fraction {
val new = batteryLevel.plus(howMuch.min(maxInput)).min(maxBatteryLevel)
val diff = new.minus(batteryLevel)
if (!simulate && batteryLevel != new) {
batteryLevel = new
listener()
} }
@Nonnull return diff
@Override
public Fraction extractEnergyInner(Fraction howMuch, boolean simulate) {
Fraction new_energy = energy_stored.minus(howMuch.min(max_output)).moreThanZero();
Fraction diff = energy_stored.minus(new_energy);
if (!simulate && !energy_stored.equalsCompact(new_energy)) {
energy_stored = new_energy;
listener.setChanged();
} }
return diff; override fun canExtract(): Boolean {
return type != MachineType.WORKER
} }
@Nonnull override fun canReceive(): Boolean {
@Override return type != MachineType.GENERATOR
public Fraction receiveEnergyOuter(Fraction howMuch, boolean simulate) {
if (machine_type == MachineType.GENERATOR) {
return Fraction.ZERO;
} }
return receiveEnergyInner(howMuch, simulate); override fun serializeNBT(): CompoundTag {
val tag = CompoundTag()
// TODO: А это вообще надо?
tag["energy_stored"] = batteryLevel.serializeNBT()
// tag["energy_stored_max"] = maxBatteryLevel.serializeNBT()
// tag["max_input"] = maxInput.serializeNBT()
// tag["max_output"] = maxOutput.serializeNBT()
return tag
} }
@Nonnull override fun deserializeNBT(nbt: CompoundTag) {
@Override nbt.ifHas("energy_stored") { batteryLevel = deserializeNBT(it) }
public Fraction receiveEnergyInner(Fraction howMuch, boolean simulate) { // nbt.ifHas("energy_stored_max") { maxBatteryLevel = deserializeNBT(it) }
Fraction new_energy = energy_stored.plus(howMuch.min(max_input)).min(energy_stored_max); // nbt.ifHas("max_input") { maxInput = deserializeNBT(it) }
Fraction diff = new_energy.minus(energy_stored); // nbt.ifHas("max_output") { maxOutput = deserializeNBT(it) }
if (!simulate && !energy_stored.equalsCompact(new_energy)) {
energy_stored = new_energy;
listener.setChanged();
} }
return diff; companion object {
} val DEFAULT_MAX_RECEIVE = Fraction(200)
val DEFAULT_MAX_EXTRACT = Fraction(200)
@Nonnull val DEFAULT_MAX_CAPACITY = Fraction(60000)
@Override
public Fraction getBatteryLevel() {
return energy_stored;
}
@Nonnull
@Override
public Fraction getMaxBatteryLevel() {
return energy_stored_max;
}
@Override
public boolean canExtract() {
return machine_type != MachineType.WORKER;
}
@Override
public boolean canReceive() {
return machine_type != MachineType.GENERATOR;
}
@Override
@Nonnull
public CompoundTag serializeNBT() {
CompoundTag tag = new CompoundTag();
tag.put("energy_stored", energy_stored.serializeNBT());
tag.put("energy_stored_max", energy_stored_max.serializeNBT());
tag.put("max_input", max_input.serializeNBT());
tag.put("max_output", max_output.serializeNBT());
return tag;
}
@Override
public void deserializeNBT(CompoundTag nbt) {
if (nbt.contains("energy_stored"))
energy_stored = Fraction.deserializeNBT(nbt.get("energy_stored"));
if (nbt.contains("energy_stored_max"))
energy_stored_max = Fraction.deserializeNBT(nbt.get("energy_stored_max"));
if (nbt.contains("max_input"))
max_input = Fraction.deserializeNBT(nbt.get("max_input"));
if (nbt.contains("max_output"))
max_output = Fraction.deserializeNBT(nbt.get("max_output"));
} }
} }

View File

@ -386,7 +386,7 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab
return ent return ent
} }
override fun getBatteryLevel(): Fraction { override val batteryLevel: Fraction get() {
if (!batteryItemStack.isEmpty) { if (!batteryItemStack.isEmpty) {
val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve() val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve()
@ -404,7 +404,7 @@ open class AndroidCapability(@JvmField protected val ent: LivingEntity) : ICapab
return battery return battery
} }
override fun getMaxBatteryLevel(): Fraction { override val maxBatteryLevel: Fraction get() {
if (batteryItemStack != ItemStack.EMPTY) { if (batteryItemStack != ItemStack.EMPTY) {
val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve() val resolver = batteryItemStack.getCapability(CapabilityEnergy.ENERGY).resolve()

View File

@ -1,63 +1,78 @@
package ru.dbotthepony.mc.otm.client.screen; package ru.dbotthepony.mc.otm.client.screen
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Inventory; import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.Dock; import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
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.Label; import ru.dbotthepony.mc.otm.menu.EnergyCounterMenu
import ru.dbotthepony.mc.otm.menu.EnergyCounterMenu; import ru.dbotthepony.mc.otm.menu.FormattingHelper
import ru.dbotthepony.mc.otm.menu.FormattingHelper;
import javax.annotation.Nullable; class EnergyCounterScreen(menu: EnergyCounterMenu, inventory: Inventory, title: Component) : MatteryScreen<EnergyCounterMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel {
val frame = super.makeMainFrame()!!
public class EnergyCounterScreen extends MatteryScreen<EnergyCounterMenu> { var label: Label = object : Label(this@EnergyCounterScreen, frame) {
public EnergyCounterScreen(EnergyCounterMenu menu, Inventory inventory, Component title) { override fun tick() {
super(menu, inventory, title); super.tick()
setText(
TranslatableComponent(
"otm.item.power.passed",
FormattingHelper.formatPower(menu.passed.value)
)
)
}
} }
@Nullable label.dock = Dock.TOP
@Override label.setDockMargin(4f, 0f, 0f, 0f)
protected FramePanel makeMainFrame() {
var frame = super.makeMainFrame();
var label = (Label) new Label(this, frame) { label = object : Label(this@EnergyCounterScreen, frame) {
@Override override fun tick() {
public void tick() { super.tick()
super.tick(); setText(
TranslatableComponent(
setText(new TranslatableComponent("otm.item.power.passed", FormattingHelper.formatPower(menu.passed.getValue()))); "otm.item.power.average",
FormattingHelper.formatPower(menu.average.value)
)
)
} }
};
label.setDock(Dock.TOP);
label.setDockMargin(4, 0, 0, 0);
label = new Label(this, frame) {
@Override
public void tick() {
super.tick();
setText(new TranslatableComponent("otm.item.power.average", FormattingHelper.formatPower(menu.average.getValue())));
} }
};
label.setDock(Dock.TOP); label.dock = Dock.TOP
label.setDockMargin(4, 0, 0, 0); label.setDockMargin(4f, 0f, 0f, 0f)
label = new Label(this, frame) { label = object : Label(this@EnergyCounterScreen, frame) {
@Override override fun tick() {
public void tick() { super.tick()
super.tick(); setText(
TranslatableComponent(
setText(new TranslatableComponent("otm.item.power.last_20_ticks", FormattingHelper.formatPower(menu.last_20_ticks.getValue()))); "otm.item.power.last_20_ticks",
FormattingHelper.formatPower(menu.last20Ticks.value)
)
)
}
} }
};
label.setDock(Dock.TOP); label.dock = Dock.TOP
label.setDockMargin(4, 0, 0, 0); label.setDockMargin(4f, 0f, 0f, 0f)
return frame; label = object : Label(this@EnergyCounterScreen, frame) {
override fun tick() {
super.tick()
setText(
TranslatableComponent(
"otm.item.power.last_tick",
FormattingHelper.formatPower(menu.lastTick.value)
)
)
}
}
label.dock = Dock.TOP
label.setDockMargin(4f, 0f, 0f, 0f)
return frame
} }
} }

View File

@ -66,15 +66,15 @@ class ItemBattery : Item {
return diff return diff
} }
override fun getMissingPower(): Fraction { override val missingPower: Fraction get() {
return if (isCreative) MatteryCapability.LONG_MAX_VALUE else super.getMissingPower() return if (isCreative) MatteryCapability.LONG_MAX_VALUE else super.missingPower
} }
override fun getBatteryLevel(): Fraction { override val batteryLevel: Fraction get() {
return if (isCreative) MatteryCapability.LONG_MAX_VALUE else energy() return if (isCreative) MatteryCapability.LONG_MAX_VALUE else energy()
} }
override fun getMaxBatteryLevel(): Fraction { override val maxBatteryLevel: Fraction get() {
return storage return storage
} }

View File

@ -29,7 +29,7 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t
} }
val progress = ProgressGaugeWidget(this) { 1f - tile!!.workingTicks.toFloat() / tile.workingTicksTotal } val progress = ProgressGaugeWidget(this) { 1f - tile!!.workingTicks.toFloat() / tile.workingTicksTotal }
val energy = LevelGaugeWidget(this, tile) val energy = LevelGaugeWidget(this, tile?.energy)
val burnTime = IntDataContainer() val burnTime = IntDataContainer()
init { init {

View File

@ -1,59 +1,52 @@
package ru.dbotthepony.mc.otm.menu; package ru.dbotthepony.mc.otm.menu
import net.minecraft.world.entity.player.Inventory; import kotlin.jvm.JvmOverloads
import net.minecraft.world.inventory.MenuType; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.level.block.entity.BlockEntity; import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.block.entity.BlockEntityEnergyCounter
import ru.dbotthepony.mc.otm.block.entity.BlockEntityEnergyCounter; import ru.dbotthepony.mc.otm.menu.data.FractionDataContainer
import ru.dbotthepony.mc.otm.menu.data.BigDecimalDataContainer;
import ru.dbotthepony.mc.otm.menu.data.FractionDataContainer;
import javax.annotation.Nullable; class EnergyCounterMenu @JvmOverloads constructor(
p_38852_: Int,
inventory: Inventory,
tile: BlockEntityEnergyCounter? = null
) : MatteryMenu(Registry.Menus.ENERGY_COUNTER, p_38852_, inventory, tile) {
@JvmField val passed = FractionDataContainer()
@JvmField val average = FractionDataContainer()
@JvmField val last20Ticks = FractionDataContainer()
@JvmField val lastTick = FractionDataContainer()
public class EnergyCounterMenu extends MatteryMenu {
public final FractionDataContainer passed = new FractionDataContainer();
public final FractionDataContainer average = new FractionDataContainer();
public final FractionDataContainer last_20_ticks = new FractionDataContainer();
// TODO: Graph and proper networking for it // TODO: Graph and proper networking for it
private int ticks_passed = 0; private var ticksPassed = 0
public EnergyCounterMenu(int p_38852_, Inventory inventory) { init {
this(p_38852_, inventory, null); addDataSlots(passed)
addDataSlots(average)
addDataSlots(last20Ticks)
addDataSlots(lastTick)
} }
public EnergyCounterMenu(int p_38852_, Inventory inventory, BlockEntityEnergyCounter tile) { override fun broadcastChanges() {
super(Registry.Menus.ENERGY_COUNTER, p_38852_, inventory, tile); if (tile is BlockEntityEnergyCounter) {
passed.value = tile.passed
average.value = tile.calcAverage(20)
lastTick.value = tile.lastTick
addDataSlots(passed); if (ticksPassed == 0) {
addDataSlots(average); last20Ticks.value = tile.sumHistory(20)
addDataSlots(last_20_ticks);
} }
@Override ticksPassed = (ticksPassed + 1) % 20
public void broadcastChanges() {
if (tile != null) {
BlockEntityEnergyCounter tile = (BlockEntityEnergyCounter) this.tile;
passed.setValue(tile.getPassed());
average.setValue(tile.calcAverage(20));
if (ticks_passed == 0) {
last_20_ticks.setValue(tile.sumHistory(20));
} }
ticks_passed = (ticks_passed + 1) % 20; super.broadcastChanges()
} }
super.broadcastChanges(); override fun getWorkingSlotStart(): Int {
return 0
} }
@Override override fun getWorkingSlotEnd(): Int {
protected int getWorkingSlotStart() { return 0
return 0;
}
@Override
protected int getWorkingSlotEnd() {
return 0;
} }
} }

View File

@ -23,8 +23,8 @@ class LevelGaugeWidget(menu: MatteryMenu) : AbstractWidget(menu) {
) : this(menu) { ) : this(menu) {
if (power == null) return if (power == null) return
this.level = power::getBatteryLevel this.level = power::batteryLevel
this.maxLevel = power::getMaxBatteryLevel this.maxLevel = power::maxBatteryLevel
} }
constructor( constructor(

View File

@ -40,6 +40,7 @@
"otm.item.power.passed": "Passed energy: %s", "otm.item.power.passed": "Passed energy: %s",
"otm.item.power.average": "Average throughput: %s/t", "otm.item.power.average": "Average throughput: %s/t",
"otm.item.power.last_20_ticks": "Last second: %s", "otm.item.power.last_20_ticks": "Last second: %s",
"otm.item.power.last_tick": "Last tick: %s",
"otm.item.power.normal.storage": "Stored energy: %s / %s", "otm.item.power.normal.storage": "Stored energy: %s / %s",
"otm.item.power.normal.throughput": "Max I/O %s / %s", "otm.item.power.normal.throughput": "Max I/O %s / %s",