From 6a1613580905c784d58b2687fc8118eca9262780 Mon Sep 17 00:00:00 2001 From: maxanier Date: Sat, 5 Oct 2024 13:54:48 +0200 Subject: [PATCH] Fix difficulty system being broken. and: f50ecbadb8b0eeb011b56bc13fc7f5baef54baa8 Fix potential crash with VampireBaron #1428 Improve Difficulty system documentation --- .../vampirism/api/difficulty/Difficulty.java | 36 ++++++++++++++++++- .../entity/vampire/VampireBaronEntity.java | 16 +++++---- .../vampirism/util/DifficultyCalculator.java | 14 +++++--- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/api/java/de/teamlapen/vampirism/api/difficulty/Difficulty.java b/src/api/java/de/teamlapen/vampirism/api/difficulty/Difficulty.java index 4f0d1ef76..44292f5c5 100755 --- a/src/api/java/de/teamlapen/vampirism/api/difficulty/Difficulty.java +++ b/src/api/java/de/teamlapen/vampirism/api/difficulty/Difficulty.java @@ -1,14 +1,48 @@ package de.teamlapen.vampirism.api.difficulty; +import org.jetbrains.annotations.NotNull; + +import static net.minecraft.util.Mth.clamp; + /** * Represents a calculated difficulty level. * The used difficulty levels are in percentage of the max reachable level. * So a level 5 in a faction which has a max level of 10 would be represented by 5/10*100=50 */ -public record Difficulty(int minPercLevel, int maxPercLevel, int avgPercLevel) { +public class Difficulty { + + /** + * Percentage between 0 and 100 + */ + public final int minPercLevel, maxPercLevel, avgPercLevel; + + public Difficulty(int mil, int mal, int al) { + mal = clamp(mal, 0, 100); + mil = clamp(mil, 0, mal); + al = clamp(al, mil, mal); + this.minPercLevel = mil; + this.maxPercLevel = mal; + this.avgPercLevel = al; + } + + public int minPercLevel() { + return minPercLevel; + } + + public int maxPercLevel() { + return maxPercLevel; + } + + public int avgPercLevel() { + return avgPercLevel; + } public boolean isZero() { return (this.minPercLevel == 0 && this.maxPercLevel == 0); } + @Override + public @NotNull String toString() { + return "Difficulty: min_" + minPercLevel + " max_" + maxPercLevel + " avg_" + avgPercLevel; + } } diff --git a/src/main/java/de/teamlapen/vampirism/entity/vampire/VampireBaronEntity.java b/src/main/java/de/teamlapen/vampirism/entity/vampire/VampireBaronEntity.java index 81af5bbc6..e36df5cfd 100644 --- a/src/main/java/de/teamlapen/vampirism/entity/vampire/VampireBaronEntity.java +++ b/src/main/java/de/teamlapen/vampirism/entity/vampire/VampireBaronEntity.java @@ -178,7 +178,7 @@ public boolean doHurtTarget(@NotNull Entity entity) { public SpawnGroupData finalizeSpawn(@NotNull ServerLevelAccessor worldIn, @NotNull DifficultyInstance difficultyIn, @NotNull MobSpawnType reason, @Nullable SpawnGroupData spawnDataIn) { this.getEntityData().set(LADY, this.getRandom().nextBoolean()); if (reason == MobSpawnType.COMMAND || reason == MobSpawnType.SPAWN_EGG) { - this.setEntityLevel(getRandom().nextInt(getMaxEntityLevel() + 1)); +// this.setEntityLevel(getRandom().nextInt(getMaxEntityLevel() + 1)); } return super.finalizeSpawn(worldIn, difficultyIn, reason, spawnDataIn); } @@ -299,17 +299,21 @@ public boolean shouldShowName() { @Override public int suggestEntityLevel(@NotNull Difficulty d) { - int avg = Math.round(((d.avgPercLevel()) / 100F - 5 / 14F) / (1F - 5 / 14F) * MAX_LEVEL); - int max = Math.round(((d.maxPercLevel()) / 100F - 5 / 14F) / (1F - 5 / 14F) * MAX_LEVEL); - int min = Math.round(((d.minPercLevel()) / 100F - 5 / 14F) / (1F - 5 / 14F) * (MAX_LEVEL)); - + //Currently, this is not called when the entity is spawned by a command or spawn egg to guarantee a spawn-> See finalizeSpawn + + //We want to distribute the baron levels between player levels 5 (from here on you need pure blood for leveling and 14 {@link de.teamlapen.vampirism.REFERENCE.HIGHEST_VAMPIRE_LEVEL} + int avg = Math.round(((d.avgPercLevel() / 100f - 5 / 14f) / (1F - 5 / 14F)) * MAX_LEVEL); + int max = Math.round(((d.maxPercLevel() / 100f - 5 / 14f) / (1F - 5 / 14F)) * MAX_LEVEL); + int min = Math.round(((d.minPercLevel() / 100f - 5 / 14f) / (1F - 5 / 14F)) * MAX_LEVEL); + //Values may be <0 leading to entity spawn being canceled + LogManager.getLogger().warn("Level " + avg + " / " + max + " / " + min + " / " + d.maxPercLevel()); return switch (random.nextInt(7)) { case 0 -> min; case 1 -> max + 1; case 2 -> avg; case 3 -> avg + 1; case 4, 5 -> random.nextInt(MAX_LEVEL + 1); - default -> random.nextInt(max + 2 - min) + min; + default -> random.nextInt(max - min + 2) + min; //Even if values are negative max> min -> argument is >=2) }; } diff --git a/src/main/java/de/teamlapen/vampirism/util/DifficultyCalculator.java b/src/main/java/de/teamlapen/vampirism/util/DifficultyCalculator.java index 8a4c92e66..29e042675 100755 --- a/src/main/java/de/teamlapen/vampirism/util/DifficultyCalculator.java +++ b/src/main/java/de/teamlapen/vampirism/util/DifficultyCalculator.java @@ -15,12 +15,12 @@ import java.util.List; /** - * Calculates a (local) difficulity based on the player faction levels + * Calculates a (local) difficulty based on the player faction levels */ public class DifficultyCalculator { /** - * Can be null if no players are found + * Can be null if no alive players are found * * @return a difficulty level based on the given player's faction levels */ @@ -31,15 +31,17 @@ Difficulty calculateDifficulty(@Nullable List playerList) { int min = Integer.MAX_VALUE; int max = 0; int sum = 0; + int playerCount = 0; for (Player p : playerList) { if (!p.isAlive()) continue; + playerCount++; FactionPlayerHandler handler = FactionPlayerHandler.get(p); int pLevel = handler.getCurrentLevel(); if (pLevel == 0) { min = 0; continue; } - int level = (int) (pLevel / (float) handler.getCurrentFaction().getHighestReachableLevel()); + int level = Math.round(pLevel / (float) handler.getCurrentFaction().getHighestReachableLevel() * 100F); if (level < min) { min = level; } @@ -48,7 +50,11 @@ Difficulty calculateDifficulty(@Nullable List playerList) { } sum += max; } - return new Difficulty(min, max, Math.round(sum / (float) playerList.size())); + //Careful, if no player is alive `min` may still be Integer.MAX_VALUE and playerCount is 0 + if (playerCount == 0) { + return null; + } + return new Difficulty(min, max, Math.round(sum / (float) playerCount)); } /**