Move to kotlin and streamline more base stuff

This commit is contained in:
DBotThePony 2022-01-04 23:28:00 +07:00
parent 58598f7e3f
commit f23be0c213
Signed by: DBot
GPG Key ID: DCC23B5715498507
25 changed files with 715 additions and 923 deletions

View File

@ -35,13 +35,13 @@ public class BlockAndroidStation extends BlockMattery implements EntityBlock {
} }
@Override @Override
public InteractionResult use(BlockState p_60503_, Level level, BlockPos pos, Player ply, InteractionHand p_60507_, BlockHitResult p_60508_) { public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player ply, InteractionHand hand, BlockHitResult blockHitResult) {
LazyOptional<IAndroidCapability> cap = ply.getCapability(MatteryCapability.ANDROID); LazyOptional<IAndroidCapability> cap = ply.getCapability(MatteryCapability.ANDROID);
if (cap.resolve().isEmpty() || !cap.resolve().get().isAndroid()) if (cap.resolve().isEmpty() || !cap.resolve().get().isAndroid())
return InteractionResult.FAIL; return InteractionResult.FAIL;
return super.use(p_60503_, level, pos, ply, p_60507_, p_60508_); return super.use(blockState, level, blockPos, ply, hand, blockHitResult);
} }
@Override @Override

View File

@ -1,48 +0,0 @@
package ru.dbotthepony.mc.otm.block;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.Block;
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 org.apache.commons.lang3.ArrayUtils;
import ru.dbotthepony.mc.otm.OverdriveThatMatters;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.Arrays;
@MethodsReturnNonnullByDefault
@ParametersAreNonnullByDefault
public abstract class BlockMatteryRotatable extends BlockMattery {
public static final EnumProperty<Direction> FACING = EnumProperty.create(
"facing",
Direction.class,
Direction.SOUTH,
Direction.WEST,
Direction.NORTH,
Direction.EAST);
public BlockMatteryRotatable() {
super();
registerDefaultState(this.getStateDefinition().any().setValue(FACING, Direction.SOUTH));
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING);
}
@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(FACING, faceToPlayer(context) ? context.getHorizontalDirection().getOpposite() : context.getHorizontalDirection());
}
public boolean faceToPlayer(BlockPlaceContext context) {
return true;
}
}

View File

@ -1,59 +0,0 @@
package ru.dbotthepony.mc.otm.container;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.common.capabilities.Capability;
import java.util.Iterator;
import java.util.Optional;
import java.util.function.Consumer;
public class ContainerIteratorCapability<T> implements java.util.Iterator<T>, Iterable<T> {
private final Container container;
private final Capability<T> cap;
private int index = 0;
private T next_stack;
public ContainerIteratorCapability(Container container, Capability<T> cap) {
this.container = container;
this.cap = cap;
}
@Override
public boolean hasNext() {
if (index >= container.getContainerSize() && next_stack == null)
return false;
if (next_stack == null) {
while (next_stack == null && index < container.getContainerSize()) {
ItemStack get = container.getItem(index);
if (!get.isEmpty()) {
get.getCapability(cap).ifPresent(t -> next_stack = t);
}
index++;
}
}
return next_stack != null;
}
@Override
public T next() {
T _next_stack = next_stack;
next_stack = null;
return _next_stack;
}
@Override
public Iterator<T> iterator() {
return this;
}
public void consume(Consumer<T> consumer) {
for (T t : this) {
consumer.accept(t);
}
}
}

View File

@ -1,55 +0,0 @@
package ru.dbotthepony.mc.otm.container;
import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack;
import java.util.Iterator;
import java.util.function.Consumer;
public class ContainerIteratorItemStack implements java.util.Iterator<ItemStack>, Iterable<ItemStack> {
private final Container container;
private int index = 0;
private ItemStack next_stack;
public ContainerIteratorItemStack(Container container) {
this.container = container;
}
@Override
public boolean hasNext() {
if (index >= container.getContainerSize() && next_stack == null)
return false;
if (next_stack == null) {
while (next_stack == null && index < container.getContainerSize()) {
ItemStack get = container.getItem(index);
if (!get.isEmpty()) {
next_stack = get;
}
index++;
}
}
return next_stack != null;
}
@Override
public ItemStack next() {
ItemStack _next_stack = next_stack;
next_stack = null;
return _next_stack;
}
@Override
public Iterator<ItemStack> iterator() {
return this;
}
public void consume(Consumer<ItemStack> consumer) {
for (ItemStack t : this) {
consumer.accept(t);
}
}
}

View File

@ -1,10 +0,0 @@
package ru.dbotthepony.mc.otm.container;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull;
@FunctionalInterface
public interface MatteryContainerExtractValidator {
boolean apply(int slot, int amount, @Nonnull ItemStack stack);
}

View File

@ -1,10 +0,0 @@
package ru.dbotthepony.mc.otm.container;
import net.minecraft.world.item.ItemStack;
import javax.annotation.Nonnull;
@FunctionalInterface
public interface MatteryContainerInsertValidator {
boolean apply(int slot, @Nonnull ItemStack stack);
}

View File

@ -51,7 +51,7 @@ inline fun CompoundTag.ifHas(s: String, type: Byte, consumer: (Tag) -> Unit) {
inline fun <reified 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) {
consumer(tag as T) consumer(tag as T)
} }
} }

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.block package ru.dbotthepony.mc.otm.block
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
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
@ -36,6 +37,10 @@ class BlockDriveViewer : BlockMatteryRotatable(), EntityBlock {
builder.add(DRIVE_PRESENT) builder.add(DRIVE_PRESENT)
} }
override fun getStateForPlacement(context: BlockPlaceContext): BlockState {
return super.getStateForPlacement(context)!!.setValue(DRIVE_PRESENT, false)
}
companion object { companion object {
val DRIVE_PRESENT = BooleanProperty.create("drive") val DRIVE_PRESENT = BooleanProperty.create("drive")
} }

View File

