Item repairer block

This commit is contained in:
DBotThePony 2023-03-22 23:48:23 +07:00
parent aa31ff4cce
commit e3993f439e
Signed by: DBot
GPG Key ID: DCC23B5715498507
22 changed files with 621 additions and 116 deletions

View File

@ -365,6 +365,8 @@ private fun blocks(provider: MatteryLanguageProvider) {
add(MBlocks.COBBLESTONE_GENERATOR, "Cobblestone Generator")
add(MBlocks.ESSENCE_STORAGE, "Essence Storage")
add(MBlocks.ESSENCE_STORAGE, "desc", "Allows to store and retrieve experience levels")
add(MBlocks.ITEM_REPAIRER, "Matter Reconstructor")
add(MBlocks.ITEM_REPAIRER, "desc", "Repairs tools using matter")
add(MBlocks.ENGINE, "Ship Engine")
add(MBlocks.HOLO_SIGN, "Holo Sign")

View File

@ -372,6 +372,8 @@ private fun blocks(provider: MatteryLanguageProvider) {
add(MBlocks.COBBLESTONE_GENERATOR, "Генератор булыжника")
add(MBlocks.ESSENCE_STORAGE, "Хранилище эссенции")
add(MBlocks.ESSENCE_STORAGE, "desc", "Позволяет хранить очки опыта")
add(MBlocks.ITEM_REPAIRER, "Материальный реконструктор")
add(MBlocks.ITEM_REPAIRER, "desc", "Чинит инструменты используя материю")
add(MBlocks.ENGINE, "Двигатель корабля")
add(MBlocks.HOLO_SIGN, "Голографическая табличка")

View File

@ -137,6 +137,7 @@ fun addLootTables(lootTables: LootTables) {
lootTables.tile(MBlocks.COBBLESTONE_GENERATOR)
lootTables.tile(MBlocks.ESSENCE_STORAGE)
lootTables.tile(MBlocks.ITEM_REPAIRER)
lootTables.tile(MBlocks.ENERGY_SERVO)
lootTables.tile(MBlocks.ENERGY_COUNTER)

View File

@ -172,6 +172,7 @@ fun addTags(tagsProvider: TagsProvider) {
MBlocks.HOLO_SIGN,
MBlocks.COBBLESTONE_GENERATOR,
MBlocks.ESSENCE_STORAGE,
MBlocks.ITEM_REPAIRER,
), Tiers.IRON)
tagsProvider.requiresPickaxe(MBlocks.TRITANIUM_ANVIL, Tiers.IRON)

View File

@ -0,0 +1,290 @@
package ru.dbotthepony.mc.otm.block.entity.matter
import net.minecraft.core.BlockPos
import net.minecraft.nbt.StringTag
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerLevel
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.Item
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import net.minecraftforge.common.ForgeConfigSpec
import net.minecraftforge.common.ForgeConfigSpec.ConfigValue
import net.minecraftforge.registries.ForgeRegistries
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage
import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl
import ru.dbotthepony.mc.otm.config.ConciseBalanceValues
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue
import ru.dbotthepony.mc.otm.core.math.defineDecimal
import ru.dbotthepony.mc.otm.core.registryName
import ru.dbotthepony.mc.otm.core.util.WriteOnce
import ru.dbotthepony.mc.otm.graph.Graph6Node
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode
import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph
import ru.dbotthepony.mc.otm.matter.IMatterValue
import ru.dbotthepony.mc.otm.matter.MatterManager
import ru.dbotthepony.mc.otm.menu.matter.ItemRepairerMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.registry.MNames
class ItemRepairerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ITEM_REPAIRER, blockPos, blockState), IMatterGraphNode {
val repairContainer = MatteryContainer(::containerChanged, 1).also(::addDroppableContainer)
private var matterPerTick = Decimal.ZERO
private var progressPerTick = 0.0
private var repairProgress = 0.0
private var lastItem: Item? = null
var canNotWork = false
override val matterNode = Graph6Node<IMatterGraphNode>(this)
val matter = MatterStorageImpl(::setChangedLight, FlowDirection.INPUT, ::CAPACITY)
val energy = WorkerEnergyStorage(::setChangedLight, ENERGY_VALUES)
init {
exposeGlobally(MatteryCapability.MATTER, matter)
exposeGlobally(MatteryCapability.MATTER_NODE, this)
savetables.stateful(::repairContainer)
savetables.stateful(::matter)
savetables.stateful(::energy)
savetables.decimal(::matterPerTick)
savetables.double(::progressPerTick)
savetables.double(::repairProgress)
savetables.Stateless(::lastItem, type = StringTag::class.java)
.withSerializer { it?.registryName?.toString()?.let(StringTag::valueOf) }
.withDeserializer { ResourceLocation.tryParse(it.asString)?.let { ForgeRegistries.ITEMS.getValue(it) } }
}
val energyConfig = ConfigurableEnergy(energy)
val itemConfig = ConfigurableItemHandler(
input = repairContainer.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
if (!stack.isRepairable || !stack.isDamaged) {
return false
}
if (!ONLY_ANVIL) {
if (MatterManager.get(stack.item).hasMatterValue) {
return true
}
}
return (matterNode.graph as MatterNetworkGraph?)
?.patterns
?.filter { stack.item.isValidRepairItem(stack, ItemStack(it.item, 1)) }
?.findFirst()?.orElse(null).let {
if (it == null) {
IMatterValue.ZERO
} else {
MatterManager.get(it.item)
}
}.hasMatterValue
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return false
}
}),
output = repairContainer.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return false
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return progressPerTick <= 0.0 || matterPerTick <= Decimal.ZERO
}
})
)
override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu {
return ItemRepairerMenu(containerID, inventory, this)
}
override fun getMatterHandler(): IMatterStorage {
return matter
}
override fun setRemoved() {
super.setRemoved()
matterNode.destroy(::MatterNetworkGraph)
}
override fun setLevel(level: Level) {
super.setLevel(level)
if (level is ServerLevel)
MatterNetworkGraph.discoverFull(this, matterNode)
}
private fun containerChanged() {
matterPerTick = Decimal.ZERO
progressPerTick = 0.0
val item = repairContainer[0]
tickList.once {
if (lastItem != item.item) {
lastItem = item.item
repairProgress = 0.0
}
if (item.isEmpty || !item.isRepairable || !item.isDamaged) {
matterPerTick = Decimal.ZERO
progressPerTick = 0.0
} else {
if (!ONLY_ANVIL) {
val matter = MatterManager.get(item.item)
if (matter.hasMatterValue) {
progressPerTick = (item.maxDamage / matter.complexity) / DIVISOR
matterPerTick = (matter.matter / matter.complexity) / DIVISOR
return@once
}
}
val found = (matterNode.graph as MatterNetworkGraph?)?.patterns?.filter { item.item.isValidRepairItem(item, ItemStack(it.item, 1)) }?.findFirst()?.orElse(null)
if (found != null) {
@Suppress("name_shadowing")
val matter = MatterManager.get(found.item) * 2
progressPerTick = (item.maxDamage / matter.complexity) / DIVISOR
matterPerTick = (matter.matter / matter.complexity) / DIVISOR
} else {
matterPerTick = Decimal.ZERO
progressPerTick = 0.0
}
}
}
}
override fun tick() {
super.tick()
if (!redstoneControl.isBlockedByRedstone) {
canNotWork = false
val item = repairContainer[0]
if (!item.isEmpty && matterPerTick.isPositive && progressPerTick > 0.0 && item.isRepairable && item.isDamaged) {
var progressPerTick = (repairProgress + progressPerTick).coerceAtMost(item.damageValue.toDouble()) - repairProgress
if (progressPerTick <= 0.0) return
if (ENERGY_CONSUMPTION.isPositive) {
if (!energy.batteryLevel.isPositive) return
val multEnergy = ENERGY_CONSUMPTION * (progressPerTick / this.progressPerTick)
progressPerTick *= (energy.extractEnergy(multEnergy, true) / multEnergy).toDouble()
if (progressPerTick <= 0.0) {
canNotWork = true
return
}
}
if (matter.storedMatter < matterPerTick) {
val graph = matterNode.graph as MatterNetworkGraph?
if (graph != null) {
val toDrain = (matterPerTick * EXTRACT_TICKS.coerceAtMost(item.damageValue)).coerceAtLeast(Decimal.ZERO).coerceAtMost(matter.missingMatter)
matter.receiveMatterInner(graph.extractMatter(toDrain, false), false)
}
}
val toDrain = matterPerTick * (progressPerTick / this.progressPerTick)
val drain = matter.extractMatterInner(toDrain, true)
if (!drain.isPositive) {
canNotWork = true
return
}
progressPerTick *= (drain / toDrain).toDouble()
if (progressPerTick <= 0.0) {
canNotWork = true
return
}
if (FAILURE_CHANCE <= 0.0 || level!!.random.nextDouble() >= FAILURE_CHANCE)
repairProgress += progressPerTick
energy.extractEnergy(ENERGY_CONSUMPTION * (progressPerTick / this.progressPerTick), false)
matter.extractMatterInner(matterPerTick * (progressPerTick / this.progressPerTick), false)
if (repairProgress >= 1.0) {
item.damageValue = (item.damageValue - repairProgress.toInt()).coerceAtLeast(0)
repairProgress %= 1.0
}
}
}
}
companion object {
val CAPACITY get() = _CAPACITY.get()
val ENERGY_CONSUMPTION get() = _ENERGY_CONSUMPTION.get()
val DIVISOR: Double get() = _DIVISOR.get()
val EXTRACT_TICKS: Int get() = _EXTRACT_TICKS.get()
val FAILURE_CHANCE: Double get() = _FAILURE_CHANCE.get()
val ONLY_ANVIL: Boolean get() = _ONLY_ANVIL.get()
private var _CAPACITY: DecimalConfigValue by WriteOnce()
private var _ENERGY_CONSUMPTION: DecimalConfigValue by WriteOnce()
private var _DIVISOR: ConfigValue<Double> by WriteOnce()
private var _FAILURE_CHANCE: ConfigValue<Double> by WriteOnce()
private var _EXTRACT_TICKS: ConfigValue<Int> by WriteOnce()
private var _ONLY_ANVIL: ConfigValue<Boolean> by WriteOnce()
var ENERGY_VALUES: ConciseBalanceValues by WriteOnce()
private set
fun registerConfig(builder: ForgeConfigSpec.Builder) {
builder.push(MNames.ITEM_REPAIRER)
ENERGY_VALUES = BlockEnergyStorageImpl.makeConfigEntry(builder, capacity = Decimal(400_000), throughput = Decimal(2_000))
_CAPACITY = builder.defineDecimal("matterCapacity", Decimal(4_000), Decimal.ONE_TENTH)
_ENERGY_CONSUMPTION = builder.defineDecimal("energyConsumption", Decimal(600), Decimal.ONE)
_ONLY_ANVIL = builder
.comment("Force repairing only by matter value of anvil materials")
.comment("Doesn't make logical sense but might be good for balancing")
.define("onlyAnvil", false)
_EXTRACT_TICKS = builder
.comment("How much ticks of matter work will be attempted to be extracted from matter network")
.comment("on matter starvation")
.comment("---")
.comment("This is a performance tuning value, do not change it if you don't know what you are doing!")
.defineInRange("extractTicks", 200, 1, Int.MAX_VALUE)
_FAILURE_CHANCE = builder
.comment("Chance that replication will fail at any given tick")
.comment("In event of failure repair tick is wasted, wasting resources")
.defineInRange("failureChance", 0.01, 0.0, 0.99)
_DIVISOR = builder
.comment("Magnitute of **slowdown** of repairer.")
.comment("If this value is 1, repairer will repair item from 0% to 100% in COMPLEXITY (of tool) ticks")
.comment("(or twice the complexity of anvil repair ingredients if tool itself has no matter value)")
.comment("---")
.comment("If value is smaller than 1, repairer will repair items faster")
.comment("If value is bigger than 1, repairer will repair items slower")
.defineInRange("divisor", 3.0, 0.1, Double.MAX_VALUE)
builder.pop()
}
}
}

