Further update hunger handling and patch FoodData

This commit is contained in:
DBotThePony 2023-06-27 21:59:14 +07:00
parent d74c8a06f5
commit 48d58c42dc
Signed by: DBot
GPG Key ID: DCC23B5715498507
5 changed files with 100 additions and 11 deletions

View File

@ -0,0 +1,49 @@
package ru.dbotthepony.mc.otm.mixin;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.food.FoodData;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
@Mixin(FoodData.class)
public class FoodDataMixin {
@Shadow
private int lastFoodLevel;
@Shadow
private int tickTimer;
@Shadow
private int foodLevel;
@Shadow
private float exhaustionLevel;
@Inject(
method = "tick(Lnet/minecraft/world/entity/player/Player;)V",
at = @At("HEAD"),
cancellable = true
)
private void tick(Player player, CallbackInfo info) {
player.getCapability(MatteryCapability.MATTERY_PLAYER).ifPresent(it -> {
if (it.isAndroid()) {
info.cancel();
// полностью подменяем логику если андроид
lastFoodLevel = foodLevel;
if (player.level().getDifficulty() == Difficulty.PEACEFUL) {
exhaustionLevel = 0f;
} else {
tickTimer = 0;
}
// не обновляем уровень истощения ибо он обнуляется логикой внутри MatteryPlayerCapability
// а так же не регенерируем
// ну и не получаем урон от "голодания"
}
});
}
}

View File

