From 094f476feab31c2e0abf055964b788b0aed559ac Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 4 Sep 2022 18:36:42 +0700 Subject: [PATCH] Quantum batteries now track statistics --- .../mc/otm/datagen/lang/English.kt | 1 + .../mc/otm/item/QuantumBatteryItem.kt | 199 ++++++++++++++---- 2 files changed, 154 insertions(+), 46 deletions(-) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 58a996234..8d77d0db1 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -130,6 +130,7 @@ private fun misc(provider: MatteryLanguageProvider) { misc("item.power.infinite.storage", "Stored energy: Infinity / Infinity") misc("item.power.infinite.throughput", "Max I/O Infinite / Infinite") misc("item.power.passed", "Passed energy: %s") + misc("item.power.received", "Received energy: %s") misc("item.power.average", "Average throughput: %s/t") misc("item.power.last_20_ticks", "Last second: %s") misc("item.power.last_tick", "Last tick: %s") 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 44ebdfdf4..7d0de072e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt @@ -4,7 +4,9 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import net.minecraft.ChatFormatting import net.minecraft.core.Direction +import net.minecraft.nbt.ByteArrayTag import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.Tag import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.chat.Component import net.minecraft.world.item.* @@ -28,13 +30,50 @@ import ru.dbotthepony.mc.otm.network.GenericNetworkChannel import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.packetHandled import ru.dbotthepony.mc.otm.saveddata.SavedCountingMap -import ru.dbotthepony.mc.otm.saveddata.SavedMapDelegate import java.util.function.Supplier class QuantumBatteryItem : Item { + class Data( + val parent: SavedCountingMap?, + val index: Int = -1, + energy: ImpreciseFraction = ImpreciseFraction.ZERO, + passed: ImpreciseFraction = ImpreciseFraction.ZERO, + received: ImpreciseFraction = ImpreciseFraction.ZERO, + ) { + constructor( + energy: ImpreciseFraction = ImpreciseFraction.ZERO, + passed: ImpreciseFraction = ImpreciseFraction.ZERO, + received: ImpreciseFraction = ImpreciseFraction.ZERO, + ) : this(null, -1, energy, passed, received) + + var energy: ImpreciseFraction = energy + set(value) { + if (field != value) { + field = value + parent?.isDirty = true + } + } + + var passed: ImpreciseFraction = passed + set(value) { + if (field != value) { + field = value + parent?.isDirty = true + } + } + + var received: ImpreciseFraction = received + set(value) { + if (field != value) { + field = value + parent?.isDirty = true + } + } + } + private inner class Power(private val stack: ItemStack) : IMatteryEnergyStorage, ICapabilityProvider { private val resolver = LazyOptional.of { this } - var delegate = SavedMapDelegate(ImpreciseFraction.ZERO) + var data = Data() override fun getCapability(cap: Capability, side: Direction?): LazyOptional { if (cap == ForgeCapabilities.ENERGY || cap == MatteryCapability.ENERGY) { @@ -53,30 +92,32 @@ class QuantumBatteryItem : Item { return ImpreciseFraction.ZERO } - if (delegate.parent == null && isServerThread()) { + if (data.parent == null && isServerThread()) { determineQuantumLink() - if (delegate.parent == null) { + if (data.parent == null) { return ImpreciseFraction.ZERO } } if (isCreative) { - val newEnergy = (delegate.value - howMuch).moreThanZero() - val diff = delegate.value - newEnergy + val newEnergy = (data.energy - howMuch).moreThanZero() + val diff = data.energy - newEnergy if (!simulate) { - delegate.value = newEnergy + data.energy = newEnergy + data.passed += diff } return diff } - val newEnergy = (delegate.value - howMuch.coerceAtMost(throughput!!)).moreThanZero() - val diff = delegate.value - newEnergy + val newEnergy = (data.energy - howMuch.coerceAtMost(throughput!!)).moreThanZero() + val diff = data.energy - newEnergy if (!simulate) { - delegate.value = newEnergy + data.energy = newEnergy + data.passed += diff } return diff @@ -91,31 +132,33 @@ class QuantumBatteryItem : Item { return ImpreciseFraction.ZERO } - if (delegate.parent == null && isServerThread()) { + if (data.parent == null && isServerThread()) { determineQuantumLink() - if (delegate.parent == null) { + if (data.parent == null) { return ImpreciseFraction.ZERO } } if (isCreative) { if (!simulate) { - delegate.value += howMuch + data.energy += howMuch + data.received += howMuch } return howMuch } - if (delegate.value >= capacity!!) { + if (data.energy >= capacity!!) { return ImpreciseFraction.ZERO } - val newEnergy = (delegate.value + howMuch.coerceAtMost(throughput!!)).coerceAtMost(capacity) - val diff = newEnergy - delegate.value + val newEnergy = (data.energy + howMuch.coerceAtMost(throughput!!)).coerceAtMost(capacity) + val diff = newEnergy - data.energy if (!simulate) { - delegate.value = newEnergy + data.energy = newEnergy + data.received += diff } return diff @@ -123,17 +166,41 @@ class QuantumBatteryItem : Item { override val batteryLevel: ImpreciseFraction get() { - if (delegate.parent == null) { + if (data.parent == null) { determineQuantumLink() } if (isClientThread()) { - return clientPowerMap[delegate.index] ?: delegate.value + return clientPowerMap[data.index]?.energy ?: data.energy } - return delegate.value + return data.energy } + val passed: ImpreciseFraction get() { + if (data.parent == null) { + determineQuantumLink() + } + + if (isClientThread()) { + return clientPowerMap[data.index]?.passed ?: data.passed + } + + return data.passed + } + + val received: ImpreciseFraction get() { + if (data.parent == null) { + determineQuantumLink() + } + + if (isClientThread()) { + return clientPowerMap[data.index]?.received ?: data.received + } + + return data.received + } + override val maxBatteryLevel: ImpreciseFraction get() = capacity ?: (batteryLevel + ImpreciseFraction.LONG_MAX_VALUE) @@ -149,39 +216,39 @@ class QuantumBatteryItem : Item { } private fun determineQuantumLink() { - if (delegate.parent == null && isServerThread()) { + if (data.parent == null && isServerThread()) { val existing = stack.tag?.getInt("link_id") if (existing == null) { - val old = delegate - delegate = saveData!!.factorize() - delegate.value = old.value - stack.tagNotNull["link_id"] = delegate.index + val old = data + data = saveData!!.factorize() + data.energy = old.energy + stack.tagNotNull["link_id"] = data.index } else { - delegate = saveData?.computeIfAbsent(existing) ?: SavedMapDelegate(null, existing, delegate.value) + data = saveData?.computeIfAbsent(existing) ?: Data(null, existing, data.energy, data.passed, data.received) } } else if (!isServerThread()) { // client ? val existing = stack.tag?.getInt("link_id") ?: return - if (existing != delegate.index) { - delegate = SavedMapDelegate(delegate.parent, existing, delegate.value) + if (existing != data.index) { + data = Data(data.parent, existing, data.energy, data.passed, data.received) } } } fun determineQuantumLinkWeak() { - if (delegate.parent == null && isServerThread()) { + if (data.parent == null && isServerThread()) { val existing = stack.tag?.getInt("link_id") if (existing != null) { - delegate = saveData?.computeIfAbsent(existing) ?: SavedMapDelegate(null, existing, delegate.value) + data = saveData?.computeIfAbsent(existing) ?: Data(null, existing, data.energy, data.passed, data.received) } } else if (!isServerThread()) { val existing = stack.tag?.getInt("link_id") ?: return - if (existing != delegate.index) { - delegate = SavedMapDelegate(delegate.parent, existing, delegate.value) + if (existing != data.index) { + data = Data(data.parent, existing, data.energy, data.passed, data.received) } } } @@ -193,19 +260,25 @@ class QuantumBatteryItem : Item { val saveDataID: String - val saveData: SavedCountingMap>? get() { + val saveData: SavedCountingMap? get() { if (isServerThread()) { return MINECRAFT_SERVER.overworld().dataStorage.computeIfAbsent({ - SavedMapDelegate.makeMap(ImpreciseFraction::serializeNBT, ImpreciseFraction.Companion::deserializeNBT, ImpreciseFraction.ZERO).load(it) + SavedCountingMap(Companion::storeValue, Companion::loadValue, ::Data).load(it) }, { - SavedMapDelegate.makeMap(ImpreciseFraction::serializeNBT, ImpreciseFraction.Companion::deserializeNBT, ImpreciseFraction.ZERO) + SavedCountingMap(Companion::storeValue, Companion::loadValue, ::Data) }, saveDataID) ?: throw NullPointerException("Unable to get save data for $this in ${MINECRAFT_SERVER.overworld()}") } return null } - val clientPowerMap: Int2ObjectAVLTreeMap by lazy { + data class ClientData( + val energy: ImpreciseFraction = ImpreciseFraction.ZERO, + val passed: ImpreciseFraction = ImpreciseFraction.ZERO, + val received: ImpreciseFraction = ImpreciseFraction.ZERO, + ) + + val clientPowerMap: Int2ObjectAVLTreeMap by lazy { check(isClient) { "Invalid side" } Int2ObjectAVLTreeMap() } @@ -242,8 +315,6 @@ class QuantumBatteryItem : Item { if (isCreative) { components.add(TranslatableComponent("otm.item.quantum_battery.creative_power", power.batteryLevel.formatPower()).withStyle(ChatFormatting.GRAY)) - components.add(TranslatableComponent("otm.item.quantum_battery.creative").withStyle(ChatFormatting.DARK_GRAY)) - components.add(TranslatableComponent("otm.item.quantum_battery.creative2").withStyle(ChatFormatting.DARK_GRAY)) } else { components.add(TranslatableComponent("otm.item.power.normal.storage", power.batteryLevel.formatPower(), capacity!!.formatPower()).withStyle(ChatFormatting.GRAY)) components.add( @@ -254,7 +325,15 @@ class QuantumBatteryItem : Item { ).withStyle(ChatFormatting.GRAY)) } - components.add(TranslatableComponent("otm.item.quantum_link_id", power.delegate.index).withStyle(ChatFormatting.DARK_GRAY)) + components.add(TranslatableComponent("otm.item.power.passed", power.passed.formatPower()).withStyle(ChatFormatting.GRAY)) + components.add(TranslatableComponent("otm.item.power.received", power.received.formatPower()).withStyle(ChatFormatting.GRAY)) + + if (isCreative) { + components.add(TranslatableComponent("otm.item.quantum_battery.creative").withStyle(ChatFormatting.DARK_GRAY)) + components.add(TranslatableComponent("otm.item.quantum_battery.creative2").withStyle(ChatFormatting.DARK_GRAY)) + } + + components.add(TranslatableComponent("otm.item.quantum_link_id", power.data.index).withStyle(ChatFormatting.DARK_GRAY)) } companion object { @@ -262,7 +341,9 @@ class QuantumBatteryItem : Item { return ChargePacket( (ForgeRegistries.ITEMS as ForgeRegistry).getValue(buff.readInt()) as QuantumBatteryItem, buff.readInt(), - buff.readImpreciseFraction() + buff.readImpreciseFraction(), + buff.readImpreciseFraction(), + buff.readImpreciseFraction(), ) } @@ -277,30 +358,56 @@ class QuantumBatteryItem : Item { power.determineQuantumLinkWeak() - if (power.delegate.index < 0) { + if (power.data.index < 0) { continue } - if (networkedChannels.add(power.delegate.index)) { - GenericNetworkChannel.send(ply, ChargePacket(item.item as QuantumBatteryItem, power.delegate.index, power.batteryLevel)) + if (networkedChannels.add(power.data.index)) { + GenericNetworkChannel.send(ply, ChargePacket(item.item as QuantumBatteryItem, power.data.index, power.batteryLevel, power.data.passed, power.data.received)) } } } } } } + + private fun loadValue(parent: SavedCountingMap, tag: Tag, index: Int): Data { + if (tag is ByteArrayTag) { + return Data(parent, index, ImpreciseFraction.deserializeNBT(tag)) + } else if (tag is CompoundTag) { + return Data(parent, index, ImpreciseFraction.deserializeNBT(tag["energy"]), ImpreciseFraction.deserializeNBT(tag["passed"]), ImpreciseFraction.deserializeNBT(tag["received"])) + } else { + return Data(parent, index) + } + } + + private fun storeValue(parent: SavedCountingMap, value: Data, index: Int): CompoundTag { + return CompoundTag().also { + it["energy"] = value.energy.serializeNBT() + it["passed"] = value.passed.serializeNBT() + it["received"] = value.received.serializeNBT() + } + } } - class ChargePacket(val type: QuantumBatteryItem, val channel: Int, val value: ImpreciseFraction) : MatteryPacket { + class ChargePacket( + val type: QuantumBatteryItem, + val channel: Int, + val energy: ImpreciseFraction, + val passed: ImpreciseFraction, + val received: ImpreciseFraction, + ) : MatteryPacket { override fun write(buff: FriendlyByteBuf) { buff.writeInt((ForgeRegistries.ITEMS as ForgeRegistry).getID(type)) buff.writeInt(channel) - buff.writeImpreciseFraction(value) + buff.writeImpreciseFraction(energy) + buff.writeImpreciseFraction(passed) + buff.writeImpreciseFraction(received) } override fun play(context: Supplier) { context.packetHandled = true - type.clientPowerMap[channel] = value + type.clientPowerMap[channel] = ClientData(energy, passed, received) } } }