View File

@ -317,7 +317,5 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
builder.pop()
}
const val IS_BOTTLING_KEY = "isBottling"
}
}

View File

@ -0,0 +1,24 @@
package ru.dbotthepony.mc.otm.block.matter
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.matter.ItemRepairerBlockEntity
class ItemRepairerBlock : RotatableMatteryBlock(), EntityBlock {
override fun newBlockEntity(pPos: BlockPos, pState: BlockState): BlockEntity {
return ItemRepairerBlockEntity(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 ItemRepairerBlockEntity) pBlockEntity.tick() }
}
}

View File

@ -1315,11 +1315,13 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return
}
val iterator = inventory.player.matteryPlayer?.exoPackContainer?.iterator()?.nonEmpty() ?: return
val iterator = inventory.player.matteryPlayer?.exoPackContainer?.iterator() ?: return
for (item in iterator) {
inventory.player.drop(item, true, false)
iterator.remove()
if (!item.isEmpty) {
inventory.player.drop(item, true, false)
iterator.remove()
}
}
}
@ -1338,10 +1340,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return
}
val iterator = player.matteryPlayer?.exoPackContainer?.iterator()?.nonEmpty() ?: return
val iterator = player.matteryPlayer?.exoPackContainer?.iterator() ?: return
for (item in iterator) {
if (hasVanishingCurse(item)) {
if (!item.isEmpty && hasVanishingCurse(item)) {
iterator.remove()
}
}

View File

@ -0,0 +1,26 @@
package ru.dbotthepony.mc.otm.client.screen.matter
import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel
import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel
import ru.dbotthepony.mc.otm.menu.matter.ItemRepairerMenu
class ItemRepairerScreen(menu: ItemRepairerMenu, inventory: Inventory, title: Component) : MatteryScreen<ItemRepairerMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
val frame = super.makeMainFrame()!!
val p = PowerGaugePanel(this, frame, menu.powerWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
MatterGaugePanel(this, frame, menu.matterWidget, LEFT_MARGIN + p.width, GAUGE_TOP_WITH_SLOT)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
SlotPanel(this, frame, menu.slot, 80f, PROGRESS_SLOT_TOP)
return frame
}
}

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.config
import ru.dbotthepony.mc.otm.block.entity.matter.ItemRepairerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.matter.MatterDecomposerBlockEntity
import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity
@ -20,6 +21,7 @@ object MachinesConfig : AbstractConfig("machines") {
MatterReplicatorBlockEntity.registerConfig(builder)
MatterScannerBlockEntity.registerConfig(builder)
MatterDecomposerBlockEntity.registerConfig(builder)
ItemRepairerBlockEntity.registerConfig(builder)
}
val PLATE_PRESS = BlockEnergyStorageImpl.makeConfigEntry(builder, MNames.PLATE_PRESS)

