Extract energy interface from mattery player into own class

This commit is contained in:
DBotThePony 2022-09-05 18:47:13 +07:00
parent 11484eeec3
commit f94e3f11e4
Signed by: DBot
GPG Key ID: DCC23B5715498507
11 changed files with 273 additions and 272 deletions

View File

@ -24,12 +24,12 @@ class NanobotsArmor(android: MatteryPlayerCapability) : AndroidFeature(AndroidFe
private var layers = 0 private var layers = 0
override fun tickServer() { override fun tickServer() {
if (layers < strength + 1 && android.extractEnergyInnerExact(ENERGY_PER_LAYER, true).isPositive) { if (layers < strength + 1 && android.androidEnergy.extractEnergyInnerExact(ENERGY_PER_LAYER, true).isPositive) {
ticksPassed++ ticksPassed++
if (ticksPassed >= TICKS[speed]) { if (ticksPassed >= TICKS[speed]) {
layers++ layers++
android.extractEnergyInner(ENERGY_PER_LAYER, false) android.androidEnergy.extractEnergyInner(ENERGY_PER_LAYER, false)
} }
} else { } else {
ticksPassed = 0 ticksPassed = 0
@ -44,7 +44,7 @@ class NanobotsArmor(android: MatteryPlayerCapability) : AndroidFeature(AndroidFe
if (absorbed > 0.1f) { if (absorbed > 0.1f) {
val powerRequired = ENERGY_PER_HITPOINT * absorbed val powerRequired = ENERGY_PER_HITPOINT * absorbed
val powerExtracted = android.extractEnergyInner(powerRequired, false) val powerExtracted = android.androidEnergy.extractEnergyInner(powerRequired, false)
val realAbsorbed = (powerExtracted / ENERGY_PER_HITPOINT).toFloat() val realAbsorbed = (powerExtracted / ENERGY_PER_HITPOINT).toFloat()
event.amount = event.amount - realAbsorbed event.amount = event.amount - realAbsorbed
(entity as ServerPlayer?)?.awardStat(StatNames.DAMAGE_ABSORBED, (realAbsorbed * 10f).roundToInt()) (entity as ServerPlayer?)?.awardStat(StatNames.DAMAGE_ABSORBED, (realAbsorbed * 10f).roundToInt())

View File

@ -25,7 +25,7 @@ class NanobotsRegeneration(android: MatteryPlayerCapability) : AndroidFeature(An
if (ticksPassed > waitTime) { if (ticksPassed > waitTime) {
val missingHealth = entity.maxHealth - entity.health val missingHealth = entity.maxHealth - entity.health
val power = ENERGY_PER_HITPOINT * missingHealth val power = ENERGY_PER_HITPOINT * missingHealth
val extracted = android.extractEnergyInner(power, false) val extracted = android.androidEnergy.extractEnergyInner(power, false)
if (extracted.isPositive) { if (extracted.isPositive) {
healTicks = (healTicks + 1).coerceAtMost(level) healTicks = (healTicks + 1).coerceAtMost(level)

View File

@ -77,13 +77,13 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) :
if (!it.isAndroid) if (!it.isAndroid)
return@ifPresentK return@ifPresentK
val missing = it.missingPower val missing = it.androidEnergy.missingPower
if (missing > ImpreciseFraction.ZERO) { if (missing > ImpreciseFraction.ZERO) {
val extract = energy.extractEnergyInner(missing, true) val extract = energy.extractEnergyInner(missing, true)
if (extract > ImpreciseFraction.ZERO) { if (extract > ImpreciseFraction.ZERO) {
val received = it.receiveEnergyOuter(extract, false) val received = it.androidEnergy.receiveEnergyOuter(extract, false)
energy.extractEnergyInner(received, false) energy.extractEnergyInner(received, false)
} }
} }

View File

@ -6,7 +6,6 @@ import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.ListTag import net.minecraft.nbt.ListTag
import net.minecraft.nbt.StringTag import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
@ -20,7 +19,6 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
import net.minecraft.world.level.GameRules import net.minecraft.world.level.GameRules
import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.capabilities.ICapabilityProvider import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.common.util.INBTSerializable import net.minecraftforge.common.util.INBTSerializable
import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.common.util.LazyOptional
@ -31,8 +29,6 @@ import net.minecraftforge.event.entity.living.LivingEvent.LivingTickEvent
import net.minecraftforge.event.entity.living.LivingHurtEvent import net.minecraftforge.event.entity.living.LivingHurtEvent
import net.minecraftforge.event.entity.player.EntityItemPickupEvent import net.minecraftforge.event.entity.player.EntityItemPickupEvent
import net.minecraftforge.event.entity.player.PlayerEvent import net.minecraftforge.event.entity.player.PlayerEvent
import net.minecraftforge.eventbus.api.EventPriority
import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent
import org.apache.commons.lang3.mutable.MutableInt import org.apache.commons.lang3.mutable.MutableInt
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
@ -47,13 +43,12 @@ import ru.dbotthepony.mc.otm.menu.ExoSuitInventoryMenu
import ru.dbotthepony.mc.otm.network.* import ru.dbotthepony.mc.otm.network.*
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MRegistry import ru.dbotthepony.mc.otm.registry.MRegistry
import ru.dbotthepony.mc.otm.registry.StatNames
import java.util.* import java.util.*
import kotlin.collections.ArrayDeque import kotlin.collections.ArrayDeque
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@Suppress("unused") @Suppress("unused")
class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEnergyStorage, INBTSerializable<CompoundTag> { class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerializable<CompoundTag> {
private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) { private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new, old) super.setChanged(slot, new, old)
@ -150,9 +145,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
private val deathLog = ArrayDeque<Pair<Int, Component>>() private val deathLog = ArrayDeque<Pair<Int, Component>>()
private var battery by synchronizer.fraction()
private var maxBattery by synchronizer.fraction(ImpreciseFraction(60000))
private val features = IdentityHashMap<AndroidFeatureType<*>, AndroidFeature>() private val features = IdentityHashMap<AndroidFeatureType<*>, AndroidFeature>()
private val networkQueue = ArrayList<Any>() private val networkQueue = ArrayList<Any>()
private val queuedTicks = ArrayList<Runnable>() private val queuedTicks = ArrayList<Runnable>()
@ -169,7 +161,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
var willBecomeAndroid by synchronizer.bool() var willBecomeAndroid by synchronizer.bool()
var isAndroid by synchronizer.bool() var isAndroid by synchronizer.bool()
var batteryItemStack by synchronizer.item()
val androidEnergy = SynchronizedPowerWithBattery(ply, synchronizer, DEFAULT_MAX_ANDROID_POWER, DEFAULT_MAX_ANDROID_POWER)
fun invalidateNetworkState() { fun invalidateNetworkState() {
invalidateNetworkIn = 10 invalidateNetworkIn = 10
@ -189,8 +182,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
shouldPlaySound = false shouldPlaySound = false
iteration = 0 iteration = 0
deathLog.clear() deathLog.clear()
battery = ImpreciseFraction(60000) androidEnergy.batteryLevel = DEFAULT_MAX_ANDROID_POWER
maxBattery = ImpreciseFraction(60000) androidEnergy.maxBatteryLevel = DEFAULT_MAX_ANDROID_POWER
} }
fun becomeAndroidAndKill() { fun becomeAndroidAndKill() {
@ -208,8 +201,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
shouldPlaySound = false shouldPlaySound = false
iteration = 0 iteration = 0
deathLog.clear() deathLog.clear()
battery = ImpreciseFraction(0) androidEnergy.batteryLevel = ImpreciseFraction.ZERO
maxBattery = ImpreciseFraction(60000) androidEnergy.maxBatteryLevel = DEFAULT_MAX_ANDROID_POWER
dropBattery() dropBattery()
} }
@ -341,9 +334,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
override fun serializeNBT(): CompoundTag { override fun serializeNBT(): CompoundTag {
val tag = CompoundTag() val tag = CompoundTag()
tag["energy_stored"] = battery.serializeNBT() tag["androidEnergy"] = androidEnergy.serializeNBT()
tag["energy_stored_max"] = maxBattery.serializeNBT()
tag["battery"] = batteryItemStack.serializeNBT()
val featureList = ListTag() val featureList = ListTag()
@ -390,14 +381,13 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
return tag return tag
} }
override fun deserializeNBT(compound: CompoundTag) { override fun deserializeNBT(tag: CompoundTag) {
iteration = compound.getInt("iteration") iteration = tag.getInt("iteration")
shouldSendIteration = compound.getBoolean("should_send_iteration") shouldSendIteration = tag.getBoolean("should_send_iteration")
deathLog.clear() deathLog.clear()
for (value in compound.getList("death_log", Tag.TAG_COMPOUND.toInt())) { for (value in tag.getCompoundList("death_log")) {
value as CompoundTag
val component = Component.Serializer.fromJson(value.getString("component")) val component = Component.Serializer.fromJson(value.getString("component"))
if (component != null) { if (component != null) {
@ -405,30 +395,17 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
} }
} }
compound.ifHas("energy_stored") { tag.map("androidEnergy", androidEnergy::deserializeNBT)
battery = ImpreciseFraction.deserializeNBT(it)
}
compound.ifHas("energy_stored_max") {
maxBattery = ImpreciseFraction.deserializeNBT(it)
}
compound.ifHas("battery", CompoundTag::class.java) {
batteryItemStack = ItemStack.of(it)
}
features.clear() features.clear()
val featuresNbt = compound.getList("features", Tag.TAG_COMPOUND.toInt()) for (featureTag in tag.getCompoundList("features")) {
val feature = MRegistry.ANDROID_FEATURES.getValue(ResourceLocation(featureTag.getString("id")))
for (tag in featuresNbt) {
if (tag is CompoundTag) {
val feature = MRegistry.ANDROID_FEATURES.getValue(ResourceLocation(tag.getString("id")))
if (feature?.isApplicable(this) == true) { if (feature?.isApplicable(this) == true) {
val instance = feature.create(this) val instance = feature.create(this)
instance.deserializeNBT(tag) instance.deserializeNBT(featureTag)
addFeature(instance) addFeature(instance)
if (!ply.level.isClientSide) { if (!ply.level.isClientSide) {
@ -436,36 +413,31 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
} }
} }
} }
}
isAndroid = compound.getBoolean("is_android") isAndroid = tag.getBoolean("is_android")
willBecomeAndroid = compound.getBoolean("will_become_android") willBecomeAndroid = tag.getBoolean("will_become_android")
research.clear() research.clear()
val list = compound.getList("research", Tag.TAG_COMPOUND.toInt()) for (researchTag in tag.getCompoundList("research")) {
val research = MRegistry.ANDROID_RESEARCH.getValue(ResourceLocation(researchTag.getString("id")))
for (tag in list) {
if (tag is CompoundTag) {
val research = MRegistry.ANDROID_RESEARCH.getValue(ResourceLocation(tag.getString("id")))
if (research != null) { if (research != null) {
val instance = research.factory(this) val instance = research.factory(this)
instance.deserializeNBT(tag) instance.deserializeNBT(researchTag)
this.research[research] = instance this.research[research] = instance
} }
} }
}
hasExoSuit = compound.getBoolean("has_exo_suit") hasExoSuit = tag.getBoolean("has_exo_suit")
exoSuitSlotCount = compound.getInt("exo_suit_slot_count") exoSuitSlotCount = tag.getInt("exo_suit_slot_count")
exoSuitContainer.deserializeNBT(compound["exo_suit_inventory"]) exoSuitContainer.deserializeNBT(tag["exo_suit_inventory"])
isExoSuitCraftingUpgraded = compound.getBoolean("exo_suit_crafting_upgraded") isExoSuitCraftingUpgraded = tag.getBoolean("exo_suit_crafting_upgraded")
} }
fun dropBattery() { fun dropBattery() {
if (batteryItemStack.isEmpty) return if (androidEnergy.item.isEmpty) return
ply.spawnAtLocation(batteryItemStack) ply.spawnAtLocation(androidEnergy.item)
batteryItemStack = ItemStack.EMPTY androidEnergy.item = ItemStack.EMPTY
} }
private fun sendNetwork(packet: Any) { private fun sendNetwork(packet: Any) {
@ -539,45 +511,37 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
if (ply.hasEffect(effect)) if (ply.hasEffect(effect))
ply.removeEffect(effect) ply.removeEffect(effect)
if (!batteryItemStack.isEmpty && battery < maxBattery) {
batteryItemStack.getCapability(ForgeCapabilities.ENERGY).ifPresent {
if (it is IMatteryEnergyStorage) {
battery += it.extractEnergyInner(maxBattery - battery, false)
} else {
battery += it.extractEnergy(maxBattery - battery, false)
}
}
}
// TODO: Maybe passive drain? // TODO: Maybe passive drain?
// extractEnergyInner(BigDecimal.valueOf(new Random().nextDouble()), false); // extractEnergyInner(BigDecimal.valueOf(new Random().nextDouble()), false);
if (ply.isSwimming && !hasFeature(AndroidFeatures.AIR_BAGS)) { if (ply.isSwimming && !hasFeature(AndroidFeatures.AIR_BAGS)) {
ply.isSwimming = false ply.isSwimming = false
} }
androidEnergy.tick()
val stats = ply.foodData val stats = ply.foodData
while (stats.foodLevel < 18 && extractEnergyInner(ENERGY_FOR_HUNGER_POINT, true) >= ENERGY_FOR_HUNGER_POINT) { while (stats.foodLevel < 18 && androidEnergy.extractEnergyInner(ENERGY_FOR_HUNGER_POINT, true) >= ENERGY_FOR_HUNGER_POINT) {
extractEnergyInner(ENERGY_FOR_HUNGER_POINT, false) androidEnergy.extractEnergyInner(ENERGY_FOR_HUNGER_POINT, false)
stats.foodLevel = stats.foodLevel + 1 stats.foodLevel = stats.foodLevel + 1
} }
// "block" quick regeneration // "block" quick regeneration
// also cause power to generate while in peaceful // also cause power to generate while in peaceful
while (stats.foodLevel > 18 && receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, true) >= ENERGY_FOR_HUNGER_POINT) { while (stats.foodLevel > 18 && androidEnergy.receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, true) >= ENERGY_FOR_HUNGER_POINT) {
receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, false) androidEnergy.receiveEnergyInner(ENERGY_FOR_HUNGER_POINT, false)
stats.foodLevel = stats.foodLevel - 1 stats.foodLevel = stats.foodLevel - 1
} }
val foodLevel = stats.foodLevel.toFloat() val foodLevel = stats.foodLevel.toFloat()
if (stats.saturationLevel < foodLevel) { if (stats.saturationLevel < foodLevel) {
val extracted = extractEnergyInner(ENERGY_FOR_HUNGER_POINT * (foodLevel - stats.saturationLevel), false) val extracted = androidEnergy.extractEnergyInner(ENERGY_FOR_HUNGER_POINT * (foodLevel - stats.saturationLevel), false)
stats.setSaturation(stats.saturationLevel + (extracted / ENERGY_FOR_HUNGER_POINT).toFloat()) stats.setSaturation(stats.saturationLevel + (extracted / ENERGY_FOR_HUNGER_POINT).toFloat())
} }
if (stats.exhaustionLevel > 0f) { if (stats.exhaustionLevel > 0f) {
val extracted = extractEnergyInner(ENERGY_FOR_HUNGER_POINT * (stats.exhaustionLevel / 4f), false) val extracted = androidEnergy.extractEnergyInner(ENERGY_FOR_HUNGER_POINT * (stats.exhaustionLevel / 4f), false)
stats.setExhaustion(stats.exhaustionLevel - (extracted / ENERGY_FOR_HUNGER_POINT).toFloat() * 4f) stats.setExhaustion(stats.exhaustionLevel - (extracted / ENERGY_FOR_HUNGER_POINT).toFloat() * 4f)
} }
@ -648,124 +612,6 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
tickInventory() tickInventory()
} }
override fun extractEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
return ImpreciseFraction.ZERO
}
override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
@Suppress("name_shadowing")
var howMuch = howMuch
var drained = ImpreciseFraction.ZERO
if (!batteryItemStack.isEmpty) {
batteryItemStack.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
if (it is IMatteryEnergyStorage) {
val extracted = it.extractEnergyOuter(howMuch, simulate)
drained += extracted
howMuch -= extracted
} else {
val extracted = it.extractEnergy(howMuch, simulate)
drained += extracted
howMuch -= extracted
}
}
if (howMuch.isZero) {
if (!simulate && ply is ServerPlayer) {
ply.awardStat(StatNames.POWER_CONSUMED, drained.toInt() * 10)
}
return drained
}
}
val new = (battery - howMuch).moreThanZero()
drained += battery - new
if (!simulate) {
battery = new
if (ply is ServerPlayer) {
ply.awardStat(StatNames.POWER_CONSUMED, drained.toInt() * 10)
}
}
return drained
}
override fun receiveEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
@Suppress("name_shadowing")
var howMuch = howMuch
var received = ImpreciseFraction.ZERO
if (!batteryItemStack.isEmpty) {
batteryItemStack.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
if (it is IMatteryEnergyStorage) {
val extracted = it.receiveEnergyOuter(howMuch, simulate)
received += extracted
howMuch -= extracted
} else {
val extracted = it.receiveEnergy(howMuch, simulate)
received += extracted
howMuch -= extracted
}
}
if (howMuch.isZero) {
return received
}
}
val new = (battery + howMuch).coerceAtMost(maxBattery)
received += new - battery
if (!simulate) {
battery = new
}
return received
}
override fun receiveEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
return receiveEnergyOuter(howMuch, simulate)
}
override var batteryLevel: ImpreciseFraction
get() {
if (!batteryItemStack.isEmpty) {
batteryItemStack.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
if (it is IMatteryEnergyStorage) {
return battery + it.batteryLevel
} else {
return battery + it.energyStored
}
}
}
return battery
}
set(value) {
battery = value
}
override var maxBatteryLevel: ImpreciseFraction
get() {
if (batteryItemStack != ItemStack.EMPTY) {
batteryItemStack.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
if (it is IMatteryEnergyStorage) {
return maxBattery + it.maxBatteryLevel
} else {
return maxBattery + it.maxEnergyStored
}
}
}
return maxBattery
}
set(value) {
maxBattery = value
}
private val resolver = LazyOptional.of { this } private val resolver = LazyOptional.of { this }
override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> { override fun <T> getCapability(cap: Capability<T>, side: Direction?): LazyOptional<T> {
@ -942,5 +788,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, IMatteryEn
val leftover = it.exoSuitContainer.addItem(event.item.item, false) val leftover = it.exoSuitContainer.addItem(event.item.item, false)
event.item.item.count = leftover.count event.item.item.count = leftover.count
} }
val DEFAULT_MAX_ANDROID_POWER = ImpreciseFraction(60000)
} }
} }