@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.android.feature
import net.minecraft.nbt.CompoundTag
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.level.GameRules
import net.minecraftforge.event.entity.living.LivingHurtEvent
import ru.dbotthepony.mc.otm.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidFeature
@ -16,7 +17,7 @@ class NanobotsRegenerationFeature(android: MatteryPlayerCapability) : AndroidFea
private var healTicks = 0
override fun tickServer() {
if (ply.health > 0f && ply.health < ply.maxHealth) {
if (ply.isHurt && ply.level().gameRules.getBoolean(GameRules.RULE_NATURAL_REGENERATION)) {
ticksPassed++
val waitTime = AndroidConfig.NanobotsRegeneration.COOLDOWN.getOrElse(healTicks) { AndroidConfig.NanobotsRegeneration.COOLDOWN.last() }

View File

@ -26,6 +26,7 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.Items
import net.minecraft.world.item.ProjectileWeaponItem
import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
import net.minecraft.world.level.GameRules
import net.minecraft.world.level.Level
import net.minecraft.world.phys.Vec3
import net.minecraftforge.common.ForgeHooks
@ -281,6 +282,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private var shouldPlaySound = false
private val research = IdentityHashMap<AndroidResearchType, AndroidResearch>()
private var nextDischargeHurt = 20
private var nextHealTick = 0
// players tracking us
// stored separately because EntityTracker and ChunkMup, etc are buried deep and
@ -340,6 +342,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
savetables.bool(::displayExoPack, "displayExoSuit")
savetables.bool(::isExoPackCraftingUpgraded, "isExoSuitCraftingUpgraded")
savetables.int(::nextDischargeHurt)
savetables.int(::nextHealTick)
savetables.vector(::lastOutsideLiquid)
savetables.location(::lastDimension)
@ -883,6 +886,12 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
val stats = ply.foodData
val fourTimesTheHunger = AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT * 4
// истощение
if (stats.exhaustionLevel > 0f) {
val extracted = androidEnergy.extractEnergy(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT * (stats.exhaustionLevel / 4f), false)
stats.setExhaustion(stats.exhaustionLevel - (extracted / AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT).toFloat() * 4f)
}
// Обычный голод
while (
stats.foodLevel < 18 &&
@ -894,10 +903,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
// "поглощение" излишек голода, как при мирном режиме, так и при поедании обычной еды
if (AndroidConfig.REGENERATE_ENERGY) {
while (stats.foodLevel > 18 && androidEnergy.receiveEnergyExact(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false)) {
while (stats.foodLevel > 18 && androidEnergy.receiveEnergyExact(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT / 2, false)) {
stats.foodLevel--
}
} else if (ply.level().server?.worldData?.difficulty != Difficulty.PEACEFUL) {
} else if (ply.level().difficulty != Difficulty.PEACEFUL) {
stats.foodLevel = stats.foodLevel.coerceAtMost(18)
}
@ -909,14 +918,23 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
stats.setSaturation(stats.saturationLevel + (extracted / AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT).toFloat())
}
// истощение
if (stats.exhaustionLevel > 0f && androidEnergy.batteryLevel >= fourTimesTheHunger) {
val extracted = androidEnergy.extractEnergy(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT * (stats.exhaustionLevel / 4f), false)
stats.setExhaustion(stats.exhaustionLevel - (extracted / AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT).toFloat() * 4f)
}
if (androidEnergy.batteryLevel <= Decimal.TEN && !ply.isCreative && ply.level().difficulty != Difficulty.PEACEFUL) {
if (stats.saturationLevel > 1f) {
if (androidEnergy.receiveEnergyExact(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false)) {
stats.setSaturation(stats.saturationLevel - 1f)
}
} else if (stats.saturationLevel > 0f) {
val received = androidEnergy.receiveEnergy(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT * stats.saturationLevel, false)
stats.setSaturation(stats.saturationLevel - (received / AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT).toFloat())
} else if (stats.foodLevel > 0) {
// так как голод не тикает для андроидов, "умереть с голоду" мы не можем
// но со стороны будет выглядеть как будто мы умираем с голода
if (androidEnergy.receiveEnergyExact(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false)) {
stats.foodLevel--
}
}
if (androidEnergy.batteryLevel <= Decimal.TEN && !ply.isCreative && ply.level().server?.worldData?.difficulty != Difficulty.PEACEFUL) {
if (stats.foodLevel <= 6 || !androidEnergy.receiveEnergyExact(AndroidConfig.ANDROID_ENERGY_PER_HUNGER_POINT, false).also { if (it) stats.foodLevel-- }) {
if (androidEnergy.batteryLevel <= Decimal.TEN) {
if (--nextDischargeHurt <= 0 && ply.hurt(DamageSource(ply.level().registryAccess().damageType(MDamageTypes.ANDROID_DISCHARGE)), 1f)) {
nextDischargeHurt = 20
}
@ -929,6 +947,15 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
}
} else {
nextDischargeHurt = 20
if (ply.isHurt && ply.level().gameRules.getBoolean(GameRules.RULE_NATURAL_REGENERATION)) {
if (--nextHealTick <= 0) {
nextHealTick = if (ply.level().difficulty == Difficulty.PEACEFUL) 10 else AndroidConfig.TIME_BETWEEN_NATURAL_REGENERATION
ply.heal(1f)
}
} else {
nextHealTick = if (ply.level().difficulty == Difficulty.PEACEFUL) 10 else AndroidConfig.TIME_BETWEEN_NATURAL_REGENERATION
}
}
}

View File

@ -11,6 +11,17 @@ object AndroidConfig : AbstractConfig("androids") {
.comment("If this is disabled, any (technically) excess hunger will be nullified, unless playing on peaceful difficulty.")
.define("REGENERATE_ENERGY", true)
val TIME_BETWEEN_NATURAL_REGENERATION: Int by builder
.comment("Time in ticks between natural health regeneration ticks")
.comment("Default value is meant to be one of downsides of being an android,")
.comment("so please, don't blindly buff it, players have ability to research into Nanobots Regeneration,")
.comment("which provide superior regeneration on average than human players.")
.comment("---")
.comment("This regeneration obeys natural regeneration gamerule")
.comment("---")
.comment("Reason for this config option is that FoodData does not tick")
.comment("for android players, since 'hunger' (for compatibility) is managed by mod in such case")
.defineInRange("TIME_BETWEEN_NATURAL_REGENERATION", 120, 0, Int.MAX_VALUE)
object NanobotsRegeneration {
init {
@ -29,7 +40,7 @@ object AndroidConfig : AbstractConfig("androids") {
.comment(" ticksSinceTakingDamage = 0")
.comment(" this.ply.heal(...)")
.comment("}")
.defineList("COOLDOWN", { mutableListOf(80, 60, 40, 20) }) { it is Int }
.defineList("COOLDOWN", { mutableListOf(60, 50, 40, 30) }) { it is Int }
val ENERGY_PER_HITPOINT by builder
.comment("Energy required to regenerate 1 health point (half a heart)")

View File

@ -7,6 +7,7 @@
"refmap": "overdrive_that_matters.refmap.json",
"mixins": [
"EnchantmentHelperMixin",
"FoodDataMixin",
"MixinPatchProjectileFinder",
"MixinLivingEntity",
"MixinAnvilBlock",