View File

@ -2,5 +2,4 @@ package ru.dbotthepony.mc.otm.core.collect
import net.minecraft.world.item.ItemStack
fun Iterator<ItemStack>.nonEmpty() = PredicateIterator(this) { !it.isEmpty }
fun MutableIterator<ItemStack>.nonEmpty() = MutablePredicateIterator(this) { !it.isEmpty }
fun Iterator<ItemStack>.nonEmpty() = FilteredIterator(this) { !it.isEmpty }

View File

@ -1,99 +0,0 @@
package ru.dbotthepony.mc.otm.core.collect
import java.util.function.Consumer
import java.util.function.Predicate
class PredicateIterator<T> : Iterator<T> {
private val parent: Iterator<T>
private val predicate: Predicate<in T>
private val consumer: Consumer<in T>?
constructor(parent: Iterator<T>, predicate: Predicate<in T>) {
this.parent = parent
this.predicate = predicate
this.consumer = null
}
constructor(parent: Iterator<T>, predicate: Predicate<in T>, consumer: Consumer<in T>) {
this.parent = parent
this.predicate = predicate
this.consumer = consumer
}
private var foundValue: Any? = Companion
var once: Boolean = false
private set
override fun hasNext(): Boolean {
if (foundValue === Companion) {
while (parent.hasNext()) {
val next = parent.next()
if (predicate.test(next)) {
foundValue = next
once = true
return true
}
}
return false
}
return true
}
@Suppress("unchecked_cast")
override fun next(): T {
if (!hasNext()) {
throw NoSuchElementException()
}
val foundValue = foundValue
if (foundValue === Companion) {
throw ConcurrentModificationException()
}
this.foundValue = Companion
consumer?.accept(foundValue as T)
return foundValue as T
}
private companion object
}
fun <T> Iterator<T>.filter(condition: Predicate<in T>) = PredicateIterator(this, condition)
class MutablePredicateIterator<T> : MutableIterator<T> {
private val parent: MutableIterator<T>
private val predicateParent: PredicateIterator<T>
constructor(parent: MutableIterator<T>, predicate: Predicate<in T>) {
this.parent = parent
this.predicateParent = PredicateIterator(parent, predicate)
}
constructor(parent: MutableIterator<T>, predicate: Predicate<in T>, consumer: Consumer<in T>) {
this.parent = parent
this.predicateParent = PredicateIterator(parent, predicate, consumer)
}
override fun hasNext(): Boolean {
return predicateParent.hasNext()
}
override fun next(): T {
return predicateParent.next()
}
override fun remove() {
if (!predicateParent.once) {
throw NoSuchElementException()
}
return parent.remove()
}
}
fun <T> MutableIterator<T>.filter(condition: Predicate<in T>) = MutablePredicateIterator(this, condition)

