Fluid tanks
general improvements to SI prefix formatter networking regarding fluid stacks Own fluid handler implementations
This commit is contained in:
parent
82e410ad33
commit
90f345a2d9
@ -177,6 +177,7 @@ private fun misc(provider: MatteryLanguageProvider) {
|
||||
|
||||
misc("suffix.merge", "%s %s")
|
||||
|
||||
misc("suffix.none", "%s %s")
|
||||
misc("suffix.kilo", "%s k%s")
|
||||
misc("suffix.mega", "%s M%s")
|
||||
misc("suffix.giga", "%s G%s")
|
||||
@ -264,9 +265,11 @@ private fun misc(provider: MatteryLanguageProvider) {
|
||||
gui("power.percentage_level", "Energy level: %s%%")
|
||||
gui("level", "%s / %s")
|
||||
gui("power.name", "MtJ")
|
||||
gui("fluid.name", "mB")
|
||||
gui("fluid.name", "B")
|
||||
gui("fluid.level", "%s / %s of %s")
|
||||
|
||||
gui("empty", "Empty")
|
||||
|
||||
gui("power.burn_time", "Burn time left: %s ticks")
|
||||
|
||||
gui("progress_widget", "Progress: %s%%")
|
||||
@ -370,6 +373,9 @@ private fun blocks(provider: MatteryLanguageProvider) {
|
||||
add(MBlocks.MATTER_RECONSTRUCTOR, "Matter Reconstructor")
|
||||
add(MBlocks.MATTER_RECONSTRUCTOR, "desc", "Repairs tools using matter")
|
||||
|
||||
add(MBlocks.FLUID_TANK, "Fluid Tank")
|
||||
add(MBlocks.FLUID_TANK, "named", "Fluid Tank (%s)")
|
||||
|
||||
add(MBlocks.ENGINE, "Ship Engine")
|
||||
add(MBlocks.HOLO_SIGN, "Holo Sign")
|
||||
|
||||
|
@ -185,6 +185,7 @@ private fun misc(provider: MatteryLanguageProvider) {
|
||||
|
||||
misc("suffix.merge", "%s %s")
|
||||
|
||||
misc("suffix.none", "%s %s")
|
||||
misc("suffix.kilo", "%s к%s")
|
||||
misc("suffix.mega", "%s М%s")
|
||||
misc("suffix.giga", "%s Г%s")
|
||||
@ -271,9 +272,11 @@ private fun misc(provider: MatteryLanguageProvider) {
|
||||
gui("power.percentage_level", "Уровень энергии: %s%%")
|
||||
gui("level", "%s / %s")
|
||||
gui("power.name", "МтДж")
|
||||
gui("fluid.name", "мВ")
|
||||
gui("fluid.name", "В")
|
||||
gui("fluid.level", "%s / %s с %s")
|
||||
|
||||
gui("empty", "Пусто")
|
||||
|
||||
gui("power.burn_time", "Оставшееся время горения: %s тиков")
|
||||
|
||||
gui("progress_widget", "Прогресс: %s%%")
|
||||
@ -377,6 +380,9 @@ private fun blocks(provider: MatteryLanguageProvider) {
|
||||
add(MBlocks.MATTER_RECONSTRUCTOR, "Материальный реконструктор")
|
||||
add(MBlocks.MATTER_RECONSTRUCTOR, "desc", "Чинит инструменты используя материю")
|
||||
|
||||
add(MBlocks.FLUID_TANK, "Жидкостный бак")
|
||||
add(MBlocks.FLUID_TANK, "named", "Жидкостный бак (%s)")
|
||||
|
||||
add(MBlocks.ENGINE, "Двигатель корабля")
|
||||
add(MBlocks.HOLO_SIGN, "Голографическая табличка")
|
||||
|
||||
|
@ -129,6 +129,7 @@ fun addLootTables(lootTables: LootTables) {
|
||||
lootTables.tile(MBlocks.COBBLESTONE_GENERATOR)
|
||||
lootTables.tile(MBlocks.ESSENCE_STORAGE)
|
||||
lootTables.tile(MBlocks.MATTER_RECONSTRUCTOR)
|
||||
lootTables.tile(MBlocks.FLUID_TANK)
|
||||
|
||||
lootTables.tile(MBlocks.ENERGY_SERVO)
|
||||
lootTables.tile(MBlocks.ENERGY_COUNTER)
|
||||
|
@ -308,4 +308,20 @@ fun addCraftingTableRecipes(consumer: Consumer<FinishedRecipe>) {
|
||||
.row(MItems.ELECTRIC_PARTS, MItems.MATTER_REPLICATOR, MItems.ELECTRIC_PARTS)
|
||||
.row(MItems.ELECTROMAGNET, MItems.ELECTROMAGNET, MItems.ELECTROMAGNET)
|
||||
.build(consumer)
|
||||
|
||||
MatteryRecipe(MItems.FLUID_CAPSULE, category = RecipeCategory.TOOLS, count = 8)
|
||||
.row(MItemTags.TRITANIUM_NUGGETS, MItemTags.TRITANIUM_NUGGETS, MItemTags.TRITANIUM_NUGGETS)
|
||||
.rowB(MItemTags.HARDENED_GLASS_PANES)
|
||||
.row(MItemTags.TRITANIUM_NUGGETS, MItemTags.TRITANIUM_NUGGETS, MItemTags.TRITANIUM_NUGGETS)
|
||||
.unlockedBy(MItemTags.HARDENED_GLASS_PANES)
|
||||
.unlockedBy(MItemTags.TRITANIUM_NUGGETS)
|
||||
.build(consumer)
|
||||
|
||||
MatteryRecipe(MItems.FLUID_TANK, category = RecipeCategory.DECORATIONS)
|
||||
.row(MItemTags.TRITANIUM_INGOTS, MItemTags.HARDENED_GLASS_PANES, MItemTags.TRITANIUM_INGOTS)
|
||||
.rowAC(MItemTags.HARDENED_GLASS_PANES, MItemTags.HARDENED_GLASS_PANES)
|
||||
.row(MItemTags.TRITANIUM_INGOTS, MItemTags.HARDENED_GLASS_PANES, MItemTags.TRITANIUM_INGOTS)
|
||||
.unlockedBy(MItemTags.HARDENED_GLASS_PANES)
|
||||
.unlockedBy(MItemTags.TRITANIUM_INGOTS)
|
||||
.build(consumer)
|
||||
}
|
||||
|
@ -171,6 +171,7 @@ fun addTags(tagsProvider: TagsProvider) {
|
||||
MBlocks.COBBLESTONE_GENERATOR,
|
||||
MBlocks.ESSENCE_STORAGE,
|
||||
MBlocks.MATTER_RECONSTRUCTOR,
|
||||
MBlocks.FLUID_TANK,
|
||||
), Tiers.IRON)
|
||||
|
||||
tagsProvider.requiresPickaxe(MBlocks.TRITANIUM_ANVIL, Tiers.IRON)
|
||||
|
@ -0,0 +1,24 @@
|
||||
package ru.dbotthepony.mc.otm.block.decorative
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import ru.dbotthepony.mc.otm.block.RotatableMatteryBlock
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
|
||||
|
||||
class FluidTankBlock : RotatableMatteryBlock(), EntityBlock {
|
||||
override fun newBlockEntity(pPos: BlockPos, pState: BlockState): BlockEntity {
|
||||
return FluidTankBlockEntity(pPos, pState)
|
||||
}
|
||||
|
||||
override fun <T : BlockEntity?> getTicker(pLevel: Level, pState: BlockState, pBlockEntityType: BlockEntityType<T>): BlockEntityTicker<T>? {
|
||||
if (pLevel.isClientSide)
|
||||
return null
|
||||
|
||||
return BlockEntityTicker { _, _, _, pBlockEntity -> if (pBlockEntity is FluidTankBlockEntity) pBlockEntity.tick() }
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
@ -388,7 +389,7 @@ abstract class MatteryWorkerBlockEntity<JobType : MatteryWorkerBlockEntity.Job>(
|
||||
fun appendHoverText(itemStack: ItemStack, blockGetter: BlockGetter?, tooltips: MutableList<Component>, flag: TooltipFlag) {
|
||||
val tag = itemStack.tag ?: return
|
||||
|
||||
val subtag = tag.get("BlockEntityTag") as? CompoundTag
|
||||
val subtag = tag.get(BlockItem.BLOCK_ENTITY_TAG) as? CompoundTag
|
||||
|
||||
if (subtag != null) {
|
||||
if (subtag.contains(WORK_TICKS_KEY) && !subtag.contains(JOB_KEY)) {
|
||||
|
@ -0,0 +1,204 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.decorative
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.CombinedItemHandler
|
||||
import ru.dbotthepony.mc.otm.capability.fluid.BlockMatteryFluidHandler
|
||||
import ru.dbotthepony.mc.otm.capability.moveFluid
|
||||
import ru.dbotthepony.mc.otm.config.ItemsConfig
|
||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.core.orNull
|
||||
import ru.dbotthepony.mc.otm.core.util.FluidStackValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu
|
||||
import ru.dbotthepony.mc.otm.registry.MBlockEntities
|
||||
|
||||
class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.FLUID_TANK, blockPos, blockState) {
|
||||
val fluid = BlockMatteryFluidHandler(::onChanged, ItemsConfig::FLUID_TANK_CAPACITY)
|
||||
var synchronizedFluid by synchronizer.Field(FluidStack.EMPTY!!, FluidStackValueCodec)
|
||||
private set
|
||||
|
||||
val fillInput = MatteryContainer(::setChangedLight, 1)
|
||||
val drainInput = MatteryContainer(::setChangedLight, 1)
|
||||
val output = MatteryContainer(::setChangedLight, 1)
|
||||
|
||||
val itemConfig = ConfigurableItemHandler(
|
||||
input = CombinedItemHandler(
|
||||
drainInput.handler(HandlerFilter.DrainableFluidContainers),
|
||||
fillInput.handler(object : HandlerFilter {
|
||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||
if (fluid.isEmpty)
|
||||
return false
|
||||
|
||||
stack.getCapability(ForgeCapabilities.FLUID_HANDLER).ifPresentK {
|
||||
if (it.fill(fluid[0], IFluidHandler.FluidAction.SIMULATE) > 0)
|
||||
return true
|
||||
}
|
||||
|
||||
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||
if (it.fill(fluid[0], IFluidHandler.FluidAction.SIMULATE) > 0)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
||||
return !canInsert(slot, stack)
|
||||
}
|
||||
})
|
||||
),
|
||||
output = output.handler(HandlerFilter.OnlyOut)
|
||||
)
|
||||
|
||||
init {
|
||||
exposeGlobally(ForgeCapabilities.FLUID_HANDLER, fluid)
|
||||
savetables.stateful(::fluid, FLUID_KEY)
|
||||
savetables.stateful(::fillInput)
|
||||
savetables.stateful(::drainInput)
|
||||
savetables.stateful(::output)
|
||||
}
|
||||
|
||||
private fun onChanged(new: FluidStack, old: FluidStack) {
|
||||
synchronizedFluid = new.copy()
|
||||
setChangedLight()
|
||||
}
|
||||
|
||||
private fun drainItem() {
|
||||
val item = drainInput[0]
|
||||
|
||||
if (item.isNotEmpty) {
|
||||
val target = if (item.count == 1) item else item.copyWithCount(1)
|
||||
val cap = target.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).orNull() ?: target.getCapability(ForgeCapabilities.FLUID_HANDLER).orNull()
|
||||
|
||||
if (cap == null) {
|
||||
if (output.consumeItem(item, simulate = false)) {
|
||||
drainInput.setChanged(0)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (fluid.isNotFull) {
|
||||
if (item.count == 1) {
|
||||
val moved0 = moveFluid(source = cap, destination = fluid)
|
||||
|
||||
if (moved0.isNotEmpty) {
|
||||
drainInput.setChanged(0)
|
||||
|
||||
if (output.consumeItem(item, simulate = false)) {
|
||||
drainInput.setChanged(0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val moved0 = moveFluid(source = cap, destination = fluid, actuallyFill = false)
|
||||
|
||||
if (moved0.isNotEmpty) {
|
||||
if (output.consumeItem(target, simulate = true)) {
|
||||
val target1 = item.copyWithCount(1)
|
||||
val cap1 = target1.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).orNull() ?: target1.getCapability(ForgeCapabilities.FLUID_HANDLER).orNull() ?: throw ConcurrentModificationException()
|
||||
|
||||
val moved1 = moveFluid(source = cap1, destination = fluid)
|
||||
|
||||
if (moved1 != moved0 || moved1.amount != moved0.amount) {
|
||||
LOGGER.error("Error moving fluids in Fluid tank at $blockPos: moved $moved0 during simulation from $target, moved $moved1 from $target1 during execution. This is likely a bug in OTM or other mod!")
|
||||
} else {
|
||||
item.count--
|
||||
drainInput.setChanged(0)
|
||||
|
||||
if (!output.consumeItem(target1, simulate = false)) {
|
||||
LOGGER.error("Unable to insert $target1 into output slot of Fluid tank at $blockPos, popping item in world instead to avoid item loss! This is likely a bug in OTM or other mod!")
|
||||
(level as? ServerLevel)?.addFreshEntity(ItemEntity(level!!, blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(), target1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun fillItem() {
|
||||
val item = fillInput[0]
|
||||
|
||||
if (item.isNotEmpty) {
|
||||
val target = if (item.count == 1) item else item.copyWithCount(1)
|
||||
val cap = target.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).orNull() ?: target.getCapability(ForgeCapabilities.FLUID_HANDLER).orNull()
|
||||
|
||||
if (cap == null) {
|
||||
if (output.consumeItem(item, simulate = false)) {
|
||||
fillInput.setChanged(0)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (fluid.isNotEmpty) {
|
||||
if (item.count == 1) {
|
||||
val moved0 = moveFluid(source = fluid, destination = cap)
|
||||
|
||||
if (moved0.isNotEmpty) {
|
||||
fillInput.setChanged(0)
|
||||
|
||||
if (output.consumeItem(item, simulate = false)) {
|
||||
fillInput.setChanged(0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val moved0 = moveFluid(source = fluid, destination = cap, actuallyDrain = false)
|
||||
|
||||
if (moved0.isNotEmpty) {
|
||||
if (output.consumeItem(target, simulate = true)) {
|
||||
val target1 = item.copyWithCount(1)
|
||||
val cap1 = target1.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).orNull() ?: target1.getCapability(ForgeCapabilities.FLUID_HANDLER).orNull() ?: throw ConcurrentModificationException()
|
||||
|
||||
val moved1 = moveFluid(source = fluid, destination = cap1)
|
||||
|
||||
if (moved1 != moved0 || moved1.amount != moved0.amount) {
|
||||
LOGGER.error("Error moving fluids in Fluid tank at $blockPos: moved $moved0 during simulation from $target, moved $moved1 from $target1 during execution. This is likely a bug in OTM or other mod!")
|
||||
} else {
|
||||
item.count--
|
||||
fillInput.setChanged(0)
|
||||
|
||||
if (!output.consumeItem(target1, simulate = false)) {
|
||||
LOGGER.error("Unable to insert $target1 into output slot of Fluid tank at $blockPos, popping item in world instead to avoid item loss! This is likely a bug in OTM or other mod!")
|
||||
(level as? ServerLevel)?.addFreshEntity(ItemEntity(level!!, blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(), target1))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
drainItem()
|
||||
fillItem()
|
||||
}
|
||||
|
||||
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
|
||||
return FluidTankMenu(containerID, inventory, this)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val FLUID_KEY = "fluid"
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
}
|
||||
}
|
@ -27,9 +27,11 @@ import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.getMekanismEnergySided
|
||||
import ru.dbotthepony.mc.otm.compat.mekanism.mekanismEnergy
|
||||
import ru.dbotthepony.mc.otm.container.awareStream
|
||||
import ru.dbotthepony.mc.otm.container.iterator
|
||||
import ru.dbotthepony.mc.otm.container.stream
|
||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||
import ru.dbotthepony.mc.otm.core.collect.ContainerItemStackEntry
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.orNull
|
||||
import ru.dbotthepony.mc.otm.core.util.formatFluidLevel
|
||||
@ -44,7 +46,7 @@ val ICapabilityProvider.matteryPlayer: MatteryPlayerCapability? get() = getCapab
|
||||
/**
|
||||
* Does a checked energy receive, calls [IMatteryEnergyStorage.receiveEnergyChecked] if possible
|
||||
*/
|
||||
internal fun IEnergyStorage.receiveEnergy(amount: Decimal, simulate: Boolean): Decimal {
|
||||
fun IEnergyStorage.receiveEnergy(amount: Decimal, simulate: Boolean): Decimal {
|
||||
if (this is IMatteryEnergyStorage)
|
||||
return receiveEnergyChecked(amount, simulate)
|
||||
|
||||
@ -60,7 +62,7 @@ internal fun IEnergyStorage.receiveEnergy(amount: Decimal, simulate: Boolean): D
|
||||
return Decimal.valueOf(receiveEnergy(amount.toInt(), simulate))
|
||||
}
|
||||
|
||||
internal fun IEnergyStorage.transcieveEnergy(amount: Decimal, isReceiving: Boolean, simulate: Boolean): Decimal {
|
||||
fun IEnergyStorage.transcieveEnergy(amount: Decimal, isReceiving: Boolean, simulate: Boolean): Decimal {
|
||||
if (isReceiving)
|
||||
return receiveEnergy(amount, simulate)
|
||||
else
|
||||
@ -70,7 +72,7 @@ internal fun IEnergyStorage.transcieveEnergy(amount: Decimal, isReceiving: Boole
|
||||
/**
|
||||
* Does a checked energy extraction, calls [IMatteryEnergyStorage.extractEnergyChecked] if possible
|
||||
*/
|
||||
internal fun IEnergyStorage.extractEnergy(amount: Decimal, simulate: Boolean): Decimal {
|
||||
fun IEnergyStorage.extractEnergy(amount: Decimal, simulate: Boolean): Decimal {
|
||||
if (this is IMatteryEnergyStorage)
|
||||
return extractEnergyChecked(amount, simulate)
|
||||
|
||||
@ -313,7 +315,7 @@ fun Player.awareAllItemsStream(includeCosmetics: Boolean = false): Stream<out Aw
|
||||
*
|
||||
* @return pair of new (advanced) [sourceSlot] and [destinationSlot]
|
||||
*/
|
||||
internal fun moveBetweenSlots(source: IItemHandler, sourceSlot: Int, destination: IItemHandler, destinationSlot: Int): Pair<Int, Int> {
|
||||
fun moveBetweenSlots(source: IItemHandler, sourceSlot: Int, destination: IItemHandler, destinationSlot: Int): Pair<Int, Int> {
|
||||
val getItem = source.extractItem(sourceSlot, Int.MAX_VALUE, true)
|
||||
|
||||
if (getItem.isEmpty) {
|
||||
@ -349,7 +351,7 @@ internal fun moveBetweenSlots(source: IItemHandler, sourceSlot: Int, destination
|
||||
}
|
||||
|
||||
@Suppress("name_shadowing")
|
||||
internal fun moveEnergy(source: IEnergyStorage, destination: IEnergyStorage, amount: Decimal = Decimal.LONG_MAX_VALUE, simulate: Boolean, ignoreFlowRestrictions: Boolean = false): Decimal {
|
||||
fun moveEnergy(source: IEnergyStorage, destination: IEnergyStorage, amount: Decimal = Decimal.LONG_MAX_VALUE, simulate: Boolean, ignoreFlowRestrictions: Boolean = false): Decimal {
|
||||
val extracted = if (ignoreFlowRestrictions && source is IMatteryEnergyStorage) source.extractEnergy(amount, true) else source.extractEnergy(amount, true)
|
||||
|
||||
if (extracted.isPositive) {
|
||||
@ -372,25 +374,17 @@ internal fun moveEnergy(source: IEnergyStorage, destination: IEnergyStorage, amo
|
||||
return Decimal.ZERO
|
||||
}
|
||||
|
||||
internal fun fluidLevel(it: IFluidHandler, tooltips: MutableList<Component>) {
|
||||
val fluid = it.getFluidInTank(0)
|
||||
internal fun IFluidHandler.fluidLevel(tooltips: MutableList<Component>) {
|
||||
val fluid = getFluidInTank(0)
|
||||
|
||||
if (fluid.isEmpty) {
|
||||
tooltips.add(formatFluidLevel(0, it.getTankCapacity(0), formatAsReadable = ShiftPressedCond).withStyle(ChatFormatting.GRAY))
|
||||
tooltips.add(formatFluidLevel(0, getTankCapacity(0), formatAsReadable = ShiftPressedCond).withStyle(ChatFormatting.GRAY))
|
||||
} else {
|
||||
tooltips.add(formatFluidLevel(fluid.amount, it.getTankCapacity(0), fluid.displayName, formatAsReadable = ShiftPressedCond).withStyle(ChatFormatting.GRAY))
|
||||
tooltips.add(formatFluidLevel(fluid.amount, getTankCapacity(0), fluid.displayName, formatAsReadable = ShiftPressedCond).withStyle(ChatFormatting.GRAY))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun moveFluid(source: IFluidHandler, sourceTank: Int? = null, destination: IFluidHandler, limit: Int = Int.MAX_VALUE, simulate: Boolean = false, actuallyDrain: Boolean = true): FluidStack {
|
||||
val drained: FluidStack
|
||||
|
||||
if (sourceTank == null) {
|
||||
drained = source.drain(limit, IFluidHandler.FluidAction.SIMULATE)
|
||||
} else {
|
||||
drained = source.drain(source.getFluidInTank(sourceTank), IFluidHandler.FluidAction.SIMULATE)
|
||||
}
|
||||
|
||||
private fun actuallyMoveFluid(drained: FluidStack, source: IFluidHandler, destination: IFluidHandler, limit: Int, actuallyDrain: Boolean, actuallyFill: Boolean): FluidStack {
|
||||
if (drained.isEmpty) return FluidStack.EMPTY
|
||||
|
||||
val filled = destination.fill(drained, IFluidHandler.FluidAction.SIMULATE)
|
||||
@ -402,7 +396,7 @@ internal fun moveFluid(source: IFluidHandler, sourceTank: Int? = null, destinati
|
||||
val filled2 = destination.fill(drained2, IFluidHandler.FluidAction.SIMULATE)
|
||||
if (filled2 != drained2.amount) return FluidStack.EMPTY
|
||||
|
||||
if (simulate) return FluidStack(drained2, filled2)
|
||||
if (!actuallyDrain && !actuallyFill) return FluidStack(drained2, filled2)
|
||||
|
||||
val drained3: FluidStack
|
||||
|
||||
@ -416,11 +410,49 @@ internal fun moveFluid(source: IFluidHandler, sourceTank: Int? = null, destinati
|
||||
drained3 = drained2
|
||||
}
|
||||
|
||||
val filled3 = destination.fill(drained3, IFluidHandler.FluidAction.EXECUTE)
|
||||
val filled3: Int
|
||||
|
||||
if (actuallyFill) {
|
||||
filled3 = destination.fill(drained3, IFluidHandler.FluidAction.EXECUTE)
|
||||
|
||||
if (filled3 != drained3.amount) {
|
||||
LOGGER.warn("Inconsistency of fluid insertion to $destination between simulate and execute modes (simulated $filled2; inserted $filled3); This can lead to duping!!!")
|
||||
}
|
||||
} else {
|
||||
filled3 = filled2
|
||||
}
|
||||
|
||||
return FluidStack(drained3, filled3)
|
||||
}
|
||||
|
||||
fun moveFluid(source: IFluidHandler, sourceTank: Int? = null, destination: IFluidHandler, limit: Int = Int.MAX_VALUE, actuallyDrain: Boolean = true, actuallyFill: Boolean = true): FluidStack {
|
||||
if (sourceTank == null) {
|
||||
for (drained in destination.iterator()) {
|
||||
if (drained.isNotEmpty) {
|
||||
val moved = actuallyMoveFluid(drained, source, destination, limit, actuallyDrain, actuallyFill)
|
||||
if (moved.isNotEmpty) return moved
|
||||
}
|
||||
}
|
||||
|
||||
for (drained in source.iterator()) {
|
||||
if (drained.isNotEmpty) {
|
||||
val moved = actuallyMoveFluid(drained, source, destination, limit, actuallyDrain, actuallyFill)
|
||||
if (moved.isNotEmpty) return moved
|
||||
}
|
||||
}
|
||||
|
||||
return FluidStack.EMPTY
|
||||
} else {
|
||||
return actuallyMoveFluid(source.drain(source.getFluidInTank(sourceTank), IFluidHandler.FluidAction.SIMULATE), source, destination, limit, actuallyDrain, actuallyFill)
|
||||
}
|
||||
}
|
||||
|
||||
val IFluidHandler.isEmpty: Boolean get() = stream().allMatch { it.isEmpty }
|
||||
val IFluidHandler.isNotEmpty: Boolean get() = stream().anyMatch { it.isNotEmpty }
|
||||
val IFluidHandler.isNotFull: Boolean get() {
|
||||
for ((i, fluid) in iterator().withIndex())
|
||||
if (fluid.isEmpty || fluid.amount < getTankCapacity(i))
|
||||
return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
package ru.dbotthepony.mc.otm.capability
|
||||
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import net.minecraft.network.chat.Component
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import java.util.function.Predicate
|
||||
|
||||
/**
|
||||
* Represents possible flow direction, both for matter and for energy
|
||||
* Represents possible flow direction, be it matter, energy, fluids, etc
|
||||
*
|
||||
* To dynamically get this enum by two booleans (by input and output states), use [FlowDirection.of]
|
||||
*
|
||||
@ -38,7 +40,7 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio
|
||||
BI_DIRECTIONAL(true, true, "otm.gui.side_mode.input_output"),
|
||||
|
||||
/**
|
||||
* Why would you want to use this
|
||||
* No flow possible
|
||||
*/
|
||||
NONE(false, false, "otm.gui.side_mode.disabled");
|
||||
|
||||
@ -62,6 +64,9 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio
|
||||
}.build()
|
||||
}
|
||||
|
||||
val translation: Component
|
||||
get() = TranslatableComponent(translationKey)
|
||||
|
||||
/**
|
||||
* Subtype test (returns true if we can assign [t] to this, e.g. we can assign [BI_DIRECTIONAL] to [INPUT])
|
||||
*/
|
||||
|
@ -0,0 +1,102 @@
|
||||
package ru.dbotthepony.mc.otm.capability.fluid
|
||||
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
|
||||
abstract class AbstractMatteryFluidHandler : IFluidHandler {
|
||||
abstract var fluid: FluidStack
|
||||
abstract val capacity: Int
|
||||
|
||||
val isEmpty: Boolean
|
||||
get() = fluid.isEmpty
|
||||
|
||||
val isNotEmpty: Boolean
|
||||
get() = fluid.isNotEmpty
|
||||
|
||||
val isNotFull: Boolean
|
||||
get() = fluid.isEmpty || fluid.amount < capacity
|
||||
|
||||
open val direction: FlowDirection
|
||||
get() = FlowDirection.BI_DIRECTIONAL
|
||||
|
||||
final override fun getTanks() = 1
|
||||
|
||||
final override fun getFluidInTank(tank: Int): FluidStack {
|
||||
require(tank == 0) { "Invalid tank: $tank" }
|
||||
return fluid.copy()
|
||||
}
|
||||
|
||||
final override fun getTankCapacity(tank: Int): Int {
|
||||
require(tank == 0) { "Invalid tank: $tank" }
|
||||
return capacity
|
||||
}
|
||||
|
||||
protected open fun isFluidValid(stack: FluidStack): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
final override fun isFluidValid(tank: Int, stack: FluidStack): Boolean {
|
||||
require(tank == 0) { "Invalid tank: $tank" }
|
||||
return isFluidValid(stack)
|
||||
}
|
||||
|
||||
final override fun fill(resource: FluidStack, action: IFluidHandler.FluidAction): Int {
|
||||
if (resource.isEmpty || !isFluidValid(resource) || !direction.input) {
|
||||
return 0
|
||||
}
|
||||
|
||||
val fluid = fluid
|
||||
|
||||
if (fluid.isEmpty || fluid.isFluidEqual(resource)) {
|
||||
val new = (fluid.amount + resource.amount).coerceAtMost(capacity)
|
||||
if (new <= fluid.amount) return 0
|
||||
|
||||
if (action.execute()) {
|
||||
this.fluid = FluidStack(resource, new)
|
||||
}
|
||||
|
||||
return new - fluid.amount
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
final override fun drain(resource: FluidStack, action: IFluidHandler.FluidAction): FluidStack {
|
||||
if (resource.isEmpty || !direction.output) {
|
||||
return FluidStack.EMPTY
|
||||
}
|
||||
|
||||
val fluid = fluid
|
||||
|
||||
if (!fluid.isEmpty && fluid.isFluidEqual(resource)) {
|
||||
return drain(resource.amount, action)
|
||||
} else {
|
||||
return FluidStack.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
final override fun drain(maxDrain: Int, action: IFluidHandler.FluidAction): FluidStack {
|
||||
require(maxDrain >= 0) { "Invalid amount to drain: $maxDrain" }
|
||||
if (maxDrain == 0 || !direction.output) return FluidStack.EMPTY
|
||||
|
||||
val fluid = fluid
|
||||
|
||||
if (fluid.isEmpty) {
|
||||
return FluidStack.EMPTY
|
||||
} else {
|
||||
val new = (fluid.amount - maxDrain).coerceAtLeast(0)
|
||||
|
||||
if (action.execute()) {
|
||||
if (new == 0) {
|
||||
this.fluid = FluidStack.EMPTY
|
||||
} else {
|
||||
this.fluid = FluidStack(fluid, new)
|
||||
}
|
||||
}
|
||||
|
||||
return FluidStack(fluid, fluid.amount - new)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package ru.dbotthepony.mc.otm.capability.fluid
|
||||
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.tagNotNull
|
||||
import java.util.function.IntSupplier
|
||||
|
||||
/**
|
||||
* Fluid handler for blocks
|
||||
*/
|
||||
class BlockMatteryFluidHandler(val onChanged: (new: FluidStack, old: FluidStack) -> Unit, private val _capacity: IntSupplier) : AbstractMatteryFluidHandler(), INBTSerializable<CompoundTag?> {
|
||||
override var fluid: FluidStack = FluidStack.EMPTY
|
||||
set(value) {
|
||||
val old = field
|
||||
field = value
|
||||
onChanged(value, old)
|
||||
}
|
||||
|
||||
override val capacity: Int
|
||||
get() = _capacity.asInt
|
||||
|
||||
override fun serializeNBT(): CompoundTag {
|
||||
return fluid.writeToNBT(CompoundTag())
|
||||
}
|
||||
|
||||
override fun deserializeNBT(nbt: CompoundTag?) {
|
||||
fluid = FluidStack.loadFluidStackFromNBT(nbt)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fluid handler for items representing block with [BlockMatteryFluidHandler]
|
||||
*/
|
||||
open class Item(itemStack: ItemStack, capacity: IntSupplier, private val nbtName: String) : ItemMatteryFluidHandler(itemStack, capacity) {
|
||||
override var fluid: FluidStack
|
||||
get() {
|
||||
val sub = itemStack.tag?.get(BlockItem.BLOCK_ENTITY_TAG) as? CompoundTag ?: return FluidStack.EMPTY
|
||||
return FluidStack.loadFluidStackFromNBT(sub[nbtName] as? CompoundTag ?: return FluidStack.EMPTY)
|
||||
}
|
||||
set(value) {
|
||||
var sub = itemStack.tagNotNull.get(BlockItem.BLOCK_ENTITY_TAG) as? CompoundTag
|
||||
|
||||
if (sub == null) {
|
||||
sub = CompoundTag()
|
||||
itemStack.tagNotNull[BlockItem.BLOCK_ENTITY_TAG] = sub
|
||||
}
|
||||
|
||||
sub[nbtName] = value.writeToNBT(CompoundTag())
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package ru.dbotthepony.mc.otm.capability.fluid
|
||||
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.common.capabilities.Capability
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.fluids.capability.IFluidHandlerItem
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.tagNotNull
|
||||
import java.util.function.IntSupplier
|
||||
|
||||
/**
|
||||
* Fluid handler for standalone items
|
||||
*/
|
||||
open class ItemMatteryFluidHandler(val itemStack: ItemStack, private val _capacity: IntSupplier) : AbstractMatteryFluidHandler(), IFluidHandlerItem, ICapabilityProvider {
|
||||
private val resolver = LazyOptional.of { this }
|
||||
|
||||
override var fluid: FluidStack
|
||||
get() { return FluidStack.loadFluidStackFromNBT(itemStack.tag?.get("fluid") as? CompoundTag ?: return FluidStack.EMPTY) }
|
||||
set(value) { itemStack.tagNotNull["fluid"] = value.writeToNBT(CompoundTag()) }
|
||||
|
||||
final override val capacity: Int
|
||||
get() = _capacity.asInt
|
||||
|
||||
final override fun getContainer(): ItemStack {
|
||||
return itemStack
|
||||
}
|
||||
|
||||
override fun <T : Any?> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
|
||||
if (cap === ForgeCapabilities.FLUID_HANDLER_ITEM || cap === ForgeCapabilities.FLUID_HANDLER) {
|
||||
return resolver.cast()
|
||||
}
|
||||
|
||||
return LazyOptional.empty()
|
||||
}
|
||||
}
|
@ -64,5 +64,11 @@ data class MatterySprite @JvmOverloads constructor(
|
||||
|
||||
override val type: SpriteType
|
||||
get() = SpriteType.SINGLE
|
||||
|
||||
companion object {
|
||||
fun single(texture: ResourceLocation, width: Float, height: Float, winding: UVWindingOrder = UVWindingOrder.NORMAL): MatterySprite {
|
||||
return MatterySprite(texture, 0f, 0f, width, height, width, height, winding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,44 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen.decorative
|
||||
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.DockResizeMode
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.PlayerEquipmentPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.makeCuriosPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.util.SpritePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.widget.FluidGaugePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu
|
||||
|
||||
class FluidTankScreen(menu: FluidTankMenu, inventory: Inventory, title: Component) : MatteryScreen<FluidTankMenu>(menu, inventory, title) {
|
||||
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
|
||||
val frame = super.makeMainFrame()!!
|
||||
|
||||
FluidGaugePanel(this, frame, menu.fluid, x = LEFT_MARGIN, y = GAUGE_TOP_WITHOUT_SLOT - 6f)
|
||||
|
||||
val s = SpritePanel(this, frame, ProgressGaugePanel.GAUGE_BACKGROUND, x = 30f, y = 30f)
|
||||
SpritePanel(this, frame, ProgressGaugePanel.GAUGE_BACKGROUND, x = 30f, y = 55f, winding = UVWindingOrder.FLOP)
|
||||
|
||||
SlotPanel(this, frame, menu.fillInput, x = 30f + s.width + 4f, y = 28f)
|
||||
SlotPanel(this, frame, menu.drainInput, x = 30f + s.width + 4f, y = 53f)
|
||||
|
||||
SlotPanel(this, frame, menu.output, x = 30f + s.width + 4f + 20f, y = 53f)
|
||||
|
||||
makeDeviceControls(this, frame, itemConfig = menu.itemConfig, redstoneConfig = menu.redstoneConfig)
|
||||
makeCuriosPanel(this, frame, menu.equipment.curiosSlots, autoAlign = true)
|
||||
|
||||
PlayerEquipmentPanel(this, frame, armorSlots = menu.equipment.armorSlots).also {
|
||||
it.leftSided = false
|
||||
it.dock = Dock.RIGHT
|
||||
it.dockResize = DockResizeMode.NONE
|
||||
}
|
||||
|
||||
return frame
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen.panels.util
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import ru.dbotthepony.mc.otm.client.render.AbstractMatterySprite
|
||||
import ru.dbotthepony.mc.otm.client.render.UVWindingOrder
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
|
||||
class SpritePanel<out S : Screen>(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
val sprite: AbstractMatterySprite,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
width: Float = sprite.width,
|
||||
height: Float = sprite.height,
|
||||
val winding: UVWindingOrder = sprite.winding
|
||||
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||
override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||
sprite.render(stack, 0f, 0f, width, height, winding)
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen.widget
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem
|
||||
import com.mojang.blaze3d.vertex.DefaultVertexFormat
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import com.mojang.blaze3d.vertex.VertexFormat
|
||||
import net.minecraft.client.gui.screens.Screen
|
||||
import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.resources.ResourceLocation
|
||||
import net.minecraft.world.inventory.InventoryMenu
|
||||
import net.minecraftforge.client.extensions.common.IClientFluidTypeExtensions
|
||||
import org.lwjgl.opengl.GL11
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.client.ShiftPressedCond
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.client.render.MatterySprite
|
||||
import ru.dbotthepony.mc.otm.client.render.tesselator
|
||||
import ru.dbotthepony.mc.otm.client.render.vertex
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.core.math.RGBAColor
|
||||
import ru.dbotthepony.mc.otm.core.math.linearInterpolation
|
||||
import ru.dbotthepony.mc.otm.core.util.formatFluidLevel
|
||||
import ru.dbotthepony.mc.otm.menu.widget.FluidGaugeWidget
|
||||
|
||||
open class FluidGaugePanel<out S : Screen>(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
val widget: FluidGaugeWidget,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f
|
||||
) : EditablePanel<S>(screen, parent, x, y, width = GAUGE.width, height = GAUGE.height) {
|
||||
init {
|
||||
scissor = true
|
||||
}
|
||||
|
||||
protected open fun makeTooltip(): MutableList<Component> {
|
||||
return mutableListOf(
|
||||
if (widget.fluid.isEmpty) TranslatableComponent("otm.gui.empty") else TextComponent(String.format("%s: %.2f%%", widget.fluid.displayName.string, widget.percentage * 100.0)),
|
||||
formatFluidLevel(if (widget.fluid.isEmpty) 0 else widget.fluid.amount, widget.maxCapacity, formatAsReadable = ShiftPressedCond)
|
||||
)
|
||||
}
|
||||
|
||||
override fun innerRenderTooltips(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float): Boolean {
|
||||
if (isHovered) {
|
||||
screen.renderComponentTooltip(stack, makeTooltip(), mouseX.toInt(), mouseY.toInt())
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||
if (widget.percentage > 0.01f && widget.fluid.isNotEmpty) {
|
||||
val data = IClientFluidTypeExtensions.of(widget.fluid.fluid)
|
||||
val texture = data.stillTexture!!
|
||||
val sprite = minecraft.getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(texture)!!
|
||||
val tint = RGBAColor.argb(data.getTintColor(widget.fluid))
|
||||
var height = (height * widget.percentage) / 16f
|
||||
var bottom = this.height
|
||||
|
||||
val matrix = stack.last().pose()
|
||||
val builder = tesselator.builder
|
||||
|
||||
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX)
|
||||
|
||||
while (height > 0.01f) {
|
||||
val thisHeight = height.coerceAtMost(1f)
|
||||
height -= thisHeight
|
||||
val actualHeight = thisHeight * 16f
|
||||
|
||||
val interp = linearInterpolation(thisHeight, sprite.v1, sprite.v0)
|
||||
|
||||
builder.vertex(matrix, 0f, bottom, 0f).uv(sprite.u0, sprite.v1).endVertex()
|
||||
builder.vertex(matrix, width, bottom, 0f).uv(sprite.u1, sprite.v1).endVertex()
|
||||
builder.vertex(matrix, width, bottom - actualHeight, 0f).uv(sprite.u1, interp).endVertex()
|
||||
builder.vertex(matrix, 0f, bottom - actualHeight, 0f).uv(sprite.u0, interp).endVertex()
|
||||
|
||||
bottom -= actualHeight
|
||||
}
|
||||
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
||||
RenderSystem.enableTexture()
|
||||
RenderSystem.enableBlend()
|
||||
RenderSystem.defaultBlendFunc()
|
||||
RenderSystem.depthFunc(GL11.GL_ALWAYS)
|
||||
|
||||
RenderSystem.setShaderColor(tint.red, tint.green, tint.blue, tint.alpha)
|
||||
RenderSystem.setShaderTexture(0, sprite.atlasLocation())
|
||||
|
||||
tesselator.end()
|
||||
|
||||
RenderSystem.setShaderColor(1f, 1f, 1f, 1f)
|
||||
RenderSystem.depthFunc(GL11.GL_LESS)
|
||||
}
|
||||
|
||||
GAUGE.render(stack, 0f, 0f, width = width, height = height)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val GAUGE = MatterySprite.single(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/fluid_level.png"), 18f, 61f)
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ import kotlin.math.cos
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
|
||||
open class MatterGaugePanel<S : Screen> @JvmOverloads constructor(
|
||||
open class MatterGaugePanel<out S : Screen> @JvmOverloads constructor(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
val widget: LevelGaugeWidget,
|
||||
|
@ -8,7 +8,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
|
||||
|
||||
open class PatternGaugePanel<S : Screen> @JvmOverloads constructor(
|
||||
open class PatternGaugePanel<out S : Screen> @JvmOverloads constructor(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
val widget: LevelGaugeWidget,
|
||||
|
@ -12,7 +12,7 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
open class ProgressGaugePanel<S : Screen> @JvmOverloads constructor(
|
||||
open class ProgressGaugePanel<out S : Screen> @JvmOverloads constructor(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>? = null,
|
||||
val widget: ProgressGaugeWidget,
|
||||
|
@ -96,5 +96,6 @@ object ItemsConfig : AbstractConfig("items") {
|
||||
builder.pop()
|
||||
}
|
||||
|
||||
val FLUID_CAPSULE_CAPACITY: Int by builder.defineInRange("LIQUID_CAPSULE_CAPACITY", 1000, 1, Int.MAX_VALUE)
|
||||
val FLUID_CAPSULE_CAPACITY: Int by builder.defineInRange("FLUID_CAPSULE_CAPACITY", 1000, 1, Int.MAX_VALUE)
|
||||
val FLUID_TANK_CAPACITY: Int by builder.defineInRange("FLUID_TANK_CAPACITY", 32_000, 1, Int.MAX_VALUE)
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import net.minecraftforge.fluids.capability.IFluidHandler
|
||||
|
||||
class FluidHandlerIterator(private val handler: IFluidHandler, initialPosition: Int = 0) : AbstractIndexBasedIterator<FluidStack>(0, initialPosition) {
|
||||
init {
|
||||
require(initialPosition in 0 .. handler.tanks) { "Invalid initial position: $initialPosition" }
|
||||
require(initialPosition in 0 until handler.tanks) { "Invalid initial position: $initialPosition" }
|
||||
}
|
||||
|
||||
override fun remove(location: Int) {
|
||||
|
@ -11,7 +11,8 @@ import java.util.stream.StreamSupport
|
||||
class FluidHandlerSpliterator(private val handler: IFluidHandler, offset: Int = 0, private val maxPos: Int = handler.tanks) : AbstractIndexBasedSpliterator<FluidStack>(offset) {
|
||||
init {
|
||||
require(offset in 0 until handler.tanks) { "Invalid offset $offset" }
|
||||
require(maxPos >= offset && maxPos in 0 until handler.tanks) { "Invalid spliterator configuration: maxPos $maxPos offset $offset max tanks ${handler.tanks}" }
|
||||
require(offset <= maxPos) { "offset <= maxPos: $offset > $maxPos!" }
|
||||
require(maxPos >= offset && maxPos in 0 .. handler.tanks) { "Invalid spliterator configuration: maxPos $maxPos offset $offset max tanks ${handler.tanks}" }
|
||||
}
|
||||
|
||||
override fun get(location: Int): FluidStack {
|
||||
|
@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.container
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.common.ForgeHooks
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
|
||||
interface HandlerFilter {
|
||||
fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||
@ -38,6 +40,38 @@ interface HandlerFilter {
|
||||
}
|
||||
}
|
||||
|
||||
object FluidContainers : HandlerFilter {
|
||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||
stack.getCapability(ForgeCapabilities.FLUID_HANDLER).ifPresentK {
|
||||
return it.tanks > 0
|
||||
}
|
||||
|
||||
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||
return it.tanks > 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
object DrainableFluidContainers : HandlerFilter {
|
||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||
stack.getCapability(ForgeCapabilities.FLUID_HANDLER).ifPresentK {
|
||||
return it.stream().anyMatch { it.isNotEmpty }
|
||||
}
|
||||
|
||||
stack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||
return it.stream().anyMatch { it.isNotEmpty }
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
|
||||
return !canInsert(slot, stack)
|
||||
}
|
||||
}
|
||||
|
||||
object OnlyIn : HandlerFilter {
|
||||
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
|
||||
return true
|
||||
|
@ -250,6 +250,9 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
return getMaxStackSize(slot)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Leftover [ItemStack]
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun addItem(stack: ItemStack, range: IntRange, simulate: Boolean = false, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack {
|
||||
if (range.last >= size || range.first < 0)
|
||||
@ -322,6 +325,25 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
return addItem(stack, 0 until size, simulate, onlyIntoExisting = onlyIntoExisting, popTime = popTime)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlike [addItem], modifies original [stack]
|
||||
*
|
||||
* @return Whenever [stack] was modified
|
||||
*/
|
||||
fun consumeItem(stack: ItemStack, simulate: Boolean, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean {
|
||||
val result = addItem(stack, 0 until size, simulate, onlyIntoExisting = onlyIntoExisting, popTime = popTime)
|
||||
|
||||
if (result.count != stack.count) {
|
||||
if (!simulate) {
|
||||
stack.count = result.count
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun fullyAddItem(stack: ItemStack, start: Int = 0, end: Int = size - 1): Boolean {
|
||||
return fullyAddItem(stack, start .. end)
|
||||
|
@ -28,6 +28,7 @@ import net.minecraft.world.level.block.state.properties.Property
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraftforge.common.ForgeHooks
|
||||
import net.minecraftforge.common.util.LazyOptional
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.items.IItemHandler
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import net.minecraftforge.registries.ForgeRegistry
|
||||
@ -87,6 +88,9 @@ inline fun <T> LazyOptional<T>.ifPresentK(lambda: (T) -> Unit) {
|
||||
|
||||
val ItemStack.tagNotNull: CompoundTag get() = orCreateTag
|
||||
|
||||
val FluidStack.isNotEmpty get() = !isEmpty
|
||||
val ItemStack.isNotEmpty get() = !isEmpty
|
||||
|
||||
inline var Entity.position: Vec3
|
||||
get() = position()
|
||||
set(value) { setPos(value) }
|
||||
|
@ -123,6 +123,14 @@ data class RGBAColor(val red: Float, val green: Float, val blue: Float, val alph
|
||||
val b = (color and 0xFF) / 255f
|
||||
return RGBAColor(r, g, b)
|
||||
}
|
||||
|
||||
fun argb(color: Int): RGBAColor {
|
||||
val a = (color and -0x1000000 ushr 24) / 255f
|
||||
val r = (color and 0xFF0000 ushr 16) / 255f
|
||||
val g = (color and 0xFF00 ushr 8) / 255f
|
||||
val b = (color and 0xFF) / 255f
|
||||
return RGBAColor(r, g, b, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.mojang.serialization.DataResult
|
||||
import com.mojang.serialization.DynamicOps
|
||||
import net.minecraft.nbt.NbtAccounter
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import ru.dbotthepony.mc.otm.core.immutableMap
|
||||
import ru.dbotthepony.mc.otm.core.math.readDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.writeDecimal
|
||||
@ -112,6 +113,7 @@ val LongValueCodec = StreamCodec(DataInputStream::readLong, 8L, DataOutputStream
|
||||
val FloatValueCodec = StreamCodec(DataInputStream::readFloat, 4L, DataOutputStream::writeFloat) { a, b -> a == b }
|
||||
val DoubleValueCodec = StreamCodec(DataInputStream::readDouble, 8L, DataOutputStream::writeDouble) { a, b -> a == b }
|
||||
val ItemStackValueCodec = StreamCodec(DataInputStream::readItem, DataOutputStream::writeItem, ItemStack::copy) { a, b -> a.equals(b, true) }
|
||||
val FluidStackValueCodec = StreamCodec(DataInputStream::readFluidStack, DataOutputStream::writeFluidStack, FluidStack::copy) { a, b -> a == b && a.amount == b.amount }
|
||||
val ItemValueCodec = StreamCodec(DataInputStream::readItemType, DataOutputStream::writeItemType) { a, b -> a === b }
|
||||
val DecimalValueCodec = StreamCodec(DataInputStream::readDecimal, DataOutputStream::writeDecimal)
|
||||
val BigDecimalValueCodec = StreamCodec(DataInputStream::readBigDecimal, DataOutputStream::writeBigDecimal)
|
||||
|
@ -7,7 +7,6 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.isNegative
|
||||
import ru.dbotthepony.mc.otm.core.math.isZero
|
||||
import java.math.BigDecimal
|
||||
import java.math.BigInteger
|
||||
import java.util.function.BooleanSupplier
|
||||
import kotlin.math.absoluteValue
|
||||
@ -61,28 +60,12 @@ fun BigInteger.formatReadableNumber(): String {
|
||||
return String(buffer)
|
||||
}
|
||||
|
||||
fun BigDecimal.determineSiPrefix(): SiPrefix? {
|
||||
if (isZero) return null
|
||||
val num = this.abs()
|
||||
|
||||
if (num >= BigDecimal.ONE) {
|
||||
return SiPrefix.MULTIPLIES.lastOrNull { it.decimal <= num }
|
||||
} else {
|
||||
return SiPrefix.DECIMALS.lastOrNull { it.decimal >= num }
|
||||
}
|
||||
}
|
||||
|
||||
fun BigInteger.determineSiPrefix(): SiPrefix? {
|
||||
if (isZero) return null
|
||||
val num = this.abs()
|
||||
return SiPrefix.MULTIPLIES.lastOrNull { it.integer!! <= num }
|
||||
}
|
||||
|
||||
fun BigInteger.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never): Component {
|
||||
require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" }
|
||||
val prefix = determineSiPrefix() ?: return concat(toString(decimalPlaces), suffix)
|
||||
val prefix = SiPrefix.determine(this)
|
||||
if (prefix.isEmpty) return concat(toString(decimalPlaces), suffix)
|
||||
val isNegative = isNegative
|
||||
val arr = (if (isNegative) -this else this).divideAndRemainder(prefix.integer)
|
||||
val arr = (if (isNegative) -this else this).divideAndRemainder(prefix.bigInteger)
|
||||
val divided = arr[0].toString()
|
||||
val remainder = arr[1].toString()
|
||||
|
||||
@ -116,41 +99,6 @@ fun BigInteger.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2, forma
|
||||
return TranslatableComponent(prefix.formatLocaleKey, String(buffer), suffix)
|
||||
}
|
||||
|
||||
fun Decimal.determineSiPrefix(): SiPrefix? {
|
||||
if (isZero) {
|
||||
return null
|
||||
}
|
||||
|
||||
val num = this.absoluteValue
|
||||
|
||||
if (num >= Decimal.ONE) {
|
||||
return SiPrefix.MULTIPLIES.lastOrNull { it.impreciseFraction <= num }
|
||||
} else {
|
||||
return SiPrefix.DECIMALS.lastOrNull { it.impreciseFraction >= num }
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.determineSiPrefix(): SiPrefix? {
|
||||
if (this == 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
val num = this.absoluteValue
|
||||
if (num <= 1) return null
|
||||
return SiPrefix.MULTIPLIES.lastOrNull { it.int != null && it.int <= num }
|
||||
}
|
||||
|
||||
fun Double.determineSiPrefix(): SiPrefix? {
|
||||
if (this == 0.0) return null
|
||||
val num = this.absoluteValue
|
||||
|
||||
if (num >= 1.0) {
|
||||
return SiPrefix.MULTIPLIES.lastOrNull { it.double <= num }
|
||||
} else {
|
||||
return SiPrefix.DECIMALS.lastOrNull { it.double >= num }
|
||||
}
|
||||
}
|
||||
|
||||
private val never = BooleanSupplier { false }
|
||||
|
||||
private fun reformat(numbers: String): String {
|
||||
@ -187,29 +135,46 @@ private fun reformat(numbers: String): String {
|
||||
})
|
||||
}
|
||||
|
||||
fun Int.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never): Component {
|
||||
fun Long.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never, bias: Int = 0): Component {
|
||||
require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" }
|
||||
if (formatAsReadable.asBoolean) return concat(reformat(toString()), suffix)
|
||||
val prefix = determineSiPrefix() ?: return concat(toString(), suffix)
|
||||
return TranslatableComponent(prefix.formatLocaleKey, "%.${decimalPlaces}f".format(this.toFloat() / prefix.int!!.toFloat()), suffix)
|
||||
if (formatAsReadable.asBoolean) {
|
||||
if (bias == 0) {
|
||||
return concat(reformat(toString()), suffix)
|
||||
} else {
|
||||
val prefix = SiPrefix.NONE.neighbour(bias)
|
||||
return TranslatableComponent(prefix.formatLocaleKey, reformat(toString()), suffix)
|
||||
}
|
||||
}
|
||||
|
||||
val prefix = SiPrefix.determine(this)
|
||||
|
||||
if (bias == 0) {
|
||||
return TranslatableComponent(prefix.formatLocaleKey, "%.${decimalPlaces}f".format(this.toDouble() / prefix.long!!.toDouble()), suffix)
|
||||
} else {
|
||||
return TranslatableComponent(SiPrefix.determine(this, bias).formatLocaleKey, "%.${decimalPlaces}f".format(this.toDouble() / prefix.long!!.toDouble()), suffix)
|
||||
}
|
||||
}
|
||||
|
||||
fun Int.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never, bias: Int = 0): Component {
|
||||
return toLong().formatSiComponent(suffix, decimalPlaces, formatAsReadable, bias)
|
||||
}
|
||||
|
||||
fun Double.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never): Component {
|
||||
require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" }
|
||||
if (formatAsReadable.asBoolean) return concat(reformat("%.${decimalPlaces}f".format(this)), suffix)
|
||||
val prefix = determineSiPrefix() ?: return concat("%.${decimalPlaces}f".format(this), suffix)
|
||||
val prefix = SiPrefix.determine(this)
|
||||
return TranslatableComponent(prefix.formatLocaleKey, "%.${decimalPlaces}f".format(this / prefix.double), suffix)
|
||||
}
|
||||
|
||||
fun Decimal.formatSiComponent(suffix: Any = "", decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never): Component {
|
||||
require(decimalPlaces >= 0) { "Invalid amount of decimal places required: $decimalPlaces" }
|
||||
if (formatAsReadable.asBoolean) return concat(reformat(toString(decimalPlaces)), suffix)
|
||||
val prefix = determineSiPrefix() ?: return concat(toString(decimalPlaces), suffix)
|
||||
return TranslatableComponent(prefix.formatLocaleKey, (this / prefix.impreciseFraction).toString(decimalPlaces), suffix)
|
||||
val prefix = SiPrefix.determine(this)
|
||||
return TranslatableComponent(prefix.formatLocaleKey, (this / prefix.decimal).toString(decimalPlaces), suffix)
|
||||
}
|
||||
|
||||
fun Int.formatPower(decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never) = formatSiComponent(TranslatableComponent("otm.gui.power.name"), decimalPlaces, formatAsReadable = formatAsReadable)
|
||||
fun Int.formatFluid(decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never) = formatSiComponent(TranslatableComponent("otm.gui.fluid.name"), decimalPlaces, formatAsReadable = formatAsReadable)
|
||||
fun Int.formatFluid(decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never) = formatSiComponent(TranslatableComponent("otm.gui.fluid.name"), decimalPlaces, formatAsReadable = formatAsReadable, bias = -1)
|
||||
fun Decimal.formatPower(decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never) = formatSiComponent(TranslatableComponent("otm.gui.power.name"), decimalPlaces, formatAsReadable = formatAsReadable)
|
||||
fun Decimal.formatMatter(decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never) = formatSiComponent(TranslatableComponent("otm.gui.matter.name"), decimalPlaces, formatAsReadable = formatAsReadable)
|
||||
fun Decimal.formatMatterFull(decimalPlaces: Int = 2, formatAsReadable: BooleanSupplier = never) = TranslatableComponent("otm.gui.matter.format", formatSiComponent(TranslatableComponent("otm.gui.matter.name"), decimalPlaces, formatAsReadable = formatAsReadable))
|
||||
|
@ -17,6 +17,8 @@ import net.minecraft.network.FriendlyByteBuf
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.material.Fluid
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import net.minecraftforge.registries.ForgeRegistry
|
||||
import java.io.*
|
||||
@ -87,6 +89,41 @@ fun InputStream.readItem(sizeLimit: NbtAccounter = NbtAccounter(1L shl 18 /* 256
|
||||
return itemStack
|
||||
}
|
||||
|
||||
fun OutputStream.writeFluidStack(value: FluidStack) {
|
||||
if (value.isEmpty) {
|
||||
write(0)
|
||||
} else {
|
||||
write(1)
|
||||
|
||||
val id = (ForgeRegistries.FLUIDS as ForgeRegistry<Fluid>).getID(value.fluid)
|
||||
writeVarIntLE(id)
|
||||
writeInt(value.amount)
|
||||
|
||||
if (value.hasTag()) {
|
||||
write(1)
|
||||
writeNbt(value.tag!!)
|
||||
} else {
|
||||
write(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun InputStream.readFluidStack(sizeLimit: NbtAccounter = NbtAccounter(1L shl 14 /* 16 KiB */)): FluidStack {
|
||||
if (read() == 0) {
|
||||
return FluidStack.EMPTY
|
||||
} else {
|
||||
val id = readVarIntLE()
|
||||
val fluid = (ForgeRegistries.FLUIDS as ForgeRegistry<Fluid>).getValue(id) ?: return FluidStack.EMPTY
|
||||
val amount = readInt()
|
||||
|
||||
if (read() > 0) {
|
||||
return FluidStack(fluid, amount, readNbt(sizeLimit))
|
||||
} else {
|
||||
return FluidStack(fluid, amount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun OutputStream.writeBigDecimal(value: BigDecimal) {
|
||||
writeInt(value.scale())
|
||||
val bytes = value.unscaledValue().toByteArray()
|
||||
|
@ -2,43 +2,53 @@ package ru.dbotthepony.mc.otm.core.util
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import java.math.BigDecimal
|
||||
import ru.dbotthepony.mc.otm.core.math.isZero
|
||||
import java.math.BigInteger
|
||||
import kotlin.math.absoluteValue
|
||||
|
||||
enum class SiPrefix(
|
||||
val power: Int,
|
||||
fractional: Boolean,
|
||||
val symbol: Char,
|
||||
) {
|
||||
// multiplies
|
||||
KILO (3, false, 'k'),
|
||||
MEGA (6, false, 'M'),
|
||||
GIGA (9, false, 'G'),
|
||||
TERA (12, false, 'T'),
|
||||
PETA (15, false, 'P'),
|
||||
EXA (18, false, 'E'),
|
||||
ZETTA(21, false, 'Z'),
|
||||
YOTTA(24, false, 'Y'),
|
||||
enum class SiPrefix(val power: Int, val symbol: String) {
|
||||
YOCTO(-8, "y"),
|
||||
ZEPTO(-7, "z"),
|
||||
ATTO (-6, "a"),
|
||||
FEMTO(-5, "f"),
|
||||
PICO (-4, "p"),
|
||||
NANO (-3, "n"),
|
||||
MICRO(-2, "μ"),
|
||||
MILLI(-1, "m"),
|
||||
|
||||
// decimals
|
||||
// DECI (1, true, 'd'),
|
||||
// CENTI(2, true, 'c'),
|
||||
MILLI(3, true, 'm'),
|
||||
MICRO(6, true, 'μ'),
|
||||
NANO (9, true, 'n'),
|
||||
PICO (12, true, 'p'),
|
||||
FEMTO(15, true, 'f'),
|
||||
ATTO (18, true, 'a'),
|
||||
ZEPTO(21, true, 'z'),
|
||||
YOCTO(24, true, 'y');
|
||||
NONE(0, "") {
|
||||
override val isEmpty: Boolean
|
||||
get() = true
|
||||
},
|
||||
|
||||
KILO (1, "k"),
|
||||
MEGA (2, "M"),
|
||||
GIGA (3, "G"),
|
||||
TERA (4, "T"),
|
||||
PETA (5, "P"),
|
||||
EXA (6, "E"),
|
||||
ZETTA(7, "Z"),
|
||||
YOTTA(8, "Y");
|
||||
|
||||
open val isEmpty: Boolean get() = false
|
||||
|
||||
val formatLocaleKey = "otm.suffix.${name.lowercase()}".intern()
|
||||
val rawLocaleKey = "otm.suffix_raw.${name.lowercase()}".intern()
|
||||
|
||||
val string = if (fractional) "0." + "0".repeat(power - 1) + "1" else "1" + "0".repeat(power)
|
||||
val string: String
|
||||
|
||||
init {
|
||||
if (power == 0) {
|
||||
string = "1"
|
||||
} else if (power < 0) {
|
||||
string = "0." + "0".repeat(power.absoluteValue * 3 - 1) + "1"
|
||||
} else {
|
||||
string = "1" + "0".repeat(power.absoluteValue * 3)
|
||||
}
|
||||
}
|
||||
|
||||
fun paddedIndex(input: String, index: Int): Char {
|
||||
val finalIndex = input.length - power + index
|
||||
val finalIndex = input.length - power.absoluteValue * 3 + index
|
||||
|
||||
if (finalIndex >= 0) {
|
||||
return input[finalIndex]
|
||||
@ -47,17 +57,35 @@ enum class SiPrefix(
|
||||
return '0'
|
||||
}
|
||||
|
||||
val decimal = BigDecimal(string)
|
||||
val impreciseFraction = Decimal(string)
|
||||
val integer = if (!fractional) BigInteger(string) else null
|
||||
val decimal = Decimal(string)
|
||||
val bigInteger = if (power >= 0) BigInteger(string) else null
|
||||
|
||||
val long = if (!fractional) string.toLongOrNull() else null
|
||||
val int = if (!fractional) string.toIntOrNull() else null
|
||||
val long = if (power >= 0) string.toLongOrNull() else null
|
||||
val double = string.toDouble()
|
||||
|
||||
fun neighbour(bias: Int): SiPrefix {
|
||||
if (bias == 0) {
|
||||
return this
|
||||
} else {
|
||||
val new = ordinal + bias
|
||||
|
||||
if (new < 0) {
|
||||
return YOCTO
|
||||
} else if (new >= VALUES.size) {
|
||||
return YOTTA
|
||||
} else {
|
||||
return VALUES[new]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val MULTIPLIES: List<SiPrefix> = ImmutableList.builder<SiPrefix>()
|
||||
val VALUES: ImmutableList<SiPrefix> = ImmutableList.copyOf(values())
|
||||
|
||||
@JvmField
|
||||
val MULTIPLIES: ImmutableList<SiPrefix> = ImmutableList.builder<SiPrefix>()
|
||||
.add(NONE)
|
||||
.add(KILO)
|
||||
.add(MEGA)
|
||||
.add(GIGA)
|
||||
@ -69,9 +97,8 @@ enum class SiPrefix(
|
||||
.build()
|
||||
|
||||
@JvmField
|
||||
val DECIMALS: List<SiPrefix> = ImmutableList.builder<SiPrefix>()
|
||||
//.add(DECI)
|
||||
//.add(CENTI)
|
||||
val DECIMALS: ImmutableList<SiPrefix> = ImmutableList.builder<SiPrefix>()
|
||||
.add(NONE)
|
||||
.add(MILLI)
|
||||
.add(MICRO)
|
||||
.add(NANO)
|
||||
@ -82,13 +109,46 @@ enum class SiPrefix(
|
||||
.add(YOCTO)
|
||||
.build()
|
||||
|
||||
@JvmField
|
||||
val DECIMALS_IMPRECISE: List<SiPrefix> = ImmutableList.builder<SiPrefix>()
|
||||
//.add(DECI)
|
||||
//.add(CENTI)
|
||||
.add(MILLI)
|
||||
.add(MICRO)
|
||||
.build()
|
||||
fun determine(value: Int, bias: Int = 0): SiPrefix {
|
||||
return determine(value.toLong(), bias)
|
||||
}
|
||||
|
||||
fun determine(value: Long, bias: Int = 0): SiPrefix {
|
||||
val num = value.absoluteValue
|
||||
if (num <= 1L) return NONE
|
||||
return MULTIPLIES.last { it.long != null && it.long <= num }.neighbour(bias)
|
||||
}
|
||||
|
||||
fun determine(value: Decimal, bias: Int = 0): SiPrefix {
|
||||
if (value.isZero) {
|
||||
return NONE
|
||||
}
|
||||
|
||||
val num = value.absoluteValue
|
||||
|
||||
if (num >= Decimal.ONE) {
|
||||
return (MULTIPLIES.lastOrNull { it.decimal <= num } ?: NONE).neighbour(bias)
|
||||
} else {
|
||||
return (DECIMALS.lastOrNull { it.decimal >= num } ?: NONE).neighbour(bias)
|
||||
}
|
||||
}
|
||||
|
||||
fun determine(value: Double, bias: Int = 0): SiPrefix {
|
||||
if (value == 0.0) return NONE
|
||||
val num = value.absoluteValue
|
||||
|
||||
if (num >= 1.0) {
|
||||
return (MULTIPLIES.lastOrNull { it.double <= num } ?: NONE).neighbour(bias)
|
||||
} else {
|
||||
return (DECIMALS.lastOrNull { it.double >= num } ?: NONE).neighbour(bias)
|
||||
}
|
||||
}
|
||||
|
||||
fun determine(value: BigInteger, bias: Int = 0): SiPrefix {
|
||||
if (value.isZero) return NONE
|
||||
val num = value.abs()
|
||||
return (MULTIPLIES.lastOrNull { it.bigInteger!! <= num } ?: NONE).neighbour(bias)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
import com.google.gson.JsonSerializationContext
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.level.storage.loot.LootContext
|
||||
import net.minecraft.world.level.storage.loot.Serializer
|
||||
@ -31,7 +32,7 @@ class CopyTileNbtFunction(filter: Stream<out String> = Stream.empty()) : LootIte
|
||||
|
||||
override fun apply(t: ItemStack, u: LootContext): ItemStack {
|
||||
val blockEntity = u.getParamOrNull(LootContextParams.BLOCK_ENTITY) ?: return t
|
||||
val result = t.tagNotNull["BlockEntityTag"] as? CompoundTag
|
||||
val result = t.tagNotNull[BlockItem.BLOCK_ENTITY_TAG] as? CompoundTag
|
||||
|
||||
val data = blockEntity.saveWithoutMetadata()
|
||||
|
||||
@ -40,7 +41,7 @@ class CopyTileNbtFunction(filter: Stream<out String> = Stream.empty()) : LootIte
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
t.tagNotNull["BlockEntityTag"] = data
|
||||
t.tagNotNull[BlockItem.BLOCK_ENTITY_TAG] = data
|
||||
} else {
|
||||
for (k in data.allKeys) {
|
||||
result[k] = data[k]!!
|
||||
|
@ -26,7 +26,7 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||
import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack
|
||||
import ru.dbotthepony.mc.otm.capability.fluid.ItemMatteryFluidHandler
|
||||
import ru.dbotthepony.mc.otm.capability.fluidLevel
|
||||
import ru.dbotthepony.mc.otm.capability.moveFluid
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
@ -36,30 +36,9 @@ import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
import ru.dbotthepony.mc.otm.core.immutableMap
|
||||
import ru.dbotthepony.mc.otm.core.orNull
|
||||
import java.util.function.IntSupplier
|
||||
|
||||
class FluidCapsuleItem(val capacity: () -> Int) : Item(Properties().stacksTo(64)) {
|
||||
private inner class Cap(itemStack: ItemStack) : FluidHandlerItemStack(itemStack, capacity.invoke()) {
|
||||
override fun fill(resource: FluidStack, doFill: IFluidHandler.FluidAction): Int {
|
||||
this.capacity = this@FluidCapsuleItem.capacity.invoke()
|
||||
return super.fill(resource, doFill)
|
||||
}
|
||||
|
||||
override fun getTankCapacity(tank: Int): Int {
|
||||
this.capacity = this@FluidCapsuleItem.capacity.invoke()
|
||||
return super.getTankCapacity(tank)
|
||||
}
|
||||
|
||||
override fun drain(resource: FluidStack?, action: IFluidHandler.FluidAction?): FluidStack {
|
||||
this.capacity = this@FluidCapsuleItem.capacity.invoke()
|
||||
return super.drain(resource, action)
|
||||
}
|
||||
|
||||
override fun drain(maxDrain: Int, action: IFluidHandler.FluidAction?): FluidStack {
|
||||
this.capacity = this@FluidCapsuleItem.capacity.invoke()
|
||||
return super.drain(maxDrain, action)
|
||||
}
|
||||
}
|
||||
|
||||
class FluidCapsuleItem(val capacity: IntSupplier) : Item(Properties().stacksTo(64)) {
|
||||
// TODO: Так как использование предмета заблокировано за player.abilities.canBuild
|
||||
// капсулу нельзя использовать в режиме приключения
|
||||
// почему же можно использовать вёдра на котлах?
|
||||
@ -89,12 +68,12 @@ class FluidCapsuleItem(val capacity: () -> Int) : Item(Properties().stacksTo(64)
|
||||
super.appendHoverText(pStack, pLevel, pTooltipComponents, pIsAdvanced)
|
||||
|
||||
pStack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||
fluidLevel(it, pTooltipComponents)
|
||||
it.fluidLevel(pTooltipComponents)
|
||||
}
|
||||
}
|
||||
|
||||
override fun initCapabilities(stack: ItemStack, nbt: CompoundTag?): ICapabilityProvider {
|
||||
return Cap(stack)
|
||||
return ItemMatteryFluidHandler(stack, capacity)
|
||||
}
|
||||
|
||||
interface Interaction {
|
||||
@ -206,7 +185,7 @@ class FluidCapsuleItem(val capacity: () -> Int) : Item(Properties().stacksTo(64)
|
||||
|
||||
if (fluid.isEmpty || player.isCrouching) {
|
||||
// заполняем из блока
|
||||
val moveResult = moveFluid(source = blockCap, destination = itemCap, simulate = player.level.isClientSide)
|
||||
val moveResult = moveFluid(source = blockCap, destination = itemCap, actuallyDrain = !player.level.isClientSide, actuallyFill = !player.level.isClientSide)
|
||||
|
||||
if (!moveResult.isEmpty) {
|
||||
val sound = moveResult.fluid.fluidType.getSound(moveResult, SoundActions.BUCKET_FILL)
|
||||
@ -228,7 +207,7 @@ class FluidCapsuleItem(val capacity: () -> Int) : Item(Properties().stacksTo(64)
|
||||
return InteractionResult.FAIL
|
||||
}
|
||||
} else {
|
||||
val moveResult = moveFluid(source = itemCap, destination = blockCap, simulate = player.level.isClientSide)
|
||||
val moveResult = moveFluid(source = itemCap, destination = blockCap, actuallyDrain = !player.level.isClientSide, actuallyFill = !player.level.isClientSide)
|
||||
|
||||
if (!moveResult.isEmpty) {
|
||||
val sound = moveResult.fluid.fluidType.getSound(moveResult, SoundActions.BUCKET_EMPTY)
|
||||
|
57
src/main/kotlin/ru/dbotthepony/mc/otm/item/FluidTankItem.kt
Normal file
57
src/main/kotlin/ru/dbotthepony/mc/otm/item/FluidTankItem.kt
Normal file
@ -0,0 +1,57 @@
|
||||
package ru.dbotthepony.mc.otm.item
|
||||
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.InteractionResult
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.TooltipFlag
|
||||
import net.minecraft.world.item.context.UseOnContext
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider
|
||||
import ru.dbotthepony.mc.otm.block.decorative.FluidTankBlock
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.fluid.BlockMatteryFluidHandler
|
||||
import ru.dbotthepony.mc.otm.capability.fluidLevel
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import java.util.function.IntSupplier
|
||||
|
||||
class FluidTankItem(block: FluidTankBlock, properties: Properties, val capacity: IntSupplier) : BlockItem(block, properties) {
|
||||
override fun initCapabilities(stack: ItemStack, nbt: CompoundTag?): ICapabilityProvider {
|
||||
return BlockMatteryFluidHandler.Item(stack, capacity, FluidTankBlockEntity.FLUID_KEY)
|
||||
}
|
||||
|
||||
override fun onItemUseFirst(stack: ItemStack, pContext: UseOnContext): InteractionResult {
|
||||
if (pContext.player?.isCrouching == true)
|
||||
return InteractionResult.PASS
|
||||
|
||||
val context = FluidCapsuleItem.Context(pContext.clickedPos, pContext.level.getBlockState(pContext.clickedPos), pContext.clickedFace)
|
||||
|
||||
if (FluidCapsuleItem.canInteract(pContext.itemInHand, pContext.player ?: return InteractionResult.FAIL, context))
|
||||
return FluidCapsuleItem.interact(pContext.itemInHand, pContext.player!!, context)
|
||||
|
||||
return super.onItemUseFirst(stack, pContext)
|
||||
}
|
||||
|
||||
override fun getName(pStack: ItemStack): Component {
|
||||
pStack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||
it.getFluidInTank(0).also {
|
||||
if (!it.isEmpty) {
|
||||
return TranslatableComponent("$descriptionId.named", it.displayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.getName(pStack)
|
||||
}
|
||||
|
||||
override fun appendHoverText(pStack: ItemStack, pLevel: Level?, pTooltip: MutableList<Component>, pFlag: TooltipFlag) {
|
||||
super.appendHoverText(pStack, pLevel, pTooltip, pFlag)
|
||||
|
||||
pStack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||
it.fluidLevel(pTooltip)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package ru.dbotthepony.mc.otm.menu.decorative
|
||||
|
||||
import net.minecraft.world.SimpleContainer
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
|
||||
import ru.dbotthepony.mc.otm.capability.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.capability.isNotFull
|
||||
import ru.dbotthepony.mc.otm.menu.MachineOutputSlot
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
||||
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
|
||||
import ru.dbotthepony.mc.otm.menu.widget.FluidGaugeWidget
|
||||
import ru.dbotthepony.mc.otm.registry.MMenus
|
||||
|
||||
class FluidTankMenu(containerId: Int, inventory: Inventory, tile: FluidTankBlockEntity? = null) : MatteryMenu(MMenus.FLUID_TANK, containerId, inventory, tile) {
|
||||
val fluid = FluidGaugeWidget(mSynchronizer, tile?.fluid)
|
||||
val equipment = makeEquipmentSlots(true)
|
||||
val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig)
|
||||
val redstoneConfig = EnumInputWithFeedback<RedstoneSetting>(this)
|
||||
|
||||
val drainInput = object : MatterySlot(tile?.drainInput ?: SimpleContainer(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return super.mayPlace(itemStack) && itemStack.getCapability(ForgeCapabilities.FLUID_HANDLER)
|
||||
.map { it.isNotEmpty }
|
||||
.orElse(itemStack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM)
|
||||
.map { it.isNotEmpty }
|
||||
.orElse(false))
|
||||
}
|
||||
}
|
||||
|
||||
val fillInput = object : MatterySlot(tile?.fillInput ?: SimpleContainer(1), 0) {
|
||||
override fun mayPlace(itemStack: ItemStack): Boolean {
|
||||
return super.mayPlace(itemStack) && itemStack.getCapability(ForgeCapabilities.FLUID_HANDLER)
|
||||
.map { it.fill(fluid.fluid, IFluidHandler.FluidAction.SIMULATE) > 0 }
|
||||
.orElse(itemStack.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM)
|
||||
.map { it.fill(fluid.fluid, IFluidHandler.FluidAction.SIMULATE) > 0 }
|
||||
.orElse(false))
|
||||
}
|
||||
}
|
||||
|
||||
val output = MachineOutputSlot(tile?.output ?: SimpleContainer(1), 0)
|
||||
|
||||
init {
|
||||
// сначала слот на заполнение из бака
|
||||
addStorageSlot(fillInput)
|
||||
addStorageSlot(drainInput)
|
||||
addStorageSlot(output)
|
||||
addInventorySlots()
|
||||
|
||||
if (tile != null) {
|
||||
redstoneConfig.with(tile.redstoneControl::redstoneSetting)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package ru.dbotthepony.mc.otm.menu.widget
|
||||
|
||||
import net.minecraftforge.fluids.FluidStack
|
||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||
import ru.dbotthepony.mc.otm.container.get
|
||||
import ru.dbotthepony.mc.otm.core.util.FluidStackValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
|
||||
import java.util.function.IntSupplier
|
||||
import java.util.function.Supplier
|
||||
|
||||
class FluidGaugeWidget(synchronizer: FieldSynchronizer) {
|
||||
constructor(menu: MatteryMenu) : this(menu.mSynchronizer)
|
||||
|
||||
var maxCapacitySupplier = IntSupplier { 0 }
|
||||
var fluidSupplier = Supplier { FluidStack.EMPTY!! }
|
||||
|
||||
val maxCapacity by synchronizer.ComputedIntField({ maxCapacitySupplier.asInt })
|
||||
val fluid by synchronizer.ComputedField({ fluidSupplier.get() }, FluidStackValueCodec)
|
||||
|
||||
val percentage: Float get() {
|
||||
if (maxCapacity <= 0 || fluid.isEmpty) {
|
||||
return 0f
|
||||
}
|
||||
|
||||
return (fluid.amount.toFloat() / maxCapacity.toFloat()).coerceIn(0f, 1f)
|
||||
}
|
||||
|
||||
constructor(synchronizer: FieldSynchronizer, fluid: IFluidHandler?, tank: Int = 0) : this(synchronizer) {
|
||||
if (fluid != null) {
|
||||
with(fluid, tank)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(menu: MatteryMenu, fluid: IFluidHandler?, tank: Int = 0) : this(menu) {
|
||||
if (fluid != null) {
|
||||
with(fluid, tank)
|
||||
}
|
||||
}
|
||||
|
||||
fun with(fluid: IFluidHandler, tank: Int = 0): FluidGaugeWidget {
|
||||
maxCapacitySupplier = IntSupplier { fluid.getTankCapacity(tank) }
|
||||
fluidSupplier = Supplier { fluid[tank] }
|
||||
return this
|
||||
}
|
||||
}
|
@ -6,19 +6,22 @@ import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.util.DecimalValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
|
||||
|
||||
@Suppress("unused")
|
||||
class LevelGaugeWidget(menu: MatteryMenu) {
|
||||
class LevelGaugeWidget(synchronizer: FieldSynchronizer) {
|
||||
constructor(menu: MatteryMenu) : this(menu.mSynchronizer)
|
||||
|
||||
var levelProvider = { Decimal.ONE }
|
||||
var maxLevelProvider = { Decimal.ONE }
|
||||
|
||||
val level by menu.mSynchronizer.ComputedField(getter = { levelProvider.invoke() }, codec = DecimalValueCodec)
|
||||
val maxLevel by menu.mSynchronizer.ComputedField(getter = { maxLevelProvider.invoke() }, codec = DecimalValueCodec)
|
||||
val level by synchronizer.ComputedField(getter = { levelProvider.invoke() }, codec = DecimalValueCodec)
|
||||
val maxLevel by synchronizer.ComputedField(getter = { maxLevelProvider.invoke() }, codec = DecimalValueCodec)
|
||||
|
||||
constructor(
|
||||
menu: MatteryMenu,
|
||||
power: IMatteryEnergyStorage?
|
||||
) : this(menu) {
|
||||
) : this(menu.mSynchronizer) {
|
||||
if (power != null) {
|
||||
with(power)
|
||||
}
|
||||
@ -27,7 +30,7 @@ class LevelGaugeWidget(menu: MatteryMenu) {
|
||||
constructor(
|
||||
menu: MatteryMenu,
|
||||
matter: IMatterStorage?
|
||||
) : this(menu) {
|
||||
) : this(menu.mSynchronizer) {
|
||||
if (matter != null) {
|
||||
with(matter)
|
||||
}
|
||||
@ -36,7 +39,7 @@ class LevelGaugeWidget(menu: MatteryMenu) {
|
||||
constructor(
|
||||
menu: MatteryMenu,
|
||||
patterns: IPatternStorage?
|
||||
) : this(menu) {
|
||||
) : this(menu.mSynchronizer) {
|
||||
if (patterns != null) {
|
||||
with(patterns)
|
||||
}
|
||||
@ -46,7 +49,43 @@ class LevelGaugeWidget(menu: MatteryMenu) {
|
||||
menu: MatteryMenu,
|
||||
level: () -> Decimal,
|
||||
maxLevel: () -> Decimal,
|
||||
) : this(menu) {
|
||||
) : this(menu.mSynchronizer) {
|
||||
this.levelProvider = level
|
||||
this.maxLevelProvider = maxLevel
|
||||
}
|
||||
|
||||
constructor(
|
||||
synchronizer: FieldSynchronizer,
|
||||
power: IMatteryEnergyStorage?
|
||||
) : this(synchronizer) {
|
||||
if (power != null) {
|
||||
with(power)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
synchronizer: FieldSynchronizer,
|
||||
matter: IMatterStorage?
|
||||
) : this(synchronizer) {
|
||||
if (matter != null) {
|
||||
with(matter)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
synchronizer: FieldSynchronizer,
|
||||
patterns: IPatternStorage?
|
||||
) : this(synchronizer) {
|
||||
if (patterns != null) {
|
||||
with(patterns)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
synchronizer: FieldSynchronizer,
|
||||
level: () -> Decimal,
|
||||
maxLevel: () -> Decimal,
|
||||
) : this(synchronizer) {
|
||||
this.levelProvider = level
|
||||
this.maxLevelProvider = maxLevel
|
||||
}
|
||||
|
@ -3,15 +3,18 @@ package ru.dbotthepony.mc.otm.menu.widget
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity
|
||||
import ru.dbotthepony.mc.otm.core.FloatSupplier
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
|
||||
import java.util.function.BooleanSupplier
|
||||
|
||||
@Suppress("unused")
|
||||
class ProgressGaugeWidget(menu: MatteryMenu) {
|
||||
class ProgressGaugeWidget(synchronizer: FieldSynchronizer) {
|
||||
constructor(menu: MatteryMenu) : this(menu.mSynchronizer)
|
||||
|
||||
var progressSupplier: FloatSupplier = FloatSupplier { 0f }
|
||||
var stuckSupplier: BooleanSupplier = BooleanSupplier { false }
|
||||
|
||||
val percentage by menu.mSynchronizer.ComputedFloatField(getter = { progressSupplier.getAsFloat() })
|
||||
val isStuck by menu.mSynchronizer.ComputedBooleanField(getter = { stuckSupplier.asBoolean })
|
||||
val percentage by synchronizer.ComputedFloatField(getter = { progressSupplier.getAsFloat() })
|
||||
val isStuck by synchronizer.ComputedBooleanField(getter = { stuckSupplier.asBoolean })
|
||||
|
||||
constructor(
|
||||
menu: MatteryMenu,
|
||||
@ -29,6 +32,22 @@ class ProgressGaugeWidget(menu: MatteryMenu) {
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
synchronizer: FieldSynchronizer,
|
||||
progress: FloatSupplier
|
||||
) : this(synchronizer) {
|
||||
this.progressSupplier = progress
|
||||
}
|
||||
|
||||
constructor(
|
||||
synchronizer: FieldSynchronizer,
|
||||
blockEntity: MatteryWorkerBlockEntity<*>?
|
||||
) : this(synchronizer) {
|
||||
if (blockEntity != null) {
|
||||
with(blockEntity)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
menu: MatteryMenu,
|
||||
progress: FloatSupplier,
|
||||
|
@ -104,6 +104,20 @@ private fun CreativeModeTab.Output.mattery(values: Iterable<Item>) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun CreativeModeTab.Output.fluids(value: Item) {
|
||||
accept(value)
|
||||
|
||||
for (fluid in ForgeRegistries.FLUIDS.values) {
|
||||
if (fluid != Fluids.EMPTY && fluid.isSource(fluid.defaultFluidState())) {
|
||||
accept(ItemStack(value, 1).also {
|
||||
it.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||
it.fill(FluidStack(fluid, it.getTankCapacity(0)), IFluidHandler.FluidAction.EXECUTE)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
|
||||
with(consumer) {
|
||||
accept(MItems.MACHINES)
|
||||
@ -147,17 +161,8 @@ internal fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) {
|
||||
accept(MItems.PATTERN_DRIVE_CREATIVE)
|
||||
accept(MItems.PATTERN_DRIVE_CREATIVE2)
|
||||
|
||||
accept(MItems.FLUID_CAPSULE)
|
||||
|
||||
for (fluid in ForgeRegistries.FLUIDS.values) {
|
||||
if (fluid != Fluids.EMPTY && fluid.isSource(fluid.defaultFluidState())) {
|
||||
accept(ItemStack(MItems.FLUID_CAPSULE, 1).also {
|
||||
it.getCapability(ForgeCapabilities.FLUID_HANDLER_ITEM).ifPresentK {
|
||||
it.fill(FluidStack(fluid, it.getTankCapacity(0)), IFluidHandler.FluidAction.EXECUTE)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
fluids(MItems.FLUID_CAPSULE)
|
||||
fluids(MItems.FLUID_TANK)
|
||||
|
||||
base(MItems.CARGO_CRATE_MINECARTS)
|
||||
|
||||
|
@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntityExplosionDebugger
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntitySphereDebugger
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.HoloSignBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.matter.*
|
||||
import ru.dbotthepony.mc.otm.block.entity.storage.*
|
||||
@ -58,6 +59,7 @@ object MBlockEntities {
|
||||
val COBBLESTONE_GENERATOR: BlockEntityType<CobblerBlockEntity> by registry.register(MNames.COBBLESTONE_GENERATOR) { BlockEntityType.Builder.of(::CobblerBlockEntity, MBlocks.COBBLESTONE_GENERATOR).build(null) }
|
||||
val ESSENCE_STORAGE: BlockEntityType<EssenceStorageBlockEntity> by registry.register(MNames.ESSENCE_STORAGE) { BlockEntityType.Builder.of(::EssenceStorageBlockEntity, MBlocks.ESSENCE_STORAGE).build(null) }
|
||||
val MATTER_RECONSTRUCTOR: BlockEntityType<MatterReconstructorBlockEntity> by registry.register(MNames.MATTER_RECONSTRUCTOR) { BlockEntityType.Builder.of(::MatterReconstructorBlockEntity, MBlocks.MATTER_RECONSTRUCTOR).build(null) }
|
||||
val FLUID_TANK: BlockEntityType<FluidTankBlockEntity> by registry.register(MNames.FLUID_TANK) { BlockEntityType.Builder.of(::FluidTankBlockEntity, MBlocks.FLUID_TANK).build(null) }
|
||||
|
||||
val STORAGE_BUS: BlockEntityType<StorageBusBlockEntity> by registry.register(MNames.STORAGE_BUS) { BlockEntityType.Builder.of(::StorageBusBlockEntity, MBlocks.STORAGE_BUS).build(null) }
|
||||
val STORAGE_IMPORTER: BlockEntityType<StorageImporterBlockEntity> by registry.register(MNames.STORAGE_IMPORTER) { BlockEntityType.Builder.of(::StorageImporterBlockEntity, MBlocks.STORAGE_IMPORTER).build(null) }
|
||||
|
@ -46,6 +46,7 @@ import ru.dbotthepony.mc.otm.block.tech.PhantomAttractorBlock
|
||||
import ru.dbotthepony.mc.otm.block.tech.PlatePressBlock
|
||||
import ru.dbotthepony.mc.otm.block.StorageCableBlock
|
||||
import ru.dbotthepony.mc.otm.block.decorative.EngineBlock
|
||||
import ru.dbotthepony.mc.otm.block.decorative.FluidTankBlock
|
||||
import ru.dbotthepony.mc.otm.block.decorative.HoloSignBlock
|
||||
import ru.dbotthepony.mc.otm.block.matter.MatterReconstructorBlock
|
||||
import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock
|
||||
@ -112,6 +113,7 @@ object MBlocks {
|
||||
val GRAVITATION_STABILIZER_LENS: Block by registry.register(MNames.GRAVITATION_STABILIZER_LENS) { BlockGravitationStabilizerLens() }
|
||||
|
||||
val PHANTOM_ATTRACTOR: Block by registry.register(MNames.PHANTOM_ATTRACTOR) { PhantomAttractorBlock() }
|
||||
val FLUID_TANK: FluidTankBlock by registry.register(MNames.FLUID_TANK) { FluidTankBlock() }
|
||||
|
||||
val TRITANIUM_ORE: Block by registry.register(MNames.TRITANIUM_ORE) { DropExperienceBlock(
|
||||
BlockBehaviour.Properties.of(Material.STONE)
|
||||
|
@ -156,6 +156,7 @@ object MItems {
|
||||
val ESSENCE_DRIVE: EssenceCapsuleItem by registry.register("essence_drive") { EssenceCapsuleItem() }
|
||||
|
||||
val FLUID_CAPSULE: FluidCapsuleItem by registry.register("fluid_capsule") { FluidCapsuleItem(ItemsConfig::FLUID_CAPSULE_CAPACITY) }
|
||||
val FLUID_TANK: FluidTankItem by registry.register(MNames.FLUID_TANK) { FluidTankItem(MBlocks.FLUID_TANK, Item.Properties().stacksTo(1), ItemsConfig::FLUID_TANK_CAPACITY) }
|
||||
|
||||
val TRITANIUM_COMPONENT: ForgeTier = ForgeTier(
|
||||
Tiers.IRON.level,
|
||||
|
@ -8,6 +8,7 @@ import net.minecraftforge.registries.DeferredRegister
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.client.screen.decorative.CargoCrateScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.decorative.FluidTankScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.decorative.HoloSignScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.decorative.MinecartCargoCrateScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.matter.MatterReconstructorScreen
|
||||
@ -35,6 +36,7 @@ import ru.dbotthepony.mc.otm.client.screen.tech.EnergyServoScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.tech.EssenceStorageScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.tech.PlatePressScreen
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.HoloSignMenu
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.MinecartCargoCrateMenu
|
||||
import ru.dbotthepony.mc.otm.menu.matter.MatterReconstructorMenu
|
||||
@ -88,6 +90,7 @@ object MMenus {
|
||||
val COBBLESTONE_GENERATOR: MenuType<CobblerMenu> by registry.register(MNames.COBBLESTONE_GENERATOR) { MenuType(::CobblerMenu) }
|
||||
val ESSENCE_STORAGE: MenuType<EssenceStorageMenu> by registry.register(MNames.ESSENCE_STORAGE) { MenuType(::EssenceStorageMenu) }
|
||||
val ITEM_REPAIER: MenuType<MatterReconstructorMenu> by registry.register(MNames.MATTER_RECONSTRUCTOR) { MenuType(::MatterReconstructorMenu) }
|
||||
val FLUID_TANK: MenuType<FluidTankMenu> by registry.register(MNames.FLUID_TANK) { MenuType(::FluidTankMenu) }
|
||||
|
||||
val STORAGE_BUS: MenuType<*> by registry.register(MNames.STORAGE_BUS) { MenuType(::StorageBusMenu) }
|
||||
val STORAGE_EXPORTER: MenuType<*> by registry.register(MNames.STORAGE_EXPORTER) { MenuType(::StorageExporterMenu) }
|
||||
@ -129,6 +132,7 @@ object MMenus {
|
||||
MenuScreens.register(COBBLESTONE_GENERATOR, ::CobblerScreen)
|
||||
MenuScreens.register(ESSENCE_STORAGE, ::EssenceStorageScreen)
|
||||
MenuScreens.register(ITEM_REPAIER, ::MatterReconstructorScreen)
|
||||
MenuScreens.register(FLUID_TANK, ::FluidTankScreen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ object MNames {
|
||||
const val METAL_BEAM = "metal_beam"
|
||||
const val ENGINE = "engine"
|
||||
const val HOLO_SIGN = "holo_sign"
|
||||
const val FLUID_TANK = "fluid_tank"
|
||||
|
||||
// blocks
|
||||
const val ANDROID_STATION = "android_station"
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 617 B |
Binary file not shown.
Loading…
Reference in New Issue
Block a user