diff --git a/CHANGELOG.md b/CHANGELOG.md index a7569ba..3c293bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,3 +72,12 @@ This changelog covers all recorded changes after `1.0.0`, grouped by release ver - Simplified and retuned parts of the stat effect implementation, including melee and magic scaling behavior. - Fixed the stats screen so custom configured max Ascend levels display correctly instead of staying at `20/20`. - Synced max Ascend and attribute caps through player stat data so the client GUI respects the server-authoritative config. + +## 2.2.3 + +- Fixed death respawns so players with fortitude bonus health respawn at their full modified maximum health instead of the vanilla 10 hearts. +- Fixed stat resets and refunds so removed bonuses immediately clamp current health back down to the recalculated maximum. +- Fixed player tick progression logic so fortitude, agility, willpower, and charisma timing is tracked per player instead of through shared server-wide counters. +- Hardened player stat synchronization against accidental non-server-player calls. +- Fixed player clone capability cleanup after copying Ascend stats to the respawned player. +- Removed an unused attack-speed lookup from weapon XP handling. diff --git a/gradle.properties b/gradle.properties index be4cc4f..f6eb1ef 100644 --- a/gradle.properties +++ b/gradle.properties @@ -53,7 +53,7 @@ mod_name=Ascend: SbA # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=All Rights Reserved # The mod version. See https://semver.org/ -mod_version=2.2.2 +mod_version=2.2.3 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html @@ -61,4 +61,4 @@ mod_group_id=net.fretux.ascend # The authors of the mod. This is a simple text string that is used for display purposes in the mod list. mod_authors=Fretux # The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list. -mod_description=Increase your powers by training your skills (Very Realistic). \ No newline at end of file +mod_description=Increase your powers by training your skills (Very Realistic). diff --git a/src/main/java/net/fretux/ascend/event/ActivityEvents.java b/src/main/java/net/fretux/ascend/event/ActivityEvents.java index b75df76..c9b448c 100644 --- a/src/main/java/net/fretux/ascend/event/ActivityEvents.java +++ b/src/main/java/net/fretux/ascend/event/ActivityEvents.java @@ -9,7 +9,6 @@ import net.minecraft.core.particles.ParticleTypes; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.effect.MobEffectCategory; -import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.gossip.GossipType; import net.minecraft.world.entity.npc.Villager; import net.minecraft.world.entity.player.Player; @@ -32,17 +31,11 @@ import net.minecraft.world.entity.animal.SnowGolem; import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraft.world.phys.AABB; -import java.util.Objects; import java.util.UUID; @Mod.EventBusSubscriber(modid = AscendMod.MODID) public class ActivityEvents { - private static int agilityTickCounter = 0; - private static int fortitudeTickCounter = 0; - private static int willpowerTickCounter = 0; - private static int charismaTickCounter = 0; - @SubscribeEvent public static void onMobKilled(LivingDeathEvent event) { if (event.getSource().getEntity() instanceof Player player && !player.level().isClientSide) { @@ -86,25 +79,22 @@ public class ActivityEvents { public static void onPlayerTickFortitude(TickEvent.PlayerTickEvent event) { Player player = event.player; if (player.level().isClientSide || event.phase != TickEvent.Phase.END) return; - fortitudeTickCounter++; - if (fortitudeTickCounter % 100 == 0) { - player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { - boolean hasNegativeEffect = player.getActiveEffects().stream() - .anyMatch(e -> e.getEffect().getCategory() == MobEffectCategory.HARMFUL); - if (player.getFoodData().getFoodLevel() <= 6 || hasNegativeEffect) { - stats.addAscendXP((int) (AscendConfig.COMMON.xpPerDamageTaken.get() * AscendConfig.COMMON.xpMultiplier.get())); - PlayerStatsProvider.sync(player); - } - }); - } + if (player.tickCount % 100 != 0) return; + player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { + boolean hasNegativeEffect = player.getActiveEffects().stream() + .anyMatch(e -> e.getEffect().getCategory() == MobEffectCategory.HARMFUL); + if (player.getFoodData().getFoodLevel() <= 6 || hasNegativeEffect) { + stats.addAscendXP((int) (AscendConfig.COMMON.xpPerDamageTaken.get() * AscendConfig.COMMON.xpMultiplier.get())); + PlayerStatsProvider.sync(player); + } + }); } @SubscribeEvent public static void onPlayerTickAgility(TickEvent.PlayerTickEvent event) { Player player = event.player; if (player.level().isClientSide || event.phase != TickEvent.Phase.END) return; - agilityTickCounter++; - if (agilityTickCounter % 40 != 0) return; + if (player.tickCount % 40 != 0) return; player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { boolean didAgileThing = player.isSprinting() @@ -142,16 +132,15 @@ public class ActivityEvents { public static void onPlayerTickWillpower(TickEvent.PlayerTickEvent event) { Player player = event.player; if (player.level().isClientSide || event.phase != TickEvent.Phase.END) return; - willpowerTickCounter++; player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { int willpower = stats.getAttributeLevel("willpower"); - if (willpower > 0 && willpowerTickCounter % 80 == 0) { + if (willpower > 0 && player.tickCount % 80 == 0) { float regen = StatEffects.getWillpowerHealthRegen(willpower); if (regen > 0.0f && player.getHealth() < player.getMaxHealth()) { player.heal(regen); } } - if (willpowerTickCounter % 200 != 0) return; + if (player.tickCount % 200 != 0) return; boolean hasNegativeEffect = player.getActiveEffects().stream() .anyMatch(e -> e.getEffect().getCategory() == MobEffectCategory.HARMFUL); boolean lowHealth = player.getHealth() <= player.getMaxHealth() * 0.25f; @@ -171,8 +160,7 @@ public class ActivityEvents { public static void onPlayerTickCharisma(TickEvent.PlayerTickEvent event) { Player player = event.player; if (player.level().isClientSide || event.phase != TickEvent.Phase.END) return; - charismaTickCounter++; - if (charismaTickCounter % 40 != 0) return; + if (player.tickCount % 40 != 0) return; player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { int charisma = stats.getAttributeLevel("charisma"); if (charisma <= 0) return; @@ -222,9 +210,6 @@ public class ActivityEvents { player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { var heldItem = player.getMainHandItem(); if (heldItem.isEmpty()) return; - double attackSpeed = Objects.requireNonNull(player.getAttribute( - Attributes.ATTACK_SPEED - )).getBaseValue(); stats.addAscendXP(3); PlayerStatsProvider.sync(player); }); diff --git a/src/main/java/net/fretux/ascend/event/PlayerEvents.java b/src/main/java/net/fretux/ascend/event/PlayerEvents.java index 54e5398..0307596 100644 --- a/src/main/java/net/fretux/ascend/event/PlayerEvents.java +++ b/src/main/java/net/fretux/ascend/event/PlayerEvents.java @@ -32,6 +32,7 @@ public class PlayerEvents { newStats.deserializeNBT(oldStats.serializeNBT()); }) ); + event.getOriginal().invalidateCaps(); if (!event.getEntity().level().isClientSide) { StatEffects.applyAll(event.getEntity()); if (event.isWasDeath()) { diff --git a/src/main/java/net/fretux/ascend/player/PlayerStatsProvider.java b/src/main/java/net/fretux/ascend/player/PlayerStatsProvider.java index 86d99e3..d48896a 100644 --- a/src/main/java/net/fretux/ascend/player/PlayerStatsProvider.java +++ b/src/main/java/net/fretux/ascend/player/PlayerStatsProvider.java @@ -39,9 +39,12 @@ public class PlayerStatsProvider implements ICapabilitySerializable } public static void sync(Player player) { + if (!(player instanceof ServerPlayer serverPlayer)) { + return; + } player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> { CompoundTag data = stats.serializeNBT(); - PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new ClientboundSyncStatsPacket(data)); }); }