View File

@ -0,0 +1,210 @@
package ru.dbotthepony.mc.otm.core.collect
import java.util.Optional
import java.util.function.BinaryOperator
import java.util.function.Predicate
import java.util.stream.Collector
class FilteredIterator<T>(private val parent: Iterator<T>, private val predicate: Predicate<in T>) : Iterator<T> {
private var foundValue: Any? = Companion
override fun hasNext(): Boolean {
if (foundValue === Companion) {
while (parent.hasNext()) {
val next = parent.next()
if (predicate.test(next)) {
foundValue = next
return true
}
}
return false
}
return true
}
@Suppress("unchecked_cast")
override fun next(): T {
var foundValue = foundValue
if (foundValue === Companion) {
if (!hasNext()) {
throw NoSuchElementException()
}
foundValue = this.foundValue
if (foundValue === Companion) {
throw ConcurrentModificationException()
}
}
this.foundValue = Companion
return foundValue as T
}
private companion object
}
class MappingIterator<T, R>(private val parent: Iterator<T>, private val transform: (T) -> R) : Iterator<R> {
override fun hasNext(): Boolean {
return parent.hasNext()
}
override fun next(): R {
return transform.invoke(parent.next())
}
}
fun <T> Iterator<T>.filter(condition: Predicate<in T>): Iterator<T> = FilteredIterator(this, condition)
fun <T, R> Iterator<T>.map(mapper: (T) -> R): Iterator<R> = MappingIterator(this, mapper)
fun <T, R> Iterator<T>.map(mapper: java.util.function.Function<T, R>): Iterator<R> = MappingIterator(this, mapper::apply)
fun <T> Iterator<T>.reduce(identity: T, reducer: (T, T) -> T): T {
var result = identity
for (value in this) {
result = reducer.invoke(result, value)
}
return result
}
fun <T> Iterator<T>.reduce(identity: T, reducer: BinaryOperator<T>): T = reduce(identity, reducer::apply)
fun <T> Iterator<T?>.filterNotNull(): Iterator<T> = filter { it != null } as Iterator<T>
fun <T> Iterator<T>.anyMatch(predicate: Predicate<in T>): Boolean {
for (value in this) {
if (predicate.test(value)) {
return true
}
}
return false
}
fun <T> Iterator<T>.allMatch(predicate: Predicate<in T>): Boolean {
for (value in this) {
if (!predicate.test(value)) {
return false
}
}
return true
}
fun <T> Iterator<T>.noneMatch(predicate: Predicate<in T>): Boolean {
for (value in this) {
if (predicate.test(value)) {
return false
}
}
return true
}
fun <T, A, R> Iterator<T>.collect(collector: Collector<T, A, R>): R {
val accumulator = collector.accumulator()
val instance = collector.supplier().get()
for (value in this) {
accumulator.accept(instance, value)
}
return collector.finisher().apply(instance)
}
fun <T : Any> Iterator<T>.findFirst(): Optional<T> {
if (hasNext()) {
return Optional.of(next())
}
return Optional.empty<T>()
}
fun <T : Any> Iterator<T>.findAny() = findFirst()
fun <T> Iterator<T>.limit(limit: Long): Iterator<T> {
require(limit > 0) { "Invalid limit $limit" }
return object : Iterator<T> {
var found = 0L
override fun hasNext(): Boolean {
return found < limit && this@limit.hasNext()
}
override fun next(): T {
if (found >= limit) {
throw NoSuchElementException()
}
return this@limit.next()
}
}
}
fun <T> Iterator<T>.skip(skip: Long): Iterator<T> {
require(skip > 0) { "Invalid skip $skip" }
return object : Iterator<T> {
var found = skip
override fun hasNext(): Boolean {
while (this@skip.hasNext() && found > 0L) {
found--
this@skip.next()
}
return this@skip.hasNext()
}
override fun next(): T {
if (!hasNext()) {
throw NoSuchElementException()
}
return this@skip.next()
}
}
}
inline fun <T> Iterator<T>.forEach(action: (T) -> Unit) {
for (value in this) {
action.invoke(value)
}
}
fun <T : Any> Iterator<T>.min(comparator: Comparator<T>): Optional<T> {
if (!hasNext()) {
return Optional.empty<T>()
}
var min = next()
for (value in this) {
if (comparator.compare(min, value) > 0) {
min = value
}
}
return Optional.of(min)
}
fun <T : Any> Iterator<T>.max(comparator: Comparator<T>): Optional<T> {
if (!hasNext()) {
return Optional.empty<T>()
}
var max = next()
for (value in this) {
if (comparator.compare(max, value) < 0) {
max = value
}
}
return Optional.of(max)
}