@ -1,67 +1,121 @@
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.world.InteractionHand; import net.minecraft.world.InteractionHand
import net.minecraft.world.InteractionResult; import net.minecraft.world.InteractionResult
import net.minecraft.world.MenuProvider; import net.minecraft.world.MenuProvider
import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level; import net.minecraft.world.item.context.BlockPlaceContext
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.Level
import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.Block
import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.EntityBlock
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.material.Material; import net.minecraft.world.level.block.state.StateDefinition
import net.minecraft.world.level.material.MaterialColor; import net.minecraft.world.level.block.state.properties.EnumProperty
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.level.material.Material
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMattery; import net.minecraft.world.level.material.MaterialColor
import net.minecraft.world.phys.BlockHitResult
import ru.dbotthepony.mc.otm.block.entity.BlockEntityMattery
import javax.annotation.Nullable; abstract class BlockMattery @JvmOverloads constructor(
import javax.annotation.ParametersAreNonnullByDefault; properties: Properties = DEFAULT_PROPERTIES
) : Block(properties) {
override fun setPlacedBy(
level: Level,
blockPos: BlockPos,
blockState: BlockState,
entity: LivingEntity?,
itemStack: ItemStack
) {
if (this is EntityBlock && itemStack.hasCustomHoverName() && !level.isClientSide) {
val tile = level.getBlockEntity(blockPos)
@MethodsReturnNonnullByDefault if (tile is BlockEntityMattery)
@ParametersAreNonnullByDefault tile.customDisplayName = itemStack.displayName
public abstract class BlockMattery extends Block {
public BlockMattery(Properties p_49795_) {
super(p_49795_);
}
public BlockMattery() {
this(BlockBehaviour.Properties.of(Material.STONE, MaterialColor.METAL).requiresCorrectToolForDrops().strength(1.5F, 25.0F));
}
@Override
public void setPlacedBy(Level p_49847_, BlockPos p_49848_, BlockState p_49849_, @Nullable LivingEntity p_49850_, ItemStack p_49851_) {
if (this instanceof EntityBlock && p_49851_.hasCustomHoverName() && !p_49847_.isClientSide && p_49847_.getBlockEntity(p_49848_) instanceof BlockEntityMattery tile) {
tile.setDisplayName(p_49851_.getDisplayName());
} }
super.setPlacedBy(p_49847_, p_49848_, p_49849_, p_49850_, p_49851_); super.setPlacedBy(level, blockPos, blockState, entity, itemStack)
} }
@Override override fun use(
@SuppressWarnings("deprecation") blockState: BlockState,
public InteractionResult use(BlockState p_60503_, Level level, BlockPos pos, Player ply, InteractionHand p_60507_, BlockHitResult p_60508_) { level: Level,
if (this instanceof EntityBlock && !level.isClientSide && level.getBlockEntity(pos) instanceof MenuProvider tile) { blockPos: BlockPos,
ply.openMenu(tile); ply: Player,
return InteractionResult.CONSUME; hand: InteractionHand,
blockHitResult: BlockHitResult
): InteractionResult {
if (this is EntityBlock && !level.isClientSide) {
val tile = level.getBlockEntity(blockPos)
if (tile is MenuProvider) {
ply.openMenu(tile)
return InteractionResult.CONSUME
}
} }
if (this instanceof EntityBlock && level.isClientSide) if (this is EntityBlock && level.isClientSide)
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS
return super.use(p_60503_, level, pos, ply, p_60507_, p_60508_); return super.use(blockState, level, blockPos, ply, hand, blockHitResult)
} }
@Override override fun neighborChanged(
@SuppressWarnings("deprecation") state: BlockState,
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block sender, BlockPos sender_pos, boolean flag) { level: Level,
super.neighborChanged(state, level, pos, sender, sender_pos, flag); pos: BlockPos,
sender: Block,
sender_pos: BlockPos,
flag: Boolean
) {
super.neighborChanged(state, level, pos, sender, sender_pos, flag)
if (this instanceof EntityBlock && !level.isClientSide && level.getBlockEntity(pos) instanceof BlockEntityMattery tile) { if (this is EntityBlock && !level.isClientSide) {
tile.setRedstoneSignal(level.getBestNeighborSignal(pos)); val tile = level.getBlockEntity(pos)
if (tile is BlockEntityMattery)
tile.redstoneSignal = level.getBestNeighborSignal(pos)
} }
} }
companion object {
@JvmField
val DEFAULT_PROPERTIES: Properties = Properties.of(Material.STONE, MaterialColor.METAL).requiresCorrectToolForDrops().strength(1.5f, 25.0f)
}
}
abstract class BlockMatteryRotatable @JvmOverloads constructor(properties: Properties = DEFAULT_PROPERTIES) : BlockMattery(properties) {
init {
registerDefaultState(getStateDefinition().any().setValue(FACING, Direction.SOUTH))
}
override fun createBlockStateDefinition(builder: StateDefinition.Builder<Block, BlockState>) {
builder.add(FACING)
}
override fun getStateForPlacement(context: BlockPlaceContext): BlockState? {
return defaultBlockState().setValue(
FACING,
if (faceToPlayer(context)) context.horizontalDirection.opposite else context.horizontalDirection
)
}
open fun faceToPlayer(context: BlockPlaceContext): Boolean {
return true
}
companion object {
@JvmField
val FACING = EnumProperty.create(
"facing",
Direction::class.java,
Direction.SOUTH,
Direction.WEST,
Direction.NORTH,
Direction.EAST
)
}
} }

View File

