From db84d137ca7c402b17c9416a0a23b00850b70895 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 16 Aug 2024 13:56:45 +1000 Subject: [PATCH 1/5] Allow setting respawnGracePeriod below 0 to always be able to sprint Make the hunger bar only appear red when the food is below 20% --- common/src/main/java/vice/sol_valheim/FoodHUD.java | 2 +- .../main/java/vice/sol_valheim/mixin/LocalPlayerMixin.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/vice/sol_valheim/FoodHUD.java b/common/src/main/java/vice/sol_valheim/FoodHUD.java index 7afa5fb..1eb6054 100644 --- a/common/src/main/java/vice/sol_valheim/FoodHUD.java +++ b/common/src/main/java/vice/sol_valheim/FoodHUD.java @@ -88,7 +88,7 @@ private static void renderFoodSlot(#if PRE_CURRENT_MC_1_19_2 PoseStack #elif POS int startWidth = width - (size * offset) - offset + 1; float ticksLeftPercent = Float.min(1.0F, (float) food.ticksLeft / foodConfig.getTime()); int barHeight = Integer.max(1, (int)((size + 2f) * ticksLeftPercent)); - int barColor = ticksLeftPercent < SOLValheim.Config.common.eatAgainPercentage ? + int barColor = ticksLeftPercent < 0.2 ? FastColor.ARGB32.color(180, 255, 10, 10) : FastColor.ARGB32.color(96, 0, 0, 0); diff --git a/common/src/main/java/vice/sol_valheim/mixin/LocalPlayerMixin.java b/common/src/main/java/vice/sol_valheim/mixin/LocalPlayerMixin.java index f4e118b..91ecba9 100644 --- a/common/src/main/java/vice/sol_valheim/mixin/LocalPlayerMixin.java +++ b/common/src/main/java/vice/sol_valheim/mixin/LocalPlayerMixin.java @@ -21,7 +21,7 @@ public boolean canStartSprinting(boolean bool) var solPlayer = (PlayerEntityMixinDataAccessor) this; var mayFly = ((LocalPlayer) (Object) this).getAbilities().mayfly; - if (mayFly || ((LocalPlayer) (Object) this).tickCount < SOLValheim.Config.common.respawnGracePeriod * 20) + if (mayFly || SOLValheim.Config.common.respawnGracePeriod < 0 || ((LocalPlayer) (Object) this).tickCount < SOLValheim.Config.common.respawnGracePeriod * 20) { return true; } @@ -42,7 +42,7 @@ public void canStartSprinting(CallbackInfoReturnable cir) var solPlayer = (PlayerEntityMixinDataAccessor) this; var mayFly = ((LocalPlayer) (Object) this).getAbilities().mayfly; - if (mayFly || ((LocalPlayer) (Object) this).tickCount < SOLValheim.Config.common.respawnGracePeriod * 20) + if (mayFly || SOLValheim.Config.common.respawnGracePeriod < 0 || ((LocalPlayer) (Object) this).tickCount < SOLValheim.Config.common.respawnGracePeriod * 20) { cir.setReturnValue(true); cir.cancel(); From 1e047beae0cc74c9648535fdf7802a408dc001d5 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 16 Aug 2024 14:31:32 +1000 Subject: [PATCH 2/5] Rudimentary hack to round health up to the nearest full heart --- .../src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java b/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java index 201bf12..5446dbd 100644 --- a/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java +++ b/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java @@ -99,6 +99,8 @@ private void onTick(CallbackInfo info) { } float maxhp = Math.min(40, (SOLValheim.Config.common.startingHealth * 2) + sol_valheim$food_data.getTotalFoodNutrition()); + if (((int)maxhp % 2) != 0) + maxhp += 1; Player player = (Player) (LivingEntity) this; player.getFoodData().setSaturation(0); From 82052f020c49b01de5049aa50c6af2cf2a5056f4 Mon Sep 17 00:00:00 2001 From: Mario Date: Fri, 16 Aug 2024 15:06:53 +1000 Subject: [PATCH 3/5] More clever health rounding --- .../main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java b/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java index 5446dbd..78067e9 100644 --- a/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java +++ b/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java @@ -99,8 +99,8 @@ private void onTick(CallbackInfo info) { } float maxhp = Math.min(40, (SOLValheim.Config.common.startingHealth * 2) + sol_valheim$food_data.getTotalFoodNutrition()); - if (((int)maxhp % 2) != 0) - maxhp += 1; + // hack: round to full hearts + maxhp = Math.round(maxhp / 2) * 2; Player player = (Player) (LivingEntity) this; player.getFoodData().setSaturation(0); From c32c4043b385060a174faffd75aaf6f7a00da87c Mon Sep 17 00:00:00 2001 From: dandy Date: Sun, 22 Dec 2024 17:17:04 -0700 Subject: [PATCH 4/5] edited config to use strings instead of resource locations --- .../main/java/vice/sol_valheim/ModConfig.java | 28 ++++++------ .../java/vice/sol_valheim/SOLValheim.java | 43 ++++++++----------- 2 files changed, 30 insertions(+), 41 deletions(-) diff --git a/common/src/main/java/vice/sol_valheim/ModConfig.java b/common/src/main/java/vice/sol_valheim/ModConfig.java index c54bd9a..d763203 100644 --- a/common/src/main/java/vice/sol_valheim/ModConfig.java +++ b/common/src/main/java/vice/sol_valheim/ModConfig.java @@ -6,6 +6,7 @@ import me.shedaniel.autoconfig.annotation.ConfigEntry; import me.shedaniel.autoconfig.serializer.PartitioningSerializer; import me.shedaniel.cloth.clothconfig.shadowed.blue.endless.jankson.Comment; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.effect.MobEffect; @@ -15,10 +16,7 @@ import net.minecraft.world.item.Items; import net.minecraft.world.item.UseAnim; -import java.util.ArrayList; -import java.util.Dictionary; -import java.util.Hashtable; -import java.util.List; +import java.util.*; @Config(name = SOLValheim.MOD_ID) @@ -30,7 +28,7 @@ public static Common.FoodConfig getFoodConfig(Item item) { if(item != Items.CAKE && !item.isEdible() && !isDrink) return null; - var existing = SOLValheim.Config.common.foodConfigs.get(item.arch$registryName()); + var existing = SOLValheim.Config.common.foodConfigs.get(item.arch$registryName().toString()); if (existing == null) { var registry = item.arch$registryName().toString(); @@ -68,13 +66,13 @@ else if (registry.contains("milk")) { existing.healthRegenModifier = 1.5f; } -// if (registry.equals("minecraft:beetroot_soup")) { -// var effectConfig = new Common.MobEffectConfig(); -// effectConfig.ID = BuiltInRegistries.MOB_EFFECT.getKey(MobEffects.MOVEMENT_SPEED).toString(); -// existing.extraEffects.add(effectConfig); -// } + if (registry.equals("minecraft:beetroot_soup")) { + var effectConfig = new Common.MobEffectConfig(); + effectConfig.ID = BuiltInRegistries.MOB_EFFECT.getKey(MobEffects.MOVEMENT_SPEED).toString(); + existing.extraEffects.add(effectConfig); + } - SOLValheim.Config.common.foodConfigs.put(item.arch$registryName(), existing); + SOLValheim.Config.common.foodConfigs.put(item.arch$registryName().toString(), existing); } return existing; @@ -130,7 +128,7 @@ Food nutrition and effect overrides (Auto Generated if Empty) - healthRegenModifier: Multiplies health regen speed - extraEffects: Extra effects provided by eating the food. Format: { String ID, float duration, int amplifier } """) - public Dictionary foodConfigs = new Hashtable<>(); + public Map foodConfigs = new HashMap<>(); public static final class FoodConfig implements ConfigData { public int nutrition; @@ -139,7 +137,7 @@ public static final class FoodConfig implements ConfigData { public List extraEffects = new ArrayList<>(); public int getTime() { - var time = (int) (SOLValheim.Config.common.defaultTimer * 20 * saturationModifier * nutrition); + int time = (int) (SOLValheim.Config.common.defaultTimer * 20 * saturationModifier * nutrition); return Math.max(time, 6000); } @@ -147,8 +145,8 @@ public int getHearts() { return Math.max(nutrition, 2); } - public float getHealthRegen() - { + public float getHealthRegen() { + // 0.25f min, 2f max return Mth.clamp(nutrition * 0.10f * healthRegenModifier, 0.25f, 2f); } } diff --git a/common/src/main/java/vice/sol_valheim/SOLValheim.java b/common/src/main/java/vice/sol_valheim/SOLValheim.java index 0684ac9..b8c20ac 100644 --- a/common/src/main/java/vice/sol_valheim/SOLValheim.java +++ b/common/src/main/java/vice/sol_valheim/SOLValheim.java @@ -54,39 +54,30 @@ public static void init() { AutoConfig.register(ModConfig.class, PartitioningSerializer.wrap(JanksonConfigSerializer::new)); Config = AutoConfig.getConfigHolder(ModConfig.class).getConfig(); - if (Config.common.foodConfigs.isEmpty()) - { - System.out.println("Generating default food configs, this might take a second."); - long startTime = System.nanoTime(); - - #if PRE_CURRENT_MC_1_19_2 - Registry.ITEM.forEach(ModConfig::getFoodConfig); - #elif POST_CURRENT_MC_1_20_1 - BuiltInRegistries.ITEM.forEach(ModConfig::getFoodConfig); - #endif - + boolean addedAny = false; + + #if PRE_CURRENT_MC_1_19_2 + for (Item item : Registry.ITEM) { + #elif POST_CURRENT_MC_1_20_1 + for (Item item : BuiltInRegistries.ITEM) { + #endif + var key = item.arch$registryName(); + var existing = Config.common.foodConfigs.get(key); + if (existing == null) { + ModConfig.getFoodConfig(item); + addedAny = true; + } + } + if (addedAny) { + //System.out.println("Generated config for missing items..."); AutoConfig.getConfigHolder(ModConfig.class).save(); - - long endTime = System.nanoTime(); - long executionTime = (endTime - startTime) / 1000000; - System.out.println("Generating default food configs took " + executionTime + "ms."); } - -// -// try { -// var field = FoodProperties.class.getDeclaredField("canAlwaysEat"); -// field.setBoolean(Items.ROTTEN_FLESH.getFoodProperties(), true); -// } -// catch (Exception e) { -// System.out.println(e); -// } } - public static void addTooltip(ItemStack item, TooltipFlag flag, List list) - { + public static void addTooltip(ItemStack item, TooltipFlag flag, List list){ var food = item.getItem(); if (food == Items.ROTTEN_FLESH) { list.add(Component.literal("☠ Empties Your Stomach!").withStyle(ChatFormatting.GREEN)); From e544cdab1f0691541f9bbe099fbaba97e6bc336a Mon Sep 17 00:00:00 2001 From: dandy Date: Sun, 22 Dec 2024 20:26:49 -0700 Subject: [PATCH 5/5] added support for custom food effects --- .../main/java/vice/sol_valheim/ModConfig.java | 6 ++ .../java/vice/sol_valheim/SOLValheim.java | 23 ++++++-- .../sol_valheim/mixin/PlayerEntityMixin.java | 55 ++++++++++++++++++- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/vice/sol_valheim/ModConfig.java b/common/src/main/java/vice/sol_valheim/ModConfig.java index d763203..f93bd09 100644 --- a/common/src/main/java/vice/sol_valheim/ModConfig.java +++ b/common/src/main/java/vice/sol_valheim/ModConfig.java @@ -106,6 +106,9 @@ public static final class Common implements ConfigData { @ConfigEntry.Gui.Tooltip() @Comment("Extra speed given when your hearts are full (0 to disable)") public float speedBoost = 0.20f; + @ConfigEntry.Gui.Tooltip() @Comment("Maximum allowed hearts from food") + public int maxFoodHealth = 100; + @ConfigEntry.Gui.Tooltip() @Comment("Number of hearts to start with") public int startingHealth = 3; @@ -121,6 +124,9 @@ public static final class Common implements ConfigData { @ConfigEntry.Gui.Tooltip() @Comment("Simulate food ticking down during night") public boolean passTicksDuringNight = true; + @ConfigEntry.Gui.Tooltip() @Comment("Whether or not food tooltips should show extra effects") + public boolean displayEffects = true; + @ConfigEntry.Gui.Tooltip(count = 5) @Comment(""" Food nutrition and effect overrides (Auto Generated if Empty) - nutrition: Affects Heart Gain & Health Regen diff --git a/common/src/main/java/vice/sol_valheim/SOLValheim.java b/common/src/main/java/vice/sol_valheim/SOLValheim.java index b8c20ac..70103fd 100644 --- a/common/src/main/java/vice/sol_valheim/SOLValheim.java +++ b/common/src/main/java/vice/sol_valheim/SOLValheim.java @@ -96,12 +96,23 @@ public static void addTooltip(ItemStack item, TooltipFlag flag, List list.add(Component.literal("⌚ " + String.format("%.0f", minutes) + " Minute" + (minutes > 1 ? "s" : "")).withStyle(ChatFormatting.GOLD)); - for (var effect : config.extraEffects) { - var eff = effect.getEffect(); - if (eff == null) - continue; - - list.add(Component.literal("★ " + eff.getDisplayName().getString() + (effect.amplifier > 1 ? " " + effect.amplifier : "")).withStyle(ChatFormatting.GREEN)); + if(!config.extraEffects.isEmpty() && Config.common.displayEffects) { + list.add(Component.literal("")); + for (var effect : config.extraEffects) { + var eff = effect.getEffect(); + if (eff == null) + continue; + + float effectDurationSeconds = config.getTime() * effect.duration / 20f; + int minutesPart = (int) (effectDurationSeconds / 60); + int secondsPart = (int) (effectDurationSeconds % 60); + + + if (eff.isBeneficial()) + list.add(Component.literal("★ " + eff.getDisplayName().getString() + (effect.amplifier > 1 ? " " + effect.amplifier : "") + String.format(" (%02d:%02d)", minutesPart, secondsPart)).withStyle(ChatFormatting.GREEN)); + else + list.add(Component.literal("❌ " + eff.getDisplayName().getString() + (effect.amplifier > 1 ? " " + effect.amplifier : "") + String.format(" (%02d:%02d)", minutesPart, secondsPart)).withStyle(ChatFormatting.DARK_RED)); + } } if (item.getUseAnimation() == UseAnim.DRINK) { diff --git a/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java b/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java index 78067e9..ff245aa 100644 --- a/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java +++ b/common/src/main/java/vice/sol_valheim/mixin/PlayerEntityMixin.java @@ -19,6 +19,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import vice.sol_valheim.ModConfig; import vice.sol_valheim.SOLValheim; import vice.sol_valheim.accessors.FoodDataPlayerAccessor; import vice.sol_valheim.accessors.PlayerEntityMixinDataAccessor; @@ -96,9 +97,27 @@ private void onTick(CallbackInfo info) { if (!sol_valheim$food_data.ItemEntries.isEmpty()) { sol_valheim$food_data.tick(); sol_valheim$trackData(); + + var player = (Player) (Object) this; + if (player.tickCount % 20 == 0) { + // Handle main eaten items + for (var eaten : sol_valheim$food_data.ItemEntries) { + var config = ModConfig.getFoodConfig(eaten.item); + if (config != null) { + sol_valheim$applyFoodEffectsToPlayer(player, eaten, config); + } + } + // Handle drink slot + if (sol_valheim$food_data.DrinkSlot != null) { + var config = ModConfig.getFoodConfig(sol_valheim$food_data.DrinkSlot.item); + if (config != null) { + sol_valheim$applyFoodEffectsToPlayer(player, sol_valheim$food_data.DrinkSlot, config); + } + } + } } - float maxhp = Math.min(40, (SOLValheim.Config.common.startingHealth * 2) + sol_valheim$food_data.getTotalFoodNutrition()); + float maxhp = Math.min(SOLValheim.Config.common.maxFoodHealth * 2, (SOLValheim.Config.common.startingHealth * 2) + sol_valheim$food_data.getTotalFoodNutrition()); // hack: round to full hearts maxhp = Math.round(maxhp / 2) * 2; @@ -125,6 +144,40 @@ else if (maxhp < 20 && speedBuff != null) } } + @Unique + private void sol_valheim$applyFoodEffectsToPlayer(Player player, + ValheimFoodData.EatenFoodItem eatenData, + ModConfig.Common.FoodConfig config) + { + int ticksLeft = eatenData.ticksLeft; + + for (var effectCfg : config.extraEffects) { + var mobEffect = effectCfg.getEffect(); + if (mobEffect == null) + continue; + + int amplifier = Math.max(effectCfg.amplifier - 1, 0); + float fractionActive = effectCfg.duration; + int totalTime = config.getTime(); + int threshold = (int) (totalTime * fractionActive); + + if (ticksLeft >= (totalTime - threshold)) { + player.addEffect( + new net.minecraft.world.effect.MobEffectInstance( + mobEffect, + 120, // just so it doesn't flash + amplifier, + false, + false + ) + ); + } + else { + player.removeEffect(mobEffect); + } + } + } + @Inject(at = {@At("HEAD")}, method = {"canEat(Z)Z"}, cancellable = true) private void onCanConsume(boolean ignorehunger, CallbackInfoReturnable info) { info.setReturnValue(true);