make various fixes
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
Always update the mod's version number in gradle.properties after a change
|
||||
|
||||
Always update CHANGELOG.md with the new changes after a change with the new version number.
|
||||
@@ -2,6 +2,23 @@
|
||||
|
||||
This changelog covers all recorded changes after `1.0.0`, grouped by release version from the git history.
|
||||
|
||||
## 2.4.1
|
||||
|
||||
- Fixed rejoining players with fortitude bonus health being left at the vanilla 20 HP after their increased maximum health was restored.
|
||||
- Applied server-side stat modifiers before the initial login synchronization so the client immediately receives the correct attributes and health state.
|
||||
|
||||
## 2.4.0
|
||||
|
||||
- Added 20 hidden advancements covering specialized, hybrid, balanced, magic, weapon-scaling, respec, and configuration-based builds.
|
||||
- Added persistent per-character respec counts, previous-build snapshots, and weapon-scaling investment history for stateful hidden advancement conditions.
|
||||
- Renamed several existing advancements, including the root, level 5, maximum-level, maximum-attribute, Knowledge, and shrine advancements.
|
||||
|
||||
## 2.3.0
|
||||
|
||||
- Added an Ascend advancement tree for reaching levels 2, 5, 10, and the configured maximum level (20 by default).
|
||||
- Added advancements for maxing an attribute, accumulating 100 Knowledge, reading a Moonseye Tome, and successfully using a Shrine of Remembrance.
|
||||
- Made advancement checks use server-authoritative progression data so milestones also work after login, respawn, and admin-granted progression.
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- Added Ascend admin commands for inspecting stats, setting attributes, granting XP, and resetting progression.
|
||||
|
||||
+1
-1
@@ -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.4
|
||||
mod_version=2.4.1
|
||||
# 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
|
||||
|
||||
@@ -8,8 +8,6 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.fretux.ascend.player.PlayerStats;
|
||||
import net.fretux.ascend.player.PlayerStatsProvider;
|
||||
import net.fretux.ascend.player.StatEffects;
|
||||
import net.fretux.ascend.network.PacketHandler;
|
||||
import net.fretux.ascend.network.ClientboundSyncStatsPacket;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
@@ -17,7 +15,6 @@ import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
|
||||
public class AscendCommand {
|
||||
@SubscribeEvent
|
||||
@@ -67,7 +64,7 @@ public class AscendCommand {
|
||||
target.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> {
|
||||
stats.setAttributeLevel(attr, value);
|
||||
StatEffects.applyAll(target);
|
||||
sync(target, stats);
|
||||
PlayerStatsProvider.sync(target);
|
||||
ctx.getSource().sendSuccess(() ->
|
||||
Component.literal("Set " + target.getName().getString() + "'s " + attr + " to " + value), true);
|
||||
});
|
||||
@@ -80,7 +77,7 @@ public class AscendCommand {
|
||||
target.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> {
|
||||
stats.addAscendXP(amount);
|
||||
StatEffects.applyAll(target);
|
||||
sync(target, stats);
|
||||
PlayerStatsProvider.sync(target);
|
||||
ctx.getSource().sendSuccess(() ->
|
||||
Component.literal("Added " + amount + " Ascend XP to " + target.getName().getString()), true);
|
||||
});
|
||||
@@ -93,17 +90,11 @@ public class AscendCommand {
|
||||
PlayerStats fresh = new PlayerStats();
|
||||
stats.deserializeNBT(fresh.serializeNBT());
|
||||
StatEffects.applyAll(target);
|
||||
sync(target, stats);
|
||||
PlayerStatsProvider.sync(target);
|
||||
ctx.getSource().sendSuccess(() ->
|
||||
Component.literal("Reset " + target.getName().getString() + "'s Ascend stats."), true);
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static void sync(ServerPlayer player, PlayerStats stats) {
|
||||
PacketHandler.INSTANCE.send(
|
||||
PacketDistributor.PLAYER.with(() -> player),
|
||||
new ClientboundSyncStatsPacket(stats.serializeNBT())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,13 @@ public class PlayerEvents {
|
||||
@SubscribeEvent
|
||||
public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) {
|
||||
if (!event.getEntity().level().isClientSide) {
|
||||
PlayerStatsProvider.sync(event.getEntity());
|
||||
float healthBeforeFortitude = event.getEntity().getHealth();
|
||||
StatEffects.applyAll(event.getEntity());
|
||||
if (Math.abs(healthBeforeFortitude - 20.0F) < 0.001F
|
||||
&& event.getEntity().getMaxHealth() > healthBeforeFortitude) {
|
||||
event.getEntity().setHealth(event.getEntity().getMaxHealth());
|
||||
}
|
||||
PlayerStatsProvider.sync(event.getEntity());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.fretux.ascend.network;
|
||||
|
||||
import net.fretux.ascend.advancement.AscendAdvancements;
|
||||
import net.fretux.ascend.compat.AscendMMCompat;
|
||||
import net.fretux.ascend.item.RemembranceEssenceItem;
|
||||
import net.fretux.ascend.player.PlayerStatsProvider;
|
||||
@@ -41,6 +42,7 @@ public class ServerboundShrineChoicePacket {
|
||||
net.fretux.ascend.player.StatEffects.applyAll(player);
|
||||
player.sendSystemMessage(Component.literal("YOU ARE A BLANK SLATE. EMPTY. FORGOTTEN."));
|
||||
RemembranceEssenceItem.consume(player);
|
||||
AscendAdvancements.grant(player, "use_shrine");
|
||||
} else {
|
||||
player.sendSystemMessage(Component.literal("YOUR MIND IS TOO EMPTY TO BE WORTH MY TOUCH."));
|
||||
player.hurt(player.level().damageSources().magic(), 4.0F);
|
||||
@@ -60,6 +62,7 @@ public class ServerboundShrineChoicePacket {
|
||||
sanity.setInsanity(0);
|
||||
player.sendSystemMessage(Component.literal("YOUR MIND EXPANDS AS IT BREAKS."));
|
||||
RemembranceEssenceItem.consume(player);
|
||||
AscendAdvancements.grant(player, "use_shrine");
|
||||
} else {
|
||||
player.sendSystemMessage(Component.literal("YOUR MIND IS NOT YET CLEAR ENOUGH."));
|
||||
}
|
||||
@@ -76,6 +79,7 @@ public class ServerboundShrineChoicePacket {
|
||||
});
|
||||
player.sendSystemMessage(Component.literal("THE SHRINE RESTORES YOUR FRACTURED MIND."));
|
||||
RemembranceEssenceItem.consume(player);
|
||||
AscendAdvancements.grant(player, "use_shrine");
|
||||
} else {
|
||||
player.sendSystemMessage(Component.literal("YOU LACK THE KNOWLEDGE TO REST."));
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import net.fretux.ascend.player.StatEffects;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -41,11 +39,7 @@ public class ServerboundSpendPointPacket {
|
||||
player.setHealth(Math.min(player.getHealth() + gainedMaxHealth, player.getMaxHealth()));
|
||||
}
|
||||
}
|
||||
CompoundTag data = stats.serializeNBT();
|
||||
PacketHandler.INSTANCE.send(
|
||||
PacketDistributor.PLAYER.with(() -> player),
|
||||
new ClientboundSyncStatsPacket(data)
|
||||
);
|
||||
PlayerStatsProvider.sync(player);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,11 +13,14 @@ public class PlayerStats {
|
||||
"light_scaling", "medium_scaling", "heavy_scaling", "magic_scaling"
|
||||
};
|
||||
private final Map<String, Integer> attributes = new HashMap<>();
|
||||
private final Map<String, Integer> lastRespecBuild = new HashMap<>();
|
||||
private int ascendLevel = 1;
|
||||
private int ascendXP = 0;
|
||||
private int unspentPoints = getPointsPerLevel();
|
||||
private int maxAscendLevel = getConfiguredMaxAscendLevel();
|
||||
private int maxAttributePoints = getConfiguredMaxAttributePoints();
|
||||
private int respecCount = 0;
|
||||
private boolean everInvestedWeaponScaling = false;
|
||||
public PlayerStats() {
|
||||
for (String attr : ATTRIBUTE_KEYS) {
|
||||
attributes.put(attr, 0);
|
||||
@@ -77,6 +80,9 @@ public class PlayerStats {
|
||||
}
|
||||
unspentPoints -= 1;
|
||||
attributes.put(attribute, level + 1);
|
||||
if (isWeaponScaling(attribute)) {
|
||||
everInvestedWeaponScaling = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -100,6 +106,9 @@ public class PlayerStats {
|
||||
if (!attributes.containsKey(attribute)) return;
|
||||
int clamped = Math.max(0, Math.min(level, getMaxAttributePoints()));
|
||||
attributes.put(attribute, clamped);
|
||||
if (clamped > 0 && isWeaponScaling(attribute)) {
|
||||
everInvestedWeaponScaling = true;
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxMana() {
|
||||
@@ -133,14 +142,47 @@ public class PlayerStats {
|
||||
|
||||
public void refundAllPoints() {
|
||||
int totalSpent = 0;
|
||||
for (String key : attributes.keySet()) {
|
||||
int lvl = attributes.get(key);
|
||||
Map<String, Integer> refundedBuild = new HashMap<>();
|
||||
for (String key : ATTRIBUTE_KEYS) {
|
||||
int lvl = attributes.getOrDefault(key, 0);
|
||||
totalSpent += lvl;
|
||||
refundedBuild.put(key, lvl);
|
||||
attributes.put(key, 0);
|
||||
}
|
||||
if (totalSpent > 0) {
|
||||
lastRespecBuild.clear();
|
||||
lastRespecBuild.putAll(refundedBuild);
|
||||
respecCount++;
|
||||
}
|
||||
unspentPoints += totalSpent;
|
||||
}
|
||||
|
||||
public int getRespecCount() {
|
||||
return respecCount;
|
||||
}
|
||||
|
||||
public boolean hasEverInvestedWeaponScaling() {
|
||||
return everInvestedWeaponScaling;
|
||||
}
|
||||
|
||||
public boolean hasNearlyRestoredLastBuild() {
|
||||
if (lastRespecBuild.isEmpty()) return false;
|
||||
int originalTotal = 0;
|
||||
int currentTotal = 0;
|
||||
int totalDifference = 0;
|
||||
for (String key : ATTRIBUTE_KEYS) {
|
||||
int original = lastRespecBuild.getOrDefault(key, 0);
|
||||
int current = attributes.getOrDefault(key, 0);
|
||||
originalTotal += original;
|
||||
currentTotal += current;
|
||||
totalDifference += Math.abs(original - current);
|
||||
}
|
||||
int allowedDifference = Math.max(2, (int) Math.ceil(originalTotal * 0.05D));
|
||||
return originalTotal > 0 && currentTotal > 0
|
||||
&& currentTotal >= originalTotal - allowedDifference
|
||||
&& totalDifference <= allowedDifference;
|
||||
}
|
||||
|
||||
public boolean hasUsedMoonseye() {
|
||||
return hasUsedMoonseye;
|
||||
}
|
||||
@@ -159,11 +201,18 @@ public class PlayerStats {
|
||||
tag.putInt("MaxAttributePoints", getMaxAttributePoints());
|
||||
tag.putInt("Knowledge", knowledge);
|
||||
tag.putBoolean("HasUsedMoonseye", hasUsedMoonseye);
|
||||
tag.putInt("RespecCount", respecCount);
|
||||
tag.putBoolean("EverInvestedWeaponScaling", everInvestedWeaponScaling);
|
||||
CompoundTag attrTag = new CompoundTag();
|
||||
for (Map.Entry<String, Integer> entry : attributes.entrySet()) {
|
||||
attrTag.putInt(entry.getKey(), entry.getValue());
|
||||
}
|
||||
tag.put("Attributes", attrTag);
|
||||
CompoundTag respecBuildTag = new CompoundTag();
|
||||
for (Map.Entry<String, Integer> entry : lastRespecBuild.entrySet()) {
|
||||
respecBuildTag.putInt(entry.getKey(), entry.getValue());
|
||||
}
|
||||
tag.put("LastRespecBuild", respecBuildTag);
|
||||
return tag;
|
||||
}
|
||||
|
||||
@@ -189,6 +238,19 @@ public class PlayerStats {
|
||||
attributes.put(key, Math.max(0, Math.min(loaded, getMaxAttributePoints())));
|
||||
}
|
||||
}
|
||||
respecCount = Math.max(0, tag.getInt("RespecCount"));
|
||||
everInvestedWeaponScaling = tag.contains("EverInvestedWeaponScaling")
|
||||
? tag.getBoolean("EverInvestedWeaponScaling")
|
||||
: getAttributeLevel("light_scaling") > 0
|
||||
|| getAttributeLevel("medium_scaling") > 0
|
||||
|| getAttributeLevel("heavy_scaling") > 0;
|
||||
lastRespecBuild.clear();
|
||||
if (tag.contains("LastRespecBuild")) {
|
||||
CompoundTag respecBuildTag = tag.getCompound("LastRespecBuild");
|
||||
for (String key : ATTRIBUTE_KEYS) {
|
||||
lastRespecBuild.put(key, Math.max(0, respecBuildTag.getInt(key)));
|
||||
}
|
||||
}
|
||||
if (tag.contains("Knowledge")) {
|
||||
knowledge = Math.max(0, tag.getInt("Knowledge"));
|
||||
}
|
||||
@@ -212,4 +274,10 @@ public class PlayerStats {
|
||||
private static int getConfiguredMaxAttributePoints() {
|
||||
return AscendConfig.COMMON.maxAttributePoints.get();
|
||||
}
|
||||
|
||||
private static boolean isWeaponScaling(String attribute) {
|
||||
return "light_scaling".equals(attribute)
|
||||
|| "medium_scaling".equals(attribute)
|
||||
|| "heavy_scaling".equals(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package net.fretux.ascend.player;
|
||||
|
||||
import net.fretux.ascend.advancement.AscendAdvancements;
|
||||
import net.fretux.ascend.network.ClientboundSyncStatsPacket;
|
||||
import net.fretux.ascend.network.PacketHandler;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -43,6 +44,7 @@ public class PlayerStatsProvider implements ICapabilitySerializable<CompoundTag>
|
||||
return;
|
||||
}
|
||||
player.getCapability(PlayerStatsProvider.PLAYER_STATS).ifPresent(stats -> {
|
||||
AscendAdvancements.checkMilestones(serverPlayer, stats);
|
||||
CompoundTag data = stats.serializeNBT();
|
||||
PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> serverPlayer),
|
||||
new ClientboundSyncStatsPacket(data));
|
||||
|
||||
@@ -34,5 +34,63 @@
|
||||
"ascend.attribute.display": "%s: %s",
|
||||
"ascend.stats.knowledge": "Knowledge: %s",
|
||||
"item.ascend.remembrance_essence": "Remembrance Essence",
|
||||
"block.ascend.shrine_of_remembrance": "Shrine of Remembrance"
|
||||
"block.ascend.shrine_of_remembrance": "Shrine of Remembrance",
|
||||
|
||||
"advancements.ascend.first_steps.title": "A Flame, Barely Kindled",
|
||||
"advancements.ascend.first_steps.description": "Reach Ascend level 2",
|
||||
"advancements.ascend.level_5.title": "The Build Begins",
|
||||
"advancements.ascend.level_5.description": "Reach Ascend level 5",
|
||||
"advancements.ascend.level_10.title": "Beyond Mortal Limits",
|
||||
"advancements.ascend.level_10.description": "Reach Ascend level 10",
|
||||
"advancements.ascend.max_level.title": "This is Ascend",
|
||||
"advancements.ascend.max_level.description": "Reach the maximum Ascend level",
|
||||
"advancements.ascend.max_attribute.title": "Fear Not the One-Trick",
|
||||
"advancements.ascend.max_attribute.description": "Max out any Ascend attribute",
|
||||
"advancements.ascend.knowledge_100.title": "Things Man Was Not Meant to Know",
|
||||
"advancements.ascend.knowledge_100.description": "Accumulate 100 Knowledge",
|
||||
"advancements.ascend.read_moonseye_tome.title": "The Moon Gazes Back",
|
||||
"advancements.ascend.read_moonseye_tome.description": "Read a Moonseye Tome",
|
||||
"advancements.ascend.use_shrine.title": "I Forgor",
|
||||
"advancements.ascend.use_shrine.description": "Make a successful choice at a Shrine of Remembrance",
|
||||
|
||||
"advancements.ascend.bonk_scholar.title": "Bonk Scholar",
|
||||
"advancements.ascend.bonk_scholar.description": "Reach 100 Strength",
|
||||
"advancements.ascend.cannot_hit_what_you_cannot_see.title": "You Cannot Hit What You Cannot See",
|
||||
"advancements.ascend.cannot_hit_what_you_cannot_see.description": "Reach 100 Agility",
|
||||
"advancements.ascend.health_bar_enthusiast.title": "Health Bar Enthusiast",
|
||||
"advancements.ascend.health_bar_enthusiast.description": "Reach 100 Fortitude",
|
||||
"advancements.ascend.big_brain_small_helmet.title": "Big Brain Time",
|
||||
"advancements.ascend.big_brain_small_helmet.description": "Reach 100 Intelligence",
|
||||
"advancements.ascend.mana_without_purpose.title": "Mana Without Purpose",
|
||||
"advancements.ascend.mana_without_purpose.description": "Reach 50 Intelligence without Iron's Spells installed",
|
||||
"advancements.ascend.unlicensed_therapist.title": "Unlicensed Therapist",
|
||||
"advancements.ascend.unlicensed_therapist.description": "Reach 100 Willpower",
|
||||
"advancements.ascend.talk_no_jutsu.title": "Talk No Jutsu",
|
||||
"advancements.ascend.talk_no_jutsu.description": "Reach 100 Charisma",
|
||||
"advancements.ascend.perfectly_balanced.title": "Perfectly Balanced",
|
||||
"advancements.ascend.perfectly_balanced.description": "Invest exactly the same number of points in all ten attributes",
|
||||
"advancements.ascend.light_work.title": "Light Work",
|
||||
"advancements.ascend.light_work.description": "Reach 100 Light Scaling",
|
||||
"advancements.ascend.medium_rare.title": "Medium Rare",
|
||||
"advancements.ascend.medium_rare.description": "Reach 100 Medium Scaling",
|
||||
"advancements.ascend.compensating.title": "Compensating",
|
||||
"advancements.ascend.compensating.description": "Reach 100 Heavy Scaling",
|
||||
"advancements.ascend.quality_build.title": "Quality Build",
|
||||
"advancements.ascend.quality_build.description": "Reach 75 in all three weapon scaling attributes",
|
||||
"advancements.ascend.oops_all_magic.title": "Oops, All Magic",
|
||||
"advancements.ascend.oops_all_magic.description": "Reach 100 Magic Scaling before investing in weapon scaling",
|
||||
"advancements.ascend.glass_cannonical.title": "Glass Cannonical",
|
||||
"advancements.ascend.glass_cannonical.description": "Reach 90 Intelligence and Magic Scaling while keeping Fortitude below 10",
|
||||
"advancements.ascend.muscle_wizard.title": "Muscle Wizard",
|
||||
"advancements.ascend.muscle_wizard.description": "Reach 100 Strength and Magic Scaling",
|
||||
"advancements.ascend.optimized_casting_environment.title": "Optimized Casting Environment",
|
||||
"advancements.ascend.optimized_casting_environment.description": "Reach 80 Intelligence, Willpower, and Magic Scaling",
|
||||
"advancements.ascend.indecisive_chosen_one.title": "Indecisive Chosen One",
|
||||
"advancements.ascend.indecisive_chosen_one.description": "Respec ten times on the same character",
|
||||
"advancements.ascend.config_enjoyer.title": "Config Enjoyer",
|
||||
"advancements.ascend.config_enjoyer.description": "Make the intended progression unrecognizable",
|
||||
"advancements.ascend.game_journalist_mode.title": "Game Journalist Mode",
|
||||
"advancements.ascend.game_journalist_mode.description": "Set Ascend XP gain extremely high",
|
||||
"advancements.ascend.definition_of_insanity.title": "The Definition of Insanity",
|
||||
"advancements.ascend.definition_of_insanity.description": "Reset your attributes, then restore nearly the same build"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user