View File

@ -7,6 +7,7 @@ import net.minecraft.world.level.block.entity.BlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.*
import ru.dbotthepony.mc.otm.core.filterNotNull
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.graph.Abstract6Graph
import ru.dbotthepony.mc.otm.graph.Graph6Node
@ -206,7 +207,7 @@ class MatterNetworkGraph : Abstract6Graph<IMatterGraphNode>(), IMatterGraphListe
}
val patterns: Stream<out IPatternState> get() {
return Streams.concat(*nodes.mapNotNull { it.value.getPatternHandler()?.patterns }.toTypedArray())
return nodes.stream().map { it.value.getPatternHandler()?.patterns }.filterNotNull().flatMap { it }
}
val patternCount: Long get() {

View File

@ -50,6 +50,8 @@ interface IMatterValue : Comparable<IMatterValue> {
* ZERO
*/
companion object : IMatterValue {
val ZERO: IMatterValue get() = this
override val matter: Decimal
get() = Decimal.ZERO
override val complexity: Double

View File

@ -6,6 +6,7 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import net.minecraft.world.SimpleContainer
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
import ru.dbotthepony.mc.otm.capability.matter.matter
import ru.dbotthepony.mc.otm.capability.matteryEnergy
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
@ -16,14 +17,11 @@ abstract class MatteryPoweredMenu protected constructor(
tile: MatteryPoweredBlockEntity? = null
) : MatteryMenu(menuType, containerID, inventory, tile) {
val powerWidget = LevelGaugeWidget(this, tile?.matteryEnergy)
val batterySlot: BatterySlot
val batterySlot = BatterySlot(tile?.batteryContainer ?: SimpleContainer(1), 0)
val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java)
init {
if (tile == null) {
batterySlot = BatterySlot(SimpleContainer(1), 0)
} else {
batterySlot = BatterySlot(tile.batteryContainer, 0)
if (tile != null) {
redstone.with(tile.redstoneControl::redstoneSetting)
}

View File

@ -0,0 +1,29 @@
package ru.dbotthepony.mc.otm.menu.matter
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.item.ItemStack
import ru.dbotthepony.mc.otm.block.entity.matter.ItemRepairerBlockEntity
import ru.dbotthepony.mc.otm.capability.matter.matter
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus
class ItemRepairerMenu(
containerId: Int,
inventory: Inventory,
tile: ItemRepairerBlockEntity? = null
) : MatteryPoweredMenu(MMenus.ITEM_REPAIER, containerId, inventory, tile) {
val matterWidget = LevelGaugeWidget(this, tile?.matter)
val slot = object : MatterySlot(tile?.repairContainer ?: SimpleContainer(1), 0) {
override fun mayPlace(itemStack: ItemStack): Boolean {
return itemStack.isRepairable && itemStack.isDamaged && super.mayPlace(itemStack)
}
}
init {
addStorageSlot(slot)
addInventorySlots()
}
}

View File

@ -57,6 +57,7 @@ object MBlockEntities {
val ENERGY_SERVO: BlockEntityType<EnergyServoBlockEntity> by registry.register(MNames.ENERGY_SERVO) { BlockEntityType.Builder.of(::EnergyServoBlockEntity, MBlocks.ENERGY_SERVO).build(null) }
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 ITEM_REPAIRER: BlockEntityType<ItemRepairerBlockEntity> by registry.register(MNames.ITEM_REPAIRER) { BlockEntityType.Builder.of(::ItemRepairerBlockEntity, MBlocks.ITEM_REPAIRER).build(null) }
val STORAGE_BUS: BlockEntityType<StorageBusBlockEntity> by registry.register(MNames.STORAGE_BUS) { BlockEntityType.Builder.of(::StorageBusBlockEntity, MBlocks.STORAGE_BUS).build(null) }
val STORAGE_IMPORTER: BlockEntityType<StorageImporterBlockEntity> by registry.register(MNames.STORAGE_IMPORTER) { BlockEntityType.Builder.of(::StorageImporterBlockEntity, MBlocks.STORAGE_IMPORTER).build(null) }

View File

@ -48,6 +48,7 @@ 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.HoloSignBlock
import ru.dbotthepony.mc.otm.block.matter.ItemRepairerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock
import ru.dbotthepony.mc.otm.block.matter.MatterCapacitorBankBlock
import ru.dbotthepony.mc.otm.block.matter.MatterDecomposerBlock
@ -93,6 +94,7 @@ object MBlocks {
val ENERGY_SERVO: Block by registry.register(MNames.ENERGY_SERVO) { EnergyServoBlock() }
val COBBLESTONE_GENERATOR: Block by registry.register(MNames.COBBLESTONE_GENERATOR) { CobblerBlock() }
val ESSENCE_STORAGE: EssenceStorageBlock by registry.register(MNames.ESSENCE_STORAGE) { EssenceStorageBlock() }
val ITEM_REPAIRER: ItemRepairerBlock by registry.register(MNames.ITEM_REPAIRER) { ItemRepairerBlock() }
val STORAGE_BUS: Block by registry.register(MNames.STORAGE_BUS) { StorageBusBlock() }
val STORAGE_IMPORTER: Block by registry.register(MNames.STORAGE_IMPORTER) { StorageImporterBlock() }

View File

@ -109,13 +109,22 @@ object MItems {
}
}
val ITEM_REPAIRER: BlockItem by registry.register(MNames.ITEM_REPAIRER) {
object : BlockItem(MBlocks.ITEM_REPAIRER, DEFAULT_PROPERTIES) {
override fun appendHoverText(p_40572_: ItemStack, p_40573_: Level?, p_40574_: MutableList<Component>, p_40575_: TooltipFlag) {
super.appendHoverText(p_40572_, p_40573_, p_40574_, p_40575_)
p_40574_.add(TranslatableComponent("$descriptionId.desc").withStyle(ChatFormatting.GRAY))
}
}
}
val MACHINES = SupplierList(
::ANDROID_STATION, ::BATTERY_BANK, ::MATTER_DECOMPOSER, ::MATTER_CAPACITOR_BANK, ::MATTER_CABLE, ::PATTERN_STORAGE,
::MATTER_SCANNER, ::MATTER_PANEL, ::MATTER_REPLICATOR, ::MATTER_BOTTLER, ::ENERGY_COUNTER, ::CHEMICAL_GENERATOR,
::PLATE_PRESS, ::MATTER_RECYCLER, ::STORAGE_BUS, ::STORAGE_IMPORTER, ::STORAGE_EXPORTER, ::DRIVE_VIEWER,
::DRIVE_RACK, ::ITEM_MONITOR, ::STORAGE_CABLE, ::STORAGE_POWER_SUPPLIER, ::ENERGY_SERVO,
::PHANTOM_ATTRACTOR,
::GRAVITATION_STABILIZER, ::COBBLESTONE_GENERATOR, ::ESSENCE_STORAGE
::PHANTOM_ATTRACTOR, ::GRAVITATION_STABILIZER, ::COBBLESTONE_GENERATOR, ::ESSENCE_STORAGE,
::ITEM_REPAIRER
)
val DEBUG_EXPLOSION_SMALL: Item by registry.register(MNames.DEBUG_EXPLOSION_SMALL) { BlockItem(MBlocks.DEBUG_EXPLOSION_SMALL, Item.Properties().stacksTo(64)) }

View File

@ -10,6 +10,7 @@ import ru.dbotthepony.mc.otm.OverdriveThatMatters
import ru.dbotthepony.mc.otm.client.screen.decorative.CargoCrateScreen
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.ItemRepairerScreen
import ru.dbotthepony.mc.otm.client.screen.matter.MatterBottlerScreen
import ru.dbotthepony.mc.otm.client.screen.matter.MatterCapacitorBankScreen
import ru.dbotthepony.mc.otm.client.screen.matter.MatterDecomposerScreen
@ -36,6 +37,7 @@ import ru.dbotthepony.mc.otm.client.screen.tech.PlatePressScreen
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu
import ru.dbotthepony.mc.otm.menu.decorative.HoloSignMenu
import ru.dbotthepony.mc.otm.menu.decorative.MinecartCargoCrateMenu
import ru.dbotthepony.mc.otm.menu.matter.ItemRepairerMenu
import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu
import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu
import ru.dbotthepony.mc.otm.menu.matter.MatterDecomposerMenu
@ -85,6 +87,7 @@ object MMenus {
val HOLO_SIGN: MenuType<HoloSignMenu> by registry.register(MNames.HOLO_SIGN) { MenuType(::HoloSignMenu) }
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<ItemRepairerMenu> by registry.register(MNames.ITEM_REPAIRER) { MenuType(::ItemRepairerMenu) }
val STORAGE_BUS: MenuType<*> by registry.register(MNames.STORAGE_BUS) { MenuType(::StorageBusMenu) }
val STORAGE_EXPORTER: MenuType<*> by registry.register(MNames.STORAGE_EXPORTER) { MenuType(::StorageExporterMenu) }
@ -125,6 +128,7 @@ object MMenus {
MenuScreens.register(HOLO_SIGN, ::HoloSignScreen)
MenuScreens.register(COBBLESTONE_GENERATOR, ::CobblerScreen)
MenuScreens.register(ESSENCE_STORAGE, ::EssenceStorageScreen)
MenuScreens.register(ITEM_REPAIER, ::ItemRepairerScreen)
}
}
}

View File

@ -23,6 +23,7 @@ object MNames {
const val MATTER_PANEL = "matter_panel"
const val MATTER_REPLICATOR = "matter_replicator"
const val MATTER_BOTTLER = "matter_bottler"
const val ITEM_REPAIRER = "item_repairer"
const val DRIVE_VIEWER = "drive_viewer"
const val DRIVE_RACK = "drive_rack"
const val ITEM_MONITOR = "item_monitor"