@ -19,7 +19,6 @@ import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.energy.CapabilityEnergy import net.minecraftforge.energy.CapabilityEnergy
import net.minecraftforge.energy.IEnergyStorage import net.minecraftforge.energy.IEnergyStorage
import net.minecraftforge.items.CapabilityItemHandler import net.minecraftforge.items.CapabilityItemHandler
import net.minecraftforge.items.IItemHandler
import ru.dbotthepony.mc.otm.Registry import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.BlockBatteryBank import ru.dbotthepony.mc.otm.block.BlockBatteryBank
import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable
@ -40,8 +39,8 @@ import javax.annotation.ParametersAreNonnullByDefault
class BlockEntityBatteryBank(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntityMattery(Registry.BlockEntities.BATTERY_BANK, p_155229_, p_155230_) { class BlockEntityBatteryBank(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntityMattery(Registry.BlockEntities.BATTERY_BANK, p_155229_, p_155230_) {
// 6 на 2 // 6 на 2
val container: MatteryContainer = object : MatteryContainer(this::setChanged, 6 * 2) { val container: MatteryContainer = object : MatteryContainer(this::setChanged, 6 * 2) {
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new_state, old_state) super.setChanged(slot, new, old)
val level = level val level = level
if (level != null) { if (level != null) {

View File

@ -31,14 +31,14 @@ class BlockEntityDriveRack(p_155229_: BlockPos, p_155230_: BlockState) :
@JvmField @JvmField
val drives: MatteryContainer = object : MatteryContainer(this::setChanged, 4) { val drives: MatteryContainer = object : MatteryContainer(this::setChanged, 4) {
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new_state, old_state) super.setChanged(slot, new, old)
old_state.getCapability(MatteryCapability.DRIVE).ifPresent { old.getCapability(MatteryCapability.DRIVE).ifPresent {
cell.computeIfAbsent(it.storageIdentity()) {c -> PoweredVirtualComponent(c, energy)}.remove(it) cell.computeIfAbsent(it.storageIdentity()) {c -> PoweredVirtualComponent(c, energy)}.remove(it)
} }
new_state.getCapability(MatteryCapability.DRIVE).ifPresent { new.getCapability(MatteryCapability.DRIVE).ifPresent {
cell.computeIfAbsent(it.storageIdentity()) {c -> PoweredVirtualComponent(c, energy)}.add(it) cell.computeIfAbsent(it.storageIdentity()) {c -> PoweredVirtualComponent(c, energy)}.add(it)
} }
} }

View File

@ -9,7 +9,6 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
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.state.BlockState import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.OverdriveThatMatters
@ -54,8 +53,8 @@ class BlockEntityDriveViewer(p_155229_: BlockPos, p_155230_: BlockState) : Block
@JvmField @JvmField
val drive_slot: MatteryContainer = object : MatteryContainer(this::setChanged, 1) { val drive_slot: MatteryContainer = object : MatteryContainer(this::setChanged, 1) {
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new_state, old_state) super.setChanged(slot, new, old)
val level = level val level = level
if (level != null) { if (level != null) {
@ -63,7 +62,7 @@ class BlockEntityDriveViewer(p_155229_: BlockPos, p_155230_: BlockState) : Block
if (!isRemoved) { if (!isRemoved) {
var state = blockState var state = blockState
if (new_state.getCapability(MatteryCapability.DRIVE).isPresent) { if (new.getCapability(MatteryCapability.DRIVE).isPresent) {
state = state.setValue(BlockDriveViewer.DRIVE_PRESENT, true) state = state.setValue(BlockDriveViewer.DRIVE_PRESENT, true)
} else { } else {
state = state.setValue(BlockDriveViewer.DRIVE_PRESENT, false) state = state.setValue(BlockDriveViewer.DRIVE_PRESENT, false)

View File

@ -2,35 +2,36 @@ package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.world.level.block.state.BlockState import net.minecraft.nbt.CompoundTag
import ru.dbotthepony.mc.otm.container.MatteryContainer import net.minecraft.network.chat.Component
import net.minecraft.world.item.ItemStack import net.minecraft.network.chat.TranslatableComponent
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler import net.minecraft.server.level.ServerLevel
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler.MatterDirection
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu import net.minecraft.world.item.ItemStack
import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import net.minecraft.network.chat.TranslatableComponent
import net.minecraft.server.level.ServerLevel
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.state.BlockState
import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.CapabilityItemHandler
import ru.dbotthepony.mc.otm.Registry import ru.dbotthepony.mc.otm.Registry
import ru.dbotthepony.mc.otm.block.BlockMatterBottler import ru.dbotthepony.mc.otm.block.BlockMatterBottler
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler
import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler.MatterDirection
import ru.dbotthepony.mc.otm.capability.matter.MatterHandlerCapability
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.container.MatteryContainerHandler
import ru.dbotthepony.mc.otm.core.Fraction import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.ifHas import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu
import ru.dbotthepony.mc.otm.set import ru.dbotthepony.mc.otm.set
class BlockEntityMatterBottler(p_155229_: BlockPos, p_155230_: BlockState) : class BlockEntityMatterBottler(p_155229_: BlockPos, p_155230_: BlockState) :
@ -86,8 +87,8 @@ class BlockEntityMatterBottler(p_155229_: BlockPos, p_155230_: BlockState) :
return 1 return 1
} }
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new_state, old_state) super.setChanged(slot, new, old)
updateBlockState() updateBlockState()
} }
} }

View File

@ -123,8 +123,8 @@ class BlockEntityMatterCapacitorBank(p_155229_: BlockPos, p_155230_: BlockState)
@JvmField @JvmField
val matterContainer = object : MatteryContainer(this::setChangedLight, 6 * 2) { val matterContainer = object : MatteryContainer(this::setChangedLight, 6 * 2) {
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new_state, old_state) super.setChanged(slot, new, old)
val level = level val level = level
if (level != null) { if (level != null) {

View File

@ -75,7 +75,7 @@ class BlockEntityMatterDecomposer(pos: BlockPos, state: BlockState)
{ slot: Int, amount: Int, stack: ItemStack? -> slot == 1 }) { slot: Int, amount: Int, stack: ItemStack? -> slot == 1 })
} }
override fun getDefaultDisplayName(): Component? { override fun getDefaultDisplayName(): Component {
return MACHINE_NAME return MACHINE_NAME
} }

View File

@ -1,182 +1,169 @@
package ru.dbotthepony.mc.otm.block.entity; package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos
import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.core.Direction; import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.nbt.ByteTag; import net.minecraft.world.MenuProvider
import net.minecraft.nbt.CompoundTag; import java.lang.Runnable
import net.minecraft.nbt.StringTag; import ru.dbotthepony.mc.otm.OverdriveThatMatters
import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel
import net.minecraft.server.level.ServerLevel; import net.minecraft.client.multiplayer.ClientLevel
import net.minecraft.world.MenuProvider; import net.minecraft.core.Direction
import net.minecraft.world.entity.player.Inventory; import net.minecraft.core.SectionPos
import net.minecraft.world.entity.player.Player; import net.minecraftforge.common.util.LazyOptional
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraft.world.level.Level; import java.lang.ref.WeakReference
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraftforge.common.capabilities.Capability; import net.minecraft.nbt.CompoundTag
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraft.nbt.StringTag
import net.minecraftforge.common.util.LazyOptional; import net.minecraft.nbt.ByteTag
import ru.dbotthepony.mc.otm.OverdriveThatMatters; import net.minecraft.network.chat.Component
import net.minecraft.world.level.Level
import net.minecraft.world.level.chunk.ChunkStatus
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
import java.util.function.Consumer
import javax.annotation.Nullable; abstract class BlockEntityMattery(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(p_155228_, p_155229_, p_155230_), MenuProvider {
import javax.annotation.ParametersAreNonnullByDefault; var customDisplayName: Component? = null
import java.lang.ref.WeakReference; var redstoneSignal = 0
import java.util.function.Consumer; set(level) {
val old = isBlockedByRedstone
field = level
val state = isBlockedByRedstone
@MethodsReturnNonnullByDefault if (old != state) {
@ParametersAreNonnullByDefault redstoneStatusUpdated(state, old)
@SuppressWarnings("unused")
public abstract class BlockEntityMattery extends BlockEntity implements MenuProvider {
protected Component display_name;
protected RedstoneSetting redstone_setting = RedstoneSetting.LOW;
protected int redstone_signal = 0;
public BlockEntityMattery(BlockEntityType<?> p_155228_, BlockPos p_155229_, BlockState p_155230_) {
super(p_155228_, p_155229_, p_155230_);
}
public void setDisplayName(Component text) {
display_name = text;
}
abstract protected Component getDefaultDisplayName();
protected void tickOnce(Runnable func) {
if (level != null)
OverdriveThatMatters.tickOnce(level, func);
}
protected void tickOnceServer(Runnable func) {
if (level instanceof ServerLevel level)
OverdriveThatMatters.tickOnce(level, func);
}
protected void tickOnceClient(Runnable func) {
if (level instanceof ClientLevel level)
OverdriveThatMatters.tickOnce(level, func);
}
protected void tickOnce(Consumer<Level> func) {
if (level != null)
OverdriveThatMatters.tickOnceSelf(level, func);
}
protected void tickOnceServer(Consumer<Level> func) {
if (level instanceof ServerLevel level)
OverdriveThatMatters.tickOnceSelf(level, func);
}
protected void tickOnceClient(Consumer<Level> func) {
if (level instanceof ClientLevel level)
OverdriveThatMatters.tickOnceSelf(level, func);
}
protected <T> LazyOptional<T> getAndBind(LazyOptional<T> old, @Nullable ICapabilityProvider provider, Capability<T> cap, @Nullable Direction side, Runnable invalidate) {
final var get = provider != null ? provider.getCapability(cap, side) : LazyOptional.empty();
if (old != get) {
if (get.isPresent()) {
final var ref = new WeakReference<>(invalidate);
get.addListener((l) -> {
final var self = ref.get();
if (self != null) {
self.run();
}
});
}
return get.cast();
}
return get.cast();
}
@Override
public Component getDisplayName() {
return display_name != null ? display_name : getDefaultDisplayName();
}
@Nullable
@Override
abstract public AbstractContainerMenu createMenu(int containerID, Inventory inventory, Player ply);
protected void redstoneStatusUpdated(boolean new_blocked, boolean old_blocked) {
}
public void setRedstoneSignal(int level) {
final var old = isBlockedByRedstone();
redstone_signal = level;
final var state = isBlockedByRedstone();
if (old != state) {
redstoneStatusUpdated(state, old);
}
}
public void setRedstoneSetting(RedstoneSetting setting) {
final var old = isBlockedByRedstone();
redstone_setting = setting;
final var state = isBlockedByRedstone();
if (old != state) {
redstoneStatusUpdated(state, old);
}
}
public RedstoneSetting getRedstoneSetting() {
return redstone_setting;
}
protected boolean isBlockedByRedstone() {
switch (redstone_setting) {
case LOW -> {
return redstone_signal > 0;
}
case HIGH -> {
return redstone_signal <= 0;
} }
} }
return false; var redstoneSetting: RedstoneSetting = RedstoneSetting.LOW
set(setting) {
val old = isBlockedByRedstone
field = setting
val state = isBlockedByRedstone
if (old != state) {
redstoneStatusUpdated(state, old)
}
}
val isBlockedByRedstone: Boolean
get() {
when (redstoneSetting) {
RedstoneSetting.LOW -> {
return redstoneSignal > 0
}
RedstoneSetting.HIGH -> {
return redstoneSignal <= 0
}
RedstoneSetting.IGNORED -> {
return false
}
}
}
protected abstract fun getDefaultDisplayName(): Component
abstract override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu?
protected fun tickOnce(func: Runnable) {
val level = level
if (level != null) OverdriveThatMatters.tickOnce(level, func)
} }
@Override protected fun tickOnceServer(func: Runnable) {
public void saveAdditional(CompoundTag nbt) { val level = level
super.saveAdditional(nbt); if (level is ServerLevel) OverdriveThatMatters.tickOnce(level, func)
if (display_name != null)
nbt.putString("Name", Component.Serializer.toJson(display_name));
nbt.putByte("redstone", (byte) redstone_setting.ordinal());
nbt.putByte("redstone_signal", (byte) redstone_signal);
} }
public void load(CompoundTag nbt) { protected fun tickOnceClient(func: Runnable) {
super.load(nbt); val level = level
if (level is ClientLevel) OverdriveThatMatters.tickOnce(level, func)
}
if (nbt.get("Name") instanceof StringTag tag) protected fun tickOnce(func: Consumer<Level>) {
display_name = Component.Serializer.fromJson(tag.getAsString()); val level = level
if (level != null) OverdriveThatMatters.tickOnceSelf(level, func)
}
if (nbt.get("redstone") instanceof ByteTag tag) protected fun tickOnceServer(func: Consumer<Level>) {
redstone_setting = RedstoneSetting.get(tag.getAsByte()); val level = level
if (level is ServerLevel) OverdriveThatMatters.tickOnceSelf(level, func)
}
if (nbt.get("redstone_signal") instanceof ByteTag tag) protected fun tickOnceClient(func: Consumer<Level>) {
redstone_signal = tag.getAsByte(); val level = level
if (level is ClientLevel) OverdriveThatMatters.tickOnceSelf(level, func)
}
protected fun <T> getAndBind(
old: LazyOptional<T>,
provider: ICapabilityProvider?,
cap: Capability<T>,
side: Direction,
invalidate: Runnable
): LazyOptional<T> {
val get = provider?.getCapability(cap, side) ?: LazyOptional.empty()
if (old !== get) {
if (get.isPresent) {
val ref = WeakReference(invalidate)
get.addListener {
ref.get()?.run()
}
}
return get.cast()
}
return get.cast()
}
override fun getDisplayName(): Component {
return customDisplayName ?: getDefaultDisplayName()
}
protected open fun redstoneStatusUpdated(new_blocked: Boolean, old_blocked: Boolean) {}
override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt)
val customDisplayName = customDisplayName
if (customDisplayName != null)
nbt.putString("Name", Component.Serializer.toJson(customDisplayName))
nbt["redstone"] = redstoneSetting.ordinal.toByte()
nbt["redstone_signal"] = redstoneSignal.toByte()
}
override fun load(nbt: CompoundTag) {
super.load(nbt)
nbt.ifHas("Name", StringTag::class.java) {
customDisplayName = Component.Serializer.fromJson(it.asString)
}
nbt.ifHas("redstone", ByteTag::class.java) {
redstoneSetting = RedstoneSetting.get(it.asInt)
}
nbt.ifHas("redstone_signal", ByteTag::class.java) {
redstoneSignal = it.asInt
}
} }
// Just to mark chunk unsaved // Just to mark chunk unsaved
public void setChangedLight() { open fun setChangedLight() {
if (level != null) { val level = level
if (level.hasChunkAt(getBlockPos())) if (level is ServerLevel) {
level.getChunkAt(getBlockPos()).setUnsaved(true); level.chunkSource.getChunkNow(
SectionPos.blockToSectionCoord(blockPos.x),
SectionPos.blockToSectionCoord(blockPos.z))?.isUnsaved = true
} }
} }
} }

View File

@ -1,132 +1,80 @@
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.CompoundTag
import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.block.entity.BlockEntityType; 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 ru.dbotthepony.mc.otm.capability.IMatteryEnergyStorage
import net.minecraftforge.energy.CapabilityEnergy; import ru.dbotthepony.mc.otm.capability.MatteryCapability
import net.minecraftforge.energy.IEnergyStorage; import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
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.container.MatteryContainer
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage; import ru.dbotthepony.mc.otm.core.Fraction
import ru.dbotthepony.mc.otm.container.MatteryContainer; import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.core.Fraction; import ru.dbotthepony.mc.otm.set
import javax.annotation.Nonnull; abstract class BlockEntityMatteryPowered(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : BlockEntityMattery(p_155228_, p_155229_, p_155230_) {
import javax.annotation.Nullable; protected lateinit var energy: MatteryMachineEnergyStorage
import javax.annotation.ParametersAreNonnullByDefault; private var resolverEnergy = LazyOptional.of { energy }
import java.math.BigDecimal; private var valid = true
import java.util.Optional; val batteryContainer = MatteryContainer(this::setChangedLight, 1)
@MethodsReturnNonnullByDefault protected fun batteryChargeLoop() {
@ParametersAreNonnullByDefault var demand = energy.receiveEnergyOuter(energy.missingPower, true)
abstract public class BlockEntityMatteryPowered extends BlockEntityMattery { if (demand.isZero()) return
protected MatteryMachineEnergyStorage energy = null;
private LazyOptional<MatteryMachineEnergyStorage> energy_resolver = LazyOptional.of(() -> energy);
private boolean valid = true;
public MatteryContainer battery_container = new MatteryContainer(this::setChanged, 1); for (stack in batteryContainer) {
if (!stack.isEmpty) {
protected void batteryChargeLoop() { stack.getCapability(CapabilityEnergy.ENERGY).ifPresent {
if (energy == null) if (it is IMatteryEnergyStorage) {
return; val diff = it.extractEnergyOuter(demand, false)
energy.receiveEnergyInner(diff, false)
if (energy.getMissingPower().compareTo(Fraction.ZERO) <= 0) demand -= diff
return; } else {
val diff = it.extractEnergy(demand, false)
var demand = energy.getMissingPower(); energy.receiveEnergyInner(diff, false)
demand -= diff
if (demand.compareTo(Fraction.ZERO) == 0)
return;
demand = demand.min(energy.receiveEnergyOuter(demand, true));
for (int i = 0; i < battery_container.getContainerSize() && demand.compareTo(Fraction.ZERO) > 0; i++) {
final var stack = battery_container.getItem(i);
if (!stack.isEmpty()) {
final var mattery_storage = stack.getCapability(MatteryCapability.ENERGY).resolve();
if (mattery_storage.isPresent()) {
final var drain = mattery_storage.get().extractEnergyOuter(demand, true);
if (drain.compareTo(Fraction.ZERO) != 0) {
final var receive = energy.receiveEnergyOuter(drain, true);
mattery_storage.get().extractEnergyOuter(receive, false);
energy.receiveEnergyOuter(receive, false);
demand = demand.minus(receive);
}
} else {
final var storage = stack.getCapability(CapabilityEnergy.ENERGY).resolve();
if (storage.isPresent()) {
final var drain = MatteryCapability.drainFE(storage.get(), demand, true);
if (drain.compareTo(Fraction.ZERO) != 0) {
final var receive = energy.receiveEnergyOuter(drain, true);
MatteryCapability.drainFE(storage.get(), receive, false);
energy.receiveEnergyOuter(receive, false);
demand = demand.minus(receive);
}
} }
} }
if (demand <= Fraction.ZERO)
return
} }
} }
} }
public BlockEntityMatteryPowered(BlockEntityType<?> p_155228_, BlockPos p_155229_, BlockState p_155230_) { override fun invalidateCaps() {
super(p_155228_, p_155229_, p_155230_); super.invalidateCaps()
valid = false
resolverEnergy.invalidate()
} }
@Override override fun reviveCaps() {
public void invalidateCaps() { super.reviveCaps()
super.invalidateCaps(); valid = true
valid = false; resolverEnergy = LazyOptional.of { energy }
energy_resolver.invalidate();
} }
@Override override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
public void reviveCaps() { if (valid && (cap === MatteryCapability.ENERGY || cap === CapabilityEnergy.ENERGY))
super.reviveCaps(); return resolverEnergy.cast()
valid = true;
energy_resolver = LazyOptional.of(() -> energy); return super.getCapability(cap, side)
} }
@Nonnull public override fun saveAdditional(nbt: CompoundTag) {
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) { super.saveAdditional(nbt)
if (valid && (cap == MatteryCapability.ENERGY || cap == CapabilityEnergy.ENERGY) && energy != null) { nbt["energy_cap"] = energy.serializeNBT()
return energy_resolver.cast(); nbt["battery_container"] = batteryContainer.serializeNBT()
}
return super.getCapability(cap, side);
} }
@Override override fun load(nbt: CompoundTag) {
public void saveAdditional(CompoundTag nbt) { nbt.ifHas("energy_cap", CompoundTag::class.java, energy::deserializeNBT)
super.saveAdditional(nbt); nbt.ifHas("battery_container", CompoundTag::class.java, batteryContainer::deserializeNBT)
super.load(nbt)
if (energy != null)
nbt.put("energy_cap", energy.serializeNBT());
nbt.put("battery_container", battery_container.serializeNBT());
}
public void load(CompoundTag nbt) {
if (energy != null && nbt.get("energy_cap") instanceof CompoundTag tag)
energy.deserializeNBT(tag);
if (nbt.contains("battery_container") && nbt.get("battery_container") instanceof CompoundTag tag)
battery_container = MatteryContainer.of(this::setChanged, tag, 1);
super.load(nbt);
} }
} }

View File

@ -5,7 +5,6 @@ import net.minecraft.core.BlockPos
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage
import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer
import java.lang.Runnable
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.capability.matter.PatternState
@ -44,19 +43,19 @@ class BlockEntityPatternStorage(p_155229_: BlockPos, p_155230_: BlockState) :
private val resolverNode = LazyOptional.of { this } private val resolverNode = LazyOptional.of { this }
@JvmField @JvmField
val patterns: MatteryContainer = object : MatteryContainer(Runnable { this.setChanged() }, 8) { val patterns: MatteryContainer = object : MatteryContainer(this::setChanged, 8) {
override fun setChanged(slot: Int, new_state: ItemStack, old_state: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
val grid = node.graph as MatterNetworkGraph? val grid = node.graph as MatterNetworkGraph?
if (grid != null && !ItemStack.isSameItemSameTags(new_state, old_state)) { if (grid != null && !ItemStack.isSameItemSameTags(new, old)) {
if (!old_state.isEmpty) { if (!old.isEmpty) {
old_state.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage -> old.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternRemoved(state!!) } cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternRemoved(state!!) }
} }
} }
if (!new_state.isEmpty) { if (!new.isEmpty) {
new_state.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage -> new.getCapability(MatteryCapability.PATTERN).ifPresent { cap: IPatternStorage ->
cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternAdded(state!!) } cap.storedPatterns.forEach { state: PatternState? -> grid.onPatternAdded(state!!) }
} }
} }
@ -64,7 +63,7 @@ class BlockEntityPatternStorage(p_155229_: BlockPos, p_155230_: BlockState) :
updateBlockstate() updateBlockstate()
} }
super.setChanged(slot, new_state, old_state) super.setChanged(slot, new, old)
} }
override fun getMaxStackSize(): Int { override fun getMaxStackSize(): Int {

View File

@ -1,31 +1,26 @@
package ru.dbotthepony.mc.otm.block.entity; package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component
import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.network.chat.TranslatableComponent
public enum RedstoneSetting { enum class RedstoneSetting(val label: TranslatableComponent, val description: TranslatableComponent) {
IGNORED(new TranslatableComponent("otm.gui.redstone.ignored"), new TranslatableComponent("otm.gui.redstone.ignored.description")), IGNORED(TranslatableComponent("otm.gui.redstone.ignored"), TranslatableComponent("otm.gui.redstone.ignored.description")),
LOW(new TranslatableComponent("otm.gui.redstone.low"), new TranslatableComponent("otm.gui.redstone.low.description")), LOW(TranslatableComponent("otm.gui.redstone.low"), TranslatableComponent("otm.gui.redstone.low.description")),
HIGH(new TranslatableComponent("otm.gui.redstone.high"), new TranslatableComponent("otm.gui.redstone.high.description")); HIGH(TranslatableComponent("otm.gui.redstone.high"), TranslatableComponent("otm.gui.redstone.high.description"));
public final Component name; operator fun next(): RedstoneSetting {
public final Component description; return values[(ordinal + 1) % values.size]
private static final RedstoneSetting[] values = RedstoneSetting.values();
RedstoneSetting(TranslatableComponent name, TranslatableComponent description) {
this.name = name;
this.description = description;
} }
public RedstoneSetting next() { companion object {
return values[(ordinal() + 1) % values.length]; private val values = values()
}
public static RedstoneSetting get(int index) { @JvmStatic
if (index < 0 || index > 2) { operator fun get(index: Int): RedstoneSetting {
return LOW; if (index !in 0 .. 2)
return LOW
return values[index]
} }
return values[index];
} }
} }

View File

@ -54,7 +54,7 @@ interface IMatteryEnergyStorage : IEnergyStorage {
val batteryLevel: Fraction val batteryLevel: Fraction
val maxBatteryLevel: Fraction val maxBatteryLevel: Fraction
val missingPower: Fraction val missingPower: Fraction
get() = maxBatteryLevel - batteryLevel get() = (maxBatteryLevel - batteryLevel).moreThanZero()
override fun receiveEnergy(maxReceive: Int, simulate: Boolean): Int { override fun receiveEnergy(maxReceive: Int, simulate: Boolean): Int {
val received = receiveEnergyOuter(maxReceive, true).toInt() val received = receiveEnergyOuter(maxReceive, true).toInt()

View File

@ -0,0 +1,83 @@
package ru.dbotthepony.mc.otm.container
import net.minecraft.world.Container
import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.capabilities.Capability
import java.util.function.Consumer
class ContainerIteratorItemStack(private val container: Container) : Iterator<ItemStack>, Iterable<ItemStack> {
private var index = 0
private var nextStack: ItemStack? = null
override fun hasNext(): Boolean {
if (index >= container.containerSize && nextStack == null)
return false
while (nextStack == null && index < container.containerSize) {
val get = container.getItem(index)
if (!get.isEmpty) {
nextStack = get
}
index++
}
return nextStack != null
}
override fun next(): ItemStack {
val nextStack = nextStack!!
this.nextStack = null
return nextStack
}
override fun iterator(): Iterator<ItemStack> {
return this
}
fun consume(consumer: Consumer<ItemStack?>) {
for (t in this) {
consumer.accept(t)
}
}
}
class ContainerIteratorCapability<T>(private val container: Container, private val cap: Capability<T>) : Iterator<T>, Iterable<T> {
private var index = 0
private var nextStack: T? = null
override fun hasNext(): Boolean {
if (index >= container.containerSize && nextStack == null)
return false
while (nextStack == null && index < container.containerSize) {
val get = container.getItem(index)
if (!get.isEmpty) {
get.getCapability(cap).ifPresent { t: T -> nextStack = t }
}
index++
}
return nextStack != null
}
override fun next(): T {
val nextStack = nextStack!!
this.nextStack = null
return nextStack
}
override fun iterator(): Iterator<T> {
return this
}
fun consume(consumer: Consumer<T>) {
for (t in this) {
consumer.accept(t)
}
}
}

View File

@ -1,361 +1,304 @@
package ru.dbotthepony.mc.otm.container; package ru.dbotthepony.mc.otm.container
import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.MethodsReturnNonnullByDefault
import net.minecraft.nbt.CompoundTag; import javax.annotation.ParametersAreNonnullByDefault
import net.minecraft.nbt.ListTag; import net.minecraft.world.item.ItemStack
import net.minecraft.nbt.Tag; import net.minecraft.nbt.CompoundTag
import net.minecraft.world.Container; import net.minecraft.nbt.ListTag
import net.minecraft.world.entity.player.Player; import net.minecraft.nbt.Tag
import net.minecraft.world.item.ItemStack; import net.minecraft.world.Container
import net.minecraftforge.common.capabilities.Capability; import kotlin.jvm.JvmOverloads
import net.minecraftforge.items.IItemHandler; import net.minecraft.world.entity.player.Player
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraftforge.common.capabilities.Capability
import ru.dbotthepony.mc.otm.ifHas
import ru.dbotthepony.mc.otm.set
import java.util.*
import java.util.function.Consumer
import javax.annotation.Nullable; open class MatteryContainer(val watcher: Runnable, private val size: Int) : Container, Iterable<ItemStack> {
import javax.annotation.ParametersAreNonnullByDefault; constructor(watcher: BlockEntity, size: Int) : this(watcher::setChanged, size)
import java.util.Arrays; // constructor(watcher: BlockEntityMattery, size: Int) : this(watcher::setChangedLight, size)
import java.util.Iterator;
import java.util.function.Consumer;
@MethodsReturnNonnullByDefault private var ignoreChangeNotifications = 0
@ParametersAreNonnullByDefault @JvmField protected val slots: Array<ItemStack> = Array(size) { ItemStack.EMPTY }
public class MatteryContainer implements Container, Iterable<ItemStack> { private val trackedSlots: Array<ItemStack> = Array(size) { ItemStack.EMPTY }
protected final Runnable watcher;
protected int ignore_change_notifications = 0;
protected final int size;
protected final ItemStack[] slots;
protected final ItemStack[] tracked_slots;
public MatteryContainer(Runnable watcher, int size) { final override fun getContainerSize() = size
this.size = size;
slots = new ItemStack[this.size]; fun startIgnoreUpdates() {
tracked_slots = new ItemStack[this.size]; if (++ignoreChangeNotifications == 1) {
Arrays.fill(slots, ItemStack.EMPTY); startedIgnoringUpdates()
Arrays.fill(tracked_slots, ItemStack.EMPTY); }
this.watcher = watcher;
} }
@SuppressWarnings("unused") fun stopIgnoreUpdates() {
public void startIgnore() { if (--ignoreChangeNotifications == 0) {
ignore_change_notifications++; stoppedIgnoringUpdates()
}
} }
@SuppressWarnings("unused") protected open fun startedIgnoringUpdates() {}
public void stopIgnore() { protected open fun stoppedIgnoringUpdates() {}
ignore_change_notifications--;
}
public MatteryContainer of(@Nullable CompoundTag tag) { fun deserializeNBT(tag: CompoundTag?) {
if (tag == null) startIgnoreUpdates()
return this;
MatteryContainer container = MatteryContainer.of(watcher, tag, getContainerSize()); for (i in 0 until size) {
setItem(i, ItemStack.EMPTY)
if (handler != null)
container.handler = handler.cloneOf(container);
return container;
}
public void deserializeNBT(@Nullable CompoundTag tag) {
ignore_change_notifications++;
for (int i = 0; i < getContainerSize(); i++) {
setItem(i, ItemStack.EMPTY);
} }
if (tag == null) { if (tag == null) {
ignore_change_notifications--; stopIgnoreUpdates()
return; return
} }
// нам не интересен размер // нам не интересен размер
tag.ifHas("items", ListTag::class.java) {
if (tag.get("items") instanceof ListTag list) { for (i in 0 until Math.min(it.size, size)) {
for (int i = 0; i < Math.min(list.size(), getContainerSize()); i++) { setItem(i, ItemStack.of(it[i] as CompoundTag))
if (list.get(i) instanceof CompoundTag get_tag) {
setItem(i, ItemStack.of(get_tag));
}
} }
} }
ignore_change_notifications--; stopIgnoreUpdates()
setChanged(); setChanged()
} }
public MatteryContainer of(@Nullable Tag tag) { fun deserializeNBT(tag: Tag?) {
if (tag == null) if (tag is CompoundTag) {
return this; deserializeNBT(tag)
if (tag instanceof CompoundTag compound)
return of(watcher, compound, getContainerSize());
return this;
}
public void deserializeNBT(@Nullable Tag tag) {
if (tag == null)
return;
if (tag instanceof CompoundTag compound) {
deserializeNBT(compound);
} }
} }
public ContainerIteratorItemStack stackIterator() { fun stacks(): ContainerIteratorItemStack {
return new ContainerIteratorItemStack(this); return ContainerIteratorItemStack(this)
} }
@SuppressWarnings("unused") fun forEachNonEmpty(consumer: (ItemStack) -> Unit) {
public void consumeNonEmpty(Consumer<ItemStack> consumer) { for (item in slots) {
stackIterator().consume(consumer); if (!item.isEmpty) {
consumer(item)
}
}
} }
public <T> ContainerIteratorCapability<T> capabilityIterator(Capability<T> cap) { fun forEachNonEmpty(consumer: (ItemStack, Int) -> Unit) {
return new ContainerIteratorCapability<>(this, cap); for (i in 0 until size) {
val item = slots[i]
if (!item.isEmpty) {
consumer(item, i)
}
}
} }
public <T> void consumeCapability(Capability<T> cap, Consumer<T> consumer) { fun <T> capabilityIterator(cap: Capability<T>): ContainerIteratorCapability<T> {
capabilityIterator(cap).consume(consumer); return ContainerIteratorCapability(this, cap)
} }
public void setChanged(int slot, ItemStack new_state, ItemStack old_state) { fun <T> consumeCapability(cap: Capability<T>, consumer: Consumer<T>) {
if (ignore_change_notifications == 0) capabilityIterator(cap).consume(consumer)
watcher.run();
} }
public CompoundTag serializeNBT() { open fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
CompoundTag tag = new CompoundTag(); if (ignoreChangeNotifications == 0) watcher.run()
tag.putInt("size", getContainerSize());
ListTag list = new ListTag();
tag.put("items", list);
for (int i = 0; i < getContainerSize(); i++)
list.add(getItem(i).serializeNBT());
return tag;
} }
public static MatteryContainer of(Runnable watcher, @Nullable CompoundTag tag, int fallback_size) { fun serializeNBT(): CompoundTag {
if (tag == null) val tag = CompoundTag()
return new MatteryContainer(watcher, fallback_size); tag["size"] = size
MatteryContainer container; val list = ListTag()
tag["items"] = list
if (tag.contains("size")) for (i in 0 until size)
container = new MatteryContainer(watcher, tag.getInt("size")); list.add(this[i].serializeNBT())
else
container = new MatteryContainer(watcher, fallback_size);
if (tag.get("items") instanceof ListTag list) return tag
for (int i = 0; i < Math.min(list.size(), container.getContainerSize()); i++)
if (list.get(i) instanceof CompoundTag get_tag)
container.setItem(i, ItemStack.of(get_tag));
return container;
} }
@SuppressWarnings("unused") fun hasEmptySlot(): Boolean {
public boolean hasEmptySlot() { for (i in 0 until size) {
for (int i = 0; i < getContainerSize(); i++) { if (this[i].isEmpty) {
if (getItem(i).isEmpty()) return true
return true; }
} }
return false; return false
} }
protected MatteryContainerHandler handler; protected var handler: MatteryContainerHandler? = null
public MatteryContainerHandler handler(MatteryContainerInsertValidator insert_validator, MatteryContainerExtractValidator extract_validator) { fun handler(
if (handler != null) insert_validator: (Int, ItemStack) -> Boolean,
return handler; extract_validator: (Int, Int, ItemStack) -> Boolean
): MatteryContainerHandler {
return handler = new MatteryContainerHandler(this, insert_validator, extract_validator); return handler ?: MatteryContainerHandler(this, insert_validator, extract_validator).also { handler = it }
} }
public MatteryContainerHandler handler(MatteryContainerInsertValidator insert_validator) { fun handler(insert_validator: (Int, ItemStack) -> Boolean): MatteryContainerHandler {
if (handler != null) return handler ?: MatteryContainerHandler(this, insert_validator).also { handler = it }
return handler;
return handler = new MatteryContainerHandler(this, insert_validator);
} }
public MatteryContainerHandler handler() { fun handler(): MatteryContainerHandler {
if (handler != null) return handler ?: MatteryContainerHandler(this).also { handler = it }
return handler;
return handler = new MatteryContainerHandler(this);
} }
public int getMaxStackSize(int slot) { open fun getMaxStackSize(slot: Int) = maxStackSize
return getMaxStackSize();
}
public ItemStack addItem(ItemStack stack, int start, int end, boolean simulate) { @JvmOverloads
if (stack.isEmpty() || start < 0 || end > size || start >= end) fun addItem(stack: ItemStack, start: Int = 0, end: Int = size, simulate: Boolean = false): ItemStack {
return ItemStack.EMPTY; if (stack.isEmpty || start < 0 || end > size || start >= end)
return ItemStack.EMPTY
final var copy = stack.copy(); val copy = stack.copy()
// двигаем в одинаковые слоты // двигаем в одинаковые слоты
for (int slot = start; slot < end; slot++) { for (slot in start until end) {
if (ItemStack.isSameItemSameTags(slots[slot], copy)) { if (ItemStack.isSameItemSameTags(slots[slot], copy)) {
var this_stack = slots[slot]; val slotStack = slots[slot]
int slot_limit = Math.min(getMaxStackSize(slot), this_stack.getMaxStackSize()); val slotLimit = Math.min(getMaxStackSize(slot), slotStack.maxStackSize)
if (this_stack.getCount() < slot_limit) { if (slotStack.count < slotLimit) {
int new_count = Math.min(this_stack.getCount() + copy.getCount(), slot_limit); val newCount = Math.min(slotStack.count + copy.count, slotLimit)
int diff = new_count - this_stack.getCount(); val diff = newCount - slotStack.count
if (!simulate) { if (!simulate) {
var old = this_stack.copy(); val old = slotStack.copy()
this_stack.setCount(new_count); slotStack.count = newCount
tracked_slots[slot] = this_stack.copy(); trackedSlots[slot] = slotStack.copy()
setChanged(slot, this_stack, old); setChanged(slot, slotStack, old)
} }
copy.shrink(diff); copy.shrink(diff)
if (copy.isEmpty()) { if (copy.isEmpty) {
return copy; return copy
} }
} }
} }
} }
// двигаем в пустые слоты // двигаем в пустые слоты
for (int slot = start; slot < end; slot++) { for (slot in start until end) {
if (slots[slot].isEmpty()) { if (slots[slot].isEmpty) {
int diff = Math.min(copy.getCount(), Math.min(getMaxStackSize(slot), copy.getMaxStackSize())); val diff = Math.min(copy.count, Math.min(getMaxStackSize(slot), copy.maxStackSize))
if (!simulate) { if (!simulate) {
var put_copy = copy.copy(); val copyToPut = copy.copy()
put_copy.setCount(diff); copyToPut.count = diff
slots[slot] = put_copy; this[slot] = copyToPut
tracked_slots[slot] = put_copy.copy();
setChanged(slot, put_copy, ItemStack.EMPTY);
} }
copy.shrink(diff); copy.shrink(diff)
if (copy.isEmpty()) { if (copy.isEmpty) {
return copy; return copy
} }
} }
} }
return copy; return copy
} }
@SuppressWarnings("unused") fun addItem(stack: ItemStack, simulate: Boolean): ItemStack {
public ItemStack addItem(ItemStack stack, boolean simulate) { return addItem(stack, 0, size, simulate)
return addItem(stack, 0, size, simulate);
} }
@SuppressWarnings("unused") @JvmOverloads
public ItemStack addItem(ItemStack stack) { fun fullyAddItem(stack: ItemStack, start: Int = 0, end: Int = size): Boolean {
return addItem(stack, 0, size, false); if (!addItem(stack, start, end, true).isEmpty)
return false
return addItem(stack, start, end, false).isEmpty
} }
public boolean fullyAddItem(ItemStack stack) { override fun isEmpty(): Boolean {
if (!addItem(stack, 0, size, true).isEmpty()) { for (stack in slots)
return false; if (!stack.isEmpty)
return false
return true
}
operator fun get(slot: Int) = getItem(slot)
operator fun set(slot: Int, stack: ItemStack) = setItem(slot, stack)
operator fun contains(other: ItemStack): Boolean {
for (i in 0 until size) {
if (ItemStack.isSameItemSameTags(this[i], other)) {
return true
}
} }
return addItem(stack, 0, size, false).isEmpty(); return false
} }
@SuppressWarnings("unused") final override fun getItem(slot: Int): ItemStack {
public boolean fullyAddItem(ItemStack stack, int start, int end) { val item = slots[slot]
if (!addItem(stack, start, end, true).isEmpty()) {
return false;
}
return addItem(stack, start, end, false).isEmpty(); if (item.isEmpty)
return ItemStack.EMPTY
else
return item
} }
@Override final override fun removeItem(slot: Int, amount: Int): ItemStack {
public int getContainerSize() { if (amount <= 0 || slot < 0 || slot >= size || slots[slot].isEmpty)
return size; return ItemStack.EMPTY
val old = slots[slot].copy()
val split = slots[slot].split(amount)
trackedSlots[slot] = slots[slot].copy()
setChanged(slot, if (slots[slot].isEmpty) ItemStack.EMPTY else slots[slot], old)
return split
} }
@Override final override fun removeItemNoUpdate(slot: Int): ItemStack {
public boolean isEmpty() { val old = slots[slot]
for (var stack : slots) slots[slot] = ItemStack.EMPTY
if (!stack.isEmpty()) trackedSlots[slot] = ItemStack.EMPTY
return false; return old
return true;
} }
@Override final override fun setItem(slot: Int, stack: ItemStack) {
public ItemStack getItem(int slot) { if (slots[slot].isEmpty && stack.isEmpty || stack === slots[slot])
return slots[slot].isEmpty() ? ItemStack.EMPTY : slots[slot]; return
val old = slots[slot]
slots[slot] = stack
trackedSlots[slot] = stack.copy()
setChanged(slot, stack, old)
} }
@Override final override fun setChanged() {
public ItemStack removeItem(int slot, int amount) { for (slot in 0 until size) {
if (amount <= 0 || slot < 0 || slot >= size || slots[slot].isEmpty()) if (!ItemStack.isSameItemSameTags(slots[slot], trackedSlots[slot])) {
return ItemStack.EMPTY; setChanged(slot, slots[slot], trackedSlots[slot])
trackedSlots[slot] = slots[slot].copy()
var old = slots[slot].copy();
var split = slots[slot].split(amount);
tracked_slots[slot] = slots[slot].copy();
setChanged(slot, slots[slot].isEmpty() ? ItemStack.EMPTY : slots[slot], old);
return split;
}
@Override
public ItemStack removeItemNoUpdate(int slot) {
var old = slots[slot];
slots[slot] = ItemStack.EMPTY;
tracked_slots[slot] = ItemStack.EMPTY;
return old;
}
@Override
public void setItem(int slot, ItemStack stack) {
if (slots[slot].isEmpty() && stack.isEmpty() || stack == slots[slot])
return;
var old = slots[slot];
slots[slot] = stack;
tracked_slots[slot] = stack.copy();
setChanged(slot, stack, old);
}
@Override
public void setChanged() {
for (int slot = 0; slot < size; slot++) {
if (!ItemStack.isSameItemSameTags(slots[slot], tracked_slots[slot])) {
setChanged(slot, slots[slot], tracked_slots[slot]);
tracked_slots[slot] = slots[slot].copy();
// mojang соси))0)0))0)))))0) // mojang соси))0)0))0)))))0)
} }
} }
} }
@Override override fun stillValid(player: Player): Boolean {
public boolean stillValid(Player player) { return true
return true;
} }
@Override final override fun clearContent() {
public void clearContent() { for (slot in 0 until size) {
for (int slot = 0; slot < size; slot++) { if (!slots[slot].isEmpty) {
if (!slots[slot].isEmpty()) { val old = slots[slot]
setChanged(slot, ItemStack.EMPTY, slots[slot]); slots[slot] = ItemStack.EMPTY
setChanged(slot, ItemStack.EMPTY, old)
} }
} }
Arrays.fill(tracked_slots, ItemStack.EMPTY); Arrays.fill(trackedSlots, ItemStack.EMPTY)
} }
@Override final override fun iterator(): Iterator<ItemStack> {
public Iterator<ItemStack> iterator() { return slots.iterator()
return Arrays.stream(slots).iterator();
} }
} }

View File

@ -1,132 +1,93 @@
package ru.dbotthepony.mc.otm.container; package ru.dbotthepony.mc.otm.container
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler
import javax.annotation.Nonnull; class MatteryContainerHandler @JvmOverloads internal constructor(
private val container: MatteryContainer,
private val insert_validator: (Int, ItemStack) -> Boolean = { _: Int, _: ItemStack -> true },
private val extract_validator: (Int, Int, ItemStack) -> Boolean = { _: Int, _: Int, _: ItemStack -> true }
) : IItemHandler {
private var handler = LazyOptional.of<IItemHandler> { this }
public class MatteryContainerHandler implements IItemHandler { fun get(): LazyOptional<IItemHandler> {
private final MatteryContainer container; return handler
private final MatteryContainerInsertValidator insert_validator;
private final MatteryContainerExtractValidator extract_validator;
MatteryContainerHandler(MatteryContainer container, MatteryContainerInsertValidator insert_validator, MatteryContainerExtractValidator extract_validator) {
this.container = container;
this.insert_validator = insert_validator;
this.extract_validator = extract_validator;
} }
MatteryContainerHandler(MatteryContainer container) { fun invalidate() {
this(container, (slot, stack) -> true, (slot, amount, stack) -> true); handler.invalidate()
} }
MatteryContainerHandler(MatteryContainer container, MatteryContainerInsertValidator insert_validator) { fun revive() {
this(container, insert_validator, (slot, amount, stack) -> true); handler = LazyOptional.of { this }
} }
private LazyOptional<IItemHandler> handler = LazyOptional.of(() -> this); override fun getSlots() = container.containerSize
override fun getStackInSlot(slot: Int) = container[slot]
public LazyOptional<IItemHandler> get() { override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
return handler; if (!insert_validator(slot, stack))
} return stack
public void invalidate() { val localStack = container[slot]
handler.invalidate();
}
public void revive() { if (localStack.isEmpty) {
handler = LazyOptional.of(() -> this);
}
@Override
public int getSlots() {
return container.getContainerSize();
}
@Nonnull
@Override
public ItemStack getStackInSlot(int slot) {
return container.getItem(slot);
}
@Nonnull
@Override
public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
if (!insert_validator.apply(slot, stack))
return stack;
ItemStack self_stack = container.getItem(slot);
if (self_stack.isEmpty()) {
if (!simulate) { if (!simulate) {
var copy = stack.copy(); val copy = stack.copy()
container.setChanged(slot, copy, ItemStack.EMPTY); container.setChanged(slot, copy, ItemStack.EMPTY)
container.setItem(slot, copy); container.setItem(slot, copy)
} }
return ItemStack.EMPTY; return ItemStack.EMPTY
} else if (self_stack.isStackable() && self_stack.getMaxStackSize() > self_stack.getCount() && ItemStack.isSameItemSameTags(self_stack, stack)) { } else if (localStack.isStackable && localStack.maxStackSize > localStack.count && ItemStack.isSameItemSameTags(localStack, stack)) {
int new_count = Math.min(self_stack.getMaxStackSize(), self_stack.getCount() + stack.getCount()); val newCount = Math.min(localStack.maxStackSize, localStack.count + stack.count)
int diff = new_count - self_stack.getCount(); val diff = newCount - localStack.count
if (diff != 0) { if (diff != 0) {
if (!simulate) { if (!simulate) {
ItemStack copy_self = self_stack.copy(); val copy = localStack.copy()
self_stack.grow(diff); localStack.grow(diff)
container.setChanged(slot, self_stack, copy_self); container.setChanged(slot, localStack, copy)
} }
ItemStack copy = stack.copy(); val copy = stack.copy()
copy.shrink(diff); copy.shrink(diff)
return copy; return copy
} }
} }
return stack; return stack
} }
@Nonnull override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack {
@Override
public ItemStack extractItem(int slot, int amount, boolean simulate) {
if (amount == 0) if (amount == 0)
return ItemStack.EMPTY; return ItemStack.EMPTY
if (amount < 0) require(amount >= 0) { "Can not extract negative amount of items" }
throw new IllegalArgumentException("Can not extract negative amount of items");
ItemStack self_stack = container.getItem(slot); val localStack = container.getItem(slot)
if (localStack.isEmpty) return ItemStack.EMPTY
if (!extract_validator(slot, amount, localStack)) return ItemStack.EMPTY
if (self_stack.isEmpty()) val minimal = Math.min(amount, localStack.count)
return ItemStack.EMPTY; val copy = localStack.copy()
copy.count = minimal
if (!extract_validator.apply(slot, amount, self_stack))
return ItemStack.EMPTY;
int minimal = Math.min(amount, self_stack.getCount());
ItemStack copy = self_stack.copy();
copy.setCount(minimal);
if (!simulate) { if (!simulate) {
ItemStack copy_self = self_stack.copy(); val copy = localStack.copy()
self_stack.shrink(minimal); localStack.shrink(minimal)
container.setChanged(slot, self_stack, copy_self); container.setChanged(slot, localStack, copy)
} }
return copy; return copy
} }
@Override override fun getSlotLimit(slot: Int): Int {
public int getSlotLimit(int slot) { return container.maxStackSize
return container.getMaxStackSize();
} }
@Override override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
public boolean isItemValid(int slot, @Nonnull ItemStack stack) { return insert_validator(slot, stack)
return insert_validator.apply(slot, stack);
}
MatteryContainerHandler cloneOf(MatteryContainer container) {
return new MatteryContainerHandler(container, insert_validator, extract_validator);
} }
} }

View File

@ -57,12 +57,12 @@ abstract class Abstract6Graph<T> {
} }
companion object { companion object {
fun <T, G : Abstract6Graph<T>> discoverFull( fun <T> discoverFull(
level: ServerLevel, level: ServerLevel,
blockPos: BlockPos, blockPos: BlockPos,
node: Graph6Node<T>, node: Graph6Node<T>,
nodeGetter: (BlockEntity) -> Graph6Node<T>?, nodeGetter: (BlockEntity) -> Graph6Node<T>?,
factory: () -> G factory: () -> Abstract6Graph<T>
) { ) {
OverdriveThatMatters.tickUntil(level) { OverdriveThatMatters.tickUntil(level) {
!node.valid || discover(level, blockPos, node, nodeGetter, factory) !node.valid || discover(level, blockPos, node, nodeGetter, factory)
@ -70,12 +70,12 @@ abstract class Abstract6Graph<T> {
} }
@JvmStatic @JvmStatic
fun <T, G : Abstract6Graph<T>> discover( fun <T> discover(
level: ServerLevel, level: ServerLevel,
blockPos: BlockPos, blockPos: BlockPos,
node: Graph6Node<T>, node: Graph6Node<T>,
nodeGetter: (BlockEntity) -> Graph6Node<T>?, nodeGetter: (BlockEntity) -> Graph6Node<T>?,
factory: () -> G factory: () -> Abstract6Graph<T>
): Boolean { ): Boolean {
var fullDiscovery = true var fullDiscovery = true

View File

@ -22,7 +22,7 @@ abstract class PoweredMatteryMenu protected constructor(
batterySlot = BatterySlot(SimpleContainer(1), 0) batterySlot = BatterySlot(SimpleContainer(1), 0)
} else { } else {
powerWidget = LevelGaugeWidget(this, tile.getCapability(MatteryCapability.ENERGY).resolve().get()) powerWidget = LevelGaugeWidget(this, tile.getCapability(MatteryCapability.ENERGY).resolve().get())
batterySlot = BatterySlot(tile.battery_container, 0) batterySlot = BatterySlot(tile.batteryContainer, 0)
} }
} }
} }