Further update hunger handling and patch FoodData
This commit is contained in:
parent
d74c8a06f5
commit
48d58c42dc
49
src/main/java/ru/dbotthepony/mc/otm/mixin/FoodDataMixin.java
Normal file
49
src/main/java/ru/dbotthepony/mc/otm/mixin/FoodDataMixin.java
Normal 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
|
||||
// а так же не регенерируем
|
||||
// ну и не получаем урон от "голодания"
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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() }
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)")
|
||||
|
@ -7,6 +7,7 @@
|
||||
"refmap": "overdrive_that_matters.refmap.json",
|
||||
"mixins": [
|
||||
"EnchantmentHelperMixin",
|
||||
"FoodDataMixin",
|
||||
"MixinPatchProjectileFinder",
|
||||
"MixinLivingEntity",
|
||||
"MixinAnvilBlock",
|
||||
|
Loading…
Reference in New Issue
Block a user