From 0fff4c003bc9ca848ee6b8b4e7421ab1f1a9931c Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 17 Sep 2022 13:59:48 +0700 Subject: [PATCH] Serverside Config Fixes #88 --- .../mc/otm/OverdriveThatMatters.java | 1 + .../ru/dbotthepony/mc/otm/ClientConfig.kt | 2 - .../kotlin/ru/dbotthepony/mc/otm/ConfigExt.kt | 42 +++++ .../dbotthepony/mc/otm/ObservedConfigValue.kt | 74 ++++++++ .../ru/dbotthepony/mc/otm/ServerConfig.kt | 142 ++++++++++++++ .../block/entity/AndroidStationBlockEntity.kt | 33 +++- .../block/entity/BatteryBankBlockEntity.kt | 2 +- .../entity/ChemicalGeneratorBlockEntity.kt | 26 ++- .../mc/otm/block/entity/MatteryBlockEntity.kt | 6 +- .../otm/block/entity/PlatePressBlockEntity.kt | 3 +- .../entity/matter/MatterBottlerBlockEntity.kt | 43 ++++- .../matter/MatterDecomposerBlockEntity.kt | 35 +++- .../matter/MatterRecyclerBlockEntity.kt | 39 +++- .../matter/MatterReplicatorBlockEntity.kt | 39 +++- .../entity/matter/MatterScannerBlockEntity.kt | 32 +++- .../entity/storage/DriveRackBlockEntity.kt | 11 +- .../entity/storage/DriveViewerBlockEntity.kt | 10 +- .../entity/storage/ItemMonitorBlockEntity.kt | 10 +- .../entity/storage/StorageBusBlockEntity.kt | 7 +- .../block/entity/storage/StorageInterfaces.kt | 6 +- .../StoragePowerSupplierBlockEntity.kt | 7 +- .../mc/otm/capability/EnergyStorageImpl.kt | 177 ++++++++++++++---- .../capability/matter/MatterHandlerImpl.kt | 38 +++- .../dbotthepony/mc/otm/core/CompoundTagExt.kt | 10 + .../kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 10 +- .../mc/otm/core/ImpreciseFraction.kt | 56 +++++- .../ru/dbotthepony/mc/otm/item/BatteryItem.kt | 80 +++++--- .../mc/otm/item/MatterCapacitorItem.kt | 23 ++- .../mc/otm/item/PatternStorageItem.kt | 12 +- .../mc/otm/item/QuantumBatteryItem.kt | 27 ++- .../mc/otm/item/SingleUseBatteryItem.kt | 17 +- .../dbotthepony/mc/otm/matter/MatterData.kt | 4 +- .../ru/dbotthepony/mc/otm/registry/MItems.kt | 21 ++- .../dbotthepony/mc/otm/registry/MRegistry.kt | 5 +- .../mc/otm/tests/ImpreciseFractionTests.kt | 30 +++ 35 files changed, 881 insertions(+), 199 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/ConfigExt.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigValue.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index fe4104967..44798ffe6 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -89,6 +89,7 @@ public final class OverdriveThatMatters { modBus.addListener(EventPriority.NORMAL, MatteryCapability::register); ClientConfig.INSTANCE.register(); + ServerConfig.INSTANCE.register(); } private void setup(final FMLCommonSetupEvent event) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ClientConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ClientConfig.kt index d22f33f77..8fb628c14 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/ClientConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ClientConfig.kt @@ -3,8 +3,6 @@ package ru.dbotthepony.mc.otm import net.minecraftforge.common.ForgeConfigSpec import net.minecraftforge.fml.ModLoadingContext import net.minecraftforge.fml.config.ModConfig -import ru.dbotthepony.mc.otm.core.getValue -import ru.dbotthepony.mc.otm.core.setValue object ClientConfig { private val spec: ForgeConfigSpec diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ConfigExt.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ConfigExt.kt new file mode 100644 index 000000000..cda780e73 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ConfigExt.kt @@ -0,0 +1,42 @@ +package ru.dbotthepony.mc.otm + +import net.minecraftforge.common.ForgeConfigSpec +import kotlin.reflect.KProperty + +operator fun ForgeConfigSpec.ConfigValue.setValue(config: Any, property: KProperty<*>, value: T) { + set(value) +} + +operator fun ForgeConfigSpec.ConfigValue.getValue(config: Any, property: KProperty<*>): T { + return get() +} + +private val builderField by lazy { + val field = ForgeConfigSpec.Builder::class.java.getDeclaredField("context") + field.isAccessible = true + field +} + +private val builderContextField by lazy { + val clazz = ForgeConfigSpec::class.java.declaredClasses.firstOrNull { it.name == "net.minecraftforge.common.ForgeConfigSpec\$BuilderContext" } ?: throw NoSuchElementException("Unable to find ForgeConfigSpec.BuilderContext") + + val field = clazz.getDeclaredField("comment") + field.isAccessible = true + field +} + +fun ForgeConfigSpec.Builder.appendComment(vararg comments: String): ForgeConfigSpec.Builder { + val context = builderField.get(this) ?: throw NullPointerException("No builder context!") + val commentList = builderContextField.get(context) as? Array ?: throw NullPointerException("BuilderContext.comment is null or not of right type!") + + val reconstruct = Array(commentList.size + comments.size) { + if (it in commentList.indices) { + commentList[it] + } else { + comments[it - commentList.size] + } + } + + builderContextField.set(context, reconstruct) + return this +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigValue.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigValue.kt new file mode 100644 index 000000000..9a622d49d --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ObservedConfigValue.kt @@ -0,0 +1,74 @@ +package ru.dbotthepony.mc.otm + +import net.minecraftforge.common.ForgeConfigSpec.ConfigValue +import org.apache.logging.log4j.LogManager +import java.util.function.Consumer +import java.util.function.Supplier +import kotlin.properties.ReadWriteProperty +import kotlin.reflect.KProperty + +abstract class ObservedConfigValue(val parent: ConfigValue) : ReadWriteProperty, Supplier, Consumer { + var rawValue: String by parent + private var observedValue: String? = null + private var cachedValue: V? = null + + protected abstract fun fromValue(value: String): V? + + /** + * value [V] -> newRawValue [String], newValue [V] + */ + protected abstract fun toValue(value: V): Pair + + override fun get(): V { + if (cachedValue == null || rawValue != observedValue) { + var deserialized = fromValue(rawValue) + + if (deserialized == null) { + val default = parent.default + deserialized = fromValue(default) + + if (deserialized == null) { + throw RuntimeException("Deserializer did not accept default value: $default") + } else { + LOGGER.error("Config value of <${parent.path.joinToString(".")}>: $rawValue is invalid, replacing with default $default") + } + + rawValue = default + } + + cachedValue = deserialized + observedValue = rawValue + } + + return cachedValue ?: throw ConcurrentModificationException() + } + + override fun getValue(thisRef: Any, property: KProperty<*>): V { + return get() + } + + override fun accept(value: V) { + if (cachedValue == null || rawValue != observedValue) { + cachedValue = fromValue(rawValue) + observedValue = rawValue + } + + if (cachedValue != value) { + val (newRaw, newValue) = toValue(value) + + if (cachedValue != newValue) { + rawValue = newRaw + observedValue = rawValue + cachedValue = newValue + } + } + } + + override fun setValue(thisRef: Any, property: KProperty<*>, value: V) { + accept(value) + } + + companion object { + private val LOGGER = LogManager.getLogger() + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt new file mode 100644 index 000000000..4a823ad62 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/ServerConfig.kt @@ -0,0 +1,142 @@ +package ru.dbotthepony.mc.otm + +import net.minecraftforge.common.ForgeConfigSpec +import net.minecraftforge.fml.ModLoadingContext +import net.minecraftforge.fml.config.ModConfig +import ru.dbotthepony.mc.otm.block.entity.AndroidStationBlockEntity +import ru.dbotthepony.mc.otm.block.entity.ChemicalGeneratorBlockEntity +import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity +import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity +import ru.dbotthepony.mc.otm.block.entity.matter.MatterReplicatorBlockEntity +import ru.dbotthepony.mc.otm.block.entity.matter.MatterScannerBlockEntity +import ru.dbotthepony.mc.otm.capability.BlockEnergyStorageImpl +import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.defineImpreciseFraction +import ru.dbotthepony.mc.otm.registry.MNames + +interface VerboseBalanceValues { + val capacity: ImpreciseFraction + val receive: ImpreciseFraction + val extract: ImpreciseFraction +} + +interface BatteryBalanceValues : VerboseBalanceValues { + val initialBatteryLevel: ImpreciseFraction +} + +interface ConciseBalanceValues { + val capacity: ImpreciseFraction + val throughput: ImpreciseFraction +} + +object ServerConfig { + private val specBuilder = ForgeConfigSpec.Builder() + private val spec: ForgeConfigSpec + private var registered = false + + private fun verboseValues(name: String, storage: ImpreciseFraction, receive: ImpreciseFraction, extract: ImpreciseFraction = receive, initialBatteryLevel: ImpreciseFraction = ImpreciseFraction.ZERO): VerboseBalanceValues { + specBuilder.push(name) + + val obj = object : VerboseBalanceValues { + override val capacity: ImpreciseFraction by specBuilder.defineImpreciseFraction("capacity", storage, minimum = ImpreciseFraction.ONE) + override val receive: ImpreciseFraction by specBuilder.defineImpreciseFraction("receive", receive, minimum = ImpreciseFraction.ONE) + override val extract: ImpreciseFraction by specBuilder.defineImpreciseFraction("extract", extract, minimum = ImpreciseFraction.ONE) + } + + specBuilder.pop() + + return obj + } + + private fun batteryValues(name: String, storage: ImpreciseFraction, receive: ImpreciseFraction, extract: ImpreciseFraction = receive, initialBatteryLevel: ImpreciseFraction = ImpreciseFraction.ZERO): BatteryBalanceValues { + specBuilder.push(name) + + val obj = object : BatteryBalanceValues { + override val capacity: ImpreciseFraction by specBuilder.defineImpreciseFraction("capacity", storage, minimum = ImpreciseFraction.ONE) + override val receive: ImpreciseFraction by specBuilder.defineImpreciseFraction("receive", receive, minimum = ImpreciseFraction.ONE) + override val extract: ImpreciseFraction by specBuilder.defineImpreciseFraction("extract", extract, minimum = ImpreciseFraction.ONE) + override val initialBatteryLevel: ImpreciseFraction by specBuilder.defineImpreciseFraction("initialBatteryLevel", initialBatteryLevel, minimum = ImpreciseFraction.ZERO) + } + + specBuilder.pop() + + return obj + } + + private fun conciseValues(name: String, storage: ImpreciseFraction, throughput: ImpreciseFraction): ConciseBalanceValues { + specBuilder.push(name) + + val obj = object : ConciseBalanceValues { + override val capacity: ImpreciseFraction by specBuilder.defineImpreciseFraction("capacity", storage, minimum = ImpreciseFraction.ONE) + override val throughput: ImpreciseFraction by specBuilder.defineImpreciseFraction("throughput", throughput, minimum = ImpreciseFraction.ONE) + } + + specBuilder.pop() + + return obj + } + + init { + specBuilder.comment("Serverside config, holds shared values that are required to be read by both client and server.").push("server") + + specBuilder.comment("Energy batteries balance values").push("energy_batteries") + } + + val BATTERY_CRUDE = batteryValues(MNames.BATTERY_CRUDE, ImpreciseFraction(100_000), ImpreciseFraction(160), ImpreciseFraction(40), ImpreciseFraction(80_000)) + val BATTERY_BASIC = batteryValues(MNames.BATTERY_BASIC, ImpreciseFraction(400_000), ImpreciseFraction(600)) + val BATTERY_NORMAL = batteryValues(MNames.BATTERY_NORMAL, ImpreciseFraction(2_000_000), ImpreciseFraction(1_000)) + val BATTERY_DENSE = batteryValues(MNames.BATTERY_DENSE, ImpreciseFraction(10_000_000), ImpreciseFraction(2_000)) + val BATTERY_CAPACITOR = batteryValues(MNames.BATTERY_CAPACITOR, ImpreciseFraction(500_000), ImpreciseFraction(50_000)) + + val QUANTUM_BATTERY = conciseValues(MNames.QUANTUM_BATTERY, ImpreciseFraction(40_000_000), ImpreciseFraction(10_000)) + val QUANTUM_CAPACITOR = conciseValues(MNames.QUANTUM_CAPACITOR, ImpreciseFraction(1_000_000), ImpreciseFraction(200_000)) + + val ZPM_BATTERY = conciseValues(MNames.ZPM_BATTERY, ImpreciseFraction(200_000_000_000_000L), ImpreciseFraction(200_000_000L)) + + init { + specBuilder.pop() + + specBuilder.comment("Matter capacitors and pattern drives balance values").push("matter_capacitors_and_drives") + } + + val MATTER_CAPACITOR_BASIC by specBuilder.defineImpreciseFraction(MNames.MATTER_CAPACITOR_BASIC, ImpreciseFraction(2), minimum = ImpreciseFraction.ONE_TENTH) + val MATTER_CAPACITOR_NORMAL by specBuilder.defineImpreciseFraction(MNames.MATTER_CAPACITOR_NORMAL, ImpreciseFraction(10), minimum = ImpreciseFraction.ONE_TENTH) + val MATTER_CAPACITOR_DENSE by specBuilder.defineImpreciseFraction(MNames.MATTER_CAPACITOR_DENSE, ImpreciseFraction(40), minimum = ImpreciseFraction.ONE_TENTH) + + val PATTERN_DRIVE_NORMAL: Int by specBuilder.defineInRange(MNames.PATTERN_DRIVE_NORMAL, 4, 1, Int.MAX_VALUE) + + init { + specBuilder.pop() + + specBuilder.comment("Balance values of machinery").push("machines") + + AndroidStationBlockEntity.registerConfig(specBuilder) + ChemicalGeneratorBlockEntity.registerConfig(specBuilder) + MatterRecyclerBlockEntity.registerConfig(specBuilder) + MatterBottlerBlockEntity.registerConfig(specBuilder) + MatterReplicatorBlockEntity.registerConfig(specBuilder) + MatterScannerBlockEntity.registerConfig(specBuilder) + } + + val PLATE_PRESS = BlockEnergyStorageImpl.makeConfigEntry(specBuilder, MNames.PLATE_PRESS) + val STORAGE_POWER_SUPPLIER = BlockEnergyStorageImpl.makeConfigEntry(specBuilder, MNames.STORAGE_POWER_SUPPLIER, capacity = ImpreciseFraction(100_000), throughput = ImpreciseFraction(320)) + val STORAGE_INTERFACES = BlockEnergyStorageImpl.makeConfigEntry(specBuilder, "storage_interfaces", capacity = ImpreciseFraction(10_000)) + val ITEM_MONITOR = BlockEnergyStorageImpl.makeConfigEntry(specBuilder, MNames.ITEM_MONITOR) + val DRIVE_VIEWER = BlockEnergyStorageImpl.makeConfigEntry(specBuilder, MNames.DRIVE_VIEWER) + val DRIVE_RACK = BlockEnergyStorageImpl.makeConfigEntry(specBuilder, MNames.DRIVE_RACK, capacity = ImpreciseFraction(80_000)) + + init { + specBuilder.pop() + } + + init { + specBuilder.pop() + spec = specBuilder.build() + } + + fun register() { + check(!registered) { "Already registered config" } + registered = true + ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, spec) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt index 44a79989c..0e34d6d9d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/AndroidStationBlockEntity.kt @@ -4,20 +4,24 @@ import net.minecraft.core.BlockPos import net.minecraft.network.chat.Component import net.minecraft.server.level.ServerPlayer import net.minecraft.world.MenuProvider -import net.minecraft.world.entity.LivingEntity import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.phys.AABB +import net.minecraftforge.common.ForgeConfigSpec import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.ImpreciseFractionConfigValue +import ru.dbotthepony.mc.otm.core.defineImpreciseFraction import ru.dbotthepony.mc.otm.core.ifPresentK import ru.dbotthepony.mc.otm.menu.AndroidStationMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.registry.WriteOnce class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider { @@ -29,7 +33,7 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override val defaultDisplayName: Component get() = MACHINE_NAME - override val energy = object : WorkerEnergyStorage(this@AndroidStationBlockEntity, STORAGE, MAX_IO, null) { + override val energy = object : WorkerEnergyStorage(this@AndroidStationBlockEntity::setChangedLight, ::CAPACITY, ::MAX_IO, { null }) { override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { return super.extractEnergyInner(howMuch, simulate).also { if (!simulate && this.batteryLevel.isZero) { @@ -93,9 +97,26 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : companion object { private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.android_station") - val STORAGE = ImpreciseFraction(100_000) - val MAX_IO = ImpreciseFraction.valueOf(2048) - val ENERGY_PER_OPERATION = ImpreciseFraction.valueOf(2048) - val ENERGY_PER_RESEARCH = ImpreciseFraction.valueOf(16384) + + private var _CAPACITY: ImpreciseFractionConfigValue by WriteOnce() + private var _MAX_IO: ImpreciseFractionConfigValue by WriteOnce() + private var _ENERGY_PER_OPERATION: ImpreciseFractionConfigValue by WriteOnce() + private var _ENERGY_PER_RESEARCH: ImpreciseFractionConfigValue by WriteOnce() + + val CAPACITY get() = _CAPACITY.get() + val MAX_IO get() = _MAX_IO.get() + val ENERGY_PER_OPERATION get() = _ENERGY_PER_OPERATION.get() + val ENERGY_PER_RESEARCH get() = _ENERGY_PER_RESEARCH.get() + + fun registerConfig(builder: ForgeConfigSpec.Builder) { + builder.push(MNames.ANDROID_STATION) + + _CAPACITY = builder.defineImpreciseFraction("capacity", ImpreciseFraction(100_000), ImpreciseFraction.ONE) + _MAX_IO = builder.defineImpreciseFraction("throughput", ImpreciseFraction.valueOf(2048), ImpreciseFraction.ONE) + _ENERGY_PER_OPERATION = builder.comment("Swapping parts, etc").defineImpreciseFraction("energyPerOperation", ImpreciseFraction.valueOf(2048), ImpreciseFraction.ONE) + _ENERGY_PER_RESEARCH = builder.defineImpreciseFraction("energyPerResearch", ImpreciseFraction.valueOf(16384), ImpreciseFraction.ONE) + + builder.pop() + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BatteryBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BatteryBankBlockEntity.kt index c892651d7..4fbfce689 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BatteryBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/BatteryBankBlockEntity.kt @@ -340,4 +340,4 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte const val CAPACITY = 6 * 2 private val LOGGER = LogManager.getLogger() } -} \ No newline at end of file +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ChemicalGeneratorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ChemicalGeneratorBlockEntity.kt index cbef4aa29..7945be571 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ChemicalGeneratorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ChemicalGeneratorBlockEntity.kt @@ -12,6 +12,7 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState +import net.minecraftforge.common.ForgeConfigSpec import net.minecraftforge.common.ForgeHooks import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities @@ -26,6 +27,8 @@ import ru.dbotthepony.mc.otm.container.MatteryContainerFilter import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.menu.ChemicalGeneratorMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.registry.WriteOnce import java.lang.ref.WeakReference class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBlockEntity(MBlockEntities.CHEMICAL_GENERATOR, pos, state), IDroppableContainer { @@ -40,7 +43,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl val container = MatteryContainer(this::setChangedLight, SLOTS) override val droppableContainer: Container get() = container - val energy = GeneratorEnergyStorage(this::setChangedLight, MAX_ENERGY, THROUGHPUT) + val energy = GeneratorEnergyStorage(this::setChangedLight, CAPACITY, THROUGHPUT) private val consumers = ArrayList>() @@ -227,17 +230,30 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryBl } companion object { - private val THROUGHPUT = ImpreciseFraction(160) - private const val THROUGHPUT_INT = 160 - private val GENERATION_SPEED = ImpreciseFraction(40) - private val MAX_ENERGY = ImpreciseFraction(24_000) + private val THROUGHPUT get() = _THROUGHPUT.get() + private val GENERATION_SPEED get() = _GENERATION_SPEED.get() + private val CAPACITY get() = _CAPACITY.get() private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.chemical_generator") + private var _THROUGHPUT: ImpreciseFractionConfigValue by WriteOnce() + private var _GENERATION_SPEED: ImpreciseFractionConfigValue by WriteOnce() + private var _CAPACITY: ImpreciseFractionConfigValue by WriteOnce() + const val SLOT_INPUT = 0 const val SLOT_BATTERY = 1 const val SLOT_RESIDUE = 2 const val SLOTS = 3 + fun registerConfig(builder: ForgeConfigSpec.Builder) { + builder.push(MNames.CHEMICAL_GENERATOR) + + _THROUGHPUT = builder.defineImpreciseFraction("throughput", ImpreciseFraction(160), ImpreciseFraction.ONE) + _GENERATION_SPEED = builder.defineImpreciseFraction("generationSpeed", ImpreciseFraction(40), ImpreciseFraction.ONE) + _CAPACITY = builder.defineImpreciseFraction("capacity", ImpreciseFraction(24_000), ImpreciseFraction.ONE) + + builder.pop() + } + const val WORK_TICKS_KEY = "workTicks" const val WORK_TICKS_TOTAL_KEY = "workTicksTotal" } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt index d253b9aae..bc5267261 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt @@ -21,6 +21,8 @@ import net.minecraft.nbt.StringTag import net.minecraft.network.chat.Component import net.minecraft.world.level.Level import net.minecraftforge.common.capabilities.Capability +import ru.dbotthepony.mc.otm.core.TextComponent +import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.ifHas import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.oncePre @@ -65,7 +67,9 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc } } - protected abstract val defaultDisplayName: Component + protected open val defaultDisplayName: Component + get() = level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos") + abstract override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? protected fun tickOnce(func: Runnable) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/PlatePressBlockEntity.kt index bd2771aae..a7d0219f1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/PlatePressBlockEntity.kt @@ -13,6 +13,7 @@ import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage @@ -31,7 +32,7 @@ class PlatePressBlockEntity( p_155230_: BlockState ) : MatteryWorkerBlockEntity(MBlockEntities.PLATE_PRESS, p_155229_, p_155230_, ::ItemJob), IDroppableContainer { val container = MatteryContainer(this::setChangedLight, 2) - override val energy = WorkerEnergyStorage(this::setChangedLight) + override val energy = WorkerEnergyStorage(this::setChangedLight, ServerConfig.PLATE_PRESS) override val droppableContainer: Container get() = container diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index 7531cbff5..498209715 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -13,14 +13,18 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState +import net.minecraftforge.common.ForgeConfigSpec import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.items.CapabilityItemHandler +import ru.dbotthepony.mc.otm.ConciseBalanceValues +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.block.matter.MatterBottlerBlock import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.block.entity.WorkerState +import ru.dbotthepony.mc.otm.capability.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler @@ -34,13 +38,16 @@ import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.menu.MatterBottlerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.core.* +import ru.dbotthepony.mc.otm.registry.MBlocks +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.registry.WriteOnce class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, p_155229_, p_155230_), IMatterGraphNode, IDroppableContainer { override val matterNode = Graph6Node(this) private val resolverNode = LazyOptional.of { this } - override val energy = WorkerEnergyStorage(this) + override val energy = WorkerEnergyStorage(this, ENERGY_VALUES) var isBottling: Boolean = true set(value) { @@ -109,7 +116,7 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } }) - val matter: MatterHandlerImpl = object : MatterHandlerImpl(this::setChangedLight, MatterDirection.BIDIRECTIONAL, CAPACITY) { + val matter: MatterHandlerImpl = object : MatterHandlerImpl(this::setChangedLight, MatterDirection.BIDIRECTIONAL, ::CAPACITY) { override val direction: MatterDirection get() { return if (this@MatterBottlerBlockEntity.isBottling) MatterDirection.RECEIVE else MatterDirection.EXTRACT } @@ -164,7 +171,7 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.MATTER_BOTTLER.name override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return MatterBottlerMenu(containerID, inventory, this) @@ -335,11 +342,31 @@ class MatterBottlerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } companion object { - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_bottler") - private val MATTER_EXCHANGE_RATE = ImpreciseFraction("0.04") - private val ENERGY_CONSUMPTION = ImpreciseFraction(20) - private val EXTRACTION_TICKS = ImpreciseFraction(200) - private val CAPACITY = ImpreciseFraction(4) + val MATTER_EXCHANGE_RATE get() = _MATTER_EXCHANGE_RATE.get() + val ENERGY_CONSUMPTION get() = _ENERGY_CONSUMPTION.get() + val EXTRACTION_TICKS get() = _EXTRACTION_TICKS.get() + val CAPACITY get() = _CAPACITY.get() + + private var _MATTER_EXCHANGE_RATE: ImpreciseFractionConfigValue by WriteOnce() + private var _ENERGY_CONSUMPTION: ImpreciseFractionConfigValue by WriteOnce() + private var _EXTRACTION_TICKS: ImpreciseFractionConfigValue by WriteOnce() + private var _CAPACITY: ImpreciseFractionConfigValue by WriteOnce() + + var ENERGY_VALUES: ConciseBalanceValues by WriteOnce() + private set + + fun registerConfig(builder: ForgeConfigSpec.Builder) { + builder.push(MNames.MATTER_BOTTLER) + + ENERGY_VALUES = BlockEnergyStorageImpl.makeConfigEntry(builder) + + _MATTER_EXCHANGE_RATE = builder.defineImpreciseFraction("matterExchangeRate", ImpreciseFraction("0.04"), ImpreciseFraction("0.0001")) + _ENERGY_CONSUMPTION = builder.defineImpreciseFraction("energyConsumption", ImpreciseFraction(20), ImpreciseFraction.ONE) + _EXTRACTION_TICKS = builder.defineImpreciseFraction("extractionTicks", ImpreciseFraction(200), ImpreciseFraction.ONE) + _CAPACITY = builder.defineImpreciseFraction("matterCapacity", ImpreciseFraction(4), ImpreciseFraction.ONE_TENTH) + + builder.pop() + } const val IS_BOTTLING_KEY = "isBottling" } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt index f276d7a55..cfe8e76e6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt @@ -12,12 +12,15 @@ import net.minecraft.world.inventory.AbstractContainerMenu 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.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.items.IItemHandler +import ru.dbotthepony.mc.otm.ConciseBalanceValues import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity +import ru.dbotthepony.mc.otm.capability.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler @@ -36,7 +39,10 @@ import ru.dbotthepony.mc.otm.matter.canDecompose import ru.dbotthepony.mc.otm.matter.getMatterValue import ru.dbotthepony.mc.otm.menu.MatterDecomposerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.registry.MItems +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.registry.WriteOnce fun moveMatterAsDustIntoContainer(_matterValue: ImpreciseFraction, container: MatteryContainer, OUTPUT_DUST_MAIN: Int, OUTPUT_DUST_STACKING: Int): ImpreciseFraction { var matterValue = _matterValue @@ -121,11 +127,11 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) } } - override val energy = WorkerEnergyStorage(this, ENERGY_STORAGE, MAX_IO) + override val energy = WorkerEnergyStorage(this, ENERGY_VALUES) private var valid = true override val matterNode = Graph6Node(this) - val matter = MatterHandlerImpl(this::setChangedLight, MatterDirection.EXTRACT, CAPACITY) + val matter = MatterHandlerImpl(this::setChangedLight, MatterDirection.EXTRACT, ::CAPACITY) private var resolverMatter = LazyOptional.of { matter } private var resolverNode = LazyOptional.of { this } @@ -149,7 +155,7 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) } override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.MATTER_DECOMPOSER.name override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return MatterDecomposerMenu(containerID, inventory, this) @@ -263,11 +269,24 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) const val OUTPUT_DUST_MAIN = 1 const val OUTPUT_DUST_STACKING = 2 - private val CAPACITY = ImpreciseFraction("20") - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_decomposer") - private val BASE_CONSUMPTION = ImpreciseFraction(240) + val CAPACITY get() = _CAPACITY.get() + val BASE_CONSUMPTION get() = _BASE_CONSUMPTION.get() - private val ENERGY_STORAGE = ImpreciseFraction(400_000) - private val MAX_IO = ImpreciseFraction(2_000) + private var _CAPACITY: ImpreciseFractionConfigValue by WriteOnce() + private var _BASE_CONSUMPTION: ImpreciseFractionConfigValue by WriteOnce() + + var ENERGY_VALUES: ConciseBalanceValues by WriteOnce() + private set + + fun registerConfig(builder: ForgeConfigSpec.Builder) { + builder.push(MNames.MATTER_DECOMPOSER) + + ENERGY_VALUES = BlockEnergyStorageImpl.makeConfigEntry(builder, capacity = ImpreciseFraction(400_000), throughput = ImpreciseFraction(2_000)) + + _CAPACITY = builder.defineImpreciseFraction("matterCapacity", ImpreciseFraction(20), ImpreciseFraction.ONE_TENTH) + _BASE_CONSUMPTION = builder.defineImpreciseFraction("baseConsumption", ImpreciseFraction(240), ImpreciseFraction.ONE) + + builder.pop() + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt index 4235177c1..6d88c8853 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt @@ -12,12 +12,14 @@ import net.minecraft.world.inventory.AbstractContainerMenu 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.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional +import ru.dbotthepony.mc.otm.ConciseBalanceValues import ru.dbotthepony.mc.otm.block.IDroppableContainer -import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity +import ru.dbotthepony.mc.otm.capability.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.IMatterHandler @@ -33,8 +35,12 @@ import ru.dbotthepony.mc.otm.item.MatterDustItem import ru.dbotthepony.mc.otm.core.map import ru.dbotthepony.mc.otm.menu.MatterRecyclerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities -import ru.dbotthepony.mc.otm.container.set +import ru.dbotthepony.mc.otm.core.ImpreciseFractionConfigValue +import ru.dbotthepony.mc.otm.core.defineImpreciseFraction import ru.dbotthepony.mc.otm.core.set +import ru.dbotthepony.mc.otm.registry.MBlocks +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.registry.WriteOnce class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, ::Job), IMatterGraphNode, IDroppableContainer { @@ -42,7 +48,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) val matter = MatterHandlerImpl( this::matterLevelUpdated, MatterDirection.EXTRACT, - STORAGE + ::CAPACITY ) val container = MatteryContainer(this::itemContainerUpdated, 1) @@ -52,7 +58,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) override val matterNode = Graph6Node(this) private var resolverNode = LazyOptional.of { this } private var valid = true - override val energy = WorkerEnergyStorage(this::powerLevelUpdated, MAX_POWER) + override val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_CONFIG) override fun getMatterHandler(): IMatterHandler { return matter @@ -119,7 +125,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) } override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.MATTER_RECYCLER.name override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return MatterRecyclerMenu(containerID, inventory, this) @@ -172,10 +178,25 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) } companion object { - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_recycler") - private val STORAGE = ImpreciseFraction(40) - private val POWER_CONSUMPTION = ImpreciseFraction(80) - private val MAX_POWER = ImpreciseFraction(80_000) + private var _CAPACITY: ImpreciseFractionConfigValue by WriteOnce() + private var _POWER_CONSUMPTION: ImpreciseFractionConfigValue by WriteOnce() + var ENERGY_CONFIG: ConciseBalanceValues by WriteOnce() + private set + + private val CAPACITY get() = _CAPACITY.get() + private val POWER_CONSUMPTION get() = _POWER_CONSUMPTION.get() + + fun registerConfig(builder: ForgeConfigSpec.Builder) { + builder.push(MNames.MATTER_RECYCLER) + + ENERGY_CONFIG = BlockEnergyStorageImpl.makeConfigEntry(builder, capacity = ImpreciseFraction(80_000)) + + _CAPACITY = builder.defineImpreciseFraction("matterCapacity", ImpreciseFraction(40), ImpreciseFraction.ONE) + _POWER_CONSUMPTION = builder.defineImpreciseFraction("powerConsumption", ImpreciseFraction(80), ImpreciseFraction.ONE) + + builder.pop() + } + private const val MATTER_TICKS = 200.0 private val MATTER_PER_TICK = ImpreciseFraction(1.0 / MATTER_TICKS) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt index e8a4c89a5..3d0173acd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt @@ -12,11 +12,14 @@ import net.minecraft.world.inventory.AbstractContainerMenu 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.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional +import ru.dbotthepony.mc.otm.ConciseBalanceValues import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity +import ru.dbotthepony.mc.otm.capability.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.* @@ -31,6 +34,9 @@ import ru.dbotthepony.mc.otm.menu.MatterReplicatorMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.* +import ru.dbotthepony.mc.otm.registry.MBlocks +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.registry.WriteOnce class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.MATTER_REPLICATOR, p_155229_, p_155230_, { @@ -94,21 +100,21 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } } - override val energy = WorkerEnergyStorage(this::powerLevelUpdated, STORAGE, MAX_IO) + override val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES) override val matterNode = Graph6Node(this) private val resolverNode = LazyOptional.of { this } val matter = MatterHandlerImpl( this::matterLevelUpdated, MatterDirection.RECEIVE, - ImpreciseFraction(2) + ::MATTER_CAPACITY ) val container = MatteryContainer(this::itemContainerUpdated, 5) private val itemHandler = container.handler(MatteryContainerFilterOnlyOut) override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.MATTER_REPLICATOR.name override val droppableContainer: Container get() = container @@ -279,11 +285,28 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } companion object { - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_replicator") - private val BASE_CONSUMPTION = ImpreciseFraction(400) - private val DRAIN_MULT = ImpreciseFraction(200) - private val STORAGE = ImpreciseFraction(200_000) - private val MAX_IO = ImpreciseFraction(4_000) + private val BASE_CONSUMPTION get() = _BASE_CONSUMPTION.get() + private val DRAIN_MULT get() = _DRAIN_MULT.get() + private val MATTER_CAPACITY get() = _MATTER_CAPACITY.get() + + private var _BASE_CONSUMPTION: ImpreciseFractionConfigValue by WriteOnce() + private var _DRAIN_MULT: ImpreciseFractionConfigValue by WriteOnce() + private var _MATTER_CAPACITY: ImpreciseFractionConfigValue by WriteOnce() + + var ENERGY_VALUES: ConciseBalanceValues by WriteOnce() + private set + + fun registerConfig(builder: ForgeConfigSpec.Builder) { + builder.push(MNames.MATTER_REPLICATOR) + + ENERGY_VALUES = BlockEnergyStorageImpl.makeConfigEntry(builder, capacity = ImpreciseFraction(200_000), throughput = ImpreciseFraction(4_000)) + + _BASE_CONSUMPTION = builder.defineImpreciseFraction("basePowerConsumption", ImpreciseFraction(400), ImpreciseFraction.ONE) + _DRAIN_MULT = builder.comment("How much 'ticks' of replication should replicator drain matter from network when running low on internal matter buffer. This is ultimately a performance value.").defineImpreciseFraction("drainMultiplier", ImpreciseFraction(200), ImpreciseFraction.ONE) + _MATTER_CAPACITY = builder.defineImpreciseFraction("matterCapacity", ImpreciseFraction(2), ImpreciseFraction.ONE_TENTH) + + builder.pop() + } const val FIRST_ACTUAL_OUTPUT_SLOT = 0 const val LAST_ACTUAL_OUTPUT_SLOT = 2 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt index 50c554b10..92eb84170 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt @@ -12,12 +12,15 @@ import net.minecraft.world.inventory.AbstractContainerMenu 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.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional +import ru.dbotthepony.mc.otm.ConciseBalanceValues import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity +import ru.dbotthepony.mc.otm.capability.BlockEnergyStorageImpl import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.IPatternState @@ -25,6 +28,8 @@ import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainerFilter import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import ru.dbotthepony.mc.otm.core.ImpreciseFractionConfigValue +import ru.dbotthepony.mc.otm.core.defineImpreciseFraction import ru.dbotthepony.mc.otm.core.map import ru.dbotthepony.mc.otm.graph.Graph6Node import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphNode @@ -32,6 +37,9 @@ import ru.dbotthepony.mc.otm.graph.matter.MatterNetworkGraph import ru.dbotthepony.mc.otm.matter.* import ru.dbotthepony.mc.otm.menu.MatterScannerMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MBlocks +import ru.dbotthepony.mc.otm.registry.MNames +import ru.dbotthepony.mc.otm.registry.WriteOnce import java.util.* import kotlin.math.pow @@ -39,7 +47,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ::ItemJob), IMatterGraphNode, IDroppableContainer { val container = MatteryContainer(this::itemContainerUpdated, 1) - override val energy = WorkerEnergyStorage(this::powerLevelUpdated, STORAGE, MAX_IO) + override val energy = WorkerEnergyStorage(this::powerLevelUpdated, ENERGY_VALUES) private val itemHandler = container.handler(object : MatteryContainerFilter { override fun canInsert(slot: Int, stack: ItemStack): Boolean { @@ -108,7 +116,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.MATTER_SCANNER.name override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return MatterScannerMenu(containerID, inventory, this) @@ -207,9 +215,19 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } companion object { - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.matter_scanner") - private val BASE_CONSUMPTION = ImpreciseFraction("40") - private val STORAGE = ImpreciseFraction(80_000) - private val MAX_IO = ImpreciseFraction(400) + private val BASE_CONSUMPTION get() = _BASE_CONSUMPTION.get() + + private var _BASE_CONSUMPTION: ImpreciseFractionConfigValue by WriteOnce() + var ENERGY_VALUES: ConciseBalanceValues by WriteOnce() + private set + + fun registerConfig(builder: ForgeConfigSpec.Builder) { + builder.push(MNames.MATTER_SCANNER) + + ENERGY_VALUES = BlockEnergyStorageImpl.makeConfigEntry(builder, capacity = ImpreciseFraction(80_000), throughput = ImpreciseFraction(400)) + _BASE_CONSUMPTION = builder.defineImpreciseFraction("baseConsumption", ImpreciseFraction(40), ImpreciseFraction.ONE) + + builder.pop() + } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt index 5c387641f..d51dacf3e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt @@ -13,6 +13,7 @@ import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.LazyOptional +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode @@ -25,11 +26,12 @@ import ru.dbotthepony.mc.otm.core.map import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.storage.* class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.DRIVE_RACK, p_155229_, p_155230_) { - override val energy = WorkerEnergyStorage(this, STORAGE) + override val energy = WorkerEnergyStorage(this, ServerConfig.DRIVE_RACK) val container: MatteryContainer = object : MatteryContainer(this::setChanged, 4) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { @@ -74,7 +76,7 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.DRIVE_RACK.name override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return DriveRackMenu(containerID, inventory, this) @@ -100,9 +102,4 @@ class DriveRackBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : super.setRemoved() cell.destroy(level) } - - companion object { - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.drive_rack") - private val STORAGE = ImpreciseFraction(80_000) - } } \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt index 07514187d..3f17d6fd1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt @@ -12,6 +12,7 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity @@ -25,6 +26,7 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.map import ru.dbotthepony.mc.otm.core.set +import ru.dbotthepony.mc.otm.registry.MBlocks import javax.annotation.ParametersAreNonnullByDefault class DriveViewerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.DRIVE_VIEWER, p_155229_, p_155230_), IDroppableContainer { @@ -46,7 +48,7 @@ class DriveViewerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte } } - override val energy = WorkerEnergyStorage(this) + override val energy = WorkerEnergyStorage(this, ServerConfig.DRIVE_VIEWER) val container: MatteryContainer = object : MatteryContainer(this::setChanged, 1) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { @@ -73,7 +75,7 @@ class DriveViewerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte override val droppableContainer: Container get() = container override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.DRIVE_VIEWER.name override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? { return DriveViewerMenu(containerID, inventory, this) @@ -92,8 +94,4 @@ class DriveViewerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte fun tick() { batteryChargeLoop() } - - companion object { - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.drive_viewer") - } } \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt index 7fa158337..62bd31287 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt @@ -26,6 +26,7 @@ import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.network.NetworkEvent import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability @@ -42,6 +43,7 @@ import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.getEnum import ru.dbotthepony.mc.otm.core.set +import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.storage.* import java.math.BigInteger import java.util.* @@ -182,7 +184,7 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ITEM_MONITOR, p_155229_, p_155230_), IStorageEventConsumer { - override val energy = WorkerEnergyStorage(this) + override val energy = WorkerEnergyStorage(this, ServerConfig.ITEM_MONITOR) var poweredView: PoweredVirtualComponent? = null private set @@ -488,7 +490,7 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.ITEM_MONITOR.name override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return ItemMonitorMenu(containerID, inventory, this) @@ -521,8 +523,4 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : super.setRemoved() cell.destroy(level) } - - companion object { - private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.item_monitor") - } } \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt index 238755480..e3c76b269 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt @@ -33,6 +33,7 @@ import ru.dbotthepony.mc.otm.graph.storage.BasicStorageGraphNode import ru.dbotthepony.mc.otm.graph.storage.StorageNetworkGraph import ru.dbotthepony.mc.otm.menu.StorageBusMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities +import ru.dbotthepony.mc.otm.registry.MBlocks import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.storage.* import java.lang.ref.WeakReference @@ -62,13 +63,13 @@ private fun Long.clamp(): Int { class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_BUS, blockPos, blockState) { override val defaultDisplayName: Component - get() = MACHINE_NAME + get() = MBlocks.STORAGE_BUS.name override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return StorageBusMenu(containerID, inventory, this) } - override val energy = WorkerEnergyStorage(this, maxBatteryLevel = MAX_POWER) + override val energy = WorkerEnergyStorage(this::setChangedLight, ServerConfig.STORAGE_INTERFACES) val cell: BasicStorageGraphNode = object : BasicStorageGraphNode(energy), GraphNodeListener { override fun onNeighbour(node: Graph6Node<*>, direction: Direction) { @@ -178,8 +179,6 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter } companion object { - private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_BUS}") - private val MAX_POWER = ImpreciseFraction(10_000) const val MAX_FILTERS = 6 * 3 } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt index 5495b8d0c..26bfa455f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt @@ -42,11 +42,9 @@ abstract class AbstractStorageImportExport( blockType: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState, - maxBatteryLevel: ImpreciseFraction = MAX_POWER, - maxInput: ImpreciseFraction? = BlockEnergyStorageImpl.DEFAULT_MAX_IO, - maxOutput: ImpreciseFraction? = maxInput + energyValues: ConciseBalanceValues = ServerConfig.STORAGE_INTERFACES ) : MatteryPoweredBlockEntity(blockType, blockPos, blockState) { - final override val energy = WorkerEnergyStorage(this, maxBatteryLevel, maxInput, maxOutput) + final override val energy = WorkerEnergyStorage(this::setChangedLight, energyValues) val cell: BasicStorageGraphNode = object : BasicStorageGraphNode(energy), GraphNodeListener { override fun onNeighbour(node: Graph6Node<*>, direction: Direction) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StoragePowerSupplierBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StoragePowerSupplierBlockEntity.kt index 659ae0184..37be97800 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StoragePowerSupplierBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StoragePowerSupplierBlockEntity.kt @@ -13,6 +13,7 @@ import net.minecraft.world.level.block.state.BlockState import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.util.LazyOptional import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability @@ -88,7 +89,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState var demand = ImpreciseFraction.ZERO var i = 0 - val available = energy.batteryLevel.coerceAtMost(MAX_IO) + val available = energy.batteryLevel.coerceAtMost(ServerConfig.STORAGE_POWER_SUPPLIER.throughput) for (demanding in graph.powerDemandingNodes) { val received = demanding.receiveEnergyOuter(available, true) @@ -114,7 +115,7 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState } } - override val energy = WorkerEnergyStorage(this, MAX_POWER, MAX_IO) + override val energy = WorkerEnergyStorage(this, ServerConfig.STORAGE_POWER_SUPPLIER) override fun saveAdditional(nbt: CompoundTag) { super.saveAdditional(nbt) @@ -128,8 +129,6 @@ class StoragePowerSupplierBlockEntity(blockPos: BlockPos, blockState: BlockState companion object { private val MACHINE_NAME = TranslatableComponent("block.${OverdriveThatMatters.MOD_ID}.${MNames.STORAGE_POWER_SUPPLIER}") - private val MAX_POWER = ImpreciseFraction(100_000) - private val MAX_IO = ImpreciseFraction(320) const val POWER_PASSED_KEY = "powerPassed" } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/EnergyStorageImpl.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/EnergyStorageImpl.kt index 2afeeed25..32971fbe6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/EnergyStorageImpl.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/EnergyStorageImpl.kt @@ -13,19 +13,23 @@ import net.minecraft.world.item.TooltipFlag import net.minecraft.world.level.BlockGetter import net.minecraft.world.level.Level import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraftforge.common.ForgeConfigSpec import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.capabilities.ICapabilityProvider import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.energy.IEnergyStorage +import ru.dbotthepony.mc.otm.ConciseBalanceValues +import ru.dbotthepony.mc.otm.VerboseBalanceValues import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.defineImpreciseFraction import ru.dbotthepony.mc.otm.core.formatPower -import ru.dbotthepony.mc.otm.core.ifPresentK import ru.dbotthepony.mc.otm.core.map +import ru.dbotthepony.mc.otm.core.mapIf import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.tagNotNull @@ -250,22 +254,48 @@ open class EnergyCapacitorItem( initialBatteryLevel: ImpreciseFraction = ImpreciseFraction.ZERO ) : ItemEnergyStorageImpl(FlowDirection.BI_DIRECTIONAL, stack, maxBatteryLevel, maxInput, maxOutput, initialBatteryLevel) -sealed class BlockEnergyStorageImpl constructor( +sealed class BlockEnergyStorageImpl( protected val listener: () -> Unit, final override val direction: FlowDirection, - maxBatteryLevel: ImpreciseFraction, - maxInput: ImpreciseFraction?, - maxOutput: ImpreciseFraction?, + private val maxBatteryLevelProvider: () -> ImpreciseFraction, + private val maxInputProvider: () -> ImpreciseFraction?, + private val maxOutputProvider: () -> ImpreciseFraction?, ) : IMatteryEnergyStorage, INBTSerializable, IEnergyStorageImpl { - final override var maxInput: ImpreciseFraction? = maxInput - protected set - final override var maxOutput: ImpreciseFraction? = maxOutput - protected set + constructor( + listener: () -> Unit, + direction: FlowDirection, + maxBatteryLevel: ImpreciseFraction, + maxInput: ImpreciseFraction?, + maxOutput: ImpreciseFraction?, + ) : this(listener, direction, { maxBatteryLevel }, { maxInput }, { maxOutput }) - override var maxBatteryLevel: ImpreciseFraction = maxBatteryLevel + private var maxInputStorage: ImpreciseFraction? = null + private var maxOutputStorage: ImpreciseFraction? = null + private var maxBatteryLevelStorage: ImpreciseFraction? = null + + final override var maxInput: ImpreciseFraction? + get() = maxInputStorage ?: maxInputProvider.invoke() protected set(value) { - if (value != field) { - field = value + if (value != maxInputStorage) { + maxInputStorage = value + listener.invoke() + } + } + + final override var maxOutput: ImpreciseFraction? + get() = maxOutputStorage ?: maxOutputProvider.invoke() + protected set(value) { + if (value != maxOutputStorage) { + maxOutputStorage = value + listener.invoke() + } + } + + override var maxBatteryLevel: ImpreciseFraction + get() = maxBatteryLevelStorage ?: maxBatteryLevelProvider.invoke() + protected set(value) { + if (value != maxBatteryLevelStorage) { + maxBatteryLevelStorage = value listener.invoke() } } @@ -353,19 +383,19 @@ sealed class BlockEnergyStorageImpl constructor( override fun serializeNBT(): CompoundTag { val tag = CompoundTag() tag[ENERGY_STORED_KEY] = batteryLevel.serializeNBT() - tag[ENERGY_STORED_MAX_KEY] = maxBatteryLevel.serializeNBT() - maxInput?.let { tag[MAX_INPUT_KEY] = it.serializeNBT() } - maxOutput?.let { tag[MAX_OUTPUT_KEY] = it.serializeNBT() } + maxBatteryLevelStorage?.let { tag[ENERGY_STORED_MAX_KEY] = it.serializeNBT() } + maxInputStorage?.let { tag[MAX_INPUT_KEY] = it.serializeNBT() } + maxOutputStorage?.let { tag[MAX_OUTPUT_KEY] = it.serializeNBT() } return tag } override fun deserializeNBT(nbt: CompoundTag) { batteryLevel = nbt.map(ENERGY_STORED_KEY, ImpreciseFraction.Companion::deserializeNBT) ?: ImpreciseFraction.ZERO - maxBatteryLevel = nbt.map(ENERGY_STORED_MAX_KEY, ImpreciseFraction.Companion::deserializeNBT) ?: ImpreciseFraction.ZERO - maxInput = nbt.map(MAX_INPUT_KEY, ImpreciseFraction.Companion::deserializeNBT) - maxOutput = nbt.map(MAX_OUTPUT_KEY, ImpreciseFraction.Companion::deserializeNBT) + maxBatteryLevelStorage = nbt.mapIf(ENERGY_STORED_MAX_KEY, ImpreciseFraction.Companion::deserializeNBT) + maxInputStorage = nbt.mapIf(MAX_INPUT_KEY, ImpreciseFraction.Companion::deserializeNBT) + maxOutputStorage = nbt.mapIf(MAX_OUTPUT_KEY, ImpreciseFraction.Companion::deserializeNBT) } var resolver: LazyOptional = LazyOptional.of { this } @@ -387,25 +417,62 @@ sealed class BlockEnergyStorageImpl constructor( const val ENERGY_STORED_MAX_KEY = "energy_stored_max" const val MAX_INPUT_KEY = "max_input" const val MAX_OUTPUT_KEY = "max_output" + + fun makeConfigEntry(builder: ForgeConfigSpec.Builder, name: String? = null, capacity: ImpreciseFraction = DEFAULT_MAX_CAPACITY, throughput: ImpreciseFraction = DEFAULT_MAX_IO): ConciseBalanceValues { + if (name != null) + builder.push(name) + + val obj = object : ConciseBalanceValues { + override val capacity: ImpreciseFraction by builder.defineImpreciseFraction("capacity", capacity, ImpreciseFraction.ONE) + override val throughput: ImpreciseFraction by builder.defineImpreciseFraction("throughput", throughput, ImpreciseFraction.ONE) + } + + if (name != null) + builder.pop() + + return obj + } } } open class WorkerEnergyStorage( listener: () -> Unit, - maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, - maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, - maxOutput: ImpreciseFraction? = maxInput + maxBatteryLevel: () -> ImpreciseFraction = { DEFAULT_MAX_CAPACITY }, + maxInput: () -> ImpreciseFraction? = { DEFAULT_MAX_IO }, + maxOutput: () -> ImpreciseFraction? = maxInput ) : BlockEnergyStorageImpl(listener, FlowDirection.INPUT, maxBatteryLevel, maxInput, maxOutput) { + constructor( + listener: () -> Unit, + maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, + maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, + maxOutput: ImpreciseFraction? = maxInput) : this(listener, { maxBatteryLevel }, { maxInput }, { maxOutput }) + + constructor( + listener: () -> Unit, + values: ConciseBalanceValues) : this(listener, values::capacity, values::throughput, values::throughput) + + constructor( + listener: BlockEntity, + values: ConciseBalanceValues) : this(listener::setChanged, values::capacity, values::throughput, values::throughput) + + constructor( + listener: () -> Unit, + values: VerboseBalanceValues) : this(listener, values::capacity, values::receive, values::extract) + + constructor( + listener: BlockEntity, + values: VerboseBalanceValues) : this(listener::setChanged, values::capacity, values::receive, values::extract) + constructor( listener: BlockEntity, maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, - maxOutput: ImpreciseFraction? = maxInput) : this({listener.setChanged()}, maxBatteryLevel, maxInput, maxOutput) + maxOutput: ImpreciseFraction? = maxInput) : this(listener::setChanged, maxBatteryLevel, maxInput, maxOutput) companion object { fun appendHoverText(itemStack: ItemStack, tooltips: MutableList) { val tag = (itemStack.tag?.get(BlockItem.BLOCK_ENTITY_TAG) as? CompoundTag)?.get(MatteryBlockEntity.ENERGY_KEY) as? CompoundTag ?: return - val cap = WorkerEnergyStorage({}) + val cap = WorkerEnergyStorage({}, DEFAULT_MAX_CAPACITY) cap.deserializeNBT(tag) batteryLevel(cap, tooltips) } @@ -418,20 +485,42 @@ open class WorkerEnergyStorage( open class GeneratorEnergyStorage( listener: () -> Unit, - maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, - maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, - maxOutput: ImpreciseFraction? = maxInput + maxBatteryLevel: () -> ImpreciseFraction = { DEFAULT_MAX_CAPACITY }, + maxInput: () -> ImpreciseFraction? = { DEFAULT_MAX_IO }, + maxOutput: () -> ImpreciseFraction? = maxInput ) : BlockEnergyStorageImpl(listener, FlowDirection.OUTPUT, maxBatteryLevel, maxInput, maxOutput) { + constructor( + listener: () -> Unit, + maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, + maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, + maxOutput: ImpreciseFraction? = maxInput) : this(listener, { maxBatteryLevel }, { maxInput }, { maxOutput }) + + constructor( + listener: () -> Unit, + values: ConciseBalanceValues) : this(listener, values::capacity, values::throughput, values::throughput) + + constructor( + listener: BlockEntity, + values: ConciseBalanceValues) : this(listener::setChanged, values::capacity, values::throughput, values::throughput) + + constructor( + listener: () -> Unit, + values: VerboseBalanceValues) : this(listener, values::capacity, values::receive, values::extract) + + constructor( + listener: BlockEntity, + values: VerboseBalanceValues) : this(listener::setChanged, values::capacity, values::receive, values::extract) + constructor( listener: BlockEntity, maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, - maxOutput: ImpreciseFraction? = maxInput) : this({listener.setChanged()}, maxBatteryLevel, maxInput, maxOutput) + maxOutput: ImpreciseFraction? = maxInput) : this(listener::setChanged, maxBatteryLevel, maxInput, maxOutput) companion object { fun appendHoverText(itemStack: ItemStack, tooltips: MutableList) { val tag = (itemStack.tag?.get(BlockItem.BLOCK_ENTITY_TAG) as? CompoundTag)?.get(MatteryBlockEntity.ENERGY_KEY) as? CompoundTag ?: return - val cap = GeneratorEnergyStorage({}) + val cap = GeneratorEnergyStorage({}, DEFAULT_MAX_CAPACITY) cap.deserializeNBT(tag) batteryLevel(cap, tooltips) } @@ -444,20 +533,42 @@ open class GeneratorEnergyStorage( open class CapacitorEnergyStorage( listener: () -> Unit, - maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, - maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, - maxOutput: ImpreciseFraction? = maxInput + maxBatteryLevel: () -> ImpreciseFraction = { DEFAULT_MAX_CAPACITY }, + maxInput: () -> ImpreciseFraction? = { DEFAULT_MAX_IO }, + maxOutput: () -> ImpreciseFraction? = maxInput ) : BlockEnergyStorageImpl(listener, FlowDirection.BI_DIRECTIONAL, maxBatteryLevel, maxInput, maxOutput) { + constructor( + listener: () -> Unit, + maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, + maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, + maxOutput: ImpreciseFraction? = maxInput) : this(listener, { maxBatteryLevel }, { maxInput }, { maxOutput }) + + constructor( + listener: () -> Unit, + values: ConciseBalanceValues) : this(listener, values::capacity, values::throughput, values::throughput) + + constructor( + listener: BlockEntity, + values: ConciseBalanceValues) : this(listener::setChanged, values::capacity, values::throughput, values::throughput) + + constructor( + listener: () -> Unit, + values: VerboseBalanceValues) : this(listener, values::capacity, values::receive, values::extract) + + constructor( + listener: BlockEntity, + values: VerboseBalanceValues) : this(listener::setChanged, values::capacity, values::receive, values::extract) + constructor( listener: BlockEntity, maxBatteryLevel: ImpreciseFraction = DEFAULT_MAX_CAPACITY, maxInput: ImpreciseFraction? = DEFAULT_MAX_IO, - maxOutput: ImpreciseFraction? = maxInput) : this({listener.setChanged()}, maxBatteryLevel, maxInput, maxOutput) + maxOutput: ImpreciseFraction? = maxInput) : this(listener::setChanged, maxBatteryLevel, maxInput, maxOutput) companion object { fun appendHoverText(itemStack: ItemStack, tooltips: MutableList) { val tag = (itemStack.tag?.get(BlockItem.BLOCK_ENTITY_TAG) as? CompoundTag)?.get(MatteryBlockEntity.ENERGY_KEY) as? CompoundTag ?: return - val cap = CapacitorEnergyStorage({}) + val cap = CapacitorEnergyStorage({}, DEFAULT_MAX_CAPACITY) cap.deserializeNBT(tag) batteryLevel(cap, tooltips) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/matter/MatterHandlerImpl.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/matter/MatterHandlerImpl.kt index 4adc14a74..82f024180 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/matter/MatterHandlerImpl.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/matter/MatterHandlerImpl.kt @@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.capability.matter import net.minecraft.nbt.CompoundTag import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.LazyOptional +import ru.dbotthepony.mc.otm.ConciseBalanceValues +import ru.dbotthepony.mc.otm.VerboseBalanceValues import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.set @@ -10,10 +12,36 @@ import ru.dbotthepony.mc.otm.core.set open class MatterHandlerImpl @JvmOverloads constructor( protected val listener: Runnable?, override val direction: MatterDirection, - override val maxStoredMatter: ImpreciseFraction, - val maxReceive: ImpreciseFraction? = null, - val maxExtract: ImpreciseFraction? = maxReceive + protected val maxStoredMatterSupplier: () -> ImpreciseFraction, + protected val maxReceiveSupplier: () -> ImpreciseFraction? = { null }, + protected val maxExtractSupplier: () -> ImpreciseFraction? = maxReceiveSupplier ) : IMatterHandler, INBTSerializable { + constructor( + listener: Runnable?, + direction: MatterDirection, + maxStoredMatter: ImpreciseFraction, + maxReceive: ImpreciseFraction? = null, + maxExtract: ImpreciseFraction? = null, + ) : this(listener, direction, { maxStoredMatter }, { maxReceive }, { maxExtract }) + + constructor( + listener: Runnable?, + direction: MatterDirection, + values: ConciseBalanceValues + ) : this(listener, direction, values::capacity, values::throughput, values::throughput) + + constructor( + listener: Runnable?, + direction: MatterDirection, + values: VerboseBalanceValues + ) : this(listener, direction, values::capacity, values::receive, values::extract) + + val maxReceive get() = maxReceiveSupplier.invoke() + val maxExtract get() = maxExtractSupplier.invoke() + + override val maxStoredMatter: ImpreciseFraction + get() = maxStoredMatterSupplier.invoke() + override var storedMatter = ImpreciseFraction.ZERO protected set @@ -48,7 +76,7 @@ open class MatterHandlerImpl @JvmOverloads constructor( if (maxReceive == null) { new = (storedMatter + howMuch).coerceAtMost(maxStoredMatter) } else { - new = (storedMatter + howMuch.coerceAtMost(maxReceive)).coerceAtMost(maxStoredMatter) + new = (storedMatter + howMuch.coerceAtMost(maxReceive!!)).coerceAtMost(maxStoredMatter) } val diff = new - storedMatter @@ -74,7 +102,7 @@ open class MatterHandlerImpl @JvmOverloads constructor( if (maxExtract == null) { new = (storedMatter - howMuch).moreThanZero() } else { - new = (storedMatter - howMuch.coerceAtMost(maxExtract)).moreThanZero() + new = (storedMatter - howMuch.coerceAtMost(maxExtract!!)).moreThanZero() } val diff = storedMatter - new diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/CompoundTagExt.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/CompoundTagExt.kt index 0991db9a8..4595a85e5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/CompoundTagExt.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/CompoundTagExt.kt @@ -51,6 +51,16 @@ inline fun CompoundTag.map(key: String, consumer: (T) -> R return null } +inline fun CompoundTag.mapIf(key: String, consumer: (T) -> R): R? { + val tag = get(key) + + if (tag is T) { + return consumer(tag) + } + + return null +} + inline fun > CompoundTag.getEnum(key: String): R { val tag = get(key) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index c25d8dc88..7f2a35d03 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -18,6 +18,7 @@ import net.minecraft.world.level.block.state.StateHolder import net.minecraft.world.level.block.state.properties.Property import net.minecraft.world.phys.Vec3 import net.minecraftforge.common.ForgeConfigSpec +import net.minecraftforge.common.ForgeConfigSpec.ConfigValue import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.items.IItemHandler import net.minecraftforge.registries.ForgeRegistries @@ -25,6 +26,7 @@ import net.minecraftforge.registries.ForgeRegistry import net.minecraftforge.registries.IForgeRegistry import net.minecraftforge.registries.RegistryManager import ru.dbotthepony.mc.otm.ClientConfig +import ru.dbotthepony.mc.otm.item.BatteryItem import java.math.BigInteger import kotlin.reflect.KProperty @@ -339,10 +341,6 @@ fun List.toImmutableList(): ImmutableList { return ImmutableList.copyOf(this) } -operator fun ForgeConfigSpec.ConfigValue.setValue(config: ClientConfig, property: KProperty<*>, value: T) { - set(value) +operator fun (() -> R).getValue(thisRef: Any, property: KProperty<*>): R { + return invoke() } - -operator fun ForgeConfigSpec.ConfigValue.getValue(config: Any, property: KProperty<*>): T { - return get() -} \ No newline at end of file diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt index 8f6831cea..8f09996d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ImpreciseFraction.kt @@ -5,6 +5,9 @@ import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.StringTag import net.minecraft.nbt.Tag import net.minecraft.network.FriendlyByteBuf +import net.minecraftforge.common.ForgeConfigSpec +import ru.dbotthepony.mc.otm.ObservedConfigValue +import ru.dbotthepony.mc.otm.appendComment import java.io.InputStream import java.io.OutputStream import java.math.BigDecimal @@ -144,7 +147,7 @@ private val BI_MINUS_ONE = -BigInteger.ONE * */ @Suppress("unused") -class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0) : Number(), Comparable { +class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Double = 0.0) : Number(), Comparable, java.io.Serializable { @JvmOverloads constructor(whole: Byte, decimal: Double = 0.0) : this(BigInteger.valueOf(whole.toLong()), decimal) @JvmOverloads constructor(whole: Short, decimal: Double = 0.0) : this(BigInteger.valueOf(whole.toLong()), decimal) @JvmOverloads constructor(whole: Int, decimal: Double = 0.0) : this(BigInteger.valueOf(whole.toLong()), decimal) @@ -752,6 +755,9 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do } companion object { + @JvmStatic + val serialVersionUID: Long = 287354739494574838L + @JvmField val MINUS_ZERO = ImpreciseFraction(0, -0.0) @JvmField val ZERO = ImpreciseFraction(BigInteger.ZERO) @JvmField val ONE = ImpreciseFraction(BigInteger.ONE) @@ -769,6 +775,8 @@ class ImpreciseFraction @JvmOverloads constructor(whole: BigInteger, decimal: Do @JvmField val DOUBLE_MAX_VALUE = ImpreciseFraction(BI_DOUBLE_MAX) @JvmField val DOUBLE_MIN_VALUE = ImpreciseFraction(BI_DOUBLE_MIN) + @JvmField val ONE_TENTH = ImpreciseFraction("0.1") + private val cache = Array(2048) { ImpreciseFraction(it - 1024) } /** @@ -860,3 +868,49 @@ fun Byte.toImpreciseFraction() = ImpreciseFraction(this) fun Short.toImpreciseFraction() = ImpreciseFraction(this) fun Long.toImpreciseFraction() = ImpreciseFraction(this) fun ImpreciseFraction.toImpreciseFraction() = this + +class ImpreciseFractionConfigValue( + parent: ForgeConfigSpec.ConfigValue, + val minimum: ImpreciseFraction? = null, + val maximum: ImpreciseFraction? = null, +) : ObservedConfigValue(parent) { + override fun fromValue(value: String): ImpreciseFraction? { + try { + val parsed = ImpreciseFraction(value) + + if (minimum != null && minimum > parsed) { + return minimum + } else if (maximum != null && maximum < parsed) { + return maximum + } + + return parsed + } catch (err: java.lang.NumberFormatException) { + return null + } + } + + override fun toValue(value: ImpreciseFraction): Pair { + return value.toString() to value + } +} + +private fun ForgeConfigSpec.Builder.commentRange(minimum: ImpreciseFraction?, maximum: ImpreciseFraction?) { + if (minimum != null && maximum != null) { + appendComment("Range: $minimum ~ $maximum") + } else if (minimum != null) { + appendComment("Range: >= $minimum") + } else if (maximum != null) { + appendComment("Range: <= $maximum") + } +} + +fun ForgeConfigSpec.Builder.defineImpreciseFraction(path: String, defaultValue: ImpreciseFraction, minimum: ImpreciseFraction? = null, maximum: ImpreciseFraction? = null): ImpreciseFractionConfigValue { + commentRange(minimum, maximum) + return ImpreciseFractionConfigValue(define(path, defaultValue.toString()), minimum, maximum) +} + +fun ForgeConfigSpec.Builder.defineImpreciseFraction(path: List, defaultValue: ImpreciseFraction, minimum: ImpreciseFraction? = null, maximum: ImpreciseFraction? = null): ImpreciseFractionConfigValue { + commentRange(minimum, maximum) + return ImpreciseFractionConfigValue(define(path, defaultValue.toString()), minimum, maximum) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/BatteryItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/BatteryItem.kt index 0b0180cff..08ecbb616 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/BatteryItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/BatteryItem.kt @@ -14,7 +14,10 @@ import net.minecraft.world.item.* import net.minecraft.world.level.Level import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.capabilities.ICapabilityProvider +import ru.dbotthepony.mc.otm.BatteryBalanceValues import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.ServerConfig +import ru.dbotthepony.mc.otm.VerboseBalanceValues import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.core.* @@ -23,7 +26,7 @@ import ru.dbotthepony.mc.otm.runIfClient import kotlin.math.roundToInt open class BatteryItem : Item { - private inner class Power(stack: ItemStack) : EnergyCapacitorItem(stack, this@BatteryItem.storage, this@BatteryItem.receive, this@BatteryItem.extract, initialBatteryLevel = this@BatteryItem.initialBatteryLevel) { + private inner class Power(stack: ItemStack) : EnergyCapacitorItem(stack, this@BatteryItem.capacity, this@BatteryItem.receive, this@BatteryItem.extract, initialBatteryLevel = this@BatteryItem.initialBatteryLevel) { override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { if (isCreative) return howMuch return super.extractEnergyInner(howMuch, simulate) @@ -44,27 +47,61 @@ open class BatteryItem : Item { } private val isCreative: Boolean - val storage: ImpreciseFraction - val receive: ImpreciseFraction - val extract: ImpreciseFraction - val initialBatteryLevel: ImpreciseFraction - constructor(storage: ImpreciseFraction, receive: ImpreciseFraction, extract: ImpreciseFraction = receive, initialBatteryLevel: ImpreciseFraction = ImpreciseFraction.ZERO) : super( - Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB) - ) { + val _capacity: () -> ImpreciseFraction + val _receive: () -> ImpreciseFraction + val _extract: () -> ImpreciseFraction + val _initialBatteryLevel: () -> ImpreciseFraction + + val capacity: ImpreciseFraction + get() = _capacity.invoke() + val receive: ImpreciseFraction + get() = _receive.invoke() + val extract: ImpreciseFraction + get() = _extract.invoke() + val initialBatteryLevel: ImpreciseFraction + get() = _initialBatteryLevel.invoke() + + constructor( + storage: ImpreciseFraction, + receive: ImpreciseFraction, + extract: ImpreciseFraction = receive, + initialBatteryLevel: ImpreciseFraction = ImpreciseFraction.ZERO + ) : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { isCreative = false - this.storage = storage - this.receive = receive - this.extract = extract - this.initialBatteryLevel = initialBatteryLevel + this._capacity = { storage } + this._receive = { receive } + this._extract = { extract } + this._initialBatteryLevel = { initialBatteryLevel } + } + + constructor( + storage: () -> ImpreciseFraction, + receive: () -> ImpreciseFraction, + extract: () -> ImpreciseFraction = receive, + initialBatteryLevel: () -> ImpreciseFraction = { ImpreciseFraction.ZERO } + ) : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { + isCreative = false + this._capacity = storage + this._receive = receive + this._extract = extract + this._initialBatteryLevel = initialBatteryLevel + } + + constructor(values: BatteryBalanceValues) : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { + isCreative = false + this._capacity = values::capacity + this._receive = values::receive + this._extract = values::extract + this._initialBatteryLevel = values::initialBatteryLevel } constructor() : super(Properties().stacksTo(1).rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { isCreative = true - storage = ImpreciseFraction.LONG_MAX_VALUE - receive = ImpreciseFraction.LONG_MAX_VALUE - extract = ImpreciseFraction.LONG_MAX_VALUE - initialBatteryLevel = ImpreciseFraction.LONG_MAX_VALUE + _capacity = { ImpreciseFraction.LONG_MAX_VALUE } + _receive = { ImpreciseFraction.LONG_MAX_VALUE } + _extract = { ImpreciseFraction.LONG_MAX_VALUE } + _initialBatteryLevel = { ImpreciseFraction.LONG_MAX_VALUE } } override fun isBarVisible(p_150899_: ItemStack): Boolean { @@ -114,7 +151,7 @@ open class BatteryItem : Item { } } -class CrudeBatteryItem : BatteryItem(MAX_STORAGE, extract = MAX_EXTRACT, receive = MAX_RECEIVE, initialBatteryLevel = INITIAL_STORAGE) { +class CrudeBatteryItem : BatteryItem(ServerConfig.BATTERY_CRUDE) { override fun appendHoverText( stack: ItemStack, p_41422_: Level?, @@ -183,11 +220,4 @@ class CrudeBatteryItem : BatteryItem(MAX_STORAGE, extract = MAX_EXTRACT, receive return itemStack } - - companion object { - val MAX_STORAGE = ImpreciseFraction(100_000) - val MAX_EXTRACT = ImpreciseFraction(160) - val MAX_RECEIVE = ImpreciseFraction(40) - val INITIAL_STORAGE = MAX_STORAGE * .8f - } -} \ No newline at end of file +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/MatterCapacitorItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/MatterCapacitorItem.kt index 15bcf7151..268a80ee3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/MatterCapacitorItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/MatterCapacitorItem.kt @@ -5,7 +5,6 @@ import net.minecraft.MethodsReturnNonnullByDefault import net.minecraft.core.Direction import net.minecraft.nbt.CompoundTag import net.minecraft.network.chat.Component -import net.minecraft.util.Mth import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Rarity @@ -17,10 +16,7 @@ import net.minecraftforge.common.util.LazyOptional import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.capability.MatteryCapability -import ru.dbotthepony.mc.otm.capability.getBarColor -import ru.dbotthepony.mc.otm.capability.getBarWidth import ru.dbotthepony.mc.otm.capability.matter.* -import ru.dbotthepony.mc.otm.capability.matteryEnergy import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.formatMatter import javax.annotation.ParametersAreNonnullByDefault @@ -51,7 +47,7 @@ class MatterCapacitorItem : Item { } override val maxStoredMatter: ImpreciseFraction get() { - return storage + return capacity } override val missingMatter: ImpreciseFraction get() { @@ -64,7 +60,7 @@ class MatterCapacitorItem : Item { override fun receiveMatterInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction { if (isCreative) return howMuch - val new = matter().plus(howMuch.coerceAtMost(maxInput)).coerceAtMost(storage) + val new = matter().plus(howMuch.coerceAtMost(maxInput)).coerceAtMost(capacity) val diff = new.minus(matter()) if (!simulate) { @@ -93,17 +89,24 @@ class MatterCapacitorItem : Item { override val direction = MatterDirection.BIDIRECTIONAL } - val storage: ImpreciseFraction + private val _capacity: () -> ImpreciseFraction + val capacity get() = _capacity.invoke() + private val isCreative: Boolean constructor(storage: ImpreciseFraction) : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { isCreative = false - this.storage = storage + _capacity = { storage } + } + + constructor(storage: () -> ImpreciseFraction) : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { + isCreative = false + _capacity = storage } constructor() : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB).rarity(Rarity.EPIC)) { isCreative = true - storage = ImpreciseFraction.LONG_MAX_VALUE + _capacity = { ImpreciseFraction.LONG_MAX_VALUE } } override fun isBarVisible(p_150899_: ItemStack): Boolean { @@ -142,7 +145,7 @@ class MatterCapacitorItem : Item { TranslatableComponent( "otm.item.matter.normal", cap.storedMatter.formatMatter(), - storage.formatMatter() + capacity.formatMatter() ).withStyle(ChatFormatting.GRAY) ) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/PatternStorageItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/PatternStorageItem.kt index 77877853e..d9f83835a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/PatternStorageItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/PatternStorageItem.kt @@ -23,17 +23,23 @@ import java.util.* import java.util.stream.Stream class PatternStorageItem : Item { - val capacity: Int + private val _capacity: () -> Int + val capacity get() = _capacity.invoke() var isCreative: Boolean constructor(capacity: Int) : super(Properties().tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB).stacksTo(1)) { - this.capacity = capacity + _capacity = { capacity } + isCreative = false + } + + constructor(capacity: () -> Int) : super(Properties().tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB).stacksTo(1)) { + _capacity = capacity isCreative = false } constructor() : super(Properties().rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB).stacksTo(1)) { isCreative = true - capacity = Int.MAX_VALUE + _capacity = { Int.MAX_VALUE } } override fun initCapabilities(stack: ItemStack, nbt: CompoundTag?): ICapabilityProvider? { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt index c7092b8e7..bed1d5f74 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt @@ -155,7 +155,7 @@ class QuantumBatteryItem : Item { return ImpreciseFraction.ZERO } - val newEnergy = (data.energy + howMuch.coerceAtMost(throughput!!)).coerceAtMost(capacity) + val newEnergy = (data.energy + howMuch.coerceAtMost(throughput!!)).coerceAtMost(capacity!!) val diff = newEnergy - data.energy if (!simulate) { @@ -257,8 +257,12 @@ class QuantumBatteryItem : Item { } val isCreative: Boolean - val capacity: ImpreciseFraction? - val throughput: ImpreciseFraction? + + private val _capacity: () -> ImpreciseFraction? + private val _throughput: () -> ImpreciseFraction? + + val capacity get() = _capacity.invoke() + val throughput get() = _throughput.invoke() val saveDataID: String @@ -287,15 +291,22 @@ class QuantumBatteryItem : Item { constructor(saveDataID: String) : super(Properties().stacksTo(1).rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { isCreative = true - capacity = null - throughput = null + _capacity = { null } + _throughput = { null } this.saveDataID = "otm_$saveDataID".intern() } constructor(saveDataID: String, capacity: ImpreciseFraction, io: ImpreciseFraction) : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { isCreative = false - this.capacity = capacity - this.throughput = io + _capacity = { capacity } + _throughput = { io } + this.saveDataID = "otm_$saveDataID".intern() + } + + constructor(saveDataID: String, values: ConciseBalanceValues) : super(Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { + isCreative = false + _capacity = values::capacity + _throughput = values::throughput this.saveDataID = "otm_$saveDataID".intern() } @@ -345,7 +356,7 @@ class QuantumBatteryItem : Item { TranslatableComponent( "otm.item.power.throughput", throughput!!.formatPower(), - throughput.formatPower() + throughput!!.formatPower() ).withStyle(ChatFormatting.GRAY)) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/SingleUseBatteryItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/SingleUseBatteryItem.kt index 14bf2ae13..308d3a6b0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/SingleUseBatteryItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/SingleUseBatteryItem.kt @@ -3,22 +3,29 @@ package ru.dbotthepony.mc.otm.item import net.minecraft.ChatFormatting import net.minecraft.nbt.CompoundTag import net.minecraft.network.chat.Component -import net.minecraft.util.Mth import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Rarity import net.minecraft.world.item.TooltipFlag import net.minecraft.world.level.Level import net.minecraftforge.common.capabilities.ICapabilityProvider +import ru.dbotthepony.mc.otm.ConciseBalanceValues import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.core.* open class SingleUseBatteryItem( - val storage: ImpreciseFraction, - val throughput: ImpreciseFraction? = null, + private val _capacity: () -> ImpreciseFraction, + private val _throughput: () -> ImpreciseFraction? = { null }, properties: Properties = Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB) ) : Item(properties) { + constructor(values: ConciseBalanceValues, properties: Properties = Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) : this(values::capacity, values::throughput, properties) + constructor(storage: ImpreciseFraction, throughput: ImpreciseFraction? = null, properties: Properties = Properties().stacksTo(1).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) : this({ storage }, { throughput }, properties) + + val capacity get() = _capacity.invoke() + val throughput get() = _throughput.invoke() + override fun appendHoverText( itemStack: ItemStack, p_41422_: Level?, @@ -31,7 +38,7 @@ open class SingleUseBatteryItem( } override fun initCapabilities(stack: ItemStack, nbt: CompoundTag?): ICapabilityProvider { - return EnergyProducerItem(stack, storage, throughput, initialBatteryLevel = storage) + return EnergyProducerItem(stack, capacity, throughput, initialBatteryLevel = capacity) } override fun isBarVisible(p_150899_: ItemStack): Boolean { @@ -51,7 +58,7 @@ open class SingleUseBatteryItem( } } -class ZPMItem : SingleUseBatteryItem(MAX_STORAGE, THROUGHPUT, Properties().stacksTo(1).rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { +class ZPMItem : SingleUseBatteryItem(ServerConfig.ZPM_BATTERY, Properties().stacksTo(1).rarity(Rarity.EPIC).tab(OverdriveThatMatters.INSTANCE.CREATIVE_TAB)) { override fun appendHoverText( itemStack: ItemStack, p_41422_: Level?, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterData.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterData.kt index 1ca801528..fba8cd71c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterData.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterData.kt @@ -130,9 +130,9 @@ private fun make(tag: TagKey, value: ImpreciseFraction, complexity: Double } private fun logResolutionError(text: String) { - LOGGER.debug("... Item chain: " + seenItems.joinToString(" -> ")) + //LOGGER.debug("... Item chain: " + seenItems.joinToString(" -> ")) // LOGGER.error("Recipe chain: " + seenRecipes.joinToString(" -> ")) - LOGGER.debug(text) + //LOGGER.debug(text) } private enum class ResultType { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt index 7140ca39b..8ea20b01b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MItems.kt @@ -14,6 +14,7 @@ import net.minecraftforge.eventbus.api.IEventBus import net.minecraftforge.registries.DeferredRegister import net.minecraftforge.registries.ForgeRegistries import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.ServerConfig import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.item.* @@ -224,14 +225,14 @@ object MItems { val PILL_HEAL: Item by registry.register(MNames.PILL_HEAL) { HealPillItem() } val BATTERY_CRUDE: Item by registry.register(MNames.BATTERY_CRUDE) { CrudeBatteryItem() } - val BATTERY_BASIC: Item by registry.register(MNames.BATTERY_BASIC) { BatteryItem(ImpreciseFraction(400_000), ImpreciseFraction(600)) } - val BATTERY_NORMAL: Item by registry.register(MNames.BATTERY_NORMAL) { BatteryItem(ImpreciseFraction(2_000_000), ImpreciseFraction(1_000)) } - val BATTERY_DENSE: Item by registry.register(MNames.BATTERY_DENSE) { BatteryItem(ImpreciseFraction(10_000_000), ImpreciseFraction(2_000)) } - val BATTERY_CAPACITOR: Item by registry.register(MNames.BATTERY_CAPACITOR) { BatteryItem(ImpreciseFraction(500_000), ImpreciseFraction(50_000)) } + val BATTERY_BASIC: Item by registry.register(MNames.BATTERY_BASIC) { BatteryItem(ServerConfig.BATTERY_BASIC) } + val BATTERY_NORMAL: Item by registry.register(MNames.BATTERY_NORMAL) { BatteryItem(ServerConfig.BATTERY_NORMAL) } + val BATTERY_DENSE: Item by registry.register(MNames.BATTERY_DENSE) { BatteryItem(ServerConfig.BATTERY_DENSE) } + val BATTERY_CAPACITOR: Item by registry.register(MNames.BATTERY_CAPACITOR) { BatteryItem(ServerConfig.BATTERY_CAPACITOR) } val BATTERY_CREATIVE: Item by registry.register(MNames.BATTERY_CREATIVE) { BatteryItem() } - val QUANTUM_BATTERY: Item by registry.register(MNames.QUANTUM_BATTERY) { QuantumBatteryItem(MNames.QUANTUM_BATTERY, ImpreciseFraction(40_000_000), ImpreciseFraction(10_000)) } - val QUANTUM_CAPACITOR: Item by registry.register(MNames.QUANTUM_CAPACITOR) { QuantumBatteryItem(MNames.QUANTUM_CAPACITOR, ImpreciseFraction(1_000_000), ImpreciseFraction(200_000)) } + val QUANTUM_BATTERY: Item by registry.register(MNames.QUANTUM_BATTERY) { QuantumBatteryItem(MNames.QUANTUM_BATTERY, ServerConfig.QUANTUM_BATTERY) } + val QUANTUM_CAPACITOR: Item by registry.register(MNames.QUANTUM_CAPACITOR) { QuantumBatteryItem(MNames.QUANTUM_CAPACITOR, ServerConfig.QUANTUM_CAPACITOR) } val QUANTUM_BATTERY_CREATIVE: Item by registry.register(MNames.QUANTUM_BATTERY_CREATIVE) { QuantumBatteryItem(MNames.QUANTUM_BATTERY_CREATIVE) } val ZPM_BATTERY: Item by registry.register(MNames.ZPM_BATTERY) { ZPMItem() } @@ -243,12 +244,12 @@ object MItems { { BATTERY_CAPACITOR }, ) - val MATTER_CAPACITOR_BASIC: Item by registry.register(MNames.MATTER_CAPACITOR_BASIC) { MatterCapacitorItem(ImpreciseFraction("2")) } - val MATTER_CAPACITOR_NORMAL: Item by registry.register(MNames.MATTER_CAPACITOR_NORMAL) { MatterCapacitorItem(ImpreciseFraction("10")) } - val MATTER_CAPACITOR_DENSE: Item by registry.register(MNames.MATTER_CAPACITOR_DENSE) { MatterCapacitorItem(ImpreciseFraction("40")) } + val MATTER_CAPACITOR_BASIC: Item by registry.register(MNames.MATTER_CAPACITOR_BASIC) { MatterCapacitorItem(ServerConfig::MATTER_CAPACITOR_BASIC) } + val MATTER_CAPACITOR_NORMAL: Item by registry.register(MNames.MATTER_CAPACITOR_NORMAL) { MatterCapacitorItem(ServerConfig::MATTER_CAPACITOR_NORMAL) } + val MATTER_CAPACITOR_DENSE: Item by registry.register(MNames.MATTER_CAPACITOR_DENSE) { MatterCapacitorItem(ServerConfig::MATTER_CAPACITOR_DENSE) } val MATTER_CAPACITOR_CREATIVE: Item by registry.register(MNames.MATTER_CAPACITOR_CREATIVE) { MatterCapacitorItem() } - val PATTERN_DRIVE_NORMAL: Item by registry.register(MNames.PATTERN_DRIVE_NORMAL) { PatternStorageItem(4) } + val PATTERN_DRIVE_NORMAL: Item by registry.register(MNames.PATTERN_DRIVE_NORMAL) { PatternStorageItem(ServerConfig::PATTERN_DRIVE_NORMAL) } val PATTERN_DRIVE_CREATIVE: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE) { PatternStorageItem() } val PATTERN_DRIVE_CREATIVE2: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE2) { CreativePatternItem() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt index b30427c48..cf9e411af 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/MRegistry.kt @@ -73,10 +73,7 @@ class WriteOnce : ReadWriteProperty { } override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) { - if (this.value != null) { - throw IllegalStateException("Property ${property.name} already initialized") - } - + check(this.value == null) { "Property ${property.name} is already initialized" } this.value = value } } diff --git a/src/test/kotlin/ru/dbotthepony/mc/otm/tests/ImpreciseFractionTests.kt b/src/test/kotlin/ru/dbotthepony/mc/otm/tests/ImpreciseFractionTests.kt index c75dfa9bc..a87a8025d 100644 --- a/src/test/kotlin/ru/dbotthepony/mc/otm/tests/ImpreciseFractionTests.kt +++ b/src/test/kotlin/ru/dbotthepony/mc/otm/tests/ImpreciseFractionTests.kt @@ -1,9 +1,14 @@ package ru.dbotthepony.mc.otm.tests +import it.unimi.dsi.fastutil.io.FastByteArrayInputStream +import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import ru.dbotthepony.mc.otm.core.ImpreciseFraction +import java.io.File +import java.io.ObjectInputStream +import java.io.ObjectOutputStream object ImpreciseFractionTests { @Test @@ -61,4 +66,29 @@ object ImpreciseFractionTests { assertEquals(ImpreciseFraction(i.toLong()), ImpreciseFraction.valueOf(i.toLong())) } } + + @Test + @DisplayName("ImpreciseFraction serialization") + fun serialization() { + val output = FastByteArrayOutputStream() + val outputStream = ObjectOutputStream(output) + + val val1 = ImpreciseFraction("283") + val val2 = ImpreciseFraction("0") + val val3 = ImpreciseFraction("-4") + val val4 = ImpreciseFraction("25.225") + + outputStream.writeObject(val1) + outputStream.writeObject(val2) + outputStream.writeObject(val3) + outputStream.writeObject(val4) + + val input = FastByteArrayInputStream(output.array, 0, output.length) + val inputStream = ObjectInputStream(input) + + assertEquals(val1, inputStream.readObject()) + assertEquals(val2, inputStream.readObject()) + assertEquals(val3, inputStream.readObject()) + assertEquals(val4, inputStream.readObject()) + } }