View File

@ -0,0 +1,171 @@
package ru.dbotthepony.mc.otm.capability
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.player.Player
import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.INBTSerializable
import ru.dbotthepony.mc.otm.core.ImpreciseFraction
import ru.dbotthepony.mc.otm.core.getImpreciseFraction
import ru.dbotthepony.mc.otm.core.getItemStack
import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.core.set
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
import ru.dbotthepony.mc.otm.registry.StatNames
class SynchronizedPowerWithBattery(
private val ply: Player,
synchronizer: FieldSynchronizer,
initialCharge: ImpreciseFraction,
maxCharge: ImpreciseFraction
) : IMatteryEnergyStorage, INBTSerializable<CompoundTag> {
private var battery by synchronizer.fraction(initialCharge)
private var maxBattery by synchronizer.fraction(maxCharge)
var item by synchronizer.item()
override fun serializeNBT(): CompoundTag {
return CompoundTag().also {
it["battery"] = battery.serializeNBT()
it["maxBattery"] = maxBattery.serializeNBT()
it["item"] = item.serializeNBT()
}
}
override fun deserializeNBT(tag: CompoundTag) {
battery = tag.getImpreciseFraction("battery")
maxBattery = tag.getImpreciseFraction("maxBattery")
item = tag.getItemStack("item")
}
fun tick() {
if (!item.isEmpty && battery < maxBattery) {
item.getCapability(ForgeCapabilities.ENERGY).ifPresent {
if (it is IMatteryEnergyStorage) {
battery += it.extractEnergyInner(maxBattery - battery, false)
} else {
battery += it.extractEnergy(maxBattery - battery, false)
}
}
}
}
override fun receiveEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
return receiveEnergyOuter(howMuch, simulate)
}
override fun extractEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
return ImpreciseFraction.ZERO
}
override fun extractEnergyInner(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
@Suppress("name_shadowing")
var howMuch = howMuch
var drained = ImpreciseFraction.ZERO
if (!item.isEmpty) {
item.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
if (it is IMatteryEnergyStorage) {
val extracted = it.extractEnergyOuter(howMuch, simulate)
drained += extracted
howMuch -= extracted
} else {
val extracted = it.extractEnergy(howMuch, simulate)
drained += extracted
howMuch -= extracted
}
}
if (howMuch.isZero) {
if (!simulate && ply is ServerPlayer) {
ply.awardStat(StatNames.POWER_CONSUMED, drained.toInt() * 10)
}
return drained
}
}
val new = (battery - howMuch).moreThanZero()
drained += battery - new
if (!simulate) {
battery = new
if (ply is ServerPlayer) {
ply.awardStat(StatNames.POWER_CONSUMED, drained.toInt() * 10)
}
}
return drained
}
override fun receiveEnergyOuter(howMuch: ImpreciseFraction, simulate: Boolean): ImpreciseFraction {
@Suppress("name_shadowing")
var howMuch = howMuch
var received = ImpreciseFraction.ZERO
if (!item.isEmpty) {
item.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
if (it is IMatteryEnergyStorage) {
val extracted = it.receiveEnergyOuter(howMuch, simulate)
received += extracted
howMuch -= extracted
} else {
val extracted = it.receiveEnergy(howMuch, simulate)
received += extracted
howMuch -= extracted
}
}
if (howMuch.isZero) {
return received
}
}
val new = (battery + howMuch).coerceAtMost(maxBattery)
received += new - battery
if (!simulate) {
battery = new
}
return received
}
override var batteryLevel: ImpreciseFraction
get() {
if (!item.isEmpty) {
item.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
if (it is IMatteryEnergyStorage) {
return battery + it.batteryLevel
} else {
return battery + it.energyStored
}
}
}
return battery
}
set(value) {
battery = value
}
override var maxBatteryLevel: ImpreciseFraction
get() {
if (item != ItemStack.EMPTY) {
item.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
if (it is IMatteryEnergyStorage) {
return maxBattery + it.maxBatteryLevel
} else {
return maxBattery + it.maxEnergyStored
}
}
}
return maxBattery
}
set(value) {
maxBattery = value
}
}

