diff --git a/src/main/java/net/fretux/skillengine/capability/PlayerSkillData.java b/src/main/java/net/fretux/skillengine/capability/PlayerSkillData.java index d07801e..e6465de 100644 --- a/src/main/java/net/fretux/skillengine/capability/PlayerSkillData.java +++ b/src/main/java/net/fretux/skillengine/capability/PlayerSkillData.java @@ -1,5 +1,6 @@ package net.fretux.skillengine.capability; +import net.fretux.skillengine.network.PacketHandler; import net.fretux.skillengine.skilltree.AbilityNode; import net.fretux.skillengine.skilltree.SkillNode; import net.fretux.skillengine.skilltree.SkillNodeRegistry; @@ -7,6 +8,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; import java.util.HashSet; import java.util.Set; @@ -199,4 +201,8 @@ public class PlayerSkillData { activeTags.clear(); unlockedAbilities.clear(); } + + public void sync(ServerPlayer player) { + PacketHandler.syncSkillsTo(player); + } } \ No newline at end of file diff --git a/src/main/java/net/fretux/skillengine/client/SkilltreeClientState.java b/src/main/java/net/fretux/skillengine/client/SkilltreeClientState.java index 0932e02..6292e59 100644 --- a/src/main/java/net/fretux/skillengine/client/SkilltreeClientState.java +++ b/src/main/java/net/fretux/skillengine/client/SkilltreeClientState.java @@ -3,8 +3,6 @@ package net.fretux.skillengine.client; import net.fretux.skillengine.SkillEngine; import net.fretux.skillengine.capability.PlayerSkillData; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.components.toasts.SystemToast; -import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; @@ -34,14 +32,6 @@ public class SkilltreeClientState { if (mc.player != null) { mc.player.playSound(SoundEvents.EXPERIENCE_ORB_PICKUP, 1f, 1.2f); } - mc.getToasts().addToast( - SystemToast.multiline( - mc, - SystemToast.SystemToastIds.TUTORIAL_HINT, - Component.literal("Node Unlocked"), - Component.literal(id.toString()) - ) - ); } public static boolean isUnlocked(ResourceLocation id) { diff --git a/src/main/java/net/fretux/skillengine/client/SkilltreeScreen.java b/src/main/java/net/fretux/skillengine/client/SkilltreeScreen.java index 9d42cf1..7482296 100644 --- a/src/main/java/net/fretux/skillengine/client/SkilltreeScreen.java +++ b/src/main/java/net/fretux/skillengine/client/SkilltreeScreen.java @@ -135,7 +135,7 @@ public class SkilltreeScreen extends Screen { private void renderSkillPointHeader(GuiGraphics gfx) { int remaining = SkilltreeClientState.getCurrentSkillPoints(); - Component pointsText = Component.literal(remaining + " skillpoints remaining") + Component pointsText = Component.literal("Skillpoints Remaining: " + remaining) .withStyle(ChatFormatting.YELLOW); gfx.drawString(font, pointsText, 10, 10, 0xFFFFFF); } @@ -250,7 +250,9 @@ public class SkilltreeScreen extends Screen { tooltip.add(Component.literal("Mutually Exclusive with:") .withStyle(ChatFormatting.RED)); for (ResourceLocation ex : hoveredNode.getExclusiveWith()) { - tooltip.add(Component.literal(" - " + ex.toString()) + SkillNode other = SkillNodeRegistry.get(ex); + Component name = other != null ? other.getTitle() : Component.literal(ex.toString()); + tooltip.add(Component.literal(" - ").append(name.copy()) .withStyle(ChatFormatting.RED)); } } @@ -309,8 +311,41 @@ public class SkilltreeScreen extends Screen { gfx.fill(0, 0, width, height, 0x88000000); gfx.fill(x, y, x + OVERLAY_WIDTH, y + OVERLAY_HEIGHT, 0xFF222222); gfx.drawCenteredString(font, ability.getTitle(), x + OVERLAY_WIDTH / 2, y + 10, 0xFFFFFF); + int textY = y + 30; if (ability.getDescription() != null) { - gfx.drawWordWrap(font, ability.getDescription(), x + 10, y + 30, OVERLAY_WIDTH - 20, 0xDDDDDD); + gfx.drawWordWrap(font, ability.getDescription(), x + 10, textY, OVERLAY_WIDTH - 20, 0xDDDDDD); + textY += 60; + } + gfx.drawString(font, + Component.literal("Cooldown: " + ability.getCooldown() / 20 + " seconds") + .withStyle(ChatFormatting.AQUA), + x + 10, + textY, + 0xFFFFFF); + textY += 15; + if (!ability.getLinks().isEmpty()) { + gfx.drawString(font, + Component.literal("Requires:") + .withStyle(ChatFormatting.GOLD), + x + 10, + textY, + 0xFFFFFF); + textY += 12; + for (ResourceLocation parent : ability.getLinks()) { + SkillNode parentNode = SkillNodeRegistry.get(parent); + AbilityNode parentAbility = AbilityNodeRegistry.get(parent); + Component name = parentNode != null + ? parentNode.getTitle() + : parentAbility != null + ? parentAbility.getTitle() + : Component.literal(parent.toString()); + gfx.drawString(font, + Component.literal(" - ").append(name), + x + 10, + textY, + 0xFFFFFF); + textY += 12; + } } } diff --git a/src/main/java/net/fretux/skillengine/compat/AscendCompatHandler.java b/src/main/java/net/fretux/skillengine/compat/AscendCompatHandler.java index d8d7c35..3ebffb3 100644 --- a/src/main/java/net/fretux/skillengine/compat/AscendCompatHandler.java +++ b/src/main/java/net/fretux/skillengine/compat/AscendCompatHandler.java @@ -3,6 +3,7 @@ package net.fretux.skillengine.compat; import net.fretux.ascend.player.PlayerStatsProvider; import net.fretux.skillengine.SkillEngine; import net.fretux.skillengine.capability.SkillEngineCapabilities; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; import net.minecraftforge.event.TickEvent; import net.minecraftforge.event.entity.player.PlayerEvent; @@ -61,6 +62,7 @@ public class AscendCompatHandler { int pointsToGive = levelsGained * SKILL_POINTS_PER_ASCEND_LEVEL; player.getCapability(SkillEngineCapabilities.PLAYER_SKILLS).ifPresent(skillData -> { skillData.addSkillPoints(pointsToGive); + skillData.sync((ServerPlayer) player); }); } LAST_ASCEND_LEVEL.put(player.getUUID(), currentLevel); diff --git a/src/main/java/net/fretux/skillengine/network/ServerboundUnlockNodePacket.java b/src/main/java/net/fretux/skillengine/network/ServerboundUnlockNodePacket.java index ca0feeb..215f81d 100644 --- a/src/main/java/net/fretux/skillengine/network/ServerboundUnlockNodePacket.java +++ b/src/main/java/net/fretux/skillengine/network/ServerboundUnlockNodePacket.java @@ -12,7 +12,6 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraftforge.network.NetworkEvent; import net.minecraftforge.network.PacketDistributor; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; public class ServerboundUnlockNodePacket { @@ -32,16 +31,11 @@ public class ServerboundUnlockNodePacket { public static void handle(ServerboundUnlockNodePacket msg, Supplier ctx) { ctx.get().enqueueWork(() -> { - ServerPlayer player = ctx.get().getSender(); if (player == null) return; - SkillNode node = SkillNodeRegistry.get(msg.nodeId); AbilityNode ability = AbilityNodeRegistry.get(msg.nodeId); - player.getCapability(SkillEngineCapabilities.PLAYER_SKILLS).ifPresent(data -> { - - // === SKILL NODE UNLOCK === if (node != null) { if (canUnlockSkillNode(player, data, node)) { data.unlockNode(node); @@ -55,8 +49,6 @@ public class ServerboundUnlockNodePacket { } return; } - - // === ABILITY NODE UNLOCK === if (ability != null) { if (canUnlockAbility(player, data, ability)) { data.unlockAbility(ability); @@ -73,20 +65,41 @@ public class ServerboundUnlockNodePacket { }); ctx.get().setPacketHandled(true); } - + private static boolean canUnlockSkillNode(ServerPlayer player, PlayerSkillData data, SkillNode node) { - if (data.isUnlocked(node.getId())) return false; - if (data.getSkillPoints() < node.getCost()) return false; + if (data.isUnlocked(node.getId())) { + SkillEngine.LOGGER.debug("cannot unlock {}: already unlocked", node.getId()); + return false; + } + if (data.getSkillPoints() < node.getCost()) { + SkillEngine.LOGGER.debug("cannot unlock {}: not enough points (have {}, need {})", + node.getId(), data.getSkillPoints(), node.getCost()); + return false; + } for (ResourceLocation ex : node.getExclusiveWith()) { - if (data.isUnlocked(ex)) return false; + if (data.isUnlocked(ex)) { + SkillEngine.LOGGER.debug("cannot unlock {}: mutually exclusive with {} which is already unlocked", + node.getId(), ex); + return false; + } } for (ResourceLocation parent : node.getLinks()) { - if (!data.isUnlocked(parent)) return false; + if (!data.isUnlocked(parent)) { + SkillEngine.LOGGER.debug("cannot unlock {}: parent {} is not unlocked", + node.getId(), parent); + return false; + } } PlayerStats stats = player.getCapability(PlayerStatsProvider.PLAYER_STATS).orElse(null); - if (stats == null) return false; + if (stats == null) { + SkillEngine.LOGGER.debug("cannot unlock {}: no PlayerStats capability", node.getId()); + return false; + } for (var e : node.getPrereqAttributes().entrySet()) { - if (stats.getAttributeLevel(e.getKey()) < e.getValue()) { + int current = stats.getAttributeLevel(e.getKey()); + if (current < e.getValue()) { + SkillEngine.LOGGER.debug("cannot unlock {}: attribute {} is {}/{}", + node.getId(), e.getKey(), current, e.getValue()); return false; } }