View File

@ -232,10 +232,10 @@ object MatteryGUI {
val yOffset = if (ply.hasEffect(MobEffects.HUNGER)) 18 else 0 val yOffset = if (ply.hasEffect(MobEffects.HUNGER)) 18 else 0
var level: Float var level: Float
if (android.maxBatteryLevel.isZero) { if (android.androidEnergy.maxBatteryLevel.isZero) {
level = 0f level = 0f
} else { } else {
level = android.batteryLevel.div(android.maxBatteryLevel).toFloat() level = android.androidEnergy.batteryLevel.div(android.androidEnergy.maxBatteryLevel).toFloat()
if (level >= 0.98f) if (level >= 0.98f)
level = 1f level = 1f

View File

@ -1,7 +1,19 @@
package ru.dbotthepony.mc.otm.core package ru.dbotthepony.mc.otm.core
import net.minecraft.nbt.ByteArrayTag
import net.minecraft.nbt.ByteTag
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.DoubleTag
import net.minecraft.nbt.FloatTag
import net.minecraft.nbt.IntArrayTag
import net.minecraft.nbt.IntTag
import net.minecraft.nbt.ListTag
import net.minecraft.nbt.LongArrayTag
import net.minecraft.nbt.LongTag
import net.minecraft.nbt.ShortTag
import net.minecraft.nbt.StringTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.world.item.ItemStack
import java.util.UUID import java.util.UUID
operator fun CompoundTag.set(index: String, value: Tag) = put(index, value) operator fun CompoundTag.set(index: String, value: Tag) = put(index, value)
@ -39,6 +51,8 @@ inline fun <R, reified T : Tag> CompoundTag.map(s: String, consumer: (T) -> R):
return null return null
} }
fun CompoundTag.getItemStack(key: String): ItemStack = map(key, ItemStack::of) ?: ItemStack.EMPTY
inline fun CompoundTag.ifHas(s: String, consumer: (Tag) -> Unit) { inline fun CompoundTag.ifHas(s: String, consumer: (Tag) -> Unit) {
val tag = get(s) val tag = get(s)
@ -62,3 +76,20 @@ inline fun <reified T : Tag> CompoundTag.ifHas(s: String, type: Class<T>, consum
consumer(tag as T) consumer(tag as T)
} }
} }
fun CompoundTag.getList(key: String): ListTag {
return this[key] as? ListTag ?: ListTag()
}
fun CompoundTag.getByteList(key: String): MutableList<ByteTag> = getList(key, Tag.TAG_BYTE.toInt()) as MutableList<ByteTag>
fun CompoundTag.getShortList(key: String): MutableList<ShortTag> = getList(key, Tag.TAG_SHORT.toInt()) as MutableList<ShortTag>
fun CompoundTag.getIntList(key: String): MutableList<IntTag> = getList(key, Tag.TAG_INT.toInt()) as MutableList<IntTag>
fun CompoundTag.getLongList(key: String): MutableList<LongTag> = getList(key, Tag.TAG_LONG.toInt()) as MutableList<LongTag>
fun CompoundTag.getFloatList(key: String): MutableList<FloatTag> = getList(key, Tag.TAG_FLOAT.toInt()) as MutableList<FloatTag>
fun CompoundTag.getDoubleList(key: String): MutableList<DoubleTag> = getList(key, Tag.TAG_DOUBLE.toInt()) as MutableList<DoubleTag>
fun CompoundTag.getByteArrayList(key: String): MutableList<ByteArrayTag> = getList(key, Tag.TAG_BYTE_ARRAY.toInt()) as MutableList<ByteArrayTag>
fun CompoundTag.getStringList(key: String): MutableList<StringTag> = getList(key, Tag.TAG_STRING.toInt()) as MutableList<StringTag>
fun CompoundTag.getListList(key: String): MutableList<ListTag> = getList(key, Tag.TAG_LIST.toInt()) as MutableList<ListTag>
fun CompoundTag.getCompoundList(key: String): MutableList<CompoundTag> = getList(key, Tag.TAG_COMPOUND.toInt()) as MutableList<CompoundTag>
fun CompoundTag.getIntArrayList(key: String): MutableList<IntArrayTag> = getList(key, Tag.TAG_INT_ARRAY.toInt()) as MutableList<IntArrayTag>
fun CompoundTag.getLongArrayList(key: String): MutableList<LongArrayTag> = getList(key, Tag.TAG_LONG_ARRAY.toInt()) as MutableList<LongArrayTag>

View File

@ -72,7 +72,7 @@ class EnergySwordItem : Item(Properties().stacksTo(1).rarity(Rarity.RARE).tab(Ov
itemStack.getCapability(MatteryCapability.ENERGY).orNull()?.let { itemStack.getCapability(MatteryCapability.ENERGY).orNull()?.let {
if (!it.extractEnergyInnerExact(ENERGY_PER_SWING, false).isZero) { if (!it.extractEnergyInnerExact(ENERGY_PER_SWING, false).isZero) {
victim.matteryPlayer?.let { victim.matteryPlayer?.let {
it.extractEnergyInner(ENERGY_ZAP, false) it.androidEnergy.extractEnergyInner(ENERGY_ZAP, false)
victim.hurt(EMPDamageSource(attacker), 8f) victim.hurt(EMPDamageSource(attacker), 8f)
} }
} }

View File

@ -108,7 +108,7 @@ class AndroidStationMenu @JvmOverloads constructor(
} }
} }
val androidBattery: MatterySlot = AndroidSlot(container { it::batteryItemStack }) { val androidBattery: MatterySlot = AndroidSlot(container { it.androidEnergy::item }) {
it.getCapability(ForgeCapabilities.ENERGY).isPresent it.getCapability(ForgeCapabilities.ENERGY).isPresent
} }

View File

@ -237,12 +237,12 @@ class FieldSynchronizer {
inner class Field<V>( inner class Field<V>(
private var field: V, private var field: V,
private val dispatcher: INetworkValueCodec<V>, private val codec: INetworkValueCodec<V>,
private val getter: FieldGetter<V>? = null, private val getter: FieldGetter<V>? = null,
private val setter: FieldSetter<V>? = null, private val setter: FieldSetter<V>? = null,
isObserver: Boolean = false, isObserver: Boolean = false,
) : IField<V> { ) : IField<V> {
private var remote: V = dispatcher.copy(field) private var remote: V = codec.copy(field)
val id = fields.size + 1 val id = fields.size + 1
@ -262,7 +262,7 @@ class FieldSynchronizer {
} }
override fun write(value: V) { override fun write(value: V) {
if (!isDirty && !dispatcher.compare(remote, value)) { if (!isDirty && !codec.compare(remote, value)) {
dirtyFields.add(this@Field) dirtyFields.add(this@Field)
isDirty = true isDirty = true
} }
@ -272,7 +272,7 @@ class FieldSynchronizer {
} }
override fun observe() { override fun observe() {
if (!isDirty && !dispatcher.compare(remote, field)) { if (!isDirty && !codec.compare(remote, field)) {
dirtyFields.add(this) dirtyFields.add(this)
isDirty = true isDirty = true
} }
@ -300,7 +300,7 @@ class FieldSynchronizer {
return return
} }
if (!isDirty && !dispatcher.compare(remote, value)) { if (!isDirty && !codec.compare(remote, value)) {
dirtyFields.add(this) dirtyFields.add(this)
isDirty = true isDirty = true
} }
@ -317,13 +317,13 @@ class FieldSynchronizer {
override fun write(stream: DataOutputStream) { override fun write(stream: DataOutputStream) {
stream.write(id) stream.write(id)
dispatcher.write(stream, field) codec.write(stream, field)
isDirty = false isDirty = false
remote = dispatcher.copy(field) remote = codec.copy(field)
} }
override fun read(stream: DataInputStream) { override fun read(stream: DataInputStream) {
val value = dispatcher.read(stream) val value = codec.read(stream)
val setter = this.setter val setter = this.setter
if (setter != null) { if (setter != null) {
@ -336,7 +336,7 @@ class FieldSynchronizer {
} }
inner class ObservedField<V> : IField<V> { inner class ObservedField<V> : IField<V> {
private val dispatcher: NetworkValueCodec<V> private val codec: NetworkValueCodec<V>
private val getter: () -> V private val getter: () -> V
private val setter: (V) -> Unit private val setter: (V) -> Unit
@ -347,14 +347,14 @@ class FieldSynchronizer {
set(value) { setter.invoke(value) } set(value) { setter.invoke(value) }
constructor(field: KMutableProperty0<V>, dispatcher: NetworkValueCodec<V>) { constructor(field: KMutableProperty0<V>, dispatcher: NetworkValueCodec<V>) {
this.dispatcher = dispatcher this.codec = dispatcher
getter = field::get getter = field::get
setter = field::set setter = field::set
remote = dispatcher.copy(value) remote = dispatcher.copy(value)
} }
constructor(getter: () -> V, setter: (V) -> Unit, dispatcher: NetworkValueCodec<V>) { constructor(getter: () -> V, setter: (V) -> Unit, dispatcher: NetworkValueCodec<V>) {
this.dispatcher = dispatcher this.codec = dispatcher
this.getter = getter this.getter = getter
this.setter = setter this.setter = setter
remote = dispatcher.copy(value) remote = dispatcher.copy(value)
@ -370,7 +370,7 @@ class FieldSynchronizer {
} }
override fun observe() { override fun observe() {
if (!isDirty && !dispatcher.compare(remote, value)) { if (!isDirty && !codec.compare(remote, value)) {
dirtyFields.add(this) dirtyFields.add(this)
isDirty = true isDirty = true
} }
@ -387,13 +387,13 @@ class FieldSynchronizer {
override fun write(stream: DataOutputStream) { override fun write(stream: DataOutputStream) {
stream.write(id) stream.write(id)
val value = value val value = value
dispatcher.write(stream, value) codec.write(stream, value)
isDirty = false isDirty = false
remote = dispatcher.copy(value) remote = codec.copy(value)
} }
override fun read(stream: DataInputStream) { override fun read(stream: DataInputStream) {
this.value = dispatcher.read(stream) this.value = codec.read(stream)
} }
} }

View File

@ -161,53 +161,6 @@ class AndroidFeatureRemovePacket(val type: AndroidFeatureType<*>) : MatteryPacke
} }
} }
class AndroidBatteryItemPacket(val item: ItemStack) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
buff.writeItem(item)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
android.batteryItemStack = item
}
}
companion object {
fun read(buff: FriendlyByteBuf): AndroidBatteryItemPacket {
return AndroidBatteryItemPacket(buff.readItem())
}
}
}
class AndroidEnergyLevelPacket(val level: ImpreciseFraction, val isMaxEnergy: Boolean) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) {
buff.writeImpreciseFraction(level)
buff.writeBoolean(isMaxEnergy)
}
override fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
val android = minecraft.player?.matteryPlayer ?: return@enqueueWork
if (isMaxEnergy) {
android.maxBatteryLevel = level
} else {
android.batteryLevel = level
}
}
}
companion object {
fun read(buff: FriendlyByteBuf): AndroidEnergyLevelPacket {
return AndroidEnergyLevelPacket(buff.readImpreciseFraction(), buff.readBoolean())
}
}
}
class PlayerIterationPacket(val iteration: Int, val deathLog: List<Pair<Int, Component>>) : MatteryPacket { class PlayerIterationPacket(val iteration: Int, val deathLog: List<Pair<Int, Component>>) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
buff.writeInt(iteration) buff.writeInt(iteration)
@ -392,8 +345,6 @@ object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
add(AndroidResearchSyncPacket::class, AndroidResearchSyncPacket.Companion::read, PLAY_TO_CLIENT) add(AndroidResearchSyncPacket::class, AndroidResearchSyncPacket.Companion::read, PLAY_TO_CLIENT)
add(AndroidFeatureSyncPacket::class, AndroidFeatureSyncPacket.Companion::read, PLAY_TO_CLIENT) add(AndroidFeatureSyncPacket::class, AndroidFeatureSyncPacket.Companion::read, PLAY_TO_CLIENT)
add(AndroidFeatureRemovePacket::class, AndroidFeatureRemovePacket.Companion::read, PLAY_TO_CLIENT) add(AndroidFeatureRemovePacket::class, AndroidFeatureRemovePacket.Companion::read, PLAY_TO_CLIENT)
add(AndroidBatteryItemPacket::class, AndroidBatteryItemPacket.Companion::read, PLAY_TO_CLIENT)
add(AndroidEnergyLevelPacket::class, AndroidEnergyLevelPacket.Companion::read, PLAY_TO_CLIENT)
add(PlayerIterationPacket::class, PlayerIterationPacket.Companion::read, PLAY_TO_CLIENT) add(PlayerIterationPacket::class, PlayerIterationPacket.Companion::read, PLAY_TO